RAHHH
This commit is contained in:
261
backend/lib/python3.12/site-packages/twisted/names/_rfc1982.py
Normal file
261
backend/lib/python3.12/site-packages/twisted/names/_rfc1982.py
Normal file
@@ -0,0 +1,261 @@
|
||||
# -*- test-case-name: twisted.names.test.test_rfc1982 -*-
|
||||
# Copyright (c) Twisted Matrix Laboratories.
|
||||
# See LICENSE for details.
|
||||
|
||||
"""
|
||||
Utilities for handling RFC1982 Serial Number Arithmetic.
|
||||
|
||||
@see: U{http://tools.ietf.org/html/rfc1982}
|
||||
|
||||
@var RFC4034_TIME_FORMAT: RRSIG Time field presentation format. The Signature
|
||||
Expiration Time and Inception Time field values MUST be represented either
|
||||
as an unsigned decimal integer indicating seconds since 1 January 1970
|
||||
00:00:00 UTC, or in the form YYYYMMDDHHmmSS in UTC. See U{RRSIG Presentation
|
||||
Format<https://tools.ietf.org/html/rfc4034#section-3.2>}
|
||||
"""
|
||||
|
||||
|
||||
import calendar
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from twisted.python.compat import nativeString
|
||||
from twisted.python.util import FancyStrMixin
|
||||
|
||||
RFC4034_TIME_FORMAT = "%Y%m%d%H%M%S"
|
||||
|
||||
|
||||
class SerialNumber(FancyStrMixin):
|
||||
"""
|
||||
An RFC1982 Serial Number.
|
||||
|
||||
This class implements RFC1982 DNS Serial Number Arithmetic.
|
||||
|
||||
SNA is used in DNS and specifically in DNSSEC as defined in RFC4034 in the
|
||||
DNSSEC Signature Expiration and Inception Fields.
|
||||
|
||||
@see: U{https://tools.ietf.org/html/rfc1982}
|
||||
@see: U{https://tools.ietf.org/html/rfc4034}
|
||||
|
||||
@ivar _serialBits: See C{serialBits} of L{__init__}.
|
||||
@ivar _number: See C{number} of L{__init__}.
|
||||
@ivar _modulo: The value at which wrapping will occur.
|
||||
@ivar _halfRing: Half C{_modulo}. If another L{SerialNumber} value is larger
|
||||
than this, it would lead to a wrapped value which is larger than the
|
||||
first and comparisons are therefore ambiguous.
|
||||
@ivar _maxAdd: Half C{_modulo} plus 1. If another L{SerialNumber} value is
|
||||
larger than this, it would lead to a wrapped value which is larger than
|
||||
the first. Comparisons with the original value would therefore be
|
||||
ambiguous.
|
||||
"""
|
||||
|
||||
showAttributes = (
|
||||
("_number", "number", "%d"),
|
||||
("_serialBits", "serialBits", "%d"),
|
||||
)
|
||||
|
||||
def __init__(self, number: int, serialBits: int = 32):
|
||||
"""
|
||||
Construct an L{SerialNumber} instance.
|
||||
|
||||
@param number: An L{int} which will be stored as the modulo
|
||||
C{number % 2 ^ serialBits}
|
||||
@type number: L{int}
|
||||
|
||||
@param serialBits: The size of the serial number space. The power of two
|
||||
which results in one larger than the largest integer corresponding
|
||||
to a serial number value.
|
||||
@type serialBits: L{int}
|
||||
"""
|
||||
self._serialBits = serialBits
|
||||
self._modulo = 2**serialBits
|
||||
self._halfRing: int = 2 ** (serialBits - 1)
|
||||
self._maxAdd = 2 ** (serialBits - 1) - 1
|
||||
self._number: int = int(number) % self._modulo
|
||||
|
||||
def _convertOther(self, other: object) -> "SerialNumber":
|
||||
"""
|
||||
Check that a foreign object is suitable for use in the comparison or
|
||||
arithmetic magic methods of this L{SerialNumber} instance. Raise
|
||||
L{TypeError} if not.
|
||||
|
||||
@param other: The foreign L{object} to be checked.
|
||||
@return: C{other} after compatibility checks and possible coercion.
|
||||
@raise TypeError: If C{other} is not compatible.
|
||||
"""
|
||||
if not isinstance(other, SerialNumber):
|
||||
raise TypeError(f"cannot compare or combine {self!r} and {other!r}")
|
||||
|
||||
if self._serialBits != other._serialBits:
|
||||
raise TypeError(
|
||||
"cannot compare or combine SerialNumber instances with "
|
||||
"different serialBits. %r and %r" % (self, other)
|
||||
)
|
||||
|
||||
return other
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""
|
||||
Return a string representation of this L{SerialNumber} instance.
|
||||
|
||||
@rtype: L{nativeString}
|
||||
"""
|
||||
return nativeString("%d" % (self._number,))
|
||||
|
||||
def __int__(self):
|
||||
"""
|
||||
@return: The integer value of this L{SerialNumber} instance.
|
||||
@rtype: L{int}
|
||||
"""
|
||||
return self._number
|
||||
|
||||
def __eq__(self, other: object) -> bool:
|
||||
"""
|
||||
Allow rich equality comparison with another L{SerialNumber} instance.
|
||||
"""
|
||||
try:
|
||||
other = self._convertOther(other)
|
||||
except TypeError:
|
||||
return NotImplemented
|
||||
return other._number == self._number
|
||||
|
||||
def __lt__(self, other: object) -> bool:
|
||||
"""
|
||||
Allow I{less than} comparison with another L{SerialNumber} instance.
|
||||
"""
|
||||
try:
|
||||
other = self._convertOther(other)
|
||||
except TypeError:
|
||||
return NotImplemented
|
||||
return (
|
||||
self._number < other._number
|
||||
and (other._number - self._number) < self._halfRing
|
||||
) or (
|
||||
self._number > other._number
|
||||
and (self._number - other._number) > self._halfRing
|
||||
)
|
||||
|
||||
def __gt__(self, other: object) -> bool:
|
||||
"""
|
||||
Allow I{greater than} comparison with another L{SerialNumber} instance.
|
||||
"""
|
||||
try:
|
||||
other_sn = self._convertOther(other)
|
||||
except TypeError:
|
||||
return NotImplemented
|
||||
return (
|
||||
self._number < other_sn._number
|
||||
and (other_sn._number - self._number) > self._halfRing
|
||||
) or (
|
||||
self._number > other_sn._number
|
||||
and (self._number - other_sn._number) < self._halfRing
|
||||
)
|
||||
|
||||
def __le__(self, other: object) -> bool:
|
||||
"""
|
||||
Allow I{less than or equal} comparison with another L{SerialNumber}
|
||||
instance.
|
||||
"""
|
||||
try:
|
||||
other = self._convertOther(other)
|
||||
except TypeError:
|
||||
return NotImplemented
|
||||
return self == other or self < other
|
||||
|
||||
def __ge__(self, other: object) -> bool:
|
||||
"""
|
||||
Allow I{greater than or equal} comparison with another L{SerialNumber}
|
||||
instance.
|
||||
"""
|
||||
try:
|
||||
other = self._convertOther(other)
|
||||
except TypeError:
|
||||
return NotImplemented
|
||||
return self == other or self > other
|
||||
|
||||
def __add__(self, other: object) -> "SerialNumber":
|
||||
"""
|
||||
Allow I{addition} with another L{SerialNumber} instance.
|
||||
|
||||
Serial numbers may be incremented by the addition of a positive
|
||||
integer n, where n is taken from the range of integers
|
||||
[0 .. (2^(SERIAL_BITS - 1) - 1)]. For a sequence number s, the
|
||||
result of such an addition, s', is defined as
|
||||
|
||||
s' = (s + n) modulo (2 ^ SERIAL_BITS)
|
||||
|
||||
where the addition and modulus operations here act upon values that are
|
||||
non-negative values of unbounded size in the usual ways of integer
|
||||
arithmetic.
|
||||
|
||||
Addition of a value outside the range
|
||||
[0 .. (2^(SERIAL_BITS - 1) - 1)] is undefined.
|
||||
|
||||
@see: U{http://tools.ietf.org/html/rfc1982#section-3.1}
|
||||
|
||||
@raise ArithmeticError: If C{other} is more than C{_maxAdd}
|
||||
ie more than half the maximum value of this serial number.
|
||||
"""
|
||||
try:
|
||||
other = self._convertOther(other)
|
||||
except TypeError:
|
||||
return NotImplemented
|
||||
if other._number <= self._maxAdd:
|
||||
return SerialNumber(
|
||||
(self._number + other._number) % self._modulo,
|
||||
serialBits=self._serialBits,
|
||||
)
|
||||
else:
|
||||
raise ArithmeticError(
|
||||
"value %r outside the range 0 .. %r"
|
||||
% (
|
||||
other._number,
|
||||
self._maxAdd,
|
||||
)
|
||||
)
|
||||
|
||||
def __hash__(self):
|
||||
"""
|
||||
Allow L{SerialNumber} instances to be hashed for use as L{dict} keys.
|
||||
|
||||
@rtype: L{int}
|
||||
"""
|
||||
return hash(self._number)
|
||||
|
||||
@classmethod
|
||||
def fromRFC4034DateString(cls, utcDateString):
|
||||
"""
|
||||
Create an L{SerialNumber} instance from a date string in format
|
||||
'YYYYMMDDHHMMSS' described in U{RFC4034
|
||||
3.2<https://tools.ietf.org/html/rfc4034#section-3.2>}.
|
||||
|
||||
The L{SerialNumber} instance stores the date as a 32bit UNIX timestamp.
|
||||
|
||||
@see: U{https://tools.ietf.org/html/rfc4034#section-3.1.5}
|
||||
|
||||
@param utcDateString: A UTC date/time string of format I{YYMMDDhhmmss}
|
||||
which will be converted to seconds since the UNIX epoch.
|
||||
@type utcDateString: L{unicode}
|
||||
|
||||
@return: An L{SerialNumber} instance containing the supplied date as a
|
||||
32bit UNIX timestamp.
|
||||
"""
|
||||
parsedDate = datetime.strptime(utcDateString, RFC4034_TIME_FORMAT)
|
||||
secondsSinceEpoch = calendar.timegm(parsedDate.utctimetuple())
|
||||
return cls(secondsSinceEpoch, serialBits=32)
|
||||
|
||||
def toRFC4034DateString(self):
|
||||
"""
|
||||
Calculate a date by treating the current L{SerialNumber} value as a UNIX
|
||||
timestamp and return a date string in the format described in
|
||||
U{RFC4034 3.2<https://tools.ietf.org/html/rfc4034#section-3.2>}.
|
||||
|
||||
@return: The date string.
|
||||
"""
|
||||
# Can't use datetime.utcfromtimestamp, because it seems to overflow the
|
||||
# signed 32bit int used in the underlying C library. SNA is unsigned
|
||||
# and capable of handling all timestamps up to 2**32.
|
||||
d = datetime(1970, 1, 1) + timedelta(seconds=self._number)
|
||||
return nativeString(d.strftime(RFC4034_TIME_FORMAT))
|
||||
|
||||
|
||||
__all__ = ["SerialNumber"]
|
||||
Reference in New Issue
Block a user