From da89d9187c8f2ed1ae69d7489ff405e61dd91dae Mon Sep 17 00:00:00 2001 From: Tobias Oberstein Date: Sat, 13 Apr 2024 20:06:05 +0200 Subject: [PATCH] rid/id helpers: full conformance with WAMP spec --- autobahn/util.py | 32 +++++++++++++++++++++++--------- docs/changelog.rst | 1 + 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/autobahn/util.py b/autobahn/util.py index bfad2ed26..33d43cfca 100644 --- a/autobahn/util.py +++ b/autobahn/util.py @@ -222,7 +222,7 @@ class IdGenerator(object): Hence, IDs can be safely used with languages that use IEEE double as their main (or only) number type (JavaScript, Lua, etc). - See https://github.com/wamp-proto/wamp-proto/blob/master/spec/basic.md#ids + .. seealso:: `WAMP Spec `_ """ def __init__(self): @@ -236,7 +236,7 @@ def next(self): :rtype: int """ self._next += 1 - if self._next > 9007199254740992: + if self._next > 9007199254740992: # enforce range [1, 2**53] self._next = 1 return self._next @@ -278,16 +278,16 @@ def __next__(self): # -# 8 byte mask with 53 LSBs set (WAMP requires IDs from [0, 2**53] -_WAMP_ID_MASK = struct.unpack(">Q", b"\x00\x1f\xff\xff\xff\xff\xff\xff")[0] +# 8 byte mask with 53 LSBs set (WAMP actually requires IDs from [1, 2**53]) +_WAMP_ID_MASK = struct.unpack(">Q", b"\x00\x1f\xff\xff\xff\xff\xff\xff")[0] # use big endian ! def rid(): """ - Generate a new random integer ID from range **[0, 2**53]**. + Generate a new random integer ID from range **[1, 2**53]**. The generated ID is uniformly distributed over the whole range, doesn't have - a period (no pseudo-random generator is used) and cryptographically strong. + a period (no pseudo-random generator is used) and IS cryptographically strong. The upper bound **2**53** is chosen since it is the maximum integer that can be represented as a IEEE double such that all smaller integers are representable as well. @@ -295,16 +295,23 @@ def rid(): Hence, IDs can be safely used with languages that use IEEE double as their main (or only) number type (JavaScript, Lua, etc). + The lower bound **1** is chosen since 0 is often used as "falsy" in languages. + + .. seealso:: `WAMP Spec `_ + :returns: A random integer ID. :rtype: int """ - return struct.unpack("@Q", os.urandom(8))[0] & _WAMP_ID_MASK + # os.urandom is "unpredictable enough for cryptographic applications" + # https://docs.python.org/3/library/os.html#os.urandom + # use range [1, 2**53] + use big endian + return (struct.unpack(">Q", os.urandom(8))[0] & _WAMP_ID_MASK) + 1 # noinspection PyShadowingBuiltins def id(): """ - Generate a new random integer ID from range **[0, 2**53]**. + Generate a new random integer ID from range **[1, 2**53]**. The generated ID is based on a pseudo-random number generator (Mersenne Twister, which has a period of 2**19937-1). It is NOT cryptographically strong, and @@ -316,10 +323,17 @@ def id(): Hence, IDs can be safely used with languages that use IEEE double as their main (or only) number type (JavaScript, Lua, etc). + The lower bound **1** is chosen since 0 is often used as "falsy" in languages. + + .. seealso:: `WAMP Spec `_ + :returns: A random integer ID. :rtype: int """ - return random.randint(0, 9007199254740992) + # "Warning: The pseudo-random generators of this module should not be used for security purposes. + # For security or cryptographic uses, see the secrets module." + # https://docs.python.org/3/library/random.html + return random.randint(1, 9007199254740992) # use range [1, 2**53] def newid(length=16): diff --git a/docs/changelog.rst b/docs/changelog.rst index 35681f6d7..282fc5bf1 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -9,6 +9,7 @@ Changelog ------ - new: bump minimum required Twisted version to 24.3.0 (`see also `_) +- fix: full conformance to WAMP spec rgd allowed ranges of WAMP (session scope) IDs (`PR #1637 `_) 23.6.2 ------