From fc4366c02869bdeb5852142fc51ffbaf82bf4005 Mon Sep 17 00:00:00 2001 From: RunasSudo Date: Sat, 16 Oct 2021 20:44:31 +1100 Subject: [PATCH] Allow hiding voters and/or votes --- eos/base/election.py | 5 +++ eos/psr/election.py | 3 ++ eosweb/core/main.py | 31 +++++++++++++++---- .../core/static/nunjucks/booth/complete.html | 6 +++- eosweb/core/templates/election/core/tabs.html | 10 ++++-- .../core/templates/election/view/ballots.html | 28 ++++++++++------- 6 files changed, 63 insertions(+), 20 deletions(-) diff --git a/eos/base/election.py b/eos/base/election.py index d052c82..3348f93 100644 --- a/eos/base/election.py +++ b/eos/base/election.py @@ -214,6 +214,8 @@ class STVResult(Result): random = BlobField() class Election(TopLevelObject): + _ver = StringField(default='0.9') + _id = UUIDField() workflow = EmbeddedObjectField(Workflow) # Once saved, we don't care what kind of workflow it is name = StringField() @@ -222,6 +224,9 @@ class Election(TopLevelObject): questions = EmbeddedObjectListField() results = EmbeddedObjectListField(is_hashed=False) + is_voters_public = BooleanField(is_hashed=False, default=False) + is_votes_public = BooleanField(is_hashed=False, default=False) + def can_audit(self): """Can prepared votes be audited?""" return False diff --git a/eos/psr/election.py b/eos/psr/election.py index 465a73b..c0917d4 100644 --- a/eos/psr/election.py +++ b/eos/psr/election.py @@ -225,6 +225,9 @@ class InternalMixingTrustee(MixingTrustee): return True class PSRElection(Election): + is_voters_public = BooleanField(is_hashed=False, default=True) + is_votes_public = BooleanField(is_hashed=False, default=True) + sk = EmbeddedObjectField(SEGPrivateKey, is_protected=True) # TODO: Threshold public_key = EmbeddedObjectField(SEGPublicKey) diff --git a/eosweb/core/main.py b/eosweb/core/main.py index 4ca3a48..0c7744d 100644 --- a/eosweb/core/main.py +++ b/eosweb/core/main.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 @@ -255,7 +255,20 @@ def elections_batch(): @using_election def election_api_json(election): is_full = 'full' in flask.request.args - return flask.Response(EosObject.to_json(EosObject.serialise_and_wrap(election, None, SerialiseOptions(should_protect=True, for_hash=(not is_full), combine_related=True))), mimetype='application/json') + + serialised = EosObject.serialise_and_wrap(election, None, SerialiseOptions(should_protect=True, for_hash=(not is_full), combine_related=True)) + + # Protect voters, votes if required + if not election.is_voters_public: + if 'voters' in serialised['value']: + del serialised['value']['voters'] + if not election.is_votes_public: + if 'voters' in serialised['value']: + for voter in serialised['value']['voters']: + if 'votes' in voter['value']: + del voter['value']['votes'] + + return flask.Response(EosObject.to_json(serialised), mimetype='application/json') @app.route('/election//view') @using_election @@ -278,14 +291,20 @@ def election_view_questions(election): @app.route('/election//view/ballots') @using_election def election_view_ballots(election): - return flask.render_template('election/view/ballots.html', election=election) + if election.is_voters_public or ('user' in flask.session and flask.session['user'].is_admin()): + return flask.render_template('election/view/ballots.html', election=election) + + return flask.Response('Voters not public', 403) @app.route('/election//voter/') @using_election def election_voter_view(election, voter_id): - voter_id = uuid.UUID(voter_id) - voter = next(voter for voter in election.voters if voter._id == voter_id) - return flask.render_template('election/voter/view.html', election=election, voter=voter) + if (election.is_voters_public and election.is_votes_public) or ('user' in flask.session and flask.session['user'].is_admin()): + voter_id = uuid.UUID(voter_id) + voter = next(voter for voter in election.voters if voter._id == voter_id) + return flask.render_template('election/voter/view.html', election=election, voter=voter) + + return flask.Response('Voters not public', 403) @app.route('/election//view/trustees') @using_election diff --git a/eosweb/core/static/nunjucks/booth/complete.html b/eosweb/core/static/nunjucks/booth/complete.html index 3e0da0e..605c713 100644 --- a/eosweb/core/static/nunjucks/booth/complete.html +++ b/eosweb/core/static/nunjucks/booth/complete.html @@ -39,7 +39,11 @@ {% endblock %} {% block buttons %} - Finish + {% if election.is_votes_public %} + Finish + {% else %} + Finish + {% endif %} {% endblock %} {% block after %} diff --git a/eosweb/core/templates/election/core/tabs.html b/eosweb/core/templates/election/core/tabs.html index 9add19b..3a44bf4 100644 --- a/eosweb/core/templates/election/core/tabs.html +++ b/eosweb/core/templates/election/core/tabs.html @@ -1,6 +1,6 @@ {# 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 @@ -19,5 +19,11 @@ {% block tabs %} {{ tab('Overview', 'election_view') }} {{ tab('Questions', 'election_view_questions') }} - {{ tab('Voters and ballots', 'election_view_ballots') }} + {% if election.is_voters_public or (session.user and session.user.is_admin()) %} + {% if election.is_votes_public or (session.user and session.user.is_admin()) %} + {{ tab('Voters and ballots', 'election_view_ballots') }} + {% else %} + {{ tab('Voters', 'election_view_ballots') }} + {% endif %} + {% endif %} {% endblock %} diff --git a/eosweb/core/templates/election/view/ballots.html b/eosweb/core/templates/election/view/ballots.html index 3de2920..ce04eff 100644 --- a/eosweb/core/templates/election/view/ballots.html +++ b/eosweb/core/templates/election/view/ballots.html @@ -2,7 +2,7 @@ {# 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 @@ -23,21 +23,27 @@ Voter - Ballot fingerprint + {% if election.is_votes_public or (session.user and session.user.is_admin()) %} + Ballot fingerprint + {% endif %} {% for voter in election.voters %} - {{ voter.name }} - {% set votes = voter.votes.get_all() %} - - {% if votes|length > 0 %} - {{ SHA256().update_obj(votes[-1].ballot).hash_as_b64(True) }} - {% else %} -   - {% endif %} - + {% if election.is_votes_public or (session.user and session.user.is_admin()) %} + {{ voter.name }} + {% set votes = voter.votes.get_all() %} + + {% if votes|length > 0 %} + {{ SHA256().update_obj(votes[-1].ballot).hash_as_b64(True) }} + {% else %} +   + {% endif %} + + {% else %} + {{ voter.name }} + {% endif %} {% endfor %}