Ticket #14093: django-uuid-session-keys.diff

File django-uuid-session-keys.diff, 23.8 KB (added by tomevans223, 5 years ago)

Patch to replace md5 session key generation with uuid session key generation. Includes verbatim copy of uuid.py from python 2.6 to fix issue that uuid is not in std libs in python 2.4

  • contrib/sessions/backends/base.py

     
    1111
    1212from django.conf import settings
    1313from django.core.exceptions import SuspiciousOperation
    14 from django.utils.hashcompat import md5_constructor
     14from django.utils.hashcompat import md5_constructor, uuid4
    1515from django.utils.crypto import constant_time_compare, salted_hmac
    1616
    1717# Use the system (hardware-based) random number generator if it exists.
     
    1919    randrange = random.SystemRandom().randrange
    2020else:
    2121    randrange = random.randrange
    22 MAX_SESSION_KEY = 18446744073709551616L     # 2 << 63
    2322
    2423class CreateError(Exception):
    2524    """
     
    161160            # No getpid() in Jython, for example
    162161            pid = 1
    163162        while 1:
    164             session_key = md5_constructor("%s%s%s%s"
    165                     % (randrange(0, MAX_SESSION_KEY), pid, time.time(),
    166                        settings.SECRET_KEY)).hexdigest()
     163            session_key = str(uuid4())
    167164            if not self.exists(session_key):
    168165                break
    169166        return session_key
  • contrib/sessions/backends/file.py

     
    2626        self.file_prefix = settings.SESSION_COOKIE_NAME
    2727        super(SessionStore, self).__init__(session_key)
    2828
    29     VALID_KEY_CHARS = set("abcdef0123456789")
     29    VALID_KEY_CHARS = set("abcdef0123456789-")
    3030
    3131    def _key_to_file(self, session_key=None):
    3232        """
     
    3636            session_key = self.session_key
    3737
    3838        # Make sure we're not vulnerable to directory traversal. Session keys
    39         # should always be md5s, so they should never contain directory
     39        # should always be UUIDs, so they should never contain directory
    4040        # components.
    4141        if not set(session_key).issubset(self.VALID_KEY_CHARS):
    4242            raise SuspiciousOperation(
  • utils/_uuid.py

     
     1r"""UUID objects (universally unique identifiers) according to RFC 4122.
     2
     3This module provides immutable UUID objects (class UUID) and the functions
     4uuid1(), uuid3(), uuid4(), uuid5() for generating version 1, 3, 4, and 5
     5UUIDs as specified in RFC 4122.
     6
     7If all you want is a unique ID, you should probably call uuid1() or uuid4().
     8Note that uuid1() may compromise privacy since it creates a UUID containing
     9the computer's network address.  uuid4() creates a random UUID.
     10
     11Typical usage:
     12
     13    >>> import uuid
     14
     15    # make a UUID based on the host ID and current time
     16    >>> uuid.uuid1()
     17    UUID('a8098c1a-f86e-11da-bd1a-00112444be1e')
     18
     19    # make a UUID using an MD5 hash of a namespace UUID and a name
     20    >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org')
     21    UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')
     22
     23    # make a random UUID
     24    >>> uuid.uuid4()
     25    UUID('16fd2706-8baf-433b-82eb-8c7fada847da')
     26
     27    # make a UUID using a SHA-1 hash of a namespace UUID and a name
     28    >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')
     29    UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')
     30
     31    # make a UUID from a string of hex digits (braces and hyphens ignored)
     32    >>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}')
     33
     34    # convert a UUID to a string of hex digits in standard form
     35    >>> str(x)
     36    '00010203-0405-0607-0809-0a0b0c0d0e0f'
     37
     38    # get the raw 16 bytes of the UUID
     39    >>> x.bytes
     40    '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f'
     41
     42    # make a UUID from a 16-byte string
     43    >>> uuid.UUID(bytes=x.bytes)
     44    UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')
     45"""
     46
     47__author__ = 'Ka-Ping Yee <ping@zesty.ca>'
     48
     49RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [
     50    'reserved for NCS compatibility', 'specified in RFC 4122',
     51    'reserved for Microsoft compatibility', 'reserved for future definition']
     52
     53class UUID(object):
     54    """Instances of the UUID class represent UUIDs as specified in RFC 4122.
     55    UUID objects are immutable, hashable, and usable as dictionary keys.
     56    Converting a UUID to a string with str() yields something in the form
     57    '12345678-1234-1234-1234-123456789abc'.  The UUID constructor accepts
     58    five possible forms: a similar string of hexadecimal digits, or a tuple
     59    of six integer fields (with 32-bit, 16-bit, 16-bit, 8-bit, 8-bit, and
     60    48-bit values respectively) as an argument named 'fields', or a string
     61    of 16 bytes (with all the integer fields in big-endian order) as an
     62    argument named 'bytes', or a string of 16 bytes (with the first three
     63    fields in little-endian order) as an argument named 'bytes_le', or a
     64    single 128-bit integer as an argument named 'int'.
     65
     66    UUIDs have these read-only attributes:
     67
     68        bytes       the UUID as a 16-byte string (containing the six
     69                    integer fields in big-endian byte order)
     70
     71        bytes_le    the UUID as a 16-byte string (with time_low, time_mid,
     72                    and time_hi_version in little-endian byte order)
     73
     74        fields      a tuple of the six integer fields of the UUID,
     75                    which are also available as six individual attributes
     76                    and two derived attributes:
     77
     78            time_low                the first 32 bits of the UUID
     79            time_mid                the next 16 bits of the UUID
     80            time_hi_version         the next 16 bits of the UUID
     81            clock_seq_hi_variant    the next 8 bits of the UUID
     82            clock_seq_low           the next 8 bits of the UUID
     83            node                    the last 48 bits of the UUID
     84
     85            time                    the 60-bit timestamp
     86            clock_seq               the 14-bit sequence number
     87
     88        hex         the UUID as a 32-character hexadecimal string
     89
     90        int         the UUID as a 128-bit integer
     91
     92        urn         the UUID as a URN as specified in RFC 4122
     93
     94        variant     the UUID variant (one of the constants RESERVED_NCS,
     95                    RFC_4122, RESERVED_MICROSOFT, or RESERVED_FUTURE)
     96
     97        version     the UUID version number (1 through 5, meaningful only
     98                    when the variant is RFC_4122)
     99    """
     100
     101    def __init__(self, hex=None, bytes=None, bytes_le=None, fields=None,
     102                       int=None, version=None):
     103        r"""Create a UUID from either a string of 32 hexadecimal digits,
     104        a string of 16 bytes as the 'bytes' argument, a string of 16 bytes
     105        in little-endian order as the 'bytes_le' argument, a tuple of six
     106        integers (32-bit time_low, 16-bit time_mid, 16-bit time_hi_version,
     107        8-bit clock_seq_hi_variant, 8-bit clock_seq_low, 48-bit node) as
     108        the 'fields' argument, or a single 128-bit integer as the 'int'
     109        argument.  When a string of hex digits is given, curly braces,
     110        hyphens, and a URN prefix are all optional.  For example, these
     111        expressions all yield the same UUID:
     112
     113        UUID('{12345678-1234-5678-1234-567812345678}')
     114        UUID('12345678123456781234567812345678')
     115        UUID('urn:uuid:12345678-1234-5678-1234-567812345678')
     116        UUID(bytes='\x12\x34\x56\x78'*4)
     117        UUID(bytes_le='\x78\x56\x34\x12\x34\x12\x78\x56' +
     118                      '\x12\x34\x56\x78\x12\x34\x56\x78')
     119        UUID(fields=(0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x567812345678))
     120        UUID(int=0x12345678123456781234567812345678)
     121
     122        Exactly one of 'hex', 'bytes', 'bytes_le', 'fields', or 'int' must
     123        be given.  The 'version' argument is optional; if given, the resulting
     124        UUID will have its variant and version set according to RFC 4122,
     125        overriding the given 'hex', 'bytes', 'bytes_le', 'fields', or 'int'.
     126        """
     127
     128        if [hex, bytes, bytes_le, fields, int].count(None) != 4:
     129            raise TypeError('need one of hex, bytes, bytes_le, fields, or int')
     130        if hex is not None:
     131            hex = hex.replace('urn:', '').replace('uuid:', '')
     132            hex = hex.strip('{}').replace('-', '')
     133            if len(hex) != 32:
     134                raise ValueError('badly formed hexadecimal UUID string')
     135            int = long(hex, 16)
     136        if bytes_le is not None:
     137            if len(bytes_le) != 16:
     138                raise ValueError('bytes_le is not a 16-char string')
     139            bytes = (bytes_le[3] + bytes_le[2] + bytes_le[1] + bytes_le[0] +
     140                     bytes_le[5] + bytes_le[4] + bytes_le[7] + bytes_le[6] +
     141                     bytes_le[8:])
     142        if bytes is not None:
     143            if len(bytes) != 16:
     144                raise ValueError('bytes is not a 16-char string')
     145            int = long(('%02x'*16) % tuple(map(ord, bytes)), 16)
     146        if fields is not None:
     147            if len(fields) != 6:
     148                raise ValueError('fields is not a 6-tuple')
     149            (time_low, time_mid, time_hi_version,
     150             clock_seq_hi_variant, clock_seq_low, node) = fields
     151            if not 0 <= time_low < 1<<32L:
     152                raise ValueError('field 1 out of range (need a 32-bit value)')
     153            if not 0 <= time_mid < 1<<16L:
     154                raise ValueError('field 2 out of range (need a 16-bit value)')
     155            if not 0 <= time_hi_version < 1<<16L:
     156                raise ValueError('field 3 out of range (need a 16-bit value)')
     157            if not 0 <= clock_seq_hi_variant < 1<<8L:
     158                raise ValueError('field 4 out of range (need an 8-bit value)')
     159            if not 0 <= clock_seq_low < 1<<8L:
     160                raise ValueError('field 5 out of range (need an 8-bit value)')
     161            if not 0 <= node < 1<<48L:
     162                raise ValueError('field 6 out of range (need a 48-bit value)')
     163            clock_seq = (clock_seq_hi_variant << 8L) | clock_seq_low
     164            int = ((time_low << 96L) | (time_mid << 80L) |
     165                   (time_hi_version << 64L) | (clock_seq << 48L) | node)
     166        if int is not None:
     167            if not 0 <= int < 1<<128L:
     168                raise ValueError('int is out of range (need a 128-bit value)')
     169        if version is not None:
     170            if not 1 <= version <= 5:
     171                raise ValueError('illegal version number')
     172            # Set the variant to RFC 4122.
     173            int &= ~(0xc000 << 48L)
     174            int |= 0x8000 << 48L
     175            # Set the version number.
     176            int &= ~(0xf000 << 64L)
     177            int |= version << 76L
     178        self.__dict__['int'] = int
     179
     180    def __cmp__(self, other):
     181        if isinstance(other, UUID):
     182            return cmp(self.int, other.int)
     183        return NotImplemented
     184
     185    def __hash__(self):
     186        return hash(self.int)
     187
     188    def __int__(self):
     189        return self.int
     190
     191    def __repr__(self):
     192        return 'UUID(%r)' % str(self)
     193
     194    def __setattr__(self, name, value):
     195        raise TypeError('UUID objects are immutable')
     196
     197    def __str__(self):
     198        hex = '%032x' % self.int
     199        return '%s-%s-%s-%s-%s' % (
     200            hex[:8], hex[8:12], hex[12:16], hex[16:20], hex[20:])
     201
     202    def get_bytes(self):
     203        bytes = ''
     204        for shift in range(0, 128, 8):
     205            bytes = chr((self.int >> shift) & 0xff) + bytes
     206        return bytes
     207
     208    bytes = property(get_bytes)
     209
     210    def get_bytes_le(self):
     211        bytes = self.bytes
     212        return (bytes[3] + bytes[2] + bytes[1] + bytes[0] +
     213                bytes[5] + bytes[4] + bytes[7] + bytes[6] + bytes[8:])
     214
     215    bytes_le = property(get_bytes_le)
     216
     217    def get_fields(self):
     218        return (self.time_low, self.time_mid, self.time_hi_version,
     219                self.clock_seq_hi_variant, self.clock_seq_low, self.node)
     220
     221    fields = property(get_fields)
     222
     223    def get_time_low(self):
     224        return self.int >> 96L
     225
     226    time_low = property(get_time_low)
     227
     228    def get_time_mid(self):
     229        return (self.int >> 80L) & 0xffff
     230
     231    time_mid = property(get_time_mid)
     232
     233    def get_time_hi_version(self):
     234        return (self.int >> 64L) & 0xffff
     235
     236    time_hi_version = property(get_time_hi_version)
     237
     238    def get_clock_seq_hi_variant(self):
     239        return (self.int >> 56L) & 0xff
     240
     241    clock_seq_hi_variant = property(get_clock_seq_hi_variant)
     242
     243    def get_clock_seq_low(self):
     244        return (self.int >> 48L) & 0xff
     245
     246    clock_seq_low = property(get_clock_seq_low)
     247
     248    def get_time(self):
     249        return (((self.time_hi_version & 0x0fffL) << 48L) |
     250                (self.time_mid << 32L) | self.time_low)
     251
     252    time = property(get_time)
     253
     254    def get_clock_seq(self):
     255        return (((self.clock_seq_hi_variant & 0x3fL) << 8L) |
     256                self.clock_seq_low)
     257
     258    clock_seq = property(get_clock_seq)
     259
     260    def get_node(self):
     261        return self.int & 0xffffffffffff
     262
     263    node = property(get_node)
     264
     265    def get_hex(self):
     266        return '%032x' % self.int
     267
     268    hex = property(get_hex)
     269
     270    def get_urn(self):
     271        return 'urn:uuid:' + str(self)
     272
     273    urn = property(get_urn)
     274
     275    def get_variant(self):
     276        if not self.int & (0x8000 << 48L):
     277            return RESERVED_NCS
     278        elif not self.int & (0x4000 << 48L):
     279            return RFC_4122
     280        elif not self.int & (0x2000 << 48L):
     281            return RESERVED_MICROSOFT
     282        else:
     283            return RESERVED_FUTURE
     284
     285    variant = property(get_variant)
     286
     287    def get_version(self):
     288        # The version bits are only meaningful for RFC 4122 UUIDs.
     289        if self.variant == RFC_4122:
     290            return int((self.int >> 76L) & 0xf)
     291
     292    version = property(get_version)
     293
     294def _find_mac(command, args, hw_identifiers, get_index):
     295    import os
     296    for dir in ['', '/sbin/', '/usr/sbin']:
     297        executable = os.path.join(dir, command)
     298        if not os.path.exists(executable):
     299            continue
     300
     301        try:
     302            # LC_ALL to get English output, 2>/dev/null to
     303            # prevent output on stderr
     304            cmd = 'LC_ALL=C %s %s 2>/dev/null' % (executable, args)
     305            pipe = os.popen(cmd)
     306        except IOError:
     307            continue
     308
     309        for line in pipe:
     310            words = line.lower().split()
     311            for i in range(len(words)):
     312                if words[i] in hw_identifiers:
     313                    return int(words[get_index(i)].replace(':', ''), 16)
     314    return None
     315
     316def _ifconfig_getnode():
     317    """Get the hardware address on Unix by running ifconfig."""
     318
     319    # This works on Linux ('' or '-a'), Tru64 ('-av'), but not all Unixes.
     320    for args in ('', '-a', '-av'):
     321        mac = _find_mac('ifconfig', args, ['hwaddr', 'ether'], lambda i: i+1)
     322        if mac:
     323            return mac
     324
     325    import socket
     326    ip_addr = socket.gethostbyname(socket.gethostname())
     327
     328    # Try getting the MAC addr from arp based on our IP address (Solaris).
     329    mac = _find_mac('arp', '-an', [ip_addr], lambda i: -1)
     330    if mac:
     331        return mac
     332
     333    # This might work on HP-UX.
     334    mac = _find_mac('lanscan', '-ai', ['lan0'], lambda i: 0)
     335    if mac:
     336        return mac
     337
     338    return None
     339
     340def _ipconfig_getnode():
     341    """Get the hardware address on Windows by running ipconfig.exe."""
     342    import os, re
     343    dirs = ['', r'c:\windows\system32', r'c:\winnt\system32']
     344    try:
     345        import ctypes
     346        buffer = ctypes.create_string_buffer(300)
     347        ctypes.windll.kernel32.GetSystemDirectoryA(buffer, 300)
     348        dirs.insert(0, buffer.value.decode('mbcs'))
     349    except:
     350        pass
     351    for dir in dirs:
     352        try:
     353            pipe = os.popen(os.path.join(dir, 'ipconfig') + ' /all')
     354        except IOError:
     355            continue
     356        for line in pipe:
     357            value = line.split(':')[-1].strip().lower()
     358            if re.match('([0-9a-f][0-9a-f]-){5}[0-9a-f][0-9a-f]', value):
     359                return int(value.replace('-', ''), 16)
     360
     361def _netbios_getnode():
     362    """Get the hardware address on Windows using NetBIOS calls.
     363    See http://support.microsoft.com/kb/118623 for details."""
     364    import win32wnet, netbios
     365    ncb = netbios.NCB()
     366    ncb.Command = netbios.NCBENUM
     367    ncb.Buffer = adapters = netbios.LANA_ENUM()
     368    adapters._pack()
     369    if win32wnet.Netbios(ncb) != 0:
     370        return
     371    adapters._unpack()
     372    for i in range(adapters.length):
     373        ncb.Reset()
     374        ncb.Command = netbios.NCBRESET
     375        ncb.Lana_num = ord(adapters.lana[i])
     376        if win32wnet.Netbios(ncb) != 0:
     377            continue
     378        ncb.Reset()
     379        ncb.Command = netbios.NCBASTAT
     380        ncb.Lana_num = ord(adapters.lana[i])
     381        ncb.Callname = '*'.ljust(16)
     382        ncb.Buffer = status = netbios.ADAPTER_STATUS()
     383        if win32wnet.Netbios(ncb) != 0:
     384            continue
     385        status._unpack()
     386        bytes = map(ord, status.adapter_address)
     387        return ((bytes[0]<<40L) + (bytes[1]<<32L) + (bytes[2]<<24L) +
     388                (bytes[3]<<16L) + (bytes[4]<<8L) + bytes[5])
     389
     390# Thanks to Thomas Heller for ctypes and for his help with its use here.
     391
     392# If ctypes is available, use it to find system routines for UUID generation.
     393_uuid_generate_random = _uuid_generate_time = _UuidCreate = None
     394try:
     395    import ctypes, ctypes.util
     396
     397    # The uuid_generate_* routines are provided by libuuid on at least
     398    # Linux and FreeBSD, and provided by libc on Mac OS X.
     399    for libname in ['uuid', 'c']:
     400        try:
     401            lib = ctypes.CDLL(ctypes.util.find_library(libname))
     402        except:
     403            continue
     404        if hasattr(lib, 'uuid_generate_random'):
     405            _uuid_generate_random = lib.uuid_generate_random
     406        if hasattr(lib, 'uuid_generate_time'):
     407            _uuid_generate_time = lib.uuid_generate_time
     408
     409    # The uuid_generate_* functions are broken on MacOS X 10.5, as noted
     410    # in issue #8621 the function generates the same sequence of values
     411    # in the parent process and all children created using fork (unless
     412    # those children use exec as well).
     413    #
     414    # Assume that the uuid_generate functions are broken from 10.5 onward,
     415    # the test can be adjusted when a later version is fixed.
     416    import sys
     417    if sys.platform == 'darwin':
     418        import os
     419        if int(os.uname()[2].split('.')[0]) >= 9:
     420            _uuid_generate_random = _uuid_generate_time = None
     421
     422    # On Windows prior to 2000, UuidCreate gives a UUID containing the
     423    # hardware address.  On Windows 2000 and later, UuidCreate makes a
     424    # random UUID and UuidCreateSequential gives a UUID containing the
     425    # hardware address.  These routines are provided by the RPC runtime.
     426    # NOTE:  at least on Tim's WinXP Pro SP2 desktop box, while the last
     427    # 6 bytes returned by UuidCreateSequential are fixed, they don't appear
     428    # to bear any relationship to the MAC address of any network device
     429    # on the box.
     430    try:
     431        lib = ctypes.windll.rpcrt4
     432    except:
     433        lib = None
     434    _UuidCreate = getattr(lib, 'UuidCreateSequential',
     435                          getattr(lib, 'UuidCreate', None))
     436except:
     437    pass
     438
     439def _unixdll_getnode():
     440    """Get the hardware address on Unix using ctypes."""
     441    _buffer = ctypes.create_string_buffer(16)
     442    _uuid_generate_time(_buffer)
     443    return UUID(bytes=_buffer.raw).node
     444
     445def _windll_getnode():
     446    """Get the hardware address on Windows using ctypes."""
     447    _buffer = ctypes.create_string_buffer(16)
     448    if _UuidCreate(_buffer) == 0:
     449        return UUID(bytes=_buffer.raw).node
     450
     451def _random_getnode():
     452    """Get a random node ID, with eighth bit set as suggested by RFC 4122."""
     453    import random
     454    return random.randrange(0, 1<<48L) | 0x010000000000L
     455
     456_node = None
     457
     458def getnode():
     459    """Get the hardware address as a 48-bit positive integer.
     460
     461    The first time this runs, it may launch a separate program, which could
     462    be quite slow.  If all attempts to obtain the hardware address fail, we
     463    choose a random 48-bit number with its eighth bit set to 1 as recommended
     464    in RFC 4122.
     465    """
     466
     467    global _node
     468    if _node is not None:
     469        return _node
     470
     471    import sys
     472    if sys.platform == 'win32':
     473        getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode]
     474    else:
     475        getters = [_unixdll_getnode, _ifconfig_getnode]
     476
     477    for getter in getters + [_random_getnode]:
     478        try:
     479            _node = getter()
     480        except:
     481            continue
     482        if _node is not None:
     483            return _node
     484
     485_last_timestamp = None
     486
     487def uuid1(node=None, clock_seq=None):
     488    """Generate a UUID from a host ID, sequence number, and the current time.
     489    If 'node' is not given, getnode() is used to obtain the hardware
     490    address.  If 'clock_seq' is given, it is used as the sequence number;
     491    otherwise a random 14-bit sequence number is chosen."""
     492
     493    # When the system provides a version-1 UUID generator, use it (but don't
     494    # use UuidCreate here because its UUIDs don't conform to RFC 4122).
     495    if _uuid_generate_time and node is clock_seq is None:
     496        _buffer = ctypes.create_string_buffer(16)
     497        _uuid_generate_time(_buffer)
     498        return UUID(bytes=_buffer.raw)
     499
     500    global _last_timestamp
     501    import time
     502    nanoseconds = int(time.time() * 1e9)
     503    # 0x01b21dd213814000 is the number of 100-ns intervals between the
     504    # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.
     505    timestamp = int(nanoseconds//100) + 0x01b21dd213814000L
     506    if _last_timestamp is not None and timestamp <= _last_timestamp:
     507        timestamp = _last_timestamp + 1
     508    _last_timestamp = timestamp
     509    if clock_seq is None:
     510        import random
     511        clock_seq = random.randrange(1<<14L) # instead of stable storage
     512    time_low = timestamp & 0xffffffffL
     513    time_mid = (timestamp >> 32L) & 0xffffL
     514    time_hi_version = (timestamp >> 48L) & 0x0fffL
     515    clock_seq_low = clock_seq & 0xffL
     516    clock_seq_hi_variant = (clock_seq >> 8L) & 0x3fL
     517    if node is None:
     518        node = getnode()
     519    return UUID(fields=(time_low, time_mid, time_hi_version,
     520                        clock_seq_hi_variant, clock_seq_low, node), version=1)
     521
     522def uuid3(namespace, name):
     523    """Generate a UUID from the MD5 hash of a namespace UUID and a name."""
     524    from hashlib import md5
     525    hash = md5(namespace.bytes + name).digest()
     526    return UUID(bytes=hash[:16], version=3)
     527
     528def uuid4():
     529    """Generate a random UUID."""
     530
     531    # When the system provides a version-4 UUID generator, use it.
     532    if _uuid_generate_random:
     533        _buffer = ctypes.create_string_buffer(16)
     534        _uuid_generate_random(_buffer)
     535        return UUID(bytes=_buffer.raw)
     536
     537    # Otherwise, get randomness from urandom or the 'random' module.
     538    try:
     539        import os
     540        return UUID(bytes=os.urandom(16), version=4)
     541    except:
     542        import random
     543        bytes = [chr(random.randrange(256)) for i in range(16)]
     544        return UUID(bytes=bytes, version=4)
     545
     546def uuid5(namespace, name):
     547    """Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
     548    from hashlib import sha1
     549    hash = sha1(namespace.bytes + name).digest()
     550    return UUID(bytes=hash[:16], version=5)
     551
     552# The following standard UUIDs are for use with uuid3() or uuid5().
     553
     554NAMESPACE_DNS = UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
     555NAMESPACE_URL = UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8')
     556NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8')
     557NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8')
  • utils/hashcompat.py

     
    1111    md5_hmac = md5_constructor
    1212    sha_constructor = hashlib.sha1
    1313    sha_hmac = sha_constructor
     14    import uuid
     15    uuid4 = uuid.uuid4
    1416else:
    1517    import md5
    1618    md5_constructor = md5.new
     
    1820    import sha
    1921    sha_constructor = sha.new
    2022    sha_hmac = sha
     23    import _uuid
     24    uuid4 = uuid.uuid4
Back to Top