def validate(self, value): super(GPGKeyValidator, self).validate(value) if value: import_result = gpg.import_keys(value) if import_result.count == 0: raise Invalid(_(u"The GPG key is not valid"))
def get_voting_count(self): #XXX: "digit_count" should be some customizable field from the election # and not defined here. (neither should be in generate_random_numbers_for_candidates ) digit_count = 10 results = [] votes_zip = getattr(self.context, 'votes_count_zip', None) if votes_zip: aux_results = {} annotation = IAnnotations(self.context) nominees = annotation['nominees'] ob = StringIO() ob.write(votes_zip.data) zip_file = ZipFile(ob, "r", ZIP_DEFLATED) for name in zip_file.namelist(): vote = zip_file.read(name)[:digit_count] nominee = nominees.get(long(vote)) if not nominee: raise Invalid(_(u"There doesn't seem to be a valid nominee for vote: %s. Data might be corrupt: %s." % (vote, nominees))) nominee_count = aux_results.get(nominee, 0) nominee_count += 1 aux_results[nominee] = nominee_count vocab = getUtility(IVocabularyFactory, name="plone.principalsource.Users") values = vocab(self.context) for nominee in self.context.nominations_roll: full_name = values.getTermByToken(nominee).title results.append({'name': full_name, 'votes': aux_results.get(nominee, 0)}) return results
def validate(self, value): super(GPGSignatureValidator, self).validate(value) data = '' ending = "_signature" _len = len(ending) signature = self.field.getName() signed_file = signature[:-_len] file = self.request.form.get('form.widgets.%s' % signed_file) if file: file.seek(0) data = file.read() file.seek(0) else: pdf_field = getattr(self.context, signed_file, None) if pdf_field: data = pdf_field.data # It would be nice to be able to do this from a stream, # but unfortunately, gnupg expects files fd, fn = tempfile.mkstemp(prefix='elections') os.write(fd, data) os.close(fd) sig = _make_binary_stream(value.data, gpg.encoding) verify = gpg.verify_file(sig, fn) if not verify.valid: if hasattr(verify, 'status'): # Error codes gnupg.py line 150 if verify.status == 'signature bad': raise Invalid( _(u"This signature is not valid for the uploaded file." )) else: raise Invalid(_(u"Error: %s." % verify.status)) else: raise Invalid(_(u"Invalid signature."))
def validate(self, value): super(GPGSignatureValidator, self).validate(value) data = '' ending = "_signature" _len = len(ending) signature = self.field.getName() signed_file = signature[:-_len] file = self.request.form.get('form.widgets.%s' % signed_file) if file: file.seek(0) data = file.read() file.seek(0) else: pdf_field = getattr(self.context, signed_file, None) if pdf_field: data = pdf_field.data # It would be nice to be able to do this from a stream, # but unfortunately, gnupg expects files fd, fn = tempfile.mkstemp(prefix='elections') os.write(fd, data) os.close(fd) sig = _make_binary_stream(value.data, gpg.encoding) verify = gpg.verify_file(sig, fn) if not verify.valid: if hasattr(verify, 'status'): # Error codes gnupg.py line 150 if verify.status == 'signature bad': raise Invalid(_(u"This signature is not valid for the uploaded file.")) else: raise Invalid(_(u"Error: %s." % verify.status)) else: raise Invalid(_(u"Invalid signature."))
def status_change_msg(self): wf_tool = getToolByName(self.context, "portal_workflow") chain = wf_tool.getChainForPortalType(self.context.portal_type) status = wf_tool.getStatusOf(chain[0], self.context) state = status['review_state'] wf_tr_map = {'internal_revision': 'can-submit-to-public', 'public_revision': 'can-select-nominees', 'nominee_revision': 'can-send-to-public', 'public': 'can-be-started', 'voting': 'should-be-ended', 'scrutiny': 'results-should-be-public', 'published': 'can-be-closed', } if state in wf_tr_map: trans_guard = getMultiAdapter((self.context, self.request), name=wf_tr_map[state]) can_call_trans = trans_guard() if not can_call_trans: if state == 'internal_revision': return _(u"Cannot send to public. You are not the CEO or you need to upload the signed configuration PDF and signature") if state == 'public_revision': return _(u"Cannot select nominees. The date has not been reached") if state == 'nominee_revision': return _(u"Cannot send to public. You are not the CEO or you need to upload the signed nomination and electoral PDF and signature") if state == 'public': return _(u"Cannot start voting. The date has not been reached") if state == 'voting': return _(u"Cannot start counting votes. The date has not been reached") if state == 'scrutiny': return _(u"Cannot publish results. The date has not been reached") if state == 'published': return _(u"Cannot close the election. You are not the CEO") return _(u"")
def cast_vote(self): #XXX: "digit_count" should be some customizable field from the election # and not defined here. (neither should be in generate_random_numbers_for_candidates ) digit_count = 10 pm = getToolByName(self.context, 'portal_membership') nominee = self.request.get("chosen_nominee") voter = pm.getAuthenticatedMember().getId() # Now, let's get the random number that belongs for this voter and # nominee annotation = IAnnotations(self.context) # This should never ever happen, but just in case... if voter not in annotation['electoral']: raise Invalid(_(u"You are not allowed to vote. Please contact the system administrator.")) if nominee not in annotation['electoral'][voter]: raise Invalid(_(u"The nominee you selected does not exist. Please contact the system administrator.")) # We get the random number assigned for this nominee to this voter random_number = annotation['electoral'][voter][nominee] # We create the new random number with the same length. new_random = long(random() * (10 ** digit_count)) # Make sure that the random number has digit_count digits: while len(str(new_random)) != digit_count: new_random = long(random() * (10 ** digit_count)) # Append it result = str(random_number) + str(new_random) receipts = annotation.get('receipts', {}) # Generate our MD5 receipt receipt = hashlib.md5(result).hexdigest() now = datetime.now() receipts[voter] = {'receipt': receipt, 'date': now} # And save it annotation['receipts'] = receipts # Now, we get our keys fingerprints. We have to do it this way because python's gnupg # uses the system gnupg, so it may happen that at some point the key is lost from # the system keyring. try: admin_fingerprint = gpg.import_keys(self.context.gpg_key_admin).results[0]['fingerprint'] except: raise Invalid(_(u"Something wrong happened with the admin GPG key.")) try: comission_fingerprint = gpg.import_keys(self.context.gpg_key_comission).results[0]['fingerprint'] except: raise Invalid(_(u"Something wrong happened with the comission GPG key.")) # Now we double cipher it. First with the comission key first = gpg.encrypt(result, comission_fingerprint) # Then with the admin's one. second = gpg.encrypt(first.data, admin_fingerprint) # Finally, store the vote in the annotation not_used_votes = annotation.get('not_used_votes', []) votes = annotation.get('votes', []) if random_number not in not_used_votes: votes.append(second.data) # And we shuffle it to improve anonymity shuffle(votes) annotation['votes'] = votes else: # XXX: This number shouldn't be usable, something wrong happened # need to figure out how to proceed in this case raise Invalid(_(u"A nominee code was tried to be reused.")) return # And now, we store the other possible random_numbers from this voter # So they cannot be used not_used_votes += [value for key, value in annotation['electoral'][voter].items() if key != 'already_voted' and value != random_number] annotation['not_used_votes'] = not_used_votes # Finally, we "mark" the voter as "already_voted" annotation['electoral'][voter]['already_voted'] = True #Done. return