This is an automated email from the ASF dual-hosted git repository. humbedooh pushed a commit to branch trunk in repository https://gitbox.apache.org/repos/asf/steve.git
commit a1d7f7357b499f32972a02347cc3bd4fb0af685c Author: Daniel Gruno <[email protected]> AuthorDate: Sun Jan 26 12:24:47 2025 +0100 Python 3 compatibility updates - hashlib now only accepts bytestrings, so we'll set up a wrapper in constants for auto-converting. - izip no longer exists, zip to be used instead - fix import paths - multipart boundary must be bytestring - cmp no longer exists, sorted() now needs a wrapper via functools --- pysteve/lib/constants.py | 6 +++++- pysteve/lib/election.py | 20 ++++++++++---------- pysteve/lib/form.py | 3 ++- pysteve/lib/plugins/stv.py | 15 ++++++++------- pysteve/lib/voter.py | 6 +++--- pysteve/www/cgi-bin/rest_voter.py | 7 ++++--- 6 files changed, 32 insertions(+), 25 deletions(-) diff --git a/pysteve/lib/constants.py b/pysteve/lib/constants.py index 4a101bb..402abc1 100644 --- a/pysteve/lib/constants.py +++ b/pysteve/lib/constants.py @@ -15,7 +15,7 @@ # limitations under the License. # - +import hashlib VOTE_TYPES = ( ) @@ -24,6 +24,10 @@ DB_TYPES = ( ) +def hexdigest(data: str): + """Wrapper for hashlib.sha224().hexdigest that handles encoding""" + return hashlib.sha224(data.encode("utf-8")).hexdigest() + def appendVote(*types): """ Append a new type of voting to the list""" global VOTE_TYPES diff --git a/pysteve/lib/election.py b/pysteve/lib/election.py index 84a2061..cc3fe36 100644 --- a/pysteve/lib/election.py +++ b/pysteve/lib/election.py @@ -19,7 +19,7 @@ import json import os import random import time -from itertools import izip +#from itertools import izip try: from __main__ import config @@ -28,9 +28,9 @@ except: config = configparser.RawConfigParser() config.read("%s/../../../steve.cfg" % (os.path.dirname(__file__))) -import constants, voter -from plugins import * -from backends import * +from lib import constants, voter +from lib.plugins import * +from lib.backends import * @@ -88,7 +88,7 @@ def createElection(eid, title, owner, monitors, starts, ends, isopen): 'monitors': monitors, 'starts': starts, 'ends': ends, - 'hash': hashlib.sha512("%f-stv-%s" % (time.time(), os.environ['REMOTE_ADDR'] if 'REMOTE_ADDR' in os.environ else random.randint(1,99999999999))).hexdigest(), + 'hash': constants.hexdigest("%f-stv-%s" % (time.time(), os.environ['REMOTE_ADDR'] if 'REMOTE_ADDR' in os.environ else random.randint(1,99999999999)), method=hashlib.sha512), 'open': isopen } backend.election_create(eid, basedata) @@ -122,9 +122,9 @@ def vote(electionID, issueID, voterID, vote): basedata = getBasedata(electionID) issueData = getIssue(electionID, issueID) if basedata and issueData: - xhash = hashlib.sha224(electionID + ":" + voterID).hexdigest() - vhash = hashlib.sha224(xhash + issueID).hexdigest() - votehash = hashlib.sha224(basedata['hash'] + issueID + voterID + vote).hexdigest() + xhash = constants.hexdigest(electionID + ":" + voterID) + vhash = constants.hexdigest(xhash + issueID) + votehash = constants.hexdigest(basedata['hash'] + issueID + voterID + vote) # Vote verification voteType = getVoteType(issueData) @@ -182,10 +182,10 @@ def getHash(electionID): votes = getVotes(electionID, issue) ihash += issuedata['hash'] output.append("Issue #%s: %s\n- Checksum: %s\n- Votes cast: %u\n" % (issue, issuedata['title'], issuedata['hash'], len(votes))) - tothash = hashlib.sha224(ihash).hexdigest() + tothash = constants.hexdigest(ihash) output.insert(0, ("You are receiving this data because you are listed as a monitor for this election.\nThe following data shows the state of the election data on disk. If any of these checksums change, especially the main checksum, then the election has been edited (rigged?) after invites were sent out.\n\nMain Election Checksum : %s\n\n" % tothash)) output.append("\nYou can monitor votes and recasts online at: %s/monitor.html?%s" % (config.get("general", "rooturl"), electionID)) return tothash, "\n".join(output) def createIssue(electionID, issueID, data): - backend.issue_create(electionID, issueID, data) \ No newline at end of file + backend.issue_create(electionID, issueID, data) diff --git a/pysteve/lib/form.py b/pysteve/lib/form.py index 9b0520f..31ce381 100644 --- a/pysteve/lib/form.py +++ b/pysteve/lib/form.py @@ -19,7 +19,8 @@ import cgi ctype, pdict = cgi.parse_header(os.environ['CONTENT_TYPE'] if 'CONTENT_TYPE' in os.environ else "") if ctype == 'multipart/form-data': - xform = cgi.parse_multipart(sys.stdin, pdict) + pdict['boundary'] = bytes(pdict['boundary'], "utf-8") + xform = cgi.parse_multipart(sys.stdin, pdict, encoding="utf-8") else: xform = cgi.FieldStorage(); diff --git a/pysteve/lib/plugins/stv.py b/pysteve/lib/plugins/stv.py index af74e54..3807790 100644 --- a/pysteve/lib/plugins/stv.py +++ b/pysteve/lib/plugins/stv.py @@ -27,6 +27,7 @@ BILLIONTH = 0.000000001 from lib import constants +import functools debug = [] @@ -137,7 +138,7 @@ class CandidateList(object): def print_results(self): for c in self.l: - print '%-40s%selected' % (c.name, c.status == ELECTED and ' ' or ' not ') + print ('%-40s%selected' % (c.name, c.status == ELECTED and ' ' or ' not ')) def dbg_display_tables(self, excess): total = excess @@ -147,7 +148,6 @@ class CandidateList(object): debug.append('%-20s %15s %15.9f' %( 'Non-transferable', ' ', excess)) debug.append('%-20s %15s %15.9f' % ( 'Total', ' ', total)) - class Candidate(object): def __init__(self, name, rand, ahead): self.name = name @@ -170,11 +170,12 @@ class Candidate(object): assert quota is not None self.weight = (self.weight * quota) / self.vote - def __cmp__(self, other): - if self.ahead < other.ahead: + @staticmethod + def cmp(a,b): + if a.ahead < b.ahead: return -1 - if self.ahead == other.ahead: - return cmp(self.vote, other.vote) + if a.ahead == b.ahead: + return (a.vote > b.vote) - (a.vote < b.vote) return 1 @@ -227,7 +228,7 @@ def calc_totals(votes, candidates): def calc_aheads(candidates): - c_sorted = sorted(candidates.l) + c_sorted = sorted(candidates.l, key=functools.cmp_to_key(Candidate.cmp)) last = 0 for i in range(1, len(c_sorted)+1): if i == len(c_sorted) or c_sorted[last] != c_sorted[i]: diff --git a/pysteve/lib/voter.py b/pysteve/lib/voter.py index dbc7242..e6007c6 100644 --- a/pysteve/lib/voter.py +++ b/pysteve/lib/voter.py @@ -33,13 +33,13 @@ from lib import constants, election backend = constants.initBackend(config) def get(election, basedata, uid): - xhash = hashlib.sha512(basedata['hash'] + uid).hexdigest() + xhash = constants.hexdigest(basedata['hash'] + uid, method=hashlib.sha512) return backend.voter_get_uid(election, xhash) def add(election, basedata, PID): - uid = hashlib.sha224("%s%s%s%s" % (PID, basedata['hash'], time.time(), random.randint(1,99999999))).hexdigest() - xhash = hashlib.sha512(basedata['hash'] + uid).hexdigest() + uid = constants.hexdigest("%s%s%s%s" % (PID, basedata['hash'], time.time(), random.randint(1,99999999))) + xhash = constants.hexdigest(basedata['hash'] + uid, method=hashlib.sha512) backend.voter_add(election, PID, xhash) return uid, xhash diff --git a/pysteve/www/cgi-bin/rest_voter.py b/pysteve/www/cgi-bin/rest_voter.py index 7b2fb12..ae951cb 100755 --- a/pysteve/www/cgi-bin/rest_voter.py +++ b/pysteve/www/cgi-bin/rest_voter.py @@ -36,11 +36,12 @@ if 'SCRIPT_FILENAME' in os.environ: config = configparser.RawConfigParser() config.read(path + '/../../steve.cfg') + # Some quick paths homedir = config.get("general", "homedir") pathinfo = os.environ['PATH_INFO'] if 'PATH_INFO' in os.environ else None -from lib import response, voter, election, form +from lib import response, voter, election, form, constants whoami = os.environ['REMOTE_USER'] if 'REMOTE_USER' in os.environ else None @@ -145,7 +146,7 @@ if pathinfo: response.respond(500, {'message': invalid}) else: votehash = election.vote(electionID, issueID, voterID, vote) - voteuid = hashlib.sha224(voterID).hexdigest() + voteuid = constants.hexdigest(voterID) # Catch proxy-emails m = re.match(r"^(.+@.*?[a-zA-Z])-[^.]+$", email) if m: @@ -198,4 +199,4 @@ if pathinfo: else: response.respond(400, {'message': 'Invalid action supplied'}) else: - response.respond(500, {'message': 'No path info supplied, aborting'}) \ No newline at end of file + response.respond(500, {'message': 'No path info supplied, aborting'})
