diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/mailman/model/pending.py | 18 | ||||
| -rw-r--r-- | src/mailman/utilities/uid.py | 32 |
2 files changed, 33 insertions, 17 deletions
diff --git a/src/mailman/model/pending.py b/src/mailman/model/pending.py index 1973820d0..b8dbb1932 100644 --- a/src/mailman/model/pending.py +++ b/src/mailman/model/pending.py @@ -24,9 +24,6 @@ __all__ = [ import json -import time -import random -import hashlib from lazr.config import as_timedelta from mailman.config import config @@ -35,12 +32,16 @@ from mailman.database.transaction import dbconnection from mailman.interfaces.pending import ( IPendable, IPended, IPendedKeyValue, IPendings) from mailman.utilities.datetime import now +from mailman.utilities.uid import TokenFactory from sqlalchemy import Column, DateTime, ForeignKey, Integer, Unicode, and_ from sqlalchemy.orm import aliased, relationship from zope.interface import implementer from zope.interface.verify import verifyObject +token_factory = TokenFactory() + + @implementer(IPendedKeyValue) class PendedKeyValue(Model): @@ -88,17 +89,8 @@ class Pendings: # Calculate the token and the lifetime. if lifetime is None: lifetime = as_timedelta(config.mailman.pending_request_life) - # Calculate a unique token. Algorithm vetted by the Timbot. time() - # has high resolution on Linux, clock() on Windows. random gives us - # about 45 bits in Python 2.2, 53 bits on Python 2.3. The time and - # clock values basically help obscure the random number generator, as - # does the hash calculation. The integral parts of the time values - # are discarded because they're the most predictable bits. for attempts in range(3): - right_now = time.time() - x = random.random() + right_now % 1.0 + time.clock() % 1.0 - # Use sha1 because it produces shorter strings. - token = hashlib.sha1(repr(x).encode('utf-8')).hexdigest() + token = token_factory.new_token() # In practice, we'll never get a duplicate, but we'll be anal # about checking anyway. if store.query(Pended).filter_by(token=token).count() == 0: diff --git a/src/mailman/utilities/uid.py b/src/mailman/utilities/uid.py index ec7948189..d20360ca0 100644 --- a/src/mailman/utilities/uid.py +++ b/src/mailman/utilities/uid.py @@ -28,8 +28,11 @@ __all__ = [ import os +import time import uuid import errno +import random +import hashlib from flufl.lock import Lock from mailman.config import config @@ -78,7 +81,7 @@ class UniqueIDFactory: # may still not be ideal due to race conditions, but I think the # tests will be serialized enough (and the ids reset between # tests) that it will not be a problem. Maybe. - return self._next_uid() + return uuid.UUID(int=self._next_uid()) while True: uid = uuid.uuid4() try: @@ -96,13 +99,13 @@ class UniqueIDFactory: next_uid = uid + 1 with open(self._uid_file, 'w') as fp: fp.write(str(next_uid)) - return uuid.UUID(int=uid) + return uid except IOError as error: if error.errno != errno.ENOENT: raise with open(self._uid_file, 'w') as fp: fp.write('2') - return uuid.UUID(int=1) + return 1 def reset(self): with self._lock: @@ -111,4 +114,25 @@ class UniqueIDFactory: -factory = UniqueIDFactory() +class TokenFactory(UniqueIDFactory): + + def __init__(self): + super(TokenFactory, self).__init__(context='token') + + def new_token(self): + """ + Calculate a unique token. Algorithm vetted by the Timbot. time() + has high resolution on Linux, clock() on Windows. random gives us + about 45 bits in Python 2.2, 53 bits on Python 2.3. The time and + clock values basically help obscure the random number generator, as + does the hash calculation. The integral parts of the time values + are discarded because they're the most predictable bits. + """ + if layers.is_testing(): + # When in testing mode we want to produce predictable tokens, see + # UniqueIDFactory for a similar use case. + return str(self._next_uid()).zfill(40) + right_now = time.time() + x = random.random() + right_now % 1.0 + time.clock() % 1.0 + # Use sha1 because it produces shorter strings. + return hashlib.sha1(repr(x).encode('utf-8')).hexdigest() |
