ajg
This commit is contained in:
parent
dff885437e
commit
08b5985396
9 changed files with 704 additions and 562 deletions
|
@ -11,223 +11,223 @@ from allauthdemo.auth.models import DemoUser
|
||||||
|
|
||||||
|
|
||||||
class EmailUser(models.Model):
|
class EmailUser(models.Model):
|
||||||
email = models.CharField(max_length=80, unique=True)
|
email = models.CharField(max_length=80, unique=True)
|
||||||
|
|
||||||
def send_email(self, subject, message, from_email=None):
|
def send_email(self, subject, message, from_email=None):
|
||||||
"""
|
"""
|
||||||
Sends an email to this User.
|
Sends an email to this User.
|
||||||
"""
|
"""
|
||||||
send_mail(subject, message, from_email, [self.email])
|
send_mail(subject, message, from_email, [self.email])
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.email
|
return self.email
|
||||||
|
|
||||||
|
|
||||||
class Event(models.Model):
|
class Event(models.Model):
|
||||||
users_organisers = models.ManyToManyField(DemoUser, blank=True, related_name="organisers")
|
users_organisers = models.ManyToManyField(DemoUser, blank=True, related_name="organisers")
|
||||||
users_trustees = models.ManyToManyField(EmailUser, blank=True, related_name="trustees")
|
users_trustees = models.ManyToManyField(EmailUser, blank=True, related_name="trustees")
|
||||||
voters = models.ManyToManyField(EmailUser, blank=True, related_name="voters")
|
voters = models.ManyToManyField(EmailUser, blank=True, related_name="voters")
|
||||||
start_time = models.DateTimeField()
|
start_time = models.DateTimeField()
|
||||||
end_time = models.DateTimeField()
|
end_time = models.DateTimeField()
|
||||||
prepared = models.BooleanField(default=False)
|
prepared = models.BooleanField(default=False)
|
||||||
ended = models.BooleanField(default=False)
|
ended = models.BooleanField(default=False)
|
||||||
public_key = models.CharField(null=True, blank=False, max_length=1024)
|
public_key = models.CharField(null=True, blank=False, max_length=1024)
|
||||||
title = models.CharField(max_length=1024)
|
title = models.CharField(max_length=1024)
|
||||||
EID = models.CharField(max_length=2048, blank=True)
|
EID = models.CharField(max_length=2048, blank=True)
|
||||||
creator = models.CharField(max_length=256, blank=True)
|
creator = models.CharField(max_length=256, blank=True)
|
||||||
c_email = models.CharField(max_length=512, blank=True)
|
c_email = models.CharField(max_length=512, blank=True)
|
||||||
trustees = models.CharField(max_length=4096)
|
trustees = models.CharField(max_length=4096)
|
||||||
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||||
|
|
||||||
# Custom helper methods
|
# Custom helper methods
|
||||||
def EID_hr(self):
|
def EID_hr(self):
|
||||||
try:
|
try:
|
||||||
EID_json = json.loads(self.EID)
|
EID_json = json.loads(self.EID)
|
||||||
return EID_json['hr']
|
return EID_json['hr']
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return self.EID
|
return self.EID
|
||||||
|
|
||||||
def EID_crypto(self):
|
def EID_crypto(self):
|
||||||
try:
|
try:
|
||||||
EID_json = json.loads(self.EID)
|
EID_json = json.loads(self.EID)
|
||||||
EID_crypto_str = EID_json['crypto']
|
EID_crypto_str = EID_json['crypto']
|
||||||
return json.dumps(json.loads(EID_crypto_str))
|
return json.dumps(json.loads(EID_crypto_str))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return "None - Event not Initialised"
|
return "None - Event not Initialised"
|
||||||
|
|
||||||
def duration(self):
|
def duration(self):
|
||||||
duration_str = self.start_time_formatted()
|
duration_str = self.start_time_formatted()
|
||||||
duration_str = duration_str + " - " + self.end_time_formatted_utc()
|
duration_str = duration_str + " - " + self.end_time_formatted_utc()
|
||||||
return duration_str
|
return duration_str
|
||||||
|
|
||||||
def start_time_formatted(self):
|
def start_time_formatted(self):
|
||||||
return self.start_time.strftime("%d-%m-%y %H:%M")
|
return self.start_time.strftime("%d-%m-%y %H:%M")
|
||||||
|
|
||||||
def start_time_formatted_utc(self):
|
def start_time_formatted_utc(self):
|
||||||
return self.start_time.strftime("%d-%m-%y %H:%M %Z")
|
return self.start_time.strftime("%d-%m-%y %H:%M %Z")
|
||||||
|
|
||||||
def end_time_formatted(self):
|
def end_time_formatted(self):
|
||||||
return self.end_time.strftime("%d-%m-%y %H:%M")
|
return self.end_time.strftime("%d-%m-%y %H:%M")
|
||||||
|
|
||||||
def end_time_formatted_utc(self):
|
def end_time_formatted_utc(self):
|
||||||
return self.end_time.strftime("%d-%m-%y %H:%M %Z")
|
return self.end_time.strftime("%d-%m-%y %H:%M %Z")
|
||||||
|
|
||||||
# Total number of options in all polls
|
# Total number of options in all polls
|
||||||
def total_num_opts(self):
|
def total_num_opts(self):
|
||||||
polls = self.polls.all()
|
polls = self.polls.all()
|
||||||
count = 0
|
count = 0
|
||||||
|
|
||||||
for poll in polls:
|
for poll in polls:
|
||||||
count += poll.options.all().count()
|
count += poll.options.all().count()
|
||||||
|
|
||||||
return count
|
return count
|
||||||
|
|
||||||
def total_num_partial_decs(self):
|
def total_num_partial_decs(self):
|
||||||
polls = self.polls.all()
|
polls = self.polls.all()
|
||||||
count = 0
|
count = 0
|
||||||
|
|
||||||
for poll in polls:
|
for poll in polls:
|
||||||
count += PartialBallotDecryption.objects.filter(poll=poll).count()
|
count += PartialBallotDecryption.objects.filter(poll=poll).count()
|
||||||
|
|
||||||
return count
|
return count
|
||||||
|
|
||||||
def all_part_decs_received(self):
|
def all_part_decs_received(self):
|
||||||
received = False
|
received = False
|
||||||
|
|
||||||
if self.total_num_partial_decs() == self.total_num_opts() * self.users_trustees.all().count():
|
if self.total_num_partial_decs() == self.total_num_opts() * self.users_trustees.all().count():
|
||||||
received = True
|
received = True
|
||||||
|
|
||||||
return received
|
return received
|
||||||
|
|
||||||
def status(self):
|
def status(self):
|
||||||
status_str = ""
|
status_str = ""
|
||||||
|
|
||||||
# Get the current date and time to compare against to establish if this is a past, current or
|
# Get the current date and time to compare against to establish if this is a past, current or
|
||||||
# future event. Prepared means the public key has been initialised
|
# future event. Prepared means the public key has been initialised
|
||||||
present = timezone.now()
|
present = timezone.now()
|
||||||
|
|
||||||
if self.ended is False:
|
if self.ended is False:
|
||||||
if present < self.start_time and self.prepared is False:
|
if present < self.start_time and self.prepared is False:
|
||||||
status_str = "Future"
|
status_str = "Future"
|
||||||
elif present < self.start_time and self.prepared is True:
|
elif present < self.start_time and self.prepared is True:
|
||||||
status_str = "Prepared"
|
status_str = "Prepared"
|
||||||
elif present >= self.start_time and present <= self.end_time and self.prepared is True:
|
elif present >= self.start_time and present <= self.end_time and self.prepared is True:
|
||||||
status_str = "Active"
|
status_str = "Active"
|
||||||
elif present >= self.start_time and present <= self.end_time and self.prepared is False:
|
elif present >= self.start_time and present <= self.end_time and self.prepared is False:
|
||||||
status_str = "Future"
|
status_str = "Future"
|
||||||
elif present > self.end_time:
|
elif present > self.end_time:
|
||||||
status_str = "Expired"
|
status_str = "Expired"
|
||||||
else:
|
else:
|
||||||
if self.all_part_decs_received():
|
if self.all_part_decs_received():
|
||||||
status_str = "Decrypted"
|
status_str = "Decrypted"
|
||||||
else:
|
else:
|
||||||
status_str = "Ended"
|
status_str = "Ended"
|
||||||
|
|
||||||
return status_str
|
return status_str
|
||||||
|
|
||||||
'''
|
'''
|
||||||
The result applies to all polls for an event so True will only be returned when votes have
|
The result applies to all polls for an event so True will only be returned when votes have
|
||||||
been received for every poll.
|
been received for every poll.
|
||||||
'''
|
'''
|
||||||
def has_received_votes(self):
|
def has_received_votes(self):
|
||||||
received_votes = True
|
received_votes = True
|
||||||
|
|
||||||
for poll in self.polls.all():
|
for poll in self.polls.all():
|
||||||
if Ballot.objects.filter(poll=poll, cast=True).count() == 0:
|
if Ballot.objects.filter(poll=poll, cast=True).count() == 0:
|
||||||
received_votes = False
|
received_votes = False
|
||||||
|
|
||||||
return received_votes
|
return received_votes
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.title
|
return self.title
|
||||||
|
|
||||||
|
|
||||||
class TrusteeKey(models.Model):
|
class TrusteeKey(models.Model):
|
||||||
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name="trustee_keys")
|
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name="trustee_keys")
|
||||||
user = models.ForeignKey(EmailUser, on_delete=models.CASCADE, related_name="trustee_keys")
|
user = models.ForeignKey(EmailUser, on_delete=models.CASCADE, related_name="trustee_keys")
|
||||||
key = models.CharField(max_length=260)
|
key = models.CharField(max_length=260)
|
||||||
|
|
||||||
|
|
||||||
class AccessKey(models.Model):
|
class AccessKey(models.Model):
|
||||||
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name="keys")
|
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name="keys")
|
||||||
user = models.ForeignKey(EmailUser, on_delete=models.CASCADE, related_name="keys")
|
user = models.ForeignKey(EmailUser, on_delete=models.CASCADE, related_name="keys")
|
||||||
key = models.CharField(max_length=255, unique=True)
|
key = models.CharField(max_length=255, unique=True)
|
||||||
|
|
||||||
def has_started(self):
|
def has_started(self):
|
||||||
return timezone.now() >= self.start
|
return timezone.now() >= self.start
|
||||||
|
|
||||||
def has_ended(self):
|
def has_ended(self):
|
||||||
return timezone.now() >= self.end
|
return timezone.now() >= self.end
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.title
|
return self.title
|
||||||
|
|
||||||
|
|
||||||
class Poll(models.Model):
|
class Poll(models.Model):
|
||||||
question_text = models.CharField(max_length=200)
|
question_text = models.CharField(max_length=200)
|
||||||
total_votes = models.IntegerField(default=0)
|
total_votes = models.IntegerField(default=0)
|
||||||
min_num_selections = models.IntegerField(default=0)
|
min_num_selections = models.IntegerField(default=0)
|
||||||
max_num_selections = models.IntegerField(default=1)
|
max_num_selections = models.IntegerField(default=1)
|
||||||
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name="polls")
|
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name="polls")
|
||||||
combined_ballots = models.CharField(max_length=4096, null=True)
|
combined_ballots = models.CharField(max_length=4096, null=True)
|
||||||
result_json = models.CharField(max_length=4096, null=True)
|
result_json = models.CharField(max_length=4096, null=True)
|
||||||
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.question_text
|
return self.question_text
|
||||||
|
|
||||||
|
|
||||||
class PollOption(models.Model):
|
class PollOption(models.Model):
|
||||||
choice_text = models.CharField(max_length=200)
|
choice_text = models.CharField(max_length=200)
|
||||||
votes = models.IntegerField(default=0)
|
votes = models.IntegerField(default=0)
|
||||||
question = models.ForeignKey(Poll, on_delete=models.CASCADE, related_name="options")
|
question = models.ForeignKey(Poll, on_delete=models.CASCADE, related_name="options")
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.choice_text
|
return self.choice_text
|
||||||
|
|
||||||
|
|
||||||
class CombinedBallot(models.Model):
|
class CombinedBallot(models.Model):
|
||||||
poll = models.ForeignKey(Poll, on_delete=models.CASCADE, related_name="combined_ballot")
|
poll = models.ForeignKey(Poll, on_delete=models.CASCADE, related_name="combined_ballot")
|
||||||
option = models.ForeignKey(PollOption, on_delete=models.CASCADE, related_name="combined_ballot")
|
option = models.ForeignKey(PollOption, on_delete=models.CASCADE, related_name="combined_ballot")
|
||||||
cipher_text_c1 = models.CharField(max_length=4096)
|
cipher_text_c1 = models.CharField(max_length=4096)
|
||||||
cipher_text_c2 = models.CharField(max_length=4096)
|
cipher_text_c2 = models.CharField(max_length=4096)
|
||||||
|
|
||||||
|
|
||||||
# A partial decryption supplied by a trustee for a combined ballot that relates to a poll option
|
# A partial decryption supplied by a trustee for a combined ballot that relates to a poll option
|
||||||
class PartialBallotDecryption(models.Model):
|
class PartialBallotDecryption(models.Model):
|
||||||
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name="decryption")
|
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name="decryption")
|
||||||
poll = models.ForeignKey(Poll, on_delete=models.CASCADE, related_name="decryption")
|
poll = models.ForeignKey(Poll, on_delete=models.CASCADE, related_name="decryption")
|
||||||
option = models.ForeignKey(PollOption, on_delete=models.CASCADE, related_name="decryption")
|
option = models.ForeignKey(PollOption, on_delete=models.CASCADE, related_name="decryption")
|
||||||
user = models.ForeignKey(EmailUser, on_delete=models.CASCADE, related_name="decryption")
|
user = models.ForeignKey(EmailUser, on_delete=models.CASCADE, related_name="decryption")
|
||||||
text = models.CharField(max_length=4096)
|
text = models.CharField(max_length=4096)
|
||||||
|
|
||||||
|
|
||||||
class Ballot(models.Model):
|
class Ballot(models.Model):
|
||||||
voter = models.ForeignKey(EmailUser, on_delete=models.CASCADE, related_name="ballots")
|
voter = models.ForeignKey(EmailUser, on_delete=models.CASCADE, related_name="ballots")
|
||||||
poll = models.ForeignKey(Poll, on_delete=models.CASCADE, related_name="ballots")
|
poll = models.ForeignKey(Poll, on_delete=models.CASCADE, related_name="ballots")
|
||||||
selection = models.CharField(max_length=1)
|
selection = models.CharField(max_length=1)
|
||||||
json_str = models.CharField(max_length=10240)
|
json_str = models.CharField(max_length=10240)
|
||||||
cast = models.BooleanField(default=False)
|
cast = models.BooleanField(default=False)
|
||||||
|
|
||||||
|
|
||||||
class EncBallot(models.Model):
|
class EncBallot(models.Model):
|
||||||
handle = models.CharField(primary_key=True, default=uuid.uuid4, editable=False, max_length=255)
|
handle = models.CharField(primary_key=True, default=uuid.uuid4, editable=False, max_length=255)
|
||||||
ballot = models.CharField(max_length=10240)
|
ballot = models.CharField(max_length=10240)
|
||||||
|
|
||||||
|
|
||||||
# Implements the new binary encoding scheme
|
# Implements the new binary encoding scheme
|
||||||
class EncryptedVote(models.Model):
|
class EncryptedVote(models.Model):
|
||||||
ballot = models.ForeignKey(Ballot, on_delete=models.CASCADE, related_name="encrypted_vote")
|
ballot = models.ForeignKey(Ballot, on_delete=models.CASCADE, related_name="encrypted_vote")
|
||||||
|
|
||||||
|
|
||||||
class CombinedEncryptedVote(models.Model):
|
class CombinedEncryptedVote(models.Model):
|
||||||
ballot = models.ForeignKey(Ballot, on_delete=models.CASCADE, related_name="comb_encrypted_vote")
|
ballot = models.ForeignKey(Ballot, on_delete=models.CASCADE, related_name="comb_encrypted_vote")
|
||||||
|
|
||||||
|
|
||||||
class VoteFragment(models.Model):
|
class VoteFragment(models.Model):
|
||||||
encrypted_vote = models.ForeignKey(EncryptedVote, on_delete=models.CASCADE, related_name="fragment", null=True)
|
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)
|
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_c1 = models.CharField(max_length=4096)
|
||||||
cipher_text_c2 = models.CharField(max_length=4096)
|
cipher_text_c2 = models.CharField(max_length=4096)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,5 +21,6 @@ urlpatterns = [
|
||||||
url(r'^(?P<event_id>[0-9a-f-]+)/poll/(?P<poll_id>[0-9a-f-]+)/vote/$', views.event_vote, name='event-vote'),
|
url(r'^(?P<event_id>[0-9a-f-]+)/poll/(?P<poll_id>[0-9a-f-]+)/vote/$', views.event_vote, name='event-vote'),
|
||||||
url(r'^(?P<event_id>[0-9a-f-]+)/create/poll/$', login_required(views.manage_questions), name='create-poll'),
|
url(r'^(?P<event_id>[0-9a-f-]+)/create/poll/$', login_required(views.manage_questions), name='create-poll'),
|
||||||
url(r'^(?P<event_id>[0-9a-f-]+)/poll/(?P<poll_id>[0-9a-f-]+)/edit$', login_required(views.edit_poll), name='edit-poll'),
|
url(r'^(?P<event_id>[0-9a-f-]+)/poll/(?P<poll_id>[0-9a-f-]+)/edit$', login_required(views.edit_poll), name='edit-poll'),
|
||||||
url(r'^audit/$', views.vote_audit, name='vote_audit')
|
url(r'^audit/$', views.vote_audit, name='vote_audit'),
|
||||||
|
url(r'^find_ballot/$', views.find_ballot, name='find_ballot')
|
||||||
]
|
]
|
||||||
|
|
|
@ -25,529 +25,559 @@ from .utils.EventModelAdaptor import EventModelAdaptor
|
||||||
|
|
||||||
class EventListView(generic.ListView):
|
class EventListView(generic.ListView):
|
||||||
|
|
||||||
model = Event
|
model = Event
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(EventListView, self).get_context_data(**kwargs)
|
context = super(EventListView, self).get_context_data(**kwargs)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class EventDetailView(generic.DetailView):
|
class EventDetailView(generic.DetailView):
|
||||||
template_name = "polls/event_detail_details.html"
|
template_name = "polls/event_detail_details.html"
|
||||||
model = Event
|
model = Event
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(EventDetailView, self).get_context_data(**kwargs)
|
context = super(EventDetailView, self).get_context_data(**kwargs)
|
||||||
context['is_organiser'] = (not self.request.user.is_anonymous()) and (self.object.users_organisers.filter(email=self.request.user.email).exists())
|
context['is_organiser'] = (not self.request.user.is_anonymous()) and (self.object.users_organisers.filter(email=self.request.user.email).exists())
|
||||||
context['decrypted'] = self.object.status() == "Decrypted"
|
context['decrypted'] = self.object.status() == "Decrypted"
|
||||||
|
|
||||||
# Get the results for all polls
|
# Get the results for all polls
|
||||||
polls = self.object.polls.all()
|
polls = self.object.polls.all()
|
||||||
|
|
||||||
results = list()
|
results = list()
|
||||||
for poll in polls:
|
for poll in polls:
|
||||||
result_json = poll.result_json
|
result_json = poll.result_json
|
||||||
|
|
||||||
if result_json is None:
|
if result_json is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if result_json[len(result_json)-1] == ',':
|
if result_json[len(result_json)-1] == ',':
|
||||||
result_json = result_json[0:len(result_json)-1]
|
result_json = result_json[0:len(result_json)-1]
|
||||||
|
|
||||||
result_json = json.loads(result_json)
|
result_json = json.loads(result_json)
|
||||||
results.append(result_json)
|
results.append(result_json)
|
||||||
|
|
||||||
context['event_results'] = results
|
context['event_results'] = results
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class EventDetailPollsView(EventDetailView):
|
class EventDetailPollsView(EventDetailView):
|
||||||
template_name = "polls/event_detail_polls.html"
|
template_name = "polls/event_detail_polls.html"
|
||||||
|
|
||||||
|
|
||||||
class EventDetailEntitiesView(EventDetailView):
|
class EventDetailEntitiesView(EventDetailView):
|
||||||
template_name = "polls/event_detail_entities.html"
|
template_name = "polls/event_detail_entities.html"
|
||||||
|
|
||||||
|
|
||||||
class EventDetailAdvancedView(EventDetailView):
|
class EventDetailAdvancedView(EventDetailView):
|
||||||
template_name = "polls/event_detail_advanced.html"
|
template_name = "polls/event_detail_advanced.html"
|
||||||
|
|
||||||
|
|
||||||
class PollDetailView(generic.View):
|
class PollDetailView(generic.View):
|
||||||
model = Poll
|
model = Poll
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(PollDetailView, self).get_context_data(**kwargs)
|
context = super(PollDetailView, self).get_context_data(**kwargs)
|
||||||
context['form'] = VoteForm(instance=self.object)
|
context['form'] = VoteForm(instance=self.object)
|
||||||
context['poll_count'] = self.object.event.polls.all().count()
|
context['poll_count'] = self.object.event.polls.all().count()
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class EventDetailResultsView(EventDetailView):
|
class EventDetailResultsView(EventDetailView):
|
||||||
template_name = "polls/event_results.html"
|
template_name = "polls/event_results.html"
|
||||||
|
|
||||||
|
|
||||||
def util_get_poll_by_event_index(event, poll_id):
|
def util_get_poll_by_event_index(event, poll_id):
|
||||||
return event.polls.get(uuid=poll_id)
|
return event.polls.get(uuid=poll_id)
|
||||||
|
|
||||||
|
|
||||||
def edit_poll(request, event_id, poll_id):
|
def edit_poll(request, event_id, poll_id):
|
||||||
event = get_object_or_404(Event, pk=event_id)
|
event = get_object_or_404(Event, pk=event_id)
|
||||||
poll = util_get_poll_by_event_index(event, poll_id)
|
poll = util_get_poll_by_event_index(event, poll_id)
|
||||||
|
|
||||||
if (poll == None):
|
if (poll == None):
|
||||||
raise Http404("Poll does not exist")
|
raise Http404("Poll does not exist")
|
||||||
|
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
form = PollForm(instance=poll, prefix="main")
|
form = PollForm(instance=poll, prefix="main")
|
||||||
formset = OptionFormset(instance=poll, prefix="formset_options")
|
formset = OptionFormset(instance=poll, prefix="formset_options")
|
||||||
return render(request, "polls/generic_form.html", {'form_title': "Edit Poll: " + poll.question_text, 'form': form, 'option_formset': formset})
|
return render(request, "polls/generic_form.html", {'form_title': "Edit Poll: " + poll.question_text, 'form': form, 'option_formset': formset})
|
||||||
elif request.method == 'POST':
|
elif request.method == 'POST':
|
||||||
form = PollForm(request.POST, instance=poll, prefix="main")
|
form = PollForm(request.POST, instance=poll, prefix="main")
|
||||||
|
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
form.save()
|
form.save()
|
||||||
|
|
||||||
formset = OptionFormset(request.POST, instance=poll, prefix="formset_options")
|
formset = OptionFormset(request.POST, instance=poll, prefix="formset_options")
|
||||||
|
|
||||||
if formset.is_valid():
|
if formset.is_valid():
|
||||||
formset.save()
|
formset.save()
|
||||||
return HttpResponseRedirect(reverse('polls:event-polls', args=[poll.event_id]))
|
return HttpResponseRedirect(reverse('polls:event-polls', args=[poll.event_id]))
|
||||||
|
|
||||||
|
|
||||||
def vote_audit(request):
|
def vote_audit(request):
|
||||||
encrypted_ballot = get_object_or_404(EncBallot, handle=''+urllib.quote_plus(request.GET.get('handle', None)))
|
handle1 = request.GET.get('handle1', None)
|
||||||
|
handle2 = request.GET.get('handle2', None)
|
||||||
|
vars = {}
|
||||||
|
|
||||||
|
if handle:
|
||||||
|
encrypted_ballot1 = get_object_or_404(EncBallot, handle=''+urllib.quote_plus(handle1))
|
||||||
|
|
||||||
|
if handle2:
|
||||||
|
encrypted_ballot2 = get_object_or_404(EncBallot, handle=''+urllib.quote_plus(handle2))
|
||||||
|
|
||||||
return render(request, "polls/vote_audit.html",
|
return render(request, "polls/vote_audit.html",
|
||||||
{
|
{
|
||||||
"ballot": encrypted_ballot.ballot
|
"handle1": handle1,
|
||||||
})
|
"ballot1": encrypted_ballot1.ballot,
|
||||||
|
"handle2": handle2,
|
||||||
|
"ballot2": encrypted_ballot2.ballot
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def find_ballot(request):
|
||||||
|
voter_id = request.GET.get('vid', None)
|
||||||
|
poll_id = request.GET.get('pid', None)
|
||||||
|
ballot = get_object_or_404(Ballot, voter=voter_id, poll=poll_id)
|
||||||
|
hash1 = request.GET.get('hash1', None)
|
||||||
|
hash2 = request.GET.get('hash2', None)
|
||||||
|
|
||||||
|
if not ballot.cast:
|
||||||
|
messages.add_message(request, messages.WARNING, "This ballot has not been cast.")
|
||||||
|
return HttpResponseRedirect(reverse("user_home"))
|
||||||
|
|
||||||
|
return render(request, "polls/find_ballot.html",
|
||||||
|
{
|
||||||
|
"ballot": ballot.json_str,
|
||||||
|
"hash1": hash1,
|
||||||
|
"hash2": hash2
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
def event_vote(request, event_id, poll_id):
|
def event_vote(request, event_id, poll_id):
|
||||||
event = get_object_or_404(Event, pk=event_id)
|
event = get_object_or_404(Event, pk=event_id)
|
||||||
|
|
||||||
if not event.prepared:
|
if not event.prepared:
|
||||||
messages.add_message(request, messages.WARNING, "This Event isn\'t ready for voting yet.")
|
messages.add_message(request, messages.WARNING, "This Event isn\'t ready for voting yet.")
|
||||||
return HttpResponseRedirect(reverse("user_home"))
|
return HttpResponseRedirect(reverse("user_home"))
|
||||||
|
|
||||||
# Lookup the specified poll
|
# Lookup the specified poll
|
||||||
poll = event.polls.get(uuid=poll_id)
|
poll = event.polls.get(uuid=poll_id)
|
||||||
|
|
||||||
if poll is None:
|
if poll is None:
|
||||||
messages.add_message(request, messages.ERROR, "There was an error loading the voting page.")
|
messages.add_message(request, messages.ERROR, "There was an error loading the voting page.")
|
||||||
return HttpResponseRedirect(reverse("user_home"))
|
return HttpResponseRedirect(reverse("user_home"))
|
||||||
|
|
||||||
polls = event.polls.all()
|
polls = event.polls.all()
|
||||||
event_poll_count = len(polls)
|
event_poll_count = len(polls)
|
||||||
prev_poll_uuid, next_poll_uuid, poll_num = False, False, 0
|
prev_poll_uuid, next_poll_uuid, poll_num = False, False, 0
|
||||||
can_vote, cant_vote_reason, has_voted, voter_email = False, "", False, ""
|
can_vote, cant_vote_reason, has_voted, voter_email = False, "", False, ""
|
||||||
|
|
||||||
for i in range(event_poll_count):
|
for i in range(event_poll_count):
|
||||||
poll = polls[i]
|
poll = polls[i]
|
||||||
poll_uuid = str(poll.uuid)
|
poll_uuid = str(poll.uuid)
|
||||||
req_poll_uuid = str(poll_id)
|
req_poll_uuid = str(poll_id)
|
||||||
|
|
||||||
if poll_uuid == req_poll_uuid:
|
if poll_uuid == req_poll_uuid:
|
||||||
poll_num = str(i+1)
|
poll_num = str(i+1)
|
||||||
|
|
||||||
# If current voting request isn't for the last poll, then make sure we link to the next
|
# If current voting request isn't for the last poll, then make sure we link to the next
|
||||||
if i != event_poll_count - 1:
|
if i != event_poll_count - 1:
|
||||||
# Only set the previous poll's uuid if we're not looking at the first poll
|
# Only set the previous poll's uuid if we're not looking at the first poll
|
||||||
if i != 0:
|
if i != 0:
|
||||||
prev_poll_uuid = str(polls[i - 1].uuid)
|
prev_poll_uuid = str(polls[i - 1].uuid)
|
||||||
|
|
||||||
next_poll_uuid = str(polls[i + 1].uuid)
|
next_poll_uuid = str(polls[i + 1].uuid)
|
||||||
else:
|
else:
|
||||||
if i != 0:
|
if i != 0:
|
||||||
prev_poll_uuid = str(polls[i - 1].uuid)
|
prev_poll_uuid = str(polls[i - 1].uuid)
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
access_key = request.GET.get('key', None)
|
access_key = request.GET.get('key', None)
|
||||||
email_key = event.keys.filter(key=access_key)
|
email_key = event.keys.filter(key=access_key)
|
||||||
email_key_str = email_key[0].key
|
email_key_str = email_key[0].key
|
||||||
|
|
||||||
if email_key.exists() and event.voters.filter(email=email_key[0].user.email).exists():
|
if email_key.exists() and event.voters.filter(email=email_key[0].user.email).exists():
|
||||||
# Passing this test means the user can vote
|
# Passing this test means the user can vote
|
||||||
voter_email = email_key[0].user.email
|
voter_email = email_key[0].user.email
|
||||||
can_vote = True
|
can_vote = True
|
||||||
|
|
||||||
# Check whether this is the first time a user is voting
|
# Check whether this is the first time a user is voting
|
||||||
ballot = Ballot.objects.filter(voter=email_key[0].user, poll=poll)
|
ballot = Ballot.objects.filter(voter=email_key[0].user, poll=poll)
|
||||||
if ballot.exists() and ballot[0].cast:
|
if ballot.exists() and ballot[0].cast:
|
||||||
has_voted = True
|
has_voted = True
|
||||||
else:
|
else:
|
||||||
can_vote = False
|
can_vote = False
|
||||||
cant_vote_reason = "You don't have permission to access this page."
|
cant_vote_reason = "You don't have permission to access this page."
|
||||||
|
|
||||||
if event.status() != "Active":
|
if event.status() != "Active":
|
||||||
can_vote = False
|
can_vote = False
|
||||||
cant_vote_reason = "The event either isn't ready for voting or it has expired and therefore you cannot vote."
|
cant_vote_reason = "The event either isn't ready for voting or it has expired and therefore you cannot vote."
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
ballot_str = request.POST.get('ballot')
|
ballot_str = request.POST.get('ballot')
|
||||||
ballot_json = json.loads(ballot_str)
|
ballot_json = json.loads(ballot_str)
|
||||||
selection = request.POST.get('selection')
|
selection = request.POST.get('selection')
|
||||||
encrypted_votes_json = ballot_json['encryptedVotes']
|
encrypted_votes_json = ballot_json['encryptedVotes']
|
||||||
|
|
||||||
enc_ballot_json = request.POST.get('encBallot')
|
enc_ballot_json = request.POST.get('encBallot')
|
||||||
handle_json = request.POST.get('handle')
|
handle_json = request.POST.get('handle')
|
||||||
|
|
||||||
# Adds or replaces the encrypted un-submitted ballot to the database for the auditor app to pick up later
|
# Adds or replaces the encrypted un-submitted ballot to the database for the auditor app to pick up later
|
||||||
if EncBallot.objects.filter(handle=handle_json).exists():
|
if EncBallot.objects.filter(handle=handle_json).exists():
|
||||||
b = EncBallot.objects.get(handle=handle_json)
|
b = EncBallot.objects.get(handle=handle_json)
|
||||||
b.ballot = enc_ballot_json
|
b.ballot = enc_ballot_json
|
||||||
b.save()
|
b.save()
|
||||||
else:
|
else:
|
||||||
b = EncBallot(handle=handle_json, ballot=enc_ballot_json)
|
b = EncBallot(handle=handle_json, ballot=enc_ballot_json)
|
||||||
b.save()
|
b.save()
|
||||||
|
|
||||||
# Before storing the encrypted votes, we need the voter's ballot
|
# 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)
|
ballot, created = Ballot.objects.get_or_create(voter=email_key[0].user, poll=poll)
|
||||||
EncryptedVote.objects.filter(ballot=ballot).delete()
|
EncryptedVote.objects.filter(ballot=ballot).delete()
|
||||||
|
|
||||||
for e_vote in encrypted_votes_json:
|
for e_vote in encrypted_votes_json:
|
||||||
# Will store the fragments of the encoding scheme that define the vote
|
# Will store the fragments of the encoding scheme that define the vote
|
||||||
encrypted_vote = EncryptedVote.objects.create(ballot=ballot)
|
encrypted_vote = EncryptedVote.objects.create(ballot=ballot)
|
||||||
fragments_json = e_vote['fragments']
|
fragments_json = e_vote['fragments']
|
||||||
|
|
||||||
for fragment in fragments_json:
|
for fragment in fragments_json:
|
||||||
VoteFragment.objects.create(encrypted_vote=encrypted_vote,
|
VoteFragment.objects.create(encrypted_vote=encrypted_vote,
|
||||||
cipher_text_c1=fragment['C1'],
|
cipher_text_c1=fragment['C1'],
|
||||||
cipher_text_c2=fragment['C2'])
|
cipher_text_c2=fragment['C2'])
|
||||||
|
|
||||||
ballot.cast = True
|
ballot.cast = True
|
||||||
ballot.selection = selection
|
ballot.selection = selection
|
||||||
ballot.json_str = ballot_str
|
ballot.json_str = ballot_str
|
||||||
ballot.save()
|
ballot.save()
|
||||||
|
|
||||||
voter = email_key[0].user
|
voter = email_key[0].user
|
||||||
combine_encrypted_votes.delay(voter, poll)
|
combine_encrypted_votes.delay(voter, poll)
|
||||||
email_voting_success.delay(voter, handle_json, event.title)
|
email_voting_success.delay(voter, handle_json, event.title)
|
||||||
|
|
||||||
if next_poll_uuid:
|
if next_poll_uuid:
|
||||||
return HttpResponseRedirect(reverse('polls:event-vote', kwargs={'event_id': event.uuid,
|
return HttpResponseRedirect(reverse('polls:event-vote', kwargs={'event_id': event.uuid,
|
||||||
'poll_id': next_poll_uuid})
|
'poll_id': next_poll_uuid})
|
||||||
+ "?key=" + email_key_str)
|
+ "?key=" + email_key_str)
|
||||||
|
|
||||||
return HttpResponse('Voted Successfully!')
|
return HttpResponse('Voted Successfully!')
|
||||||
|
|
||||||
return render(request, "polls/event_vote.html",
|
return render(request, "polls/event_vote.html",
|
||||||
{
|
{
|
||||||
"object": poll, "poll_num": poll_num, "event": event, "poll_count": event.polls.all().count(),
|
"object": poll, "poll_num": poll_num, "event": event, "poll_count": event.polls.all().count(),
|
||||||
"prev_uuid": prev_poll_uuid, "next_uuid": next_poll_uuid, "min_selection": poll.min_num_selections,
|
"prev_uuid": prev_poll_uuid, "next_uuid": next_poll_uuid, "min_selection": poll.min_num_selections,
|
||||||
"max_selection": poll.max_num_selections, "can_vote": can_vote, "cant_vote_reason": cant_vote_reason,
|
"max_selection": poll.max_num_selections, "can_vote": can_vote, "cant_vote_reason": cant_vote_reason,
|
||||||
"voter_email": voter_email, "has_voted": has_voted, "a_key": email_key_str
|
"voter_email": voter_email, "has_voted": has_voted, "a_key": email_key_str
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
def event_trustee_setup(request, event_id):
|
def event_trustee_setup(request, event_id):
|
||||||
# Obtain the event and the event preparation access key that's been supplied
|
# Obtain the event and the event preparation access key that's been supplied
|
||||||
event = get_object_or_404(Event, pk=event_id)
|
event = get_object_or_404(Event, pk=event_id)
|
||||||
access_key = request.GET.get('key', None)
|
access_key = request.GET.get('key', None)
|
||||||
|
|
||||||
# If the a_key is present, check it's valid and related to a trustee EmailUser instance for this event
|
# If the a_key is present, check it's valid and related to a trustee EmailUser instance for this event
|
||||||
if access_key:
|
if access_key:
|
||||||
email_key = event.keys.filter(key=access_key)
|
email_key = event.keys.filter(key=access_key)
|
||||||
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=email_key[0].user.email).exists():
|
||||||
if TrusteeKey.objects.filter(event=event, user=email_key[0].user).exists():
|
if TrusteeKey.objects.filter(event=event, user=email_key[0].user).exists():
|
||||||
return render(request, "polls/event_setup.html", {"is_trustee": True,
|
return render(request, "polls/event_setup.html", {"is_trustee": True,
|
||||||
"can_submit": False,
|
"can_submit": False,
|
||||||
"access_denied_reason": "You have already submitted your public key for this event. Thank you!"
|
"access_denied_reason": "You have already submitted your public key for this event. Thank you!"
|
||||||
})
|
})
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = EventSetupForm(request.POST)
|
form = EventSetupForm(request.POST)
|
||||||
|
|
||||||
# If form data is valid, create a TrusteeKey object with the supplied public key
|
# If form data is valid, create a TrusteeKey object with the supplied public key
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
public_key = request.POST.get("public_key")
|
public_key = request.POST.get("public_key")
|
||||||
key = TrusteeKey.objects.get_or_create(event=event, user=email_key[0].user)[0]
|
key = TrusteeKey.objects.get_or_create(event=event, user=email_key[0].user)[0]
|
||||||
key.key = public_key
|
key.key = public_key
|
||||||
key.save()
|
key.save()
|
||||||
|
|
||||||
# When all trustees have supplied their public key, we can combine them to create a master key
|
# When all trustees have supplied their public key, we can combine them to create a master key
|
||||||
# The event will now be ready to receive votes on the various polls that have been defined -
|
# The event will now be ready to receive votes on the various polls that have been defined -
|
||||||
# voters therefore need to be informed
|
# voters therefore need to be informed
|
||||||
if event.trustee_keys.count() == event.users_trustees.count():
|
if event.trustee_keys.count() == event.users_trustees.count():
|
||||||
create_ballots.delay(event)
|
create_ballots.delay(event)
|
||||||
generate_combpk.delay(event)
|
generate_combpk.delay(event)
|
||||||
email_voters_vote_url.delay(event.voters.all(), event)
|
email_voters_vote_url.delay(event.voters.all(), event)
|
||||||
email_organisers_next_steps.delay(event)
|
email_organisers_next_steps.delay(event)
|
||||||
|
|
||||||
success_msg = 'You have successfully submitted your public key for this event!'
|
success_msg = 'You have successfully submitted your public key for this event!'
|
||||||
messages.add_message(request, messages.SUCCESS, success_msg)
|
messages.add_message(request, messages.SUCCESS, success_msg)
|
||||||
|
|
||||||
return HttpResponseRedirect(reverse("user_home"))
|
return HttpResponseRedirect(reverse("user_home"))
|
||||||
else:
|
else:
|
||||||
form = EventSetupForm()
|
form = EventSetupForm()
|
||||||
return render(request, "polls/event_setup.html", {"event": event,
|
return render(request, "polls/event_setup.html", {"event": event,
|
||||||
"form": form,
|
"form": form,
|
||||||
"user_email": email_key[0].user.email,
|
"user_email": email_key[0].user.email,
|
||||||
"is_trustee": True,
|
"is_trustee": True,
|
||||||
"can_submit": True
|
"can_submit": True
|
||||||
})
|
})
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return render(request, "polls/event_setup.html", {"is_trustee": False,
|
return render(request, "polls/event_setup.html", {"is_trustee": False,
|
||||||
"can_submit": False,
|
"can_submit": False,
|
||||||
"access_denied_reason": "You do not have permission to access this page."
|
"access_denied_reason": "You do not have permission to access this page."
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
def event_end(request, event_id):
|
def event_end(request, event_id):
|
||||||
event = get_object_or_404(Event, pk=event_id)
|
event = get_object_or_404(Event, pk=event_id)
|
||||||
|
|
||||||
if not event.ended:
|
if not event.ended:
|
||||||
event_ended.delay(event)
|
event_ended.delay(event)
|
||||||
|
|
||||||
# Mark the event as ended
|
# Mark the event as ended
|
||||||
event.ended = True
|
event.ended = True
|
||||||
event.save()
|
event.save()
|
||||||
|
|
||||||
return HttpResponseRedirect(reverse('polls:view-event', args=[event_id]))
|
return HttpResponseRedirect(reverse('polls:view-event', args=[event_id]))
|
||||||
|
|
||||||
|
|
||||||
def event_trustee_decrypt(request, event_id):
|
def event_trustee_decrypt(request, event_id):
|
||||||
event = get_object_or_404(Event, pk=event_id)
|
event = get_object_or_404(Event, pk=event_id)
|
||||||
access_key = request.GET.get('key', None)
|
access_key = request.GET.get('key', None)
|
||||||
|
|
||||||
if access_key:
|
if access_key:
|
||||||
email_key = event.keys.filter(key=access_key)
|
email_key = event.keys.filter(key=access_key)
|
||||||
trustee = email_key[0].user
|
trustee = email_key[0].user
|
||||||
|
|
||||||
if email_key.exists() and event.users_trustees.filter(email=trustee.email).exists():
|
if email_key.exists() and event.users_trustees.filter(email=trustee.email).exists():
|
||||||
|
|
||||||
if PartialBallotDecryption.objects.filter(event=event, user=trustee).count() == event.total_num_opts():
|
if PartialBallotDecryption.objects.filter(event=event, user=trustee).count() == event.total_num_opts():
|
||||||
return render(request, "polls/event_decrypt.html", {"is_trustee": True,
|
return render(request, "polls/event_decrypt.html", {"is_trustee": True,
|
||||||
"can_submit": False,
|
"can_submit": False,
|
||||||
"access_denied_reason": "You have already submitted your partial decryptions for this event. Thank you!"
|
"access_denied_reason": "You have already submitted your partial decryptions for this event. Thank you!"
|
||||||
})
|
})
|
||||||
elif request.method == "GET":
|
elif request.method == "GET":
|
||||||
# Get the Trustee's original PK - used in the template for SK validation
|
# Get the Trustee's original PK - used in the template for SK validation
|
||||||
trustee_pk = TrusteeKey.objects.get(event=event, user=trustee).key
|
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
|
# Gen a list of ciphers from the combined ballots for every opt of every poll
|
||||||
polls = event.polls.all()
|
polls = event.polls.all()
|
||||||
poll_ciphers = []
|
poll_ciphers = []
|
||||||
|
|
||||||
for poll in polls:
|
for poll in polls:
|
||||||
options = poll.options.all()
|
options = poll.options.all()
|
||||||
|
|
||||||
options_ciphers = []
|
options_ciphers = []
|
||||||
for option in options:
|
for option in options:
|
||||||
combined_ballot = CombinedBallot.objects.filter(poll=poll, option=option).get()
|
combined_ballot = CombinedBallot.objects.filter(poll=poll, option=option).get()
|
||||||
|
|
||||||
cipher = {}
|
cipher = {}
|
||||||
cipher['C1'] = combined_ballot.cipher_text_c1
|
cipher['C1'] = combined_ballot.cipher_text_c1
|
||||||
cipher['C2'] = combined_ballot.cipher_text_c2
|
cipher['C2'] = combined_ballot.cipher_text_c2
|
||||||
options_ciphers.append(cipher)
|
options_ciphers.append(cipher)
|
||||||
|
|
||||||
poll_ciphers.append(options_ciphers)
|
poll_ciphers.append(options_ciphers)
|
||||||
|
|
||||||
return render(request,
|
return render(request,
|
||||||
"polls/event_decrypt.html",
|
"polls/event_decrypt.html",
|
||||||
{
|
{
|
||||||
"event": event,
|
"event": event,
|
||||||
"user_email": trustee.email,
|
"user_email": trustee.email,
|
||||||
"trustee_pk": trustee_pk,
|
"trustee_pk": trustee_pk,
|
||||||
"poll_ciphers": poll_ciphers,
|
"poll_ciphers": poll_ciphers,
|
||||||
"is_trustee": True,
|
"is_trustee": True,
|
||||||
"can_submit": True
|
"can_submit": True
|
||||||
})
|
})
|
||||||
|
|
||||||
elif request.method == "POST":
|
elif request.method == "POST":
|
||||||
polls = event.polls.all()
|
polls = event.polls.all()
|
||||||
polls_count = len(polls)
|
polls_count = len(polls)
|
||||||
|
|
||||||
for i in range(polls_count):
|
for i in range(polls_count):
|
||||||
options = polls[i].options.all()
|
options = polls[i].options.all()
|
||||||
options_count = len(options)
|
options_count = len(options)
|
||||||
|
|
||||||
for j in range(options_count):
|
for j in range(options_count):
|
||||||
input_name = str("")
|
input_name = str("")
|
||||||
input_name = "poll-" + str(i) + "-cipher-" + str(j)
|
input_name = "poll-" + str(i) + "-cipher-" + str(j)
|
||||||
|
|
||||||
part_dec = request.POST.get(input_name)
|
part_dec = request.POST.get(input_name)
|
||||||
|
|
||||||
PartialBallotDecryption.objects.create(event=event,
|
PartialBallotDecryption.objects.create(event=event,
|
||||||
poll=polls[i],
|
poll=polls[i],
|
||||||
option=options[j],
|
option=options[j],
|
||||||
user=trustee,
|
user=trustee,
|
||||||
text=part_dec)
|
text=part_dec)
|
||||||
|
|
||||||
if event.all_part_decs_received():
|
if event.all_part_decs_received():
|
||||||
# Decrypt the result once all partial decryptions have been received
|
# Decrypt the result once all partial decryptions have been received
|
||||||
# This will email all organisers once the results are ready
|
# This will email all organisers once the results are ready
|
||||||
combine_decryptions_and_tally.delay(event)
|
combine_decryptions_and_tally.delay(event)
|
||||||
else:
|
else:
|
||||||
# TODO: Get how many trustees have submitted a partial decryption
|
# TODO: Get how many trustees have submitted a partial decryption
|
||||||
# TODO: Then get how many are left to submit their partial decryptions
|
# TODO: Then get how many are left to submit their partial decryptions
|
||||||
# TODO: Then email the list of organisers to update them with this information
|
# TODO: Then email the list of organisers to update them with this information
|
||||||
str("")
|
str("")
|
||||||
|
|
||||||
messages.add_message(request, messages.SUCCESS, 'Your partial decryptions have been successfully submitted')
|
messages.add_message(request, messages.SUCCESS, 'Your partial decryptions have been successfully submitted')
|
||||||
return HttpResponseRedirect(reverse("user_home"))
|
return HttpResponseRedirect(reverse("user_home"))
|
||||||
|
|
||||||
# Without an access key, the client does not have permission to access this page
|
# Without an access key, the client does not have permission to access this page
|
||||||
return render(request, "polls/event_decrypt.html", {"is_trustee": False,
|
return render(request, "polls/event_decrypt.html", {"is_trustee": False,
|
||||||
"can_submit": False,
|
"can_submit": False,
|
||||||
"access_denied_reason": "You don't have permission to access this page."
|
"access_denied_reason": "You don't have permission to access this page."
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
def manage_questions(request, event_id):
|
def manage_questions(request, event_id):
|
||||||
|
|
||||||
event = get_object_or_404(Event, pk=event_id)
|
event = get_object_or_404(Event, pk=event_id)
|
||||||
|
|
||||||
if (request.user.is_anonymous()) or (not event.users_organisers.filter(email=request.user.email).exists()):
|
if (request.user.is_anonymous()) or (not event.users_organisers.filter(email=request.user.email).exists()):
|
||||||
messages.add_message(request, messages.WARNING, 'You do not have permission to access: ' + request.path)
|
messages.add_message(request, messages.WARNING, 'You do not have permission to access: ' + request.path)
|
||||||
return HttpResponseRedirect(reverse("user_home"))
|
return HttpResponseRedirect(reverse("user_home"))
|
||||||
|
|
||||||
poll = Poll()
|
poll = Poll()
|
||||||
formset = OptionFormset(instance=poll, prefix="formset_organiser")
|
formset = OptionFormset(instance=poll, prefix="formset_organiser")
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = PollForm(request.POST, prefix="main")
|
form = PollForm(request.POST, prefix="main")
|
||||||
formset = OptionFormset(request.POST, prefix="formset_organiser") # incase form fails, we still want to retain formset data
|
formset = OptionFormset(request.POST, prefix="formset_organiser") # incase form fails, we still want to retain formset data
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
poll = form.save(commit=False)
|
poll = form.save(commit=False)
|
||||||
poll.event_id = event_id
|
poll.event_id = event_id
|
||||||
poll.save()
|
poll.save()
|
||||||
formset = OptionFormset(request.POST, prefix="formset_organiser", instance=poll)
|
formset = OptionFormset(request.POST, prefix="formset_organiser", instance=poll)
|
||||||
if formset.is_valid():
|
if formset.is_valid():
|
||||||
formset.save()
|
formset.save()
|
||||||
create_ballots_for_poll.delay(poll)
|
create_ballots_for_poll.delay(poll)
|
||||||
messages.add_message(request, messages.SUCCESS, 'Poll created successfully')
|
messages.add_message(request, messages.SUCCESS, 'Poll created successfully')
|
||||||
return HttpResponseRedirect(reverse('polls:event-polls', args=[poll.event_id]))
|
return HttpResponseRedirect(reverse('polls:event-polls', args=[poll.event_id]))
|
||||||
|
|
||||||
return render(request, "polls/create_poll.html", {"event": event, "question_form": form, "option_formset": formset})
|
return render(request, "polls/create_poll.html", {"event": event, "question_form": form, "option_formset": formset})
|
||||||
|
|
||||||
elif request.method == "GET":
|
elif request.method == "GET":
|
||||||
form = PollForm(prefix="main") #, instance=poll
|
form = PollForm(prefix="main") #, instance=poll
|
||||||
return render(request, "polls/create_poll.html", {"event": event, "question_form": form, "option_formset": formset})
|
return render(request, "polls/create_poll.html", {"event": event, "question_form": form, "option_formset": formset})
|
||||||
else:
|
else:
|
||||||
return HttpResponseNotAllowed()
|
return HttpResponseNotAllowed()
|
||||||
|
|
||||||
|
|
||||||
def render_invalid(request, events, demo_users, invalid_fields):
|
def render_invalid(request, events, demo_users, invalid_fields):
|
||||||
return render(request,
|
return render(request,
|
||||||
"polls/create_event.html",
|
"polls/create_event.html",
|
||||||
{
|
{
|
||||||
"G_R_SITE_KEY": settings.RECAPTCHA_PUBLIC_KEY,
|
"G_R_SITE_KEY": settings.RECAPTCHA_PUBLIC_KEY,
|
||||||
"user_email": request.user.email,
|
"user_email": request.user.email,
|
||||||
"events": events,
|
"events": events,
|
||||||
"demo_users": demo_users,
|
"demo_users": demo_users,
|
||||||
"invalid_fields": invalid_fields
|
"invalid_fields": invalid_fields
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
def create_event(request):
|
def create_event(request):
|
||||||
# Obtain context data for the rendering of the html template and validation
|
# Obtain context data for the rendering of the html template and validation
|
||||||
events = Event.objects.all()
|
events = Event.objects.all()
|
||||||
demo_users = DemoUser.objects.all()
|
demo_users = DemoUser.objects.all()
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
'''Perform Google reCAPTCHA validation'''
|
'''Perform Google reCAPTCHA validation'''
|
||||||
recaptcha_response = request.POST.get('g-recaptcha-response')
|
recaptcha_response = request.POST.get('g-recaptcha-response')
|
||||||
url = 'https://www.google.com/recaptcha/api/siteverify'
|
url = 'https://www.google.com/recaptcha/api/siteverify'
|
||||||
values = {
|
values = {
|
||||||
'secret': settings.RECAPTCHA_PRIVATE_KEY,
|
'secret': settings.RECAPTCHA_PRIVATE_KEY,
|
||||||
'response': recaptcha_response
|
'response': recaptcha_response
|
||||||
}
|
}
|
||||||
data = urllib.urlencode(values)
|
data = urllib.urlencode(values)
|
||||||
req = urllib2.Request(url, data)
|
req = urllib2.Request(url, data)
|
||||||
response = urllib2.urlopen(req)
|
response = urllib2.urlopen(req)
|
||||||
result = json.load(response)
|
result = json.load(response)
|
||||||
|
|
||||||
'''Perform form data validation'''
|
'''Perform form data validation'''
|
||||||
adaptor = EventModelAdaptor(request.POST, request.user)
|
adaptor = EventModelAdaptor(request.POST, request.user)
|
||||||
form_data_valid = adaptor.isFormDataValid(events, demo_users)
|
form_data_valid = adaptor.isFormDataValid(events, demo_users)
|
||||||
|
|
||||||
'''Process form data based on above results'''
|
'''Process form data based on above results'''
|
||||||
if result['success']:
|
if result['success']:
|
||||||
if form_data_valid:
|
if form_data_valid:
|
||||||
# Create the new event using the form data
|
# Create the new event using the form data
|
||||||
adaptor.extractData()
|
adaptor.extractData()
|
||||||
new_event = adaptor.updateModel()
|
new_event = adaptor.updateModel()
|
||||||
|
|
||||||
# Update the EID to include the GP in its EID
|
# Update the EID to include the GP in its EID
|
||||||
update_EID.delay(new_event)
|
update_EID.delay(new_event)
|
||||||
|
|
||||||
# Send an email to all trustees for event preparation
|
# Send an email to all trustees for event preparation
|
||||||
trustees = new_event.users_trustees.all()
|
trustees = new_event.users_trustees.all()
|
||||||
email_trustees_prep.delay(trustees, new_event)
|
email_trustees_prep.delay(trustees, new_event)
|
||||||
|
|
||||||
adaptor.clear_data()
|
adaptor.clear_data()
|
||||||
|
|
||||||
return HttpResponseRedirect(reverse('polls:index'))
|
return HttpResponseRedirect(reverse('polls:index'))
|
||||||
else:
|
else:
|
||||||
invalid_fields = adaptor.getInvalidFormFields()
|
invalid_fields = adaptor.getInvalidFormFields()
|
||||||
adaptor.clear_data()
|
adaptor.clear_data()
|
||||||
return render_invalid(request, events, demo_users, invalid_fields)
|
return render_invalid(request, events, demo_users, invalid_fields)
|
||||||
else:
|
else:
|
||||||
invalid_fields = adaptor.getInvalidFormFields()
|
invalid_fields = adaptor.getInvalidFormFields()
|
||||||
invalid_fields['recaptcha'] = {'error': 'The reCAPTCHA server validation failed, please try again.'}
|
invalid_fields['recaptcha'] = {'error': 'The reCAPTCHA server validation failed, please try again.'}
|
||||||
adaptor.clear_data()
|
adaptor.clear_data()
|
||||||
return render_invalid(request, events, demo_users, invalid_fields)
|
return render_invalid(request, events, demo_users, invalid_fields)
|
||||||
|
|
||||||
elif request.method == "GET":
|
elif request.method == "GET":
|
||||||
# Render the template
|
# Render the template
|
||||||
return render(request,
|
return render(request,
|
||||||
"polls/create_event.html",
|
"polls/create_event.html",
|
||||||
{
|
{
|
||||||
"G_R_SITE_KEY": settings.RECAPTCHA_PUBLIC_KEY,
|
"G_R_SITE_KEY": settings.RECAPTCHA_PUBLIC_KEY,
|
||||||
"user_email": request.user.email,
|
"user_email": request.user.email,
|
||||||
"events": events,
|
"events": events,
|
||||||
"demo_users": demo_users
|
"demo_users": demo_users
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
return HttpResponseNotAllowed()
|
return HttpResponseNotAllowed()
|
||||||
|
|
||||||
|
|
||||||
def edit_event(request, event_id):
|
def edit_event(request, event_id):
|
||||||
event = get_object_or_404(Event, pk=event_id)
|
event = get_object_or_404(Event, pk=event_id)
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
form = EventEditForm(instance=event, prefix="main")
|
form = EventEditForm(instance=event, prefix="main")
|
||||||
'''
|
'''
|
||||||
organiser_initial_data = [{'email': request.user.email}]
|
organiser_initial_data = [{'email': request.user.email}]
|
||||||
trustee_initial_data = []
|
trustee_initial_data = []
|
||||||
for user in event.users_organisers.exclude(email=request.user.email):
|
for user in event.users_organisers.exclude(email=request.user.email):
|
||||||
organiser_initial_data.append({'email': user.email})
|
organiser_initial_data.append({'email': user.email})
|
||||||
organiser_formset = OrganiserFormSet(prefix="formset_organiser", initial=organiser_initial_data)
|
organiser_formset = OrganiserFormSet(prefix="formset_organiser", initial=organiser_initial_data)
|
||||||
for trustee in event.users_trustees.all():
|
for trustee in event.users_trustees.all():
|
||||||
trustee_initial_data.append({'email': trustee.email})
|
trustee_initial_data.append({'email': trustee.email})
|
||||||
trustee_formset = TrusteeFormSet(prefix="formset_trustee", initial=trustee_initial_data)
|
trustee_formset = TrusteeFormSet(prefix="formset_trustee", initial=trustee_initial_data)
|
||||||
'''
|
'''
|
||||||
elif request.method == "POST":
|
elif request.method == "POST":
|
||||||
form = EventEditForm(request.POST, instance=event, prefix="main")
|
form = EventEditForm(request.POST, instance=event, prefix="main")
|
||||||
#trustee_formset = TrusteeFormSet(request.POST, prefix="formset_trustee")
|
#trustee_formset = TrusteeFormSet(request.POST, prefix="formset_trustee")
|
||||||
#organiser_formset = OrganiserFormSet(request.POST, prefix="formset_organiser") # incase form fails, we still want to retain formset data
|
#organiser_formset = OrganiserFormSet(request.POST, prefix="formset_organiser") # incase form fails, we still want to retain formset data
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
form.save()
|
form.save()
|
||||||
'''
|
'''
|
||||||
if organiser_formset.is_valid():
|
if organiser_formset.is_valid():
|
||||||
event.users_organisers.clear()
|
event.users_organisers.clear()
|
||||||
for oform in organiser_formset:
|
for oform in organiser_formset:
|
||||||
if (oform.cleaned_data.get('email')):
|
if (oform.cleaned_data.get('email')):
|
||||||
event.users_organisers.add(DemoUser.objects.get(email=oform.cleaned_data['email']))
|
event.users_organisers.add(DemoUser.objects.get(email=oform.cleaned_data['email']))
|
||||||
event.users_organisers.add(request.user) # always add editor/creator
|
event.users_organisers.add(request.user) # always add editor/creator
|
||||||
if trustee_formset.is_valid():
|
if trustee_formset.is_valid():
|
||||||
event.users_trustees.clear()
|
event.users_trustees.clear()
|
||||||
for tform in trustee_formset:
|
for tform in trustee_formset:
|
||||||
if (tform.cleaned_data.get('email')):
|
if (tform.cleaned_data.get('email')):
|
||||||
event.users_trustees.add(EmailUser.objects.get_or_create(email=tform.cleaned_data['email'])[0])
|
event.users_trustees.add(EmailUser.objects.get_or_create(email=tform.cleaned_data['email'])[0])
|
||||||
'''
|
'''
|
||||||
return HttpResponseRedirect(reverse('polls:view-event', kwargs={'pk': event.id}))
|
return HttpResponseRedirect(reverse('polls:view-event', kwargs={'pk': event.id}))
|
||||||
return render(request, "polls/generic_form.html", {"form_title": "Edit Event: " + event.title, "form": form}) #"organiser_formset": organiser_formset, "trustee_formset": trustee_formset})
|
return render(request, "polls/generic_form.html", {"form_title": "Edit Event: " + event.title, "form": form}) #"organiser_formset": organiser_formset, "trustee_formset": trustee_formset})
|
||||||
#trustee_formset = TrusteeFormSet(request.POST, prefix="formset_trustee", instance=event)
|
#trustee_formset = TrusteeFormSet(request.POST, prefix="formset_trustee", instance=event)
|
||||||
|
|
||||||
|
|
||||||
def del_event(request, event_id):
|
def del_event(request, event_id):
|
||||||
event = get_object_or_404(Event, pk=event_id)
|
event = get_object_or_404(Event, pk=event_id)
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
return render(request, "polls/del_event.html", {"event_title": event.title, "event_id": event.uuid})
|
return render(request, "polls/del_event.html", {"event_title": event.title, "event_id": event.uuid})
|
||||||
elif request.method == "POST":
|
elif request.method == "POST":
|
||||||
event.delete()
|
event.delete()
|
||||||
return HttpResponseRedirect(reverse('polls:index'))
|
return HttpResponseRedirect(reverse('polls:index'))
|
|
@ -21,6 +21,7 @@
|
||||||
<script src="{% static 'js/decrypt_event.js' %}" type="text/javascript"></script>
|
<script src="{% static 'js/decrypt_event.js' %}" type="text/javascript"></script>
|
||||||
<script src="{% static 'js/event_vote.js' %}" type="text/javascript"></script>
|
<script src="{% static 'js/event_vote.js' %}" type="text/javascript"></script>
|
||||||
<script src="{% static 'js/vote_audit.js' %}" type="text/javascript"></script>
|
<script src="{% static 'js/vote_audit.js' %}" type="text/javascript"></script>
|
||||||
|
<script src="{% static 'js/find_ballot.js' %}" type="text/javascript"></script>
|
||||||
<script src="{% static 'js/encrypt.js' %}" type="text/javascript"></script>
|
<script src="{% static 'js/encrypt.js' %}" type="text/javascript"></script>
|
||||||
<script src="{% static 'js/event_setup.js' %}" type="text/javascript"></script>
|
<script src="{% static 'js/event_setup.js' %}" type="text/javascript"></script>
|
||||||
|
|
||||||
|
|
11
allauthdemo/templates/polls/find_ballot.html
Normal file
11
allauthdemo/templates/polls/find_ballot.html
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{% extends "bases/bootstrap-with-nav.html" %}
|
||||||
|
{% load staticfiles %}
|
||||||
|
{% load bootstrap3 %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<pre hidden id="ballot_found">{{ ballot }}</pre>
|
||||||
|
<pre hidden id="ballot_hashes">{{ hash1 }};{{ hash2 }}</pre>
|
||||||
|
<h1 id="ballot_result"></h1>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -4,15 +4,31 @@
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<input id="SK" value="temporary" type="text"/>
|
<label class="gp-1" for="handle1">Ballot #1 handle:</label>
|
||||||
<button id="begin-test">Verify Ballot</button>
|
<input class="gp-1" id="handle1" value="{{ handle1 }}" type="text"/>
|
||||||
<br>
|
<label class="gp-1" for="handle2">Ballot handle:</label>
|
||||||
<br>
|
<input class="gp-1" id="handle2" value="{{ handle2 }}" type="text"/>
|
||||||
<label for="ballot">AES-encrypted ballot from server</label>
|
<button class="gp-1" id="retrieve-ballots">Retrieve Ballots</button>
|
||||||
<pre id="ballot">{{ ballot }}</pre>
|
|
||||||
<label for="ballot-content">Decrypted ballot</label>
|
<hr>
|
||||||
<pre id="ballot-content"></pre>
|
|
||||||
<label for="ballot">Ballot encoding</label>
|
<label class="gp-2" for="ballot1">AES-encrypted ballot #1 from server</label>
|
||||||
<pre id="ballot-result"></pre>
|
<pre class="gp-2" id="ballot1">{{ ballot }}</pre>
|
||||||
|
<input class="gp-2" id="SK1" value="temporary" type="text"/>
|
||||||
|
<button class="gp-2" id="decrypt-ballot1">Decrypt Ballot</button>
|
||||||
|
<label class="gp-3" for="ballot-content1">Decrypted ballot</label>
|
||||||
|
<pre class="gp-3" id="ballot-content1"></pre>
|
||||||
|
<label class="gp-3" for="ballot-result1">Ballot encoding</label>
|
||||||
|
<pre class="gp-3" id="ballot-result1"></pre>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<label class="gp-2" for="ballot2">AES-encrypted ballot #2 from server</label>
|
||||||
|
<pre class="gp-2" id="ballot2">{{ ballot2 }}</pre>
|
||||||
|
<input class="gp-2" id="SK2" value="temporary" type="text"/>
|
||||||
|
<button class="gp-2" id="decrypt-ballot2">Decrypt Ballot</button>
|
||||||
|
<label class="gp-3" for="ballot-content2">Decrypted ballot</label>
|
||||||
|
<pre class="gp-3" id="ballot-content2"></pre>
|
||||||
|
<label class="gp-3" for="ballot-result2">Ballot encoding</label>
|
||||||
|
<pre class="gp-3" id="ballot-result2"></pre>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
|
@ -328,12 +328,51 @@ function generateBallots() {
|
||||||
var ballotB = generateBallot();
|
var ballotB = generateBallot();
|
||||||
progressBar.setAttribute("style", "width: 100%;");
|
progressBar.setAttribute("style", "width: 100%;");
|
||||||
|
|
||||||
showFirstQRCode(ballotA, ballotB, selectedOption);
|
showIDsQRCode(ballotA, ballotB, selectedOption);
|
||||||
}, 150);
|
}, 150);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showIDsQRCode(ballotA, ballotB, selectedOption) {
|
||||||
|
var voterID = window.location.search.slice(1).split(/=(.+)/)[1];
|
||||||
|
var eventID = window.location.href.split('/')[4];
|
||||||
|
var pollID = $('#poll-num').text();
|
||||||
|
|
||||||
|
// Display a QR code with ID details
|
||||||
|
var modalDialog = $('#modalDialog');
|
||||||
|
var title = modalDialog.find('.modal-title');
|
||||||
|
var body = modalDialog.find('.modal-body');
|
||||||
|
|
||||||
|
body.empty();
|
||||||
|
title.text('Step 0 of 3: Scan this');
|
||||||
|
|
||||||
|
let pleaseScanP = document.createElement('p');
|
||||||
|
pleaseScanP.innerHTML = "Please scan the following QR code from your DEMOS 2 mobile application:";
|
||||||
|
|
||||||
|
let QRDiv = document.createElement('div');
|
||||||
|
var QRCodeImg = document.createElement('img');
|
||||||
|
QRCodeImg.setAttribute('class', 'QR-code');
|
||||||
|
QRCodeImg.setAttribute('id', "qr-img");
|
||||||
|
new QRCode(QRCodeImg, voterID+";"+eventID+";"+pollID);
|
||||||
|
QRDiv.append(QRCodeImg);
|
||||||
|
|
||||||
|
body.append(pleaseScanP);
|
||||||
|
body.append(QRDiv);
|
||||||
|
|
||||||
|
// Prepare the appropriate dialog buttons
|
||||||
|
updateDialogButtons(DIALOG_BTN_STATES.STEP_1);
|
||||||
|
|
||||||
|
if(!dialogOpen) {
|
||||||
|
modalDialog.modal('toggle');
|
||||||
|
dialogOpen = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#nextDialogBtn').click(function(e) {
|
||||||
|
showHashQRCode(ballotA, ballotB, selectedOption);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Called in stage 1 of 3 in the voting process
|
// Called in stage 1 of 3 in the voting process
|
||||||
function showFirstQRCode(ballotA, ballotB, selectedOption) {
|
function showHashQRCode(ballotA, ballotB, selectedOption) {
|
||||||
var ballots = new Array(ballotA, ballotB);
|
var ballots = new Array(ballotA, ballotB);
|
||||||
var ballotHashes = new Array(2);
|
var ballotHashes = new Array(2);
|
||||||
|
|
||||||
|
@ -350,7 +389,7 @@ function showFirstQRCode(ballotA, ballotB, selectedOption) {
|
||||||
title.text('Step 1 of 3: Link Your Vote');
|
title.text('Step 1 of 3: Link Your Vote');
|
||||||
|
|
||||||
let pleaseScanP = document.createElement('p');
|
let pleaseScanP = document.createElement('p');
|
||||||
pleaseScanP.innerHTML = "Please scan the following QR code from your DEMOS 2 mobile application:";
|
pleaseScanP.innerHTML = "Please scan the following QR code from your DEMOS 2 auditor:";
|
||||||
|
|
||||||
let QRDiv = document.createElement('div');
|
let QRDiv = document.createElement('div');
|
||||||
var QRCodeImg = document.createElement('img');
|
var QRCodeImg = document.createElement('img');
|
||||||
|
@ -551,19 +590,22 @@ function sendBallotsToServer(selection, selectedBallot, otherBallot) {
|
||||||
var pk = new ctx.ECP(0);
|
var pk = new ctx.ECP(0);
|
||||||
pk.copy(tempPK.PK);
|
pk.copy(tempPK.PK);
|
||||||
|
|
||||||
var voterID = window.location.search.slice(1).split(/=(.+)/)[1];//.slice(0, -2);
|
// Prepares the unselected ballot to send, encrypted, to the server.
|
||||||
|
// Creates the unique ballot ID for the unselected ballot
|
||||||
|
var voterID = window.location.search.slice(1).split(/=(.+)/)[1];
|
||||||
var eventID = window.location.href.split('/')[4];
|
var eventID = window.location.href.split('/')[4];
|
||||||
var pollNum = $('#poll-num').text();
|
var pollNum = $('#poll-num').text();
|
||||||
var ballotID = encodeURIComponent(btoa(JSON.stringify({voterID: voterID, eventID: eventID, pollNum: pollNum})));
|
var ballotID = encodeURIComponent(btoa(JSON.stringify({voterID: voterID, eventID: eventID, pollNum: pollNum})));
|
||||||
|
|
||||||
// TODO: Generate a SK rather than using a static one. UUID generated server side and then injected JS side?
|
// TODO: Generate a SK rather than using a static one. UUID generated server side and then injected JS side?
|
||||||
JSON.stringify(otherBallot)
|
|
||||||
var SK = "temporary";
|
var SK = "temporary";
|
||||||
var encAlt = sjcl.encrypt(SK, JSON.stringify(otherBallot));
|
var encAlt = sjcl.encrypt(SK, JSON.stringify({ballotID: ballotID, ballot: otherBallot}));
|
||||||
|
|
||||||
|
// Generates an HMAC to protect the encrypted ballot from tampering.
|
||||||
var out = (new sjcl.misc.hmac(key, sjcl.hash.sha256)).mac(encAlt);
|
var out = (new sjcl.misc.hmac(key, sjcl.hash.sha256)).mac(encAlt);
|
||||||
var hmac = sjcl.codec.hex.fromBits(out);
|
var hmac = sjcl.codec.hex.fromBits(out);
|
||||||
|
|
||||||
|
// Prepares the selected ballot to submit to the server.
|
||||||
let selectedBallotAsStr = JSON.stringify(selectedBallot);
|
let selectedBallotAsStr = JSON.stringify(selectedBallot);
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type : "POST",
|
type : "POST",
|
||||||
url : window.location,
|
url : window.location,
|
||||||
|
@ -593,7 +635,7 @@ function onAfterBallotSend(ballotID, SK, hmac) {
|
||||||
instructions1P.innerHTML = instructions1Txt;
|
instructions1P.innerHTML = instructions1Txt;
|
||||||
body.append(instructions1P);
|
body.append(instructions1P);
|
||||||
|
|
||||||
// Add the second section: QR code that contains the ballot identifier
|
// Add the second section: QR code that contains the ballot identifier and HMAC
|
||||||
var QRCodeImg = document.createElement('img');
|
var QRCodeImg = document.createElement('img');
|
||||||
QRCodeImg.setAttribute('class', 'QR-code');
|
QRCodeImg.setAttribute('class', 'QR-code');
|
||||||
new QRCode(QRCodeImg, ballotID+";"+btoa(hmac));
|
new QRCode(QRCodeImg, ballotID+";"+btoa(hmac));
|
||||||
|
|
10
static/js/find_ballot.js
Normal file
10
static/js/find_ballot.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
$( document ).ready(function() {
|
||||||
|
ballotHash = SHA256Hash(stringtobytes(JSON.stringify($('#ballot-found').text())), true);
|
||||||
|
var hashes = $('#ballot_hashes').text().split(';');
|
||||||
|
$('#ballot_result').text("Ballot not found!");
|
||||||
|
for (var i = 0; i <= 1; i++) {
|
||||||
|
if (hashes[i] == ballotHash) {
|
||||||
|
$('#ballot_result').text("Ballot found!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -6,6 +6,25 @@ function getBytes(arr) {
|
||||||
return new Uint8Array(arr);
|
return new Uint8Array(arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$( document ).ready(function() {
|
||||||
|
$('.gp-2, .gp-3').hide();
|
||||||
|
var n = 0;
|
||||||
|
for (var i = 0; i <= 1; i++) {
|
||||||
|
if ($('#handle'+i).val() != "") {
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (n == 2) {
|
||||||
|
$('ballot-group'+i+' .gp-1').css('opacity','0.6');
|
||||||
|
$('#retrieve-ballots').prop('disabled', true);
|
||||||
|
$('ballot-group'+i+' .gp-2').show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#retrieve-ballots').click(function() {
|
||||||
|
window.location = "/audit?handle="+$('#handle1').val()+'&handle2='+$('#handle2').val();
|
||||||
|
});
|
||||||
|
|
||||||
$('#begin-test').click(function() {
|
$('#begin-test').click(function() {
|
||||||
var ctx = new CTX("BN254CX");
|
var ctx = new CTX("BN254CX");
|
||||||
var ciphertext = {
|
var ciphertext = {
|
||||||
|
@ -44,7 +63,19 @@ $('#begin-test').click(function() {
|
||||||
// test whether C2/(C1)^r = g^0 or g^1, and record g's exponent.
|
// test whether C2/(C1)^r = g^0 or g^1, and record g's exponent.
|
||||||
//var c1 = ctx.PAIR.GTpow(ciphertext.C1, ciphertext.r);
|
//var c1 = ctx.PAIR.GTpow(ciphertext.C1, ciphertext.r);
|
||||||
|
|
||||||
var m = ciphertext.C2.div(Math.pow(ciphertext.C1, ciphertext.r));
|
var B;
|
||||||
|
var j;
|
||||||
|
for (j = 0; j <= 1; j++) {
|
||||||
|
//use D as temp var
|
||||||
|
B = new ctx.BIG(j);
|
||||||
|
D = ctx.PAIR.G1mul(params.g1,B);
|
||||||
|
if (D.equals(gM)) {
|
||||||
|
return {
|
||||||
|
M:j
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
console.log("m = "+m);
|
console.log("m = "+m);
|
||||||
encoding += (m) ? "1" : "0";
|
encoding += (m) ? "1" : "0";
|
||||||
|
|
||||||
|
|
Reference in a new issue