Updated the voting and event decryption pages. On the voting page, added the ability to vote by selecting checkboxes instead of a drop down select menu. This adds flexibility at event creation to specify a wide range of min and max option selections for polls. On the event decryption page, SK validation was added based on the stored trustee PK as well as a dialog to display any validation errors. Most of the updates took place behind the scenes at the backend.

This commit is contained in:
vince0656 2018-07-13 17:19:35 +01:00
parent 3fd9173666
commit 745fdf06b1
10 changed files with 503 additions and 152 deletions

View file

@ -51,7 +51,7 @@ class Event(models.Model):
try:
EID_json = json.loads(self.EID)
EID_crypto_str = EID_json['crypto']
return json.loads(EID_crypto_str)
return json.dumps(json.loads(EID_crypto_str))
except ValueError:
return "None - Event not Initialised"
@ -213,8 +213,13 @@ class EncryptedVote(models.Model):
ballot = models.ForeignKey(Ballot, on_delete=models.CASCADE, related_name="encrypted_vote")
class CombinedEncryptedVote(models.Model):
ballot = models.ForeignKey(Ballot, on_delete=models.CASCADE, related_name="comb_encrypted_vote")
class VoteFragment(models.Model):
encrypted_vote = models.ForeignKey(EncryptedVote, on_delete=models.CASCADE, related_name="fragment")
encrypted_vote = models.ForeignKey(EncryptedVote, on_delete=models.CASCADE, related_name="fragment", null=True)
comb_encrypted_vote = models.ForeignKey(CombinedEncryptedVote, on_delete=models.CASCADE, related_name="fragment", null=True)
cipher_text_c1 = models.CharField(max_length=4096)
cipher_text_c2 = models.CharField(max_length=4096)

View file

@ -7,7 +7,7 @@ from celery import task
from django.conf import settings
from allauthdemo.polls.models import AccessKey, Ballot, CombinedBallot, PartialBallotDecryption
from allauthdemo.polls.models import AccessKey, Ballot, CombinedBallot, PartialBallotDecryption, EncryptedVote, CombinedEncryptedVote, VoteFragment
from .crypto_rpc import param, combpk, add_ciphers, get_tally
@ -58,6 +58,7 @@ def email_trustees_dec(event):
trustee.send_email(email_subject, email_body)
def get_email_sign_off():
sign_off = str("")
sign_off += "\n\nPlease note: This email address is not monitored so please don't reply to this email.\n\n"
@ -66,6 +67,7 @@ def get_email_sign_off():
return sign_off
'''
Combines all of the voter ballots for a poll option into a single 'CombinedBallot'
'''
@ -83,7 +85,7 @@ def combine_ballots(polls):
frags_c2 = list()
for ballot in ballots:
enc_vote = ballot.encrypted_vote.get()
enc_vote = ballot.comb_encrypted_vote.get()
if enc_vote is not None:
fragments = enc_vote.fragment.all()
@ -102,6 +104,34 @@ def combine_ballots(polls):
cipher_text_c1=combined_cipher['C1'],
cipher_text_c2=combined_cipher['C2'])
@task()
def combine_encrypted_votes(voter, poll):
poll_options_count = poll.options.all().count()
ballot = Ballot.objects.get_or_create(voter=voter, poll=poll)[0]
e_votes = EncryptedVote.objects.filter(ballot=ballot)
CombinedEncryptedVote.objects.filter(ballot=ballot).delete()
comb_e_vote = CombinedEncryptedVote.objects.create(ballot=ballot)
for i in range(poll_options_count):
frags_c1 = list()
frags_c2 = list()
for e_vote in e_votes:
fragments = e_vote.fragment.all()
frags_c1.append(fragments[i].cipher_text_c1)
frags_c2.append(fragments[i].cipher_text_c2)
ciphers = {
'c1s': frags_c1,
'c2s': frags_c2
}
combined_cipher = add_ciphers(ciphers)
VoteFragment.objects.create(comb_encrypted_vote=comb_e_vote,
cipher_text_c1=combined_cipher['C1'],
cipher_text_c2=combined_cipher['C2'])
@task()
def create_ballots(event):
voters = event.voters.all()

View file

@ -11,11 +11,11 @@ from django.views import generic
from django.conf import settings
from .forms import PollForm, OptionFormset, VoteForm, EventSetupForm, EventEditForm
from .models import Event, Poll, Ballot, EncryptedVote, TrusteeKey, PartialBallotDecryption, CombinedBallot
from .models import Event, Poll, Ballot, EncryptedVote, TrusteeKey, PartialBallotDecryption, CombinedBallot, VoteFragment
from allauthdemo.auth.models import DemoUser
from .tasks import email_trustees_prep, update_EID, generate_combpk, event_ended, create_ballots
from .tasks import create_ballots_for_poll, email_voters_vote_url, combine_decryptions_and_tally
from .tasks import create_ballots_for_poll, email_voters_vote_url, combine_decryptions_and_tally, combine_encrypted_votes
from .utils.EventModelAdaptor import EventModelAdaptor
@ -153,39 +153,35 @@ def event_vote(request, event_id, poll_id):
cant_vote_reason = "The event either isn't ready for voting or it has expired and therefore you cannot vote."
if request.method == "POST":
ballot = Ballot.objects.get_or_create(voter=email_key[0].user, poll=poll)[0]
data = json.loads(request.POST.lists()[0][0])
ballot_json = data['ballot']
encrypted_votes_json = ballot_json['encryptedVotes']
# Will store the fragments of the encoding scheme that define the vote
encrypted_vote = EncryptedVote.objects.get_or_create(ballot=ballot)[0]
# Before storing the encrypted votes, we need the voter's ballot
ballot, created = Ballot.objects.get_or_create(voter=email_key[0].user, poll=poll)
EncryptedVote.objects.filter(ballot=ballot).delete()
# Clear any existing fragments - a voter changing their vote
encrypted_vote.fragment.all().delete()
for e_vote in encrypted_votes_json:
# Will store the fragments of the encoding scheme that define the vote
encrypted_vote = EncryptedVote.objects.create(ballot=ballot)
fragments_json = e_vote['fragments']
# Add in the new ciphers
fragment_count = int(request.POST['vote_frag_count'])
for i in range(fragment_count):
i_str = str(i)
cipher_c1 = request.POST['cipher_c1_frag_' + i_str]
cipher_c2 = request.POST['cipher_c2_frag_' + i_str]
encrypted_vote.fragment.create(encrypted_vote=encrypted_vote,
cipher_text_c1=cipher_c1,
cipher_text_c2=cipher_c2)
for fragment in fragments_json:
VoteFragment.objects.create(encrypted_vote=encrypted_vote,
cipher_text_c1=fragment['C1'],
cipher_text_c2=fragment['C2'])
ballot.cast = True
ballot.save()
combine_encrypted_votes.delay(email_key[0].user, poll)
if next_poll_uuid:
return HttpResponseRedirect(reverse('polls:event-vote', kwargs={'event_id': event.uuid,
'poll_id': next_poll_uuid})
+ "?key=" + email_key_str)
else:
# The user has finished voting in the event
success_msg = 'You have successfully cast your vote(s)!'
messages.add_message(request, messages.SUCCESS, success_msg)
return HttpResponseRedirect(reverse("user_home"))
return HttpResponse('Voted Successfully!')
return render(request, "polls/event_vote.html",
{
@ -273,16 +269,20 @@ def event_trustee_decrypt(request, event_id):
if access_key:
email_key = event.keys.filter(key=access_key)
trustee = email_key[0].user
if email_key.exists() and event.users_trustees.filter(email=email_key[0].user.email).exists():
if email_key.exists() and event.users_trustees.filter(email=trustee.email).exists():
if PartialBallotDecryption.objects.filter(event=event, user=email_key[0].user).count() == event.total_num_opts():
if PartialBallotDecryption.objects.filter(event=event, user=trustee).count() == event.total_num_opts():
warning_msg = 'You have already provided your decryption key for this event - Thank You'
messages.add_message(request, messages.WARNING, warning_msg)
return HttpResponseRedirect(reverse("user_home"))
elif request.method == "GET":
# Get the Trustee's original PK - used in the template for SK validation
trustee_pk = TrusteeKey.objects.get(event=event, user=trustee).key
# Gen a list of ciphers from the combined ballots for every opt of every poll
polls = event.polls.all()
poll_ciphers = []
@ -305,7 +305,8 @@ def event_trustee_decrypt(request, event_id):
"polls/event_decrypt.html",
{
"event": event,
"user_email": email_key[0].user.email,
"user_email": trustee.email,
"trustee_pk": trustee_pk,
"poll_ciphers": poll_ciphers
})
@ -318,7 +319,7 @@ def event_trustee_decrypt(request, event_id):
options_count = len(options)
for j in range(options_count):
input_name = ""
input_name = str("")
input_name = "poll-" + str(i) + "-cipher-" + str(j)
part_dec = request.POST[input_name]
@ -326,7 +327,7 @@ def event_trustee_decrypt(request, event_id):
PartialBallotDecryption.objects.create(event=event,
poll=polls[i],
option=options[j],
user=email_key[0].user,
user=trustee,
text=part_dec)
if event.all_part_decs_received():