summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mailman/model/pending.py18
-rw-r--r--src/mailman/utilities/uid.py32
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()