diff --git a/eos/base/election.py b/eos/base/election.py index df9b0ff..d052c82 100644 --- a/eos/base/election.py +++ b/eos/base/election.py @@ -1,5 +1,5 @@ # Eos - Verifiable elections -# Copyright © 2017-2019 RunasSudo (Yingtong Li) +# Copyright © 2017-2021 RunasSudo (Yingtong Li) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by @@ -29,6 +29,9 @@ class NullEncryptedAnswer(EncryptedAnswer): def decrypt(self): return None, self.answer + + def deaudit(self): + return self class Ballot(EmbeddedObject): #_id = UUIDField() @@ -219,6 +222,10 @@ class Election(TopLevelObject): questions = EmbeddedObjectListField() results = EmbeddedObjectListField(is_hashed=False) + def can_audit(self): + """Can prepared votes be audited?""" + return False + def verify(self): #__pragma__('skip') from eos.core.hashing import SHA256 diff --git a/eos/base/tests.py b/eos/base/tests.py index b4980d0..64fc5f5 100644 --- a/eos/base/tests.py +++ b/eos/base/tests.py @@ -1,5 +1,5 @@ # Eos - Verifiable elections -# Copyright © 2017-18 RunasSudo (Yingtong Li) +# Copyright © 2017-2021 RunasSudo (Yingtong Li) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by @@ -38,7 +38,7 @@ class ElectionTestCase(EosTestCase): def test_run_election(self): # Set up election election = Election() - election.workflow = WorkflowBase() + election.workflow = BaseWorkflow() # Check _instance self.assertEqual(election.workflow._instance, (election, 'workflow')) diff --git a/eos/base/workflow.py b/eos/base/workflow.py index 2b2290e..70e546f 100644 --- a/eos/base/workflow.py +++ b/eos/base/workflow.py @@ -1,5 +1,5 @@ # Eos - Verifiable elections -# Copyright © 2017-18 RunasSudo (Yingtong Li) +# Copyright © 2017-2021 RunasSudo (Yingtong Li) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by @@ -58,7 +58,12 @@ class WorkflowTask(EmbeddedObject): def are_dependencies_met(self): for depends_on_desc in self.depends_on: - for depends_on_task in self.workflow.get_tasks(depends_on_desc): + depends_on_tasks = list(self.workflow.get_tasks(depends_on_desc)) + + if len(depends_on_tasks) == 0: + return False + + for depends_on_task in depends_on_tasks: if depends_on_task.status is not WorkflowTaskStatus.EXITED: return False return True @@ -184,7 +189,9 @@ class TaskReleaseResults(WorkflowTask): # Concrete workflows # ================== -class WorkflowBase(Workflow): +class BaseWorkflow(Workflow): + """Base workflow, with no encryption""" + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) diff --git a/eos/psr/election.py b/eos/psr/election.py index f54ef3c..465a73b 100644 --- a/eos/psr/election.py +++ b/eos/psr/election.py @@ -1,5 +1,5 @@ # Eos - Verifiable elections -# Copyright © 2017 RunasSudo (Yingtong Li) +# Copyright © 2017-2021 RunasSudo (Yingtong Li) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by @@ -230,7 +230,12 @@ class PSRElection(Election): public_key = EmbeddedObjectField(SEGPublicKey) mixing_trustees = EmbeddedObjectListField() + def can_audit(self): + """Overrides Election.can_audit""" + return True + def verify(self): + """Overrides Election.verify""" # Verify ballots super().verify() diff --git a/eosweb/core/static/js/booth_worker.js b/eosweb/core/static/js/booth_worker.js index 1d505b9..b8fa9a3 100644 --- a/eosweb/core/static/js/booth_worker.js +++ b/eosweb/core/static/js/booth_worker.js @@ -1,6 +1,6 @@ /* Eos - Verifiable elections - Copyright © 2017-2019 RunasSudo (Yingtong Li) + Copyright © 2017-2021 RunasSudo (Yingtong Li) This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by @@ -22,17 +22,34 @@ isLibrariesLoaded = false; eosjs = null; function generateEncryptedVote(election, answers, should_do_fingerprint) { - encrypted_answers = []; - for (var q_num = 0; q_num < answers.length; q_num++) { - answer_json = answers[q_num]; - answer = eosjs.eos.core.objects.EosObject.deserialise_and_unwrap(answer_json, null); - encrypted_answer = eosjs.eos.psr.election.BlockEncryptedAnswer.encrypt(election.public_key, answer, election.questions.__getitem__(q_num).max_bits() + 32); // +32 bits for the length - encrypted_answers.push(eosjs.eos.core.objects.EosObject.serialise_and_wrap(encrypted_answer, null)); + if (election._name === 'eos.psr.election.PSRElection') { + encrypted_answers = []; + for (var q_num = 0; q_num < answers.length; q_num++) { + answer_json = answers[q_num]; + answer = eosjs.eos.core.objects.EosObject.deserialise_and_unwrap(answer_json, null); + encrypted_answer = eosjs.eos.psr.election.BlockEncryptedAnswer.encrypt(election.public_key, answer, election.questions.__getitem__(q_num).max_bits() + 32); // +32 bits for the length + encrypted_answers.push(eosjs.eos.core.objects.EosObject.serialise_and_wrap(encrypted_answer, null)); + } + + postMessage({ + encrypted_answers: encrypted_answers + }); + } else if (election._name === 'eos.base.election.Election') { + encrypted_answers = []; + for (var q_num = 0; q_num < answers.length; q_num++) { + answer_json = answers[q_num]; + answer = eosjs.eos.core.objects.EosObject.deserialise_and_unwrap(answer_json, null); + encrypted_answer = eosjs.eos.base.election.NullEncryptedAnswer(); + encrypted_answer.answer = answer; + encrypted_answers.push(eosjs.eos.core.objects.EosObject.serialise_and_wrap(encrypted_answer, null)); + } + + postMessage({ + encrypted_answers: encrypted_answers + }); + } else { + throw "Don't know how to encrypt ballots in election of type " + election._name; } - - postMessage({ - encrypted_answers: encrypted_answers - }); } onmessage = function(msg) { diff --git a/eosweb/core/static/nunjucks/booth/base.html b/eosweb/core/static/nunjucks/booth/base.html index d9b3897..6953205 100644 --- a/eosweb/core/static/nunjucks/booth/base.html +++ b/eosweb/core/static/nunjucks/booth/base.html @@ -1,6 +1,6 @@ {# Eos - Verifiable elections - Copyright © 2017-2019 RunasSudo (Yingtong Li) + Copyright © 2017-2021 RunasSudo (Yingtong Li) This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by @@ -32,9 +32,17 @@ {% elif template == 'booth/audit.html' %} {% set menuindex = 4 %} {% elif template == 'booth/cast.html' %} - {% set menuindex = 5 %} + {% if election.can_audit() %} + {% set menuindex = 5 %} + {% else %} + {% set menuindex = 4 %} + {% endif %} {% elif template == 'booth/complete.html' %} - {% set menuindex = 6 %} + {% if election.can_audit() %} + {% set menuindex = 6 %} + {% else %} + {% set menuindex = 5 %} + {% endif %} {% endif %} {% macro menuitem(index, text) %} @@ -50,9 +58,14 @@ {{ menuitem(1, "Welcome") }} {{ menuitem(2, "Select") }} {{ menuitem(3, "Review") }} - {{ menuitem(4, "Audit") }} - {{ menuitem(5, "Cast") }} - {{ menuitem(6, "Finish") }} + {% if election.can_audit() %} + {{ menuitem(4, "Audit") }} + {{ menuitem(5, "Cast") }} + {{ menuitem(6, "Finish") }} + {% else %} + {{ menuitem(4, "Cast") }} + {{ menuitem(5, "Finish") }} + {% endif %}
diff --git a/eosweb/core/static/nunjucks/booth/cast.html b/eosweb/core/static/nunjucks/booth/cast.html index 9a78604..15362d7 100644 --- a/eosweb/core/static/nunjucks/booth/cast.html +++ b/eosweb/core/static/nunjucks/booth/cast.html @@ -2,7 +2,7 @@ {# Eos - Verifiable elections - Copyright © 2017-2019 RunasSudo (Yingtong Li) + Copyright © 2017-2021 RunasSudo (Yingtong Li) This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by @@ -20,7 +20,7 @@ {% block content %}
-

Your vote has not yet been cast. Please make a note of your ballot fingerprint, {{ eosjs.eos.core.hashing.SHA256().update_obj(ballot).hash_as_b64(true) }}.

+

Your vote has not yet been cast.{% if election.can_audit() %} Please make a note of your ballot fingerprint, {{ eosjs.eos.core.hashing.SHA256().update_obj(ballot).hash_as_b64(true) }}.{% endif %}

Your vote has not yet been cast. Please follow the instructions to continue.

@@ -69,10 +69,12 @@ {% endblock %} {% block after %} -
-
Information for advanced users
-

Your full ballot fingerprint is {{ eosjs.eos.core.hashing.SHA256().update_obj(ballot).hash_as_b64() }}.

-
+ {% if election.can_audit() %} +
+
Information for advanced users
+

Your full ballot fingerprint is {{ eosjs.eos.core.hashing.SHA256().update_obj(ballot).hash_as_b64() }}.

+
+ {% endif %}