rimossi cloudscraper, simplejson e torrentool, aggiornato sambatools

This commit is contained in:
marco
2020-12-26 14:37:12 +01:00
parent 483fab34df
commit e755d71127
147 changed files with 21555 additions and 17142 deletions
+1
View File
@@ -0,0 +1 @@
# This file is necessary to make this directory a package.
+706
View File
@@ -0,0 +1,706 @@
#
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2020, Ilya Etingof <etingof@gmail.com>
# License: http://snmplabs.com/pyasn1/license.html
#
import sys
from pyasn1 import error
from pyasn1.type import constraint
from pyasn1.type import tag
from pyasn1.type import tagmap
__all__ = ['Asn1Item', 'Asn1Type', 'SimpleAsn1Type',
'ConstructedAsn1Type']
class Asn1Item(object):
@classmethod
def getTypeId(cls, increment=1):
try:
Asn1Item._typeCounter += increment
except AttributeError:
Asn1Item._typeCounter = increment
return Asn1Item._typeCounter
class Asn1Type(Asn1Item):
"""Base class for all classes representing ASN.1 types.
In the user code, |ASN.1| class is normally used only for telling
ASN.1 objects from others.
Note
----
For as long as ASN.1 is concerned, a way to compare ASN.1 types
is to use :meth:`isSameTypeWith` and :meth:`isSuperTypeOf` methods.
"""
#: Set or return a :py:class:`~pyasn1.type.tag.TagSet` object representing
#: ASN.1 tag(s) associated with |ASN.1| type.
tagSet = tag.TagSet()
#: Default :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
#: object imposing constraints on initialization values.
subtypeSpec = constraint.ConstraintsIntersection()
# Disambiguation ASN.1 types identification
typeId = None
def __init__(self, **kwargs):
readOnly = {
'tagSet': self.tagSet,
'subtypeSpec': self.subtypeSpec
}
readOnly.update(kwargs)
self.__dict__.update(readOnly)
self._readOnly = readOnly
def __setattr__(self, name, value):
if name[0] != '_' and name in self._readOnly:
raise error.PyAsn1Error('read-only instance attribute "%s"' % name)
self.__dict__[name] = value
def __str__(self):
return self.prettyPrint()
@property
def readOnly(self):
return self._readOnly
@property
def effectiveTagSet(self):
"""For |ASN.1| type is equivalent to *tagSet*
"""
return self.tagSet # used by untagged types
@property
def tagMap(self):
"""Return a :class:`~pyasn1.type.tagmap.TagMap` object mapping ASN.1 tags to ASN.1 objects within callee object.
"""
return tagmap.TagMap({self.tagSet: self})
def isSameTypeWith(self, other, matchTags=True, matchConstraints=True):
"""Examine |ASN.1| type for equality with other ASN.1 type.
ASN.1 tags (:py:mod:`~pyasn1.type.tag`) and constraints
(:py:mod:`~pyasn1.type.constraint`) are examined when carrying
out ASN.1 types comparison.
Python class inheritance relationship is NOT considered.
Parameters
----------
other: a pyasn1 type object
Class instance representing ASN.1 type.
Returns
-------
: :class:`bool`
:obj:`True` if *other* is |ASN.1| type,
:obj:`False` otherwise.
"""
return (self is other or
(not matchTags or self.tagSet == other.tagSet) and
(not matchConstraints or self.subtypeSpec == other.subtypeSpec))
def isSuperTypeOf(self, other, matchTags=True, matchConstraints=True):
"""Examine |ASN.1| type for subtype relationship with other ASN.1 type.
ASN.1 tags (:py:mod:`~pyasn1.type.tag`) and constraints
(:py:mod:`~pyasn1.type.constraint`) are examined when carrying
out ASN.1 types comparison.
Python class inheritance relationship is NOT considered.
Parameters
----------
other: a pyasn1 type object
Class instance representing ASN.1 type.
Returns
-------
: :class:`bool`
:obj:`True` if *other* is a subtype of |ASN.1| type,
:obj:`False` otherwise.
"""
return (not matchTags or
(self.tagSet.isSuperTagSetOf(other.tagSet)) and
(not matchConstraints or self.subtypeSpec.isSuperTypeOf(other.subtypeSpec)))
@staticmethod
def isNoValue(*values):
for value in values:
if value is not noValue:
return False
return True
def prettyPrint(self, scope=0):
raise NotImplementedError()
# backward compatibility
def getTagSet(self):
return self.tagSet
def getEffectiveTagSet(self):
return self.effectiveTagSet
def getTagMap(self):
return self.tagMap
def getSubtypeSpec(self):
return self.subtypeSpec
# backward compatibility
def hasValue(self):
return self.isValue
# Backward compatibility
Asn1ItemBase = Asn1Type
class NoValue(object):
"""Create a singleton instance of NoValue class.
The *NoValue* sentinel object represents an instance of ASN.1 schema
object as opposed to ASN.1 value object.
Only ASN.1 schema-related operations can be performed on ASN.1
schema objects.
Warning
-------
Any operation attempted on the *noValue* object will raise the
*PyAsn1Error* exception.
"""
skipMethods = {
'__slots__',
# attributes
'__getattribute__',
'__getattr__',
'__setattr__',
'__delattr__',
# class instance
'__class__',
'__init__',
'__del__',
'__new__',
'__repr__',
'__qualname__',
'__objclass__',
'im_class',
'__sizeof__',
# pickle protocol
'__reduce__',
'__reduce_ex__',
'__getnewargs__',
'__getinitargs__',
'__getstate__',
'__setstate__',
}
_instance = None
def __new__(cls):
if cls._instance is None:
def getPlug(name):
def plug(self, *args, **kw):
raise error.PyAsn1Error('Attempted "%s" operation on ASN.1 schema object' % name)
return plug
op_names = [name
for typ in (str, int, list, dict)
for name in dir(typ)
if (name not in cls.skipMethods and
name.startswith('__') and
name.endswith('__') and
callable(getattr(typ, name)))]
for name in set(op_names):
setattr(cls, name, getPlug(name))
cls._instance = object.__new__(cls)
return cls._instance
def __getattr__(self, attr):
if attr in self.skipMethods:
raise AttributeError('Attribute %s not present' % attr)
raise error.PyAsn1Error('Attempted "%s" operation on ASN.1 schema object' % attr)
def __repr__(self):
return '<%s object>' % self.__class__.__name__
noValue = NoValue()
class SimpleAsn1Type(Asn1Type):
"""Base class for all simple classes representing ASN.1 types.
ASN.1 distinguishes types by their ability to hold other objects.
Scalar types are known as *simple* in ASN.1.
In the user code, |ASN.1| class is normally used only for telling
ASN.1 objects from others.
Note
----
For as long as ASN.1 is concerned, a way to compare ASN.1 types
is to use :meth:`isSameTypeWith` and :meth:`isSuperTypeOf` methods.
"""
#: Default payload value
defaultValue = noValue
def __init__(self, value=noValue, **kwargs):
Asn1Type.__init__(self, **kwargs)
if value is noValue:
value = self.defaultValue
else:
value = self.prettyIn(value)
try:
self.subtypeSpec(value)
except error.PyAsn1Error:
exType, exValue, exTb = sys.exc_info()
raise exType('%s at %s' % (exValue, self.__class__.__name__))
self._value = value
def __repr__(self):
representation = '%s %s object' % (
self.__class__.__name__, self.isValue and 'value' or 'schema')
for attr, value in self.readOnly.items():
if value:
representation += ', %s %s' % (attr, value)
if self.isValue:
value = self.prettyPrint()
if len(value) > 32:
value = value[:16] + '...' + value[-16:]
representation += ', payload [%s]' % value
return '<%s>' % representation
def __eq__(self, other):
return self is other and True or self._value == other
def __ne__(self, other):
return self._value != other
def __lt__(self, other):
return self._value < other
def __le__(self, other):
return self._value <= other
def __gt__(self, other):
return self._value > other
def __ge__(self, other):
return self._value >= other
if sys.version_info[0] <= 2:
def __nonzero__(self):
return self._value and True or False
else:
def __bool__(self):
return self._value and True or False
def __hash__(self):
return hash(self._value)
@property
def isValue(self):
"""Indicate that |ASN.1| object represents ASN.1 value.
If *isValue* is :obj:`False` then this object represents just
ASN.1 schema.
If *isValue* is :obj:`True` then, in addition to its ASN.1 schema
features, this object can also be used like a Python built-in object
(e.g. :class:`int`, :class:`str`, :class:`dict` etc.).
Returns
-------
: :class:`bool`
:obj:`False` if object represents just ASN.1 schema.
:obj:`True` if object represents ASN.1 schema and can be used as a normal value.
Note
----
There is an important distinction between PyASN1 schema and value objects.
The PyASN1 schema objects can only participate in ASN.1 schema-related
operations (e.g. defining or testing the structure of the data). Most
obvious uses of ASN.1 schema is to guide serialisation codecs whilst
encoding/decoding serialised ASN.1 contents.
The PyASN1 value objects can **additionally** participate in many operations
involving regular Python objects (e.g. arithmetic, comprehension etc).
"""
return self._value is not noValue
def clone(self, value=noValue, **kwargs):
"""Create a modified version of |ASN.1| schema or value object.
The `clone()` method accepts the same set arguments as |ASN.1|
class takes on instantiation except that all arguments
of the `clone()` method are optional.
Whatever arguments are supplied, they are used to create a copy
of `self` taking precedence over the ones used to instantiate `self`.
Note
----
Due to the immutable nature of the |ASN.1| object, if no arguments
are supplied, no new |ASN.1| object will be created and `self` will
be returned instead.
"""
if value is noValue:
if not kwargs:
return self
value = self._value
initializers = self.readOnly.copy()
initializers.update(kwargs)
return self.__class__(value, **initializers)
def subtype(self, value=noValue, **kwargs):
"""Create a specialization of |ASN.1| schema or value object.
The subtype relationship between ASN.1 types has no correlation with
subtype relationship between Python types. ASN.1 type is mainly identified
by its tag(s) (:py:class:`~pyasn1.type.tag.TagSet`) and value range
constraints (:py:class:`~pyasn1.type.constraint.ConstraintsIntersection`).
These ASN.1 type properties are implemented as |ASN.1| attributes.
The `subtype()` method accepts the same set arguments as |ASN.1|
class takes on instantiation except that all parameters
of the `subtype()` method are optional.
With the exception of the arguments described below, the rest of
supplied arguments they are used to create a copy of `self` taking
precedence over the ones used to instantiate `self`.
The following arguments to `subtype()` create a ASN.1 subtype out of
|ASN.1| type:
Other Parameters
----------------
implicitTag: :py:class:`~pyasn1.type.tag.Tag`
Implicitly apply given ASN.1 tag object to `self`'s
:py:class:`~pyasn1.type.tag.TagSet`, then use the result as
new object's ASN.1 tag(s).
explicitTag: :py:class:`~pyasn1.type.tag.Tag`
Explicitly apply given ASN.1 tag object to `self`'s
:py:class:`~pyasn1.type.tag.TagSet`, then use the result as
new object's ASN.1 tag(s).
subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
Add ASN.1 constraints object to one of the `self`'s, then
use the result as new object's ASN.1 constraints.
Returns
-------
:
new instance of |ASN.1| schema or value object
Note
----
Due to the immutable nature of the |ASN.1| object, if no arguments
are supplied, no new |ASN.1| object will be created and `self` will
be returned instead.
"""
if value is noValue:
if not kwargs:
return self
value = self._value
initializers = self.readOnly.copy()
implicitTag = kwargs.pop('implicitTag', None)
if implicitTag is not None:
initializers['tagSet'] = self.tagSet.tagImplicitly(implicitTag)
explicitTag = kwargs.pop('explicitTag', None)
if explicitTag is not None:
initializers['tagSet'] = self.tagSet.tagExplicitly(explicitTag)
for arg, option in kwargs.items():
initializers[arg] += option
return self.__class__(value, **initializers)
def prettyIn(self, value):
return value
def prettyOut(self, value):
return str(value)
def prettyPrint(self, scope=0):
return self.prettyOut(self._value)
def prettyPrintType(self, scope=0):
return '%s -> %s' % (self.tagSet, self.__class__.__name__)
# Backward compatibility
AbstractSimpleAsn1Item = SimpleAsn1Type
#
# Constructed types:
# * There are five of them: Sequence, SequenceOf/SetOf, Set and Choice
# * ASN1 types and values are represened by Python class instances
# * Value initialization is made for defaulted components only
# * Primary method of component addressing is by-position. Data model for base
# type is Python sequence. Additional type-specific addressing methods
# may be implemented for particular types.
# * SequenceOf and SetOf types do not implement any additional methods
# * Sequence, Set and Choice types also implement by-identifier addressing
# * Sequence, Set and Choice types also implement by-asn1-type (tag) addressing
# * Sequence and Set types may include optional and defaulted
# components
# * Constructed types hold a reference to component types used for value
# verification and ordering.
# * Component type is a scalar type for SequenceOf/SetOf types and a list
# of types for Sequence/Set/Choice.
#
class ConstructedAsn1Type(Asn1Type):
"""Base class for all constructed classes representing ASN.1 types.
ASN.1 distinguishes types by their ability to hold other objects.
Those "nesting" types are known as *constructed* in ASN.1.
In the user code, |ASN.1| class is normally used only for telling
ASN.1 objects from others.
Note
----
For as long as ASN.1 is concerned, a way to compare ASN.1 types
is to use :meth:`isSameTypeWith` and :meth:`isSuperTypeOf` methods.
"""
#: If :obj:`True`, requires exact component type matching,
#: otherwise subtype relation is only enforced
strictConstraints = False
componentType = None
# backward compatibility, unused
sizeSpec = constraint.ConstraintsIntersection()
def __init__(self, **kwargs):
readOnly = {
'componentType': self.componentType,
# backward compatibility, unused
'sizeSpec': self.sizeSpec
}
# backward compatibility: preserve legacy sizeSpec support
kwargs = self._moveSizeSpec(**kwargs)
readOnly.update(kwargs)
Asn1Type.__init__(self, **readOnly)
def _moveSizeSpec(self, **kwargs):
# backward compatibility, unused
sizeSpec = kwargs.pop('sizeSpec', self.sizeSpec)
if sizeSpec:
subtypeSpec = kwargs.pop('subtypeSpec', self.subtypeSpec)
if subtypeSpec:
subtypeSpec = sizeSpec
else:
subtypeSpec += sizeSpec
kwargs['subtypeSpec'] = subtypeSpec
return kwargs
def __repr__(self):
representation = '%s %s object' % (
self.__class__.__name__, self.isValue and 'value' or 'schema'
)
for attr, value in self.readOnly.items():
if value is not noValue:
representation += ', %s=%r' % (attr, value)
if self.isValue and self.components:
representation += ', payload [%s]' % ', '.join(
[repr(x) for x in self.components])
return '<%s>' % representation
def __eq__(self, other):
return self is other or self.components == other
def __ne__(self, other):
return self.components != other
def __lt__(self, other):
return self.components < other
def __le__(self, other):
return self.components <= other
def __gt__(self, other):
return self.components > other
def __ge__(self, other):
return self.components >= other
if sys.version_info[0] <= 2:
def __nonzero__(self):
return bool(self.components)
else:
def __bool__(self):
return bool(self.components)
@property
def components(self):
raise error.PyAsn1Error('Method not implemented')
def _cloneComponentValues(self, myClone, cloneValueFlag):
pass
def clone(self, **kwargs):
"""Create a modified version of |ASN.1| schema object.
The `clone()` method accepts the same set arguments as |ASN.1|
class takes on instantiation except that all arguments
of the `clone()` method are optional.
Whatever arguments are supplied, they are used to create a copy
of `self` taking precedence over the ones used to instantiate `self`.
Possible values of `self` are never copied over thus `clone()` can
only create a new schema object.
Returns
-------
:
new instance of |ASN.1| type/value
Note
----
Due to the mutable nature of the |ASN.1| object, even if no arguments
are supplied, a new |ASN.1| object will be created and returned.
"""
cloneValueFlag = kwargs.pop('cloneValueFlag', False)
initializers = self.readOnly.copy()
initializers.update(kwargs)
clone = self.__class__(**initializers)
if cloneValueFlag:
self._cloneComponentValues(clone, cloneValueFlag)
return clone
def subtype(self, **kwargs):
"""Create a specialization of |ASN.1| schema object.
The `subtype()` method accepts the same set arguments as |ASN.1|
class takes on instantiation except that all parameters
of the `subtype()` method are optional.
With the exception of the arguments described below, the rest of
supplied arguments they are used to create a copy of `self` taking
precedence over the ones used to instantiate `self`.
The following arguments to `subtype()` create a ASN.1 subtype out of
|ASN.1| type.
Other Parameters
----------------
implicitTag: :py:class:`~pyasn1.type.tag.Tag`
Implicitly apply given ASN.1 tag object to `self`'s
:py:class:`~pyasn1.type.tag.TagSet`, then use the result as
new object's ASN.1 tag(s).
explicitTag: :py:class:`~pyasn1.type.tag.Tag`
Explicitly apply given ASN.1 tag object to `self`'s
:py:class:`~pyasn1.type.tag.TagSet`, then use the result as
new object's ASN.1 tag(s).
subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
Add ASN.1 constraints object to one of the `self`'s, then
use the result as new object's ASN.1 constraints.
Returns
-------
:
new instance of |ASN.1| type/value
Note
----
Due to the mutable nature of the |ASN.1| object, even if no arguments
are supplied, a new |ASN.1| object will be created and returned.
"""
initializers = self.readOnly.copy()
cloneValueFlag = kwargs.pop('cloneValueFlag', False)
implicitTag = kwargs.pop('implicitTag', None)
if implicitTag is not None:
initializers['tagSet'] = self.tagSet.tagImplicitly(implicitTag)
explicitTag = kwargs.pop('explicitTag', None)
if explicitTag is not None:
initializers['tagSet'] = self.tagSet.tagExplicitly(explicitTag)
for arg, option in kwargs.items():
initializers[arg] += option
clone = self.__class__(**initializers)
if cloneValueFlag:
self._cloneComponentValues(clone, cloneValueFlag)
return clone
def getComponentByPosition(self, idx):
raise error.PyAsn1Error('Method not implemented')
def setComponentByPosition(self, idx, value, verifyConstraints=True):
raise error.PyAsn1Error('Method not implemented')
def setComponents(self, *args, **kwargs):
for idx, value in enumerate(args):
self[idx] = value
for k in kwargs:
self[k] = kwargs[k]
return self
# backward compatibility
def setDefaultComponents(self):
pass
def getComponentType(self):
return self.componentType
# backward compatibility, unused
def verifySizeSpec(self):
self.subtypeSpec(self)
# Backward compatibility
AbstractConstructedAsn1Item = ConstructedAsn1Type
+335
View File
@@ -0,0 +1,335 @@
#
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2020, Ilya Etingof <etingof@gmail.com>
# License: http://snmplabs.com/pyasn1/license.html
#
import sys
from pyasn1 import error
from pyasn1.type import tag
from pyasn1.type import univ
__all__ = ['NumericString', 'PrintableString', 'TeletexString', 'T61String', 'VideotexString',
'IA5String', 'GraphicString', 'VisibleString', 'ISO646String',
'GeneralString', 'UniversalString', 'BMPString', 'UTF8String']
NoValue = univ.NoValue
noValue = univ.noValue
class AbstractCharacterString(univ.OctetString):
"""Creates |ASN.1| schema or value object.
|ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`,
its objects are immutable and duck-type Python 2 :class:`str` or Python 3
:class:`bytes`. When used in octet-stream context, |ASN.1| type assumes
"|encoding|" encoding.
Keyword Args
------------
value: :class:`unicode`, :class:`str`, :class:`bytes` or |ASN.1| object
:class:`unicode` object (Python 2) or :class:`str` (Python 3),
alternatively :class:`str` (Python 2) or :class:`bytes` (Python 3)
representing octet-stream of serialised unicode string
(note `encoding` parameter) or |ASN.1| class instance.
If `value` is not given, schema object will be created.
tagSet: :py:class:`~pyasn1.type.tag.TagSet`
Object representing non-default ASN.1 tag(s)
subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
Object representing non-default ASN.1 subtype constraint(s). Constraints
verification for |ASN.1| type occurs automatically on object
instantiation.
encoding: :py:class:`str`
Unicode codec ID to encode/decode :class:`unicode` (Python 2) or
:class:`str` (Python 3) the payload when |ASN.1| object is used
in octet-stream context.
Raises
------
~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error
On constraint violation or bad initializer.
"""
if sys.version_info[0] <= 2:
def __str__(self):
try:
# `str` is Py2 text representation
return self._value.encode(self.encoding)
except UnicodeEncodeError:
exc = sys.exc_info()[1]
raise error.PyAsn1UnicodeEncodeError(
"Can't encode string '%s' with codec "
"%s" % (self._value, self.encoding), exc
)
def __unicode__(self):
return unicode(self._value)
def prettyIn(self, value):
try:
if isinstance(value, unicode):
return value
elif isinstance(value, str):
return value.decode(self.encoding)
elif isinstance(value, (tuple, list)):
return self.prettyIn(''.join([chr(x) for x in value]))
elif isinstance(value, univ.OctetString):
return value.asOctets().decode(self.encoding)
else:
return unicode(value)
except (UnicodeDecodeError, LookupError):
exc = sys.exc_info()[1]
raise error.PyAsn1UnicodeDecodeError(
"Can't decode string '%s' with codec "
"%s" % (value, self.encoding), exc
)
def asOctets(self, padding=True):
return str(self)
def asNumbers(self, padding=True):
return tuple([ord(x) for x in str(self)])
else:
def __str__(self):
# `unicode` is Py3 text representation
return str(self._value)
def __bytes__(self):
try:
return self._value.encode(self.encoding)
except UnicodeEncodeError:
exc = sys.exc_info()[1]
raise error.PyAsn1UnicodeEncodeError(
"Can't encode string '%s' with codec "
"%s" % (self._value, self.encoding), exc
)
def prettyIn(self, value):
try:
if isinstance(value, str):
return value
elif isinstance(value, bytes):
return value.decode(self.encoding)
elif isinstance(value, (tuple, list)):
return self.prettyIn(bytes(value))
elif isinstance(value, univ.OctetString):
return value.asOctets().decode(self.encoding)
else:
return str(value)
except (UnicodeDecodeError, LookupError):
exc = sys.exc_info()[1]
raise error.PyAsn1UnicodeDecodeError(
"Can't decode string '%s' with codec "
"%s" % (value, self.encoding), exc
)
def asOctets(self, padding=True):
return bytes(self)
def asNumbers(self, padding=True):
return tuple(bytes(self))
#
# See OctetString.prettyPrint() for the explanation
#
def prettyOut(self, value):
return value
def prettyPrint(self, scope=0):
# first see if subclass has its own .prettyOut()
value = self.prettyOut(self._value)
if value is not self._value:
return value
return AbstractCharacterString.__str__(self)
def __reversed__(self):
return reversed(self._value)
class NumericString(AbstractCharacterString):
__doc__ = AbstractCharacterString.__doc__
#: Set (on class, not on instance) or return a
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
#: associated with |ASN.1| type.
tagSet = AbstractCharacterString.tagSet.tagImplicitly(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 18)
)
encoding = 'us-ascii'
# Optimization for faster codec lookup
typeId = AbstractCharacterString.getTypeId()
class PrintableString(AbstractCharacterString):
__doc__ = AbstractCharacterString.__doc__
#: Set (on class, not on instance) or return a
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
#: associated with |ASN.1| type.
tagSet = AbstractCharacterString.tagSet.tagImplicitly(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 19)
)
encoding = 'us-ascii'
# Optimization for faster codec lookup
typeId = AbstractCharacterString.getTypeId()
class TeletexString(AbstractCharacterString):
__doc__ = AbstractCharacterString.__doc__
#: Set (on class, not on instance) or return a
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
#: associated with |ASN.1| type.
tagSet = AbstractCharacterString.tagSet.tagImplicitly(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 20)
)
encoding = 'iso-8859-1'
# Optimization for faster codec lookup
typeId = AbstractCharacterString.getTypeId()
class T61String(TeletexString):
__doc__ = TeletexString.__doc__
# Optimization for faster codec lookup
typeId = AbstractCharacterString.getTypeId()
class VideotexString(AbstractCharacterString):
__doc__ = AbstractCharacterString.__doc__
#: Set (on class, not on instance) or return a
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
#: associated with |ASN.1| type.
tagSet = AbstractCharacterString.tagSet.tagImplicitly(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 21)
)
encoding = 'iso-8859-1'
# Optimization for faster codec lookup
typeId = AbstractCharacterString.getTypeId()
class IA5String(AbstractCharacterString):
__doc__ = AbstractCharacterString.__doc__
#: Set (on class, not on instance) or return a
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
#: associated with |ASN.1| type.
tagSet = AbstractCharacterString.tagSet.tagImplicitly(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 22)
)
encoding = 'us-ascii'
# Optimization for faster codec lookup
typeId = AbstractCharacterString.getTypeId()
class GraphicString(AbstractCharacterString):
__doc__ = AbstractCharacterString.__doc__
#: Set (on class, not on instance) or return a
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
#: associated with |ASN.1| type.
tagSet = AbstractCharacterString.tagSet.tagImplicitly(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 25)
)
encoding = 'iso-8859-1'
# Optimization for faster codec lookup
typeId = AbstractCharacterString.getTypeId()
class VisibleString(AbstractCharacterString):
__doc__ = AbstractCharacterString.__doc__
#: Set (on class, not on instance) or return a
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
#: associated with |ASN.1| type.
tagSet = AbstractCharacterString.tagSet.tagImplicitly(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 26)
)
encoding = 'us-ascii'
# Optimization for faster codec lookup
typeId = AbstractCharacterString.getTypeId()
class ISO646String(VisibleString):
__doc__ = VisibleString.__doc__
# Optimization for faster codec lookup
typeId = AbstractCharacterString.getTypeId()
class GeneralString(AbstractCharacterString):
__doc__ = AbstractCharacterString.__doc__
#: Set (on class, not on instance) or return a
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
#: associated with |ASN.1| type.
tagSet = AbstractCharacterString.tagSet.tagImplicitly(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 27)
)
encoding = 'iso-8859-1'
# Optimization for faster codec lookup
typeId = AbstractCharacterString.getTypeId()
class UniversalString(AbstractCharacterString):
__doc__ = AbstractCharacterString.__doc__
#: Set (on class, not on instance) or return a
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
#: associated with |ASN.1| type.
tagSet = AbstractCharacterString.tagSet.tagImplicitly(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 28)
)
encoding = "utf-32-be"
# Optimization for faster codec lookup
typeId = AbstractCharacterString.getTypeId()
class BMPString(AbstractCharacterString):
__doc__ = AbstractCharacterString.__doc__
#: Set (on class, not on instance) or return a
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
#: associated with |ASN.1| type.
tagSet = AbstractCharacterString.tagSet.tagImplicitly(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 30)
)
encoding = "utf-16-be"
# Optimization for faster codec lookup
typeId = AbstractCharacterString.getTypeId()
class UTF8String(AbstractCharacterString):
__doc__ = AbstractCharacterString.__doc__
#: Set (on class, not on instance) or return a
#: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
#: associated with |ASN.1| type.
tagSet = AbstractCharacterString.tagSet.tagImplicitly(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12)
)
encoding = "utf-8"
# Optimization for faster codec lookup
typeId = AbstractCharacterString.getTypeId()
+756
View File
@@ -0,0 +1,756 @@
#
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2020, Ilya Etingof <etingof@gmail.com>
# License: http://snmplabs.com/pyasn1/license.html
#
# Original concept and code by Mike C. Fletcher.
#
import sys
from pyasn1.type import error
__all__ = ['SingleValueConstraint', 'ContainedSubtypeConstraint',
'ValueRangeConstraint', 'ValueSizeConstraint',
'PermittedAlphabetConstraint', 'InnerTypeConstraint',
'ConstraintsExclusion', 'ConstraintsIntersection',
'ConstraintsUnion']
class AbstractConstraint(object):
def __init__(self, *values):
self._valueMap = set()
self._setValues(values)
self.__hash = hash((self.__class__.__name__, self._values))
def __call__(self, value, idx=None):
if not self._values:
return
try:
self._testValue(value, idx)
except error.ValueConstraintError:
raise error.ValueConstraintError(
'%s failed at: %r' % (self, sys.exc_info()[1])
)
def __repr__(self):
representation = '%s object' % (self.__class__.__name__)
if self._values:
representation += ', consts %s' % ', '.join(
[repr(x) for x in self._values])
return '<%s>' % representation
def __eq__(self, other):
return self is other and True or self._values == other
def __ne__(self, other):
return self._values != other
def __lt__(self, other):
return self._values < other
def __le__(self, other):
return self._values <= other
def __gt__(self, other):
return self._values > other
def __ge__(self, other):
return self._values >= other
if sys.version_info[0] <= 2:
def __nonzero__(self):
return self._values and True or False
else:
def __bool__(self):
return self._values and True or False
def __hash__(self):
return self.__hash
def _setValues(self, values):
self._values = values
def _testValue(self, value, idx):
raise error.ValueConstraintError(value)
# Constraints derivation logic
def getValueMap(self):
return self._valueMap
def isSuperTypeOf(self, otherConstraint):
# TODO: fix possible comparison of set vs scalars here
return (otherConstraint is self or
not self._values or
otherConstraint == self or
self in otherConstraint.getValueMap())
def isSubTypeOf(self, otherConstraint):
return (otherConstraint is self or
not self or
otherConstraint == self or
otherConstraint in self._valueMap)
class SingleValueConstraint(AbstractConstraint):
"""Create a SingleValueConstraint object.
The SingleValueConstraint satisfies any value that
is present in the set of permitted values.
Objects of this type are iterable (emitting constraint values) and
can act as operands for some arithmetic operations e.g. addition
and subtraction. The latter can be used for combining multiple
SingleValueConstraint objects into one.
The SingleValueConstraint object can be applied to
any ASN.1 type.
Parameters
----------
*values: :class:`int`
Full set of values permitted by this constraint object.
Examples
--------
.. code-block:: python
class DivisorOfSix(Integer):
'''
ASN.1 specification:
Divisor-Of-6 ::= INTEGER (1 | 2 | 3 | 6)
'''
subtypeSpec = SingleValueConstraint(1, 2, 3, 6)
# this will succeed
divisor_of_six = DivisorOfSix(1)
# this will raise ValueConstraintError
divisor_of_six = DivisorOfSix(7)
"""
def _setValues(self, values):
self._values = values
self._set = set(values)
def _testValue(self, value, idx):
if value not in self._set:
raise error.ValueConstraintError(value)
# Constrains can be merged or reduced
def __contains__(self, item):
return item in self._set
def __iter__(self):
return iter(self._set)
def __sub__(self, constraint):
return self.__class__(*(self._set.difference(constraint)))
def __add__(self, constraint):
return self.__class__(*(self._set.union(constraint)))
def __sub__(self, constraint):
return self.__class__(*(self._set.difference(constraint)))
class ContainedSubtypeConstraint(AbstractConstraint):
"""Create a ContainedSubtypeConstraint object.
The ContainedSubtypeConstraint satisfies any value that
is present in the set of permitted values and also
satisfies included constraints.
The ContainedSubtypeConstraint object can be applied to
any ASN.1 type.
Parameters
----------
*values:
Full set of values and constraint objects permitted
by this constraint object.
Examples
--------
.. code-block:: python
class DivisorOfEighteen(Integer):
'''
ASN.1 specification:
Divisors-of-18 ::= INTEGER (INCLUDES Divisors-of-6 | 9 | 18)
'''
subtypeSpec = ContainedSubtypeConstraint(
SingleValueConstraint(1, 2, 3, 6), 9, 18
)
# this will succeed
divisor_of_eighteen = DivisorOfEighteen(9)
# this will raise ValueConstraintError
divisor_of_eighteen = DivisorOfEighteen(10)
"""
def _testValue(self, value, idx):
for constraint in self._values:
if isinstance(constraint, AbstractConstraint):
constraint(value, idx)
elif value not in self._set:
raise error.ValueConstraintError(value)
class ValueRangeConstraint(AbstractConstraint):
"""Create a ValueRangeConstraint object.
The ValueRangeConstraint satisfies any value that
falls in the range of permitted values.
The ValueRangeConstraint object can only be applied
to :class:`~pyasn1.type.univ.Integer` and
:class:`~pyasn1.type.univ.Real` types.
Parameters
----------
start: :class:`int`
Minimum permitted value in the range (inclusive)
end: :class:`int`
Maximum permitted value in the range (inclusive)
Examples
--------
.. code-block:: python
class TeenAgeYears(Integer):
'''
ASN.1 specification:
TeenAgeYears ::= INTEGER (13 .. 19)
'''
subtypeSpec = ValueRangeConstraint(13, 19)
# this will succeed
teen_year = TeenAgeYears(18)
# this will raise ValueConstraintError
teen_year = TeenAgeYears(20)
"""
def _testValue(self, value, idx):
if value < self.start or value > self.stop:
raise error.ValueConstraintError(value)
def _setValues(self, values):
if len(values) != 2:
raise error.PyAsn1Error(
'%s: bad constraint values' % (self.__class__.__name__,)
)
self.start, self.stop = values
if self.start > self.stop:
raise error.PyAsn1Error(
'%s: screwed constraint values (start > stop): %s > %s' % (
self.__class__.__name__,
self.start, self.stop
)
)
AbstractConstraint._setValues(self, values)
class ValueSizeConstraint(ValueRangeConstraint):
"""Create a ValueSizeConstraint object.
The ValueSizeConstraint satisfies any value for
as long as its size falls within the range of
permitted sizes.
The ValueSizeConstraint object can be applied
to :class:`~pyasn1.type.univ.BitString`,
:class:`~pyasn1.type.univ.OctetString` (including
all :ref:`character ASN.1 types <type.char>`),
:class:`~pyasn1.type.univ.SequenceOf`
and :class:`~pyasn1.type.univ.SetOf` types.
Parameters
----------
minimum: :class:`int`
Minimum permitted size of the value (inclusive)
maximum: :class:`int`
Maximum permitted size of the value (inclusive)
Examples
--------
.. code-block:: python
class BaseballTeamRoster(SetOf):
'''
ASN.1 specification:
BaseballTeamRoster ::= SET SIZE (1..25) OF PlayerNames
'''
componentType = PlayerNames()
subtypeSpec = ValueSizeConstraint(1, 25)
# this will succeed
team = BaseballTeamRoster()
team.extend(['Jan', 'Matej'])
encode(team)
# this will raise ValueConstraintError
team = BaseballTeamRoster()
team.extend(['Jan'] * 26)
encode(team)
Note
----
Whenever ValueSizeConstraint is applied to mutable types
(e.g. :class:`~pyasn1.type.univ.SequenceOf`,
:class:`~pyasn1.type.univ.SetOf`), constraint
validation only happens at the serialisation phase rather
than schema instantiation phase (as it is with immutable
types).
"""
def _testValue(self, value, idx):
valueSize = len(value)
if valueSize < self.start or valueSize > self.stop:
raise error.ValueConstraintError(value)
class PermittedAlphabetConstraint(SingleValueConstraint):
"""Create a PermittedAlphabetConstraint object.
The PermittedAlphabetConstraint satisfies any character
string for as long as all its characters are present in
the set of permitted characters.
Objects of this type are iterable (emitting constraint values) and
can act as operands for some arithmetic operations e.g. addition
and subtraction.
The PermittedAlphabetConstraint object can only be applied
to the :ref:`character ASN.1 types <type.char>` such as
:class:`~pyasn1.type.char.IA5String`.
Parameters
----------
*alphabet: :class:`str`
Full set of characters permitted by this constraint object.
Example
-------
.. code-block:: python
class BooleanValue(IA5String):
'''
ASN.1 specification:
BooleanValue ::= IA5String (FROM ('T' | 'F'))
'''
subtypeSpec = PermittedAlphabetConstraint('T', 'F')
# this will succeed
truth = BooleanValue('T')
truth = BooleanValue('TF')
# this will raise ValueConstraintError
garbage = BooleanValue('TAF')
ASN.1 `FROM ... EXCEPT ...` clause can be modelled by combining multiple
PermittedAlphabetConstraint objects into one:
Example
-------
.. code-block:: python
class Lipogramme(IA5String):
'''
ASN.1 specification:
Lipogramme ::=
IA5String (FROM (ALL EXCEPT ("e"|"E")))
'''
subtypeSpec = (
PermittedAlphabetConstraint(*string.printable) -
PermittedAlphabetConstraint('e', 'E')
)
# this will succeed
lipogramme = Lipogramme('A work of fiction?')
# this will raise ValueConstraintError
lipogramme = Lipogramme('Eel')
Note
----
Although `ConstraintsExclusion` object could seemingly be used for this
purpose, practically, for it to work, it needs to represent its operand
constraints as sets and intersect one with the other. That would require
the insight into the constraint values (and their types) that are otherwise
hidden inside the constraint object.
Therefore it's more practical to model `EXCEPT` clause at
`PermittedAlphabetConstraint` level instead.
"""
def _setValues(self, values):
self._values = values
self._set = set(values)
def _testValue(self, value, idx):
if not self._set.issuperset(value):
raise error.ValueConstraintError(value)
class ComponentPresentConstraint(AbstractConstraint):
"""Create a ComponentPresentConstraint object.
The ComponentPresentConstraint is only satisfied when the value
is not `None`.
The ComponentPresentConstraint object is typically used with
`WithComponentsConstraint`.
Examples
--------
.. code-block:: python
present = ComponentPresentConstraint()
# this will succeed
present('whatever')
# this will raise ValueConstraintError
present(None)
"""
def _setValues(self, values):
self._values = ('<must be present>',)
if values:
raise error.PyAsn1Error('No arguments expected')
def _testValue(self, value, idx):
if value is None:
raise error.ValueConstraintError(
'Component is not present:')
class ComponentAbsentConstraint(AbstractConstraint):
"""Create a ComponentAbsentConstraint object.
The ComponentAbsentConstraint is only satisfied when the value
is `None`.
The ComponentAbsentConstraint object is typically used with
`WithComponentsConstraint`.
Examples
--------
.. code-block:: python
absent = ComponentAbsentConstraint()
# this will succeed
absent(None)
# this will raise ValueConstraintError
absent('whatever')
"""
def _setValues(self, values):
self._values = ('<must be absent>',)
if values:
raise error.PyAsn1Error('No arguments expected')
def _testValue(self, value, idx):
if value is not None:
raise error.ValueConstraintError(
'Component is not absent: %r' % value)
class WithComponentsConstraint(AbstractConstraint):
"""Create a WithComponentsConstraint object.
The `WithComponentsConstraint` satisfies any mapping object that has
constrained fields present or absent, what is indicated by
`ComponentPresentConstraint` and `ComponentAbsentConstraint`
objects respectively.
The `WithComponentsConstraint` object is typically applied
to :class:`~pyasn1.type.univ.Set` or
:class:`~pyasn1.type.univ.Sequence` types.
Parameters
----------
*fields: :class:`tuple`
Zero or more tuples of (`field`, `constraint`) indicating constrained
fields.
Notes
-----
On top of the primary use of `WithComponentsConstraint` (ensuring presence
or absence of particular components of a :class:`~pyasn1.type.univ.Set` or
:class:`~pyasn1.type.univ.Sequence`), it is also possible to pass any other
constraint objects or their combinations. In case of scalar fields, these
constraints will be verified in addition to the constraints belonging to
scalar components themselves. However, formally, these additional
constraints do not change the type of these ASN.1 objects.
Examples
--------
.. code-block:: python
class Item(Sequence): # Set is similar
'''
ASN.1 specification:
Item ::= SEQUENCE {
id INTEGER OPTIONAL,
name OCTET STRING OPTIONAL
} WITH COMPONENTS id PRESENT, name ABSENT | id ABSENT, name PRESENT
'''
componentType = NamedTypes(
OptionalNamedType('id', Integer()),
OptionalNamedType('name', OctetString())
)
withComponents = ConstraintsUnion(
WithComponentsConstraint(
('id', ComponentPresentConstraint()),
('name', ComponentAbsentConstraint())
),
WithComponentsConstraint(
('id', ComponentAbsentConstraint()),
('name', ComponentPresentConstraint())
)
)
item = Item()
# This will succeed
item['id'] = 1
# This will succeed
item.reset()
item['name'] = 'John'
# This will fail (on encoding)
item.reset()
descr['id'] = 1
descr['name'] = 'John'
"""
def _testValue(self, value, idx):
for field, constraint in self._values:
constraint(value.get(field))
def _setValues(self, values):
AbstractConstraint._setValues(self, values)
# This is a bit kludgy, meaning two op modes within a single constraint
class InnerTypeConstraint(AbstractConstraint):
"""Value must satisfy the type and presence constraints"""
def _testValue(self, value, idx):
if self.__singleTypeConstraint:
self.__singleTypeConstraint(value)
elif self.__multipleTypeConstraint:
if idx not in self.__multipleTypeConstraint:
raise error.ValueConstraintError(value)
constraint, status = self.__multipleTypeConstraint[idx]
if status == 'ABSENT': # XXX presence is not checked!
raise error.ValueConstraintError(value)
constraint(value)
def _setValues(self, values):
self.__multipleTypeConstraint = {}
self.__singleTypeConstraint = None
for v in values:
if isinstance(v, tuple):
self.__multipleTypeConstraint[v[0]] = v[1], v[2]
else:
self.__singleTypeConstraint = v
AbstractConstraint._setValues(self, values)
# Logic operations on constraints
class ConstraintsExclusion(AbstractConstraint):
"""Create a ConstraintsExclusion logic operator object.
The ConstraintsExclusion logic operator succeeds when the
value does *not* satisfy the operand constraint.
The ConstraintsExclusion object can be applied to
any constraint and logic operator object.
Parameters
----------
*constraints:
Constraint or logic operator objects.
Examples
--------
.. code-block:: python
class LuckyNumber(Integer):
subtypeSpec = ConstraintsExclusion(
SingleValueConstraint(13)
)
# this will succeed
luckyNumber = LuckyNumber(12)
# this will raise ValueConstraintError
luckyNumber = LuckyNumber(13)
Note
----
The `FROM ... EXCEPT ...` ASN.1 clause should be modeled by combining
constraint objects into one. See `PermittedAlphabetConstraint` for more
information.
"""
def _testValue(self, value, idx):
for constraint in self._values:
try:
constraint(value, idx)
except error.ValueConstraintError:
continue
raise error.ValueConstraintError(value)
def _setValues(self, values):
AbstractConstraint._setValues(self, values)
class AbstractConstraintSet(AbstractConstraint):
def __getitem__(self, idx):
return self._values[idx]
def __iter__(self):
return iter(self._values)
def __add__(self, value):
return self.__class__(*(self._values + (value,)))
def __radd__(self, value):
return self.__class__(*((value,) + self._values))
def __len__(self):
return len(self._values)
# Constraints inclusion in sets
def _setValues(self, values):
self._values = values
for constraint in values:
if constraint:
self._valueMap.add(constraint)
self._valueMap.update(constraint.getValueMap())
class ConstraintsIntersection(AbstractConstraintSet):
"""Create a ConstraintsIntersection logic operator object.
The ConstraintsIntersection logic operator only succeeds
if *all* its operands succeed.
The ConstraintsIntersection object can be applied to
any constraint and logic operator objects.
The ConstraintsIntersection object duck-types the immutable
container object like Python :py:class:`tuple`.
Parameters
----------
*constraints:
Constraint or logic operator objects.
Examples
--------
.. code-block:: python
class CapitalAndSmall(IA5String):
'''
ASN.1 specification:
CapitalAndSmall ::=
IA5String (FROM ("A".."Z"|"a".."z"))
'''
subtypeSpec = ConstraintsIntersection(
PermittedAlphabetConstraint('A', 'Z'),
PermittedAlphabetConstraint('a', 'z')
)
# this will succeed
capital_and_small = CapitalAndSmall('Hello')
# this will raise ValueConstraintError
capital_and_small = CapitalAndSmall('hello')
"""
def _testValue(self, value, idx):
for constraint in self._values:
constraint(value, idx)
class ConstraintsUnion(AbstractConstraintSet):
"""Create a ConstraintsUnion logic operator object.
The ConstraintsUnion logic operator succeeds if
*at least* a single operand succeeds.
The ConstraintsUnion object can be applied to
any constraint and logic operator objects.
The ConstraintsUnion object duck-types the immutable
container object like Python :py:class:`tuple`.
Parameters
----------
*constraints:
Constraint or logic operator objects.
Examples
--------
.. code-block:: python
class CapitalOrSmall(IA5String):
'''
ASN.1 specification:
CapitalOrSmall ::=
IA5String (FROM ("A".."Z") | FROM ("a".."z"))
'''
subtypeSpec = ConstraintsUnion(
PermittedAlphabetConstraint('A', 'Z'),
PermittedAlphabetConstraint('a', 'z')
)
# this will succeed
capital_or_small = CapitalAndSmall('Hello')
# this will raise ValueConstraintError
capital_or_small = CapitalOrSmall('hello!')
"""
def _testValue(self, value, idx):
for constraint in self._values:
try:
constraint(value, idx)
except error.ValueConstraintError:
pass
else:
return
raise error.ValueConstraintError(
'all of %s failed for "%s"' % (self._values, value)
)
# TODO:
# refactor InnerTypeConstraint
# add tests for type check
# implement other constraint types
# make constraint validation easy to skip
+11
View File
@@ -0,0 +1,11 @@
#
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2020, Ilya Etingof <etingof@gmail.com>
# License: http://snmplabs.com/pyasn1/license.html
#
from pyasn1.error import PyAsn1Error
class ValueConstraintError(PyAsn1Error):
pass
+561
View File
@@ -0,0 +1,561 @@
#
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2020, Ilya Etingof <etingof@gmail.com>
# License: http://snmplabs.com/pyasn1/license.html
#
import sys
from pyasn1 import error
from pyasn1.type import tag
from pyasn1.type import tagmap
__all__ = ['NamedType', 'OptionalNamedType', 'DefaultedNamedType',
'NamedTypes']
try:
any
except NameError:
any = lambda x: bool(filter(bool, x))
class NamedType(object):
"""Create named field object for a constructed ASN.1 type.
The |NamedType| object represents a single name and ASN.1 type of a constructed ASN.1 type.
|NamedType| objects are immutable and duck-type Python :class:`tuple` objects
holding *name* and *asn1Object* components.
Parameters
----------
name: :py:class:`str`
Field name
asn1Object:
ASN.1 type object
"""
isOptional = False
isDefaulted = False
def __init__(self, name, asn1Object, openType=None):
self.__name = name
self.__type = asn1Object
self.__nameAndType = name, asn1Object
self.__openType = openType
def __repr__(self):
representation = '%s=%r' % (self.name, self.asn1Object)
if self.openType:
representation += ', open type %r' % self.openType
return '<%s object, type %s>' % (
self.__class__.__name__, representation)
def __eq__(self, other):
return self.__nameAndType == other
def __ne__(self, other):
return self.__nameAndType != other
def __lt__(self, other):
return self.__nameAndType < other
def __le__(self, other):
return self.__nameAndType <= other
def __gt__(self, other):
return self.__nameAndType > other
def __ge__(self, other):
return self.__nameAndType >= other
def __hash__(self):
return hash(self.__nameAndType)
def __getitem__(self, idx):
return self.__nameAndType[idx]
def __iter__(self):
return iter(self.__nameAndType)
@property
def name(self):
return self.__name
@property
def asn1Object(self):
return self.__type
@property
def openType(self):
return self.__openType
# Backward compatibility
def getName(self):
return self.name
def getType(self):
return self.asn1Object
class OptionalNamedType(NamedType):
__doc__ = NamedType.__doc__
isOptional = True
class DefaultedNamedType(NamedType):
__doc__ = NamedType.__doc__
isDefaulted = True
class NamedTypes(object):
"""Create a collection of named fields for a constructed ASN.1 type.
The NamedTypes object represents a collection of named fields of a constructed ASN.1 type.
*NamedTypes* objects are immutable and duck-type Python :class:`dict` objects
holding *name* as keys and ASN.1 type object as values.
Parameters
----------
*namedTypes: :class:`~pyasn1.type.namedtype.NamedType`
Examples
--------
.. code-block:: python
class Description(Sequence):
'''
ASN.1 specification:
Description ::= SEQUENCE {
surname IA5String,
first-name IA5String OPTIONAL,
age INTEGER DEFAULT 40
}
'''
componentType = NamedTypes(
NamedType('surname', IA5String()),
OptionalNamedType('first-name', IA5String()),
DefaultedNamedType('age', Integer(40))
)
descr = Description()
descr['surname'] = 'Smith'
descr['first-name'] = 'John'
"""
def __init__(self, *namedTypes, **kwargs):
self.__namedTypes = namedTypes
self.__namedTypesLen = len(self.__namedTypes)
self.__minTagSet = self.__computeMinTagSet()
self.__nameToPosMap = self.__computeNameToPosMap()
self.__tagToPosMap = self.__computeTagToPosMap()
self.__ambiguousTypes = 'terminal' not in kwargs and self.__computeAmbiguousTypes() or {}
self.__uniqueTagMap = self.__computeTagMaps(unique=True)
self.__nonUniqueTagMap = self.__computeTagMaps(unique=False)
self.__hasOptionalOrDefault = any([True for namedType in self.__namedTypes
if namedType.isDefaulted or namedType.isOptional])
self.__hasOpenTypes = any([True for namedType in self.__namedTypes
if namedType.openType])
self.__requiredComponents = frozenset(
[idx for idx, nt in enumerate(self.__namedTypes) if not nt.isOptional and not nt.isDefaulted]
)
self.__keys = frozenset([namedType.name for namedType in self.__namedTypes])
self.__values = tuple([namedType.asn1Object for namedType in self.__namedTypes])
self.__items = tuple([(namedType.name, namedType.asn1Object) for namedType in self.__namedTypes])
def __repr__(self):
representation = ', '.join(['%r' % x for x in self.__namedTypes])
return '<%s object, types %s>' % (
self.__class__.__name__, representation)
def __eq__(self, other):
return self.__namedTypes == other
def __ne__(self, other):
return self.__namedTypes != other
def __lt__(self, other):
return self.__namedTypes < other
def __le__(self, other):
return self.__namedTypes <= other
def __gt__(self, other):
return self.__namedTypes > other
def __ge__(self, other):
return self.__namedTypes >= other
def __hash__(self):
return hash(self.__namedTypes)
def __getitem__(self, idx):
try:
return self.__namedTypes[idx]
except TypeError:
return self.__namedTypes[self.__nameToPosMap[idx]]
def __contains__(self, key):
return key in self.__nameToPosMap
def __iter__(self):
return (x[0] for x in self.__namedTypes)
if sys.version_info[0] <= 2:
def __nonzero__(self):
return self.__namedTypesLen > 0
else:
def __bool__(self):
return self.__namedTypesLen > 0
def __len__(self):
return self.__namedTypesLen
# Python dict protocol
def values(self):
return self.__values
def keys(self):
return self.__keys
def items(self):
return self.__items
def clone(self):
return self.__class__(*self.__namedTypes)
class PostponedError(object):
def __init__(self, errorMsg):
self.__errorMsg = errorMsg
def __getitem__(self, item):
raise error.PyAsn1Error(self.__errorMsg)
def __computeTagToPosMap(self):
tagToPosMap = {}
for idx, namedType in enumerate(self.__namedTypes):
tagMap = namedType.asn1Object.tagMap
if isinstance(tagMap, NamedTypes.PostponedError):
return tagMap
if not tagMap:
continue
for _tagSet in tagMap.presentTypes:
if _tagSet in tagToPosMap:
return NamedTypes.PostponedError('Duplicate component tag %s at %s' % (_tagSet, namedType))
tagToPosMap[_tagSet] = idx
return tagToPosMap
def __computeNameToPosMap(self):
nameToPosMap = {}
for idx, namedType in enumerate(self.__namedTypes):
if namedType.name in nameToPosMap:
return NamedTypes.PostponedError('Duplicate component name %s at %s' % (namedType.name, namedType))
nameToPosMap[namedType.name] = idx
return nameToPosMap
def __computeAmbiguousTypes(self):
ambiguousTypes = {}
partialAmbiguousTypes = ()
for idx, namedType in reversed(tuple(enumerate(self.__namedTypes))):
if namedType.isOptional or namedType.isDefaulted:
partialAmbiguousTypes = (namedType,) + partialAmbiguousTypes
else:
partialAmbiguousTypes = (namedType,)
if len(partialAmbiguousTypes) == len(self.__namedTypes):
ambiguousTypes[idx] = self
else:
ambiguousTypes[idx] = NamedTypes(*partialAmbiguousTypes, **dict(terminal=True))
return ambiguousTypes
def getTypeByPosition(self, idx):
"""Return ASN.1 type object by its position in fields set.
Parameters
----------
idx: :py:class:`int`
Field index
Returns
-------
:
ASN.1 type
Raises
------
~pyasn1.error.PyAsn1Error
If given position is out of fields range
"""
try:
return self.__namedTypes[idx].asn1Object
except IndexError:
raise error.PyAsn1Error('Type position out of range')
def getPositionByType(self, tagSet):
"""Return field position by its ASN.1 type.
Parameters
----------
tagSet: :class:`~pysnmp.type.tag.TagSet`
ASN.1 tag set distinguishing one ASN.1 type from others.
Returns
-------
: :py:class:`int`
ASN.1 type position in fields set
Raises
------
~pyasn1.error.PyAsn1Error
If *tagSet* is not present or ASN.1 types are not unique within callee *NamedTypes*
"""
try:
return self.__tagToPosMap[tagSet]
except KeyError:
raise error.PyAsn1Error('Type %s not found' % (tagSet,))
def getNameByPosition(self, idx):
"""Return field name by its position in fields set.
Parameters
----------
idx: :py:class:`idx`
Field index
Returns
-------
: :py:class:`str`
Field name
Raises
------
~pyasn1.error.PyAsn1Error
If given field name is not present in callee *NamedTypes*
"""
try:
return self.__namedTypes[idx].name
except IndexError:
raise error.PyAsn1Error('Type position out of range')
def getPositionByName(self, name):
"""Return field position by filed name.
Parameters
----------
name: :py:class:`str`
Field name
Returns
-------
: :py:class:`int`
Field position in fields set
Raises
------
~pyasn1.error.PyAsn1Error
If *name* is not present or not unique within callee *NamedTypes*
"""
try:
return self.__nameToPosMap[name]
except KeyError:
raise error.PyAsn1Error('Name %s not found' % (name,))
def getTagMapNearPosition(self, idx):
"""Return ASN.1 types that are allowed at or past given field position.
Some ASN.1 serialisation allow for skipping optional and defaulted fields.
Some constructed ASN.1 types allow reordering of the fields. When recovering
such objects it may be important to know which types can possibly be
present at any given position in the field sets.
Parameters
----------
idx: :py:class:`int`
Field index
Returns
-------
: :class:`~pyasn1.type.tagmap.TagMap`
Map if ASN.1 types allowed at given field position
Raises
------
~pyasn1.error.PyAsn1Error
If given position is out of fields range
"""
try:
return self.__ambiguousTypes[idx].tagMap
except KeyError:
raise error.PyAsn1Error('Type position out of range')
def getPositionNearType(self, tagSet, idx):
"""Return the closest field position where given ASN.1 type is allowed.
Some ASN.1 serialisation allow for skipping optional and defaulted fields.
Some constructed ASN.1 types allow reordering of the fields. When recovering
such objects it may be important to know at which field position, in field set,
given *tagSet* is allowed at or past *idx* position.
Parameters
----------
tagSet: :class:`~pyasn1.type.tag.TagSet`
ASN.1 type which field position to look up
idx: :py:class:`int`
Field position at or past which to perform ASN.1 type look up
Returns
-------
: :py:class:`int`
Field position in fields set
Raises
------
~pyasn1.error.PyAsn1Error
If *tagSet* is not present or not unique within callee *NamedTypes*
or *idx* is out of fields range
"""
try:
return idx + self.__ambiguousTypes[idx].getPositionByType(tagSet)
except KeyError:
raise error.PyAsn1Error('Type position out of range')
def __computeMinTagSet(self):
minTagSet = None
for namedType in self.__namedTypes:
asn1Object = namedType.asn1Object
try:
tagSet = asn1Object.minTagSet
except AttributeError:
tagSet = asn1Object.tagSet
if minTagSet is None or tagSet < minTagSet:
minTagSet = tagSet
return minTagSet or tag.TagSet()
@property
def minTagSet(self):
"""Return the minimal TagSet among ASN.1 type in callee *NamedTypes*.
Some ASN.1 types/serialisation protocols require ASN.1 types to be
arranged based on their numerical tag value. The *minTagSet* property
returns that.
Returns
-------
: :class:`~pyasn1.type.tagset.TagSet`
Minimal TagSet among ASN.1 types in callee *NamedTypes*
"""
return self.__minTagSet
def __computeTagMaps(self, unique):
presentTypes = {}
skipTypes = {}
defaultType = None
for namedType in self.__namedTypes:
tagMap = namedType.asn1Object.tagMap
if isinstance(tagMap, NamedTypes.PostponedError):
return tagMap
for tagSet in tagMap:
if unique and tagSet in presentTypes:
return NamedTypes.PostponedError('Non-unique tagSet %s of %s at %s' % (tagSet, namedType, self))
presentTypes[tagSet] = namedType.asn1Object
skipTypes.update(tagMap.skipTypes)
if defaultType is None:
defaultType = tagMap.defaultType
elif tagMap.defaultType is not None:
return NamedTypes.PostponedError('Duplicate default ASN.1 type at %s' % (self,))
return tagmap.TagMap(presentTypes, skipTypes, defaultType)
@property
def tagMap(self):
"""Return a *TagMap* object from tags and types recursively.
Return a :class:`~pyasn1.type.tagmap.TagMap` object by
combining tags from *TagMap* objects of children types and
associating them with their immediate child type.
Example
-------
.. code-block:: python
OuterType ::= CHOICE {
innerType INTEGER
}
Calling *.tagMap* on *OuterType* will yield a map like this:
.. code-block:: python
Integer.tagSet -> Choice
"""
return self.__nonUniqueTagMap
@property
def tagMapUnique(self):
"""Return a *TagMap* object from unique tags and types recursively.
Return a :class:`~pyasn1.type.tagmap.TagMap` object by
combining tags from *TagMap* objects of children types and
associating them with their immediate child type.
Example
-------
.. code-block:: python
OuterType ::= CHOICE {
innerType INTEGER
}
Calling *.tagMapUnique* on *OuterType* will yield a map like this:
.. code-block:: python
Integer.tagSet -> Choice
Note
----
Duplicate *TagSet* objects found in the tree of children
types would cause error.
"""
return self.__uniqueTagMap
@property
def hasOptionalOrDefault(self):
return self.__hasOptionalOrDefault
@property
def hasOpenTypes(self):
return self.__hasOpenTypes
@property
def namedTypes(self):
return tuple(self.__namedTypes)
@property
def requiredComponents(self):
return self.__requiredComponents
+192
View File
@@ -0,0 +1,192 @@
#
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2020, Ilya Etingof <etingof@gmail.com>
# License: http://snmplabs.com/pyasn1/license.html
#
# ASN.1 named integers
#
from pyasn1 import error
__all__ = ['NamedValues']
class NamedValues(object):
"""Create named values object.
The |NamedValues| object represents a collection of string names
associated with numeric IDs. These objects are used for giving
names to otherwise numerical values.
|NamedValues| objects are immutable and duck-type Python
:class:`dict` object mapping ID to name and vice-versa.
Parameters
----------
*args: variable number of two-element :py:class:`tuple`
name: :py:class:`str`
Value label
value: :py:class:`int`
Numeric value
Keyword Args
------------
name: :py:class:`str`
Value label
value: :py:class:`int`
Numeric value
Examples
--------
.. code-block:: pycon
>>> nv = NamedValues('a', 'b', ('c', 0), d=1)
>>> nv
>>> {'c': 0, 'd': 1, 'a': 2, 'b': 3}
>>> nv[0]
'c'
>>> nv['a']
2
"""
def __init__(self, *args, **kwargs):
self.__names = {}
self.__numbers = {}
anonymousNames = []
for namedValue in args:
if isinstance(namedValue, (tuple, list)):
try:
name, number = namedValue
except ValueError:
raise error.PyAsn1Error('Not a proper attribute-value pair %r' % (namedValue,))
else:
anonymousNames.append(namedValue)
continue
if name in self.__names:
raise error.PyAsn1Error('Duplicate name %s' % (name,))
if number in self.__numbers:
raise error.PyAsn1Error('Duplicate number %s=%s' % (name, number))
self.__names[name] = number
self.__numbers[number] = name
for name, number in kwargs.items():
if name in self.__names:
raise error.PyAsn1Error('Duplicate name %s' % (name,))
if number in self.__numbers:
raise error.PyAsn1Error('Duplicate number %s=%s' % (name, number))
self.__names[name] = number
self.__numbers[number] = name
if anonymousNames:
number = self.__numbers and max(self.__numbers) + 1 or 0
for name in anonymousNames:
if name in self.__names:
raise error.PyAsn1Error('Duplicate name %s' % (name,))
self.__names[name] = number
self.__numbers[number] = name
number += 1
def __repr__(self):
representation = ', '.join(['%s=%d' % x for x in self.items()])
if len(representation) > 64:
representation = representation[:32] + '...' + representation[-32:]
return '<%s object, enums %s>' % (
self.__class__.__name__, representation)
def __eq__(self, other):
return dict(self) == other
def __ne__(self, other):
return dict(self) != other
def __lt__(self, other):
return dict(self) < other
def __le__(self, other):
return dict(self) <= other
def __gt__(self, other):
return dict(self) > other
def __ge__(self, other):
return dict(self) >= other
def __hash__(self):
return hash(self.items())
# Python dict protocol (read-only)
def __getitem__(self, key):
try:
return self.__numbers[key]
except KeyError:
return self.__names[key]
def __len__(self):
return len(self.__names)
def __contains__(self, key):
return key in self.__names or key in self.__numbers
def __iter__(self):
return iter(self.__names)
def values(self):
return iter(self.__numbers)
def keys(self):
return iter(self.__names)
def items(self):
for name in self.__names:
yield name, self.__names[name]
# support merging
def __add__(self, namedValues):
return self.__class__(*tuple(self.items()) + tuple(namedValues.items()))
# XXX clone/subtype?
def clone(self, *args, **kwargs):
new = self.__class__(*args, **kwargs)
return self + new
# legacy protocol
def getName(self, value):
if value in self.__numbers:
return self.__numbers[value]
def getValue(self, name):
if name in self.__names:
return self.__names[name]
def getValues(self, *names):
try:
return [self.__names[name] for name in names]
except KeyError:
raise error.PyAsn1Error(
'Unknown bit identifier(s): %s' % (set(names).difference(self.__names),)
)
+104
View File
@@ -0,0 +1,104 @@
#
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2020, Ilya Etingof <etingof@gmail.com>
# License: http://snmplabs.com/pyasn1/license.html
#
__all__ = ['OpenType']
class OpenType(object):
"""Create ASN.1 type map indexed by a value
The *OpenType* object models an untyped field of a constructed ASN.1
type. In ASN.1 syntax it is usually represented by the
`ANY DEFINED BY` for scalars or `SET OF ANY DEFINED BY`,
`SEQUENCE OF ANY DEFINED BY` for container types clauses. Typically
used together with :class:`~pyasn1.type.univ.Any` object.
OpenType objects duck-type a read-only Python :class:`dict` objects,
however the passed `typeMap` is not copied, but stored by reference.
That means the user can manipulate `typeMap` at run time having this
reflected on *OpenType* object behavior.
The |OpenType| class models an untyped field of a constructed ASN.1
type. In ASN.1 syntax it is usually represented by the
`ANY DEFINED BY` for scalars or `SET OF ANY DEFINED BY`,
`SEQUENCE OF ANY DEFINED BY` for container types clauses. Typically
used with :class:`~pyasn1.type.univ.Any` type.
Parameters
----------
name: :py:class:`str`
Field name
typeMap: :py:class:`dict`
A map of value->ASN.1 type. It's stored by reference and can be
mutated later to register new mappings.
Examples
--------
For untyped scalars:
.. code-block:: python
openType = OpenType(
'id', {1: Integer(),
2: OctetString()}
)
Sequence(
componentType=NamedTypes(
NamedType('id', Integer()),
NamedType('blob', Any(), openType=openType)
)
)
For untyped `SET OF` or `SEQUENCE OF` vectors:
.. code-block:: python
openType = OpenType(
'id', {1: Integer(),
2: OctetString()}
)
Sequence(
componentType=NamedTypes(
NamedType('id', Integer()),
NamedType('blob', SetOf(componentType=Any()),
openType=openType)
)
)
"""
def __init__(self, name, typeMap=None):
self.__name = name
if typeMap is None:
self.__typeMap = {}
else:
self.__typeMap = typeMap
@property
def name(self):
return self.__name
# Python dict protocol
def values(self):
return self.__typeMap.values()
def keys(self):
return self.__typeMap.keys()
def items(self):
return self.__typeMap.items()
def __contains__(self, key):
return key in self.__typeMap
def __getitem__(self, key):
return self.__typeMap[key]
def __iter__(self):
return iter(self.__typeMap)
+335
View File
@@ -0,0 +1,335 @@
#
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2020, Ilya Etingof <etingof@gmail.com>
# License: http://snmplabs.com/pyasn1/license.html
#
from pyasn1 import error
__all__ = ['tagClassUniversal', 'tagClassApplication', 'tagClassContext',
'tagClassPrivate', 'tagFormatSimple', 'tagFormatConstructed',
'tagCategoryImplicit', 'tagCategoryExplicit',
'tagCategoryUntagged', 'Tag', 'TagSet']
#: Identifier for ASN.1 class UNIVERSAL
tagClassUniversal = 0x00
#: Identifier for ASN.1 class APPLICATION
tagClassApplication = 0x40
#: Identifier for ASN.1 class context-specific
tagClassContext = 0x80
#: Identifier for ASN.1 class private
tagClassPrivate = 0xC0
#: Identifier for "simple" ASN.1 structure (e.g. scalar)
tagFormatSimple = 0x00
#: Identifier for "constructed" ASN.1 structure (e.g. may have inner components)
tagFormatConstructed = 0x20
tagCategoryImplicit = 0x01
tagCategoryExplicit = 0x02
tagCategoryUntagged = 0x04
class Tag(object):
"""Create ASN.1 tag
Represents ASN.1 tag that can be attached to a ASN.1 type to make
types distinguishable from each other.
*Tag* objects are immutable and duck-type Python :class:`tuple` objects
holding three integer components of a tag.
Parameters
----------
tagClass: :py:class:`int`
Tag *class* value
tagFormat: :py:class:`int`
Tag *format* value
tagId: :py:class:`int`
Tag ID value
"""
def __init__(self, tagClass, tagFormat, tagId):
if tagId < 0:
raise error.PyAsn1Error('Negative tag ID (%s) not allowed' % tagId)
self.__tagClass = tagClass
self.__tagFormat = tagFormat
self.__tagId = tagId
self.__tagClassId = tagClass, tagId
self.__hash = hash(self.__tagClassId)
def __repr__(self):
representation = '[%s:%s:%s]' % (
self.__tagClass, self.__tagFormat, self.__tagId)
return '<%s object, tag %s>' % (
self.__class__.__name__, representation)
def __eq__(self, other):
return self.__tagClassId == other
def __ne__(self, other):
return self.__tagClassId != other
def __lt__(self, other):
return self.__tagClassId < other
def __le__(self, other):
return self.__tagClassId <= other
def __gt__(self, other):
return self.__tagClassId > other
def __ge__(self, other):
return self.__tagClassId >= other
def __hash__(self):
return self.__hash
def __getitem__(self, idx):
if idx == 0:
return self.__tagClass
elif idx == 1:
return self.__tagFormat
elif idx == 2:
return self.__tagId
else:
raise IndexError()
def __iter__(self):
yield self.__tagClass
yield self.__tagFormat
yield self.__tagId
def __and__(self, otherTag):
return self.__class__(self.__tagClass & otherTag.tagClass,
self.__tagFormat & otherTag.tagFormat,
self.__tagId & otherTag.tagId)
def __or__(self, otherTag):
return self.__class__(self.__tagClass | otherTag.tagClass,
self.__tagFormat | otherTag.tagFormat,
self.__tagId | otherTag.tagId)
@property
def tagClass(self):
"""ASN.1 tag class
Returns
-------
: :py:class:`int`
Tag class
"""
return self.__tagClass
@property
def tagFormat(self):
"""ASN.1 tag format
Returns
-------
: :py:class:`int`
Tag format
"""
return self.__tagFormat
@property
def tagId(self):
"""ASN.1 tag ID
Returns
-------
: :py:class:`int`
Tag ID
"""
return self.__tagId
class TagSet(object):
"""Create a collection of ASN.1 tags
Represents a combination of :class:`~pyasn1.type.tag.Tag` objects
that can be attached to a ASN.1 type to make types distinguishable
from each other.
*TagSet* objects are immutable and duck-type Python :class:`tuple` objects
holding arbitrary number of :class:`~pyasn1.type.tag.Tag` objects.
Parameters
----------
baseTag: :class:`~pyasn1.type.tag.Tag`
Base *Tag* object. This tag survives IMPLICIT tagging.
*superTags: :class:`~pyasn1.type.tag.Tag`
Additional *Tag* objects taking part in subtyping.
Examples
--------
.. code-block:: python
class OrderNumber(NumericString):
'''
ASN.1 specification
Order-number ::=
[APPLICATION 5] IMPLICIT NumericString
'''
tagSet = NumericString.tagSet.tagImplicitly(
Tag(tagClassApplication, tagFormatSimple, 5)
)
orderNumber = OrderNumber('1234')
"""
def __init__(self, baseTag=(), *superTags):
self.__baseTag = baseTag
self.__superTags = superTags
self.__superTagsClassId = tuple(
[(superTag.tagClass, superTag.tagId) for superTag in superTags]
)
self.__lenOfSuperTags = len(superTags)
self.__hash = hash(self.__superTagsClassId)
def __repr__(self):
representation = '-'.join(['%s:%s:%s' % (x.tagClass, x.tagFormat, x.tagId)
for x in self.__superTags])
if representation:
representation = 'tags ' + representation
else:
representation = 'untagged'
return '<%s object, %s>' % (self.__class__.__name__, representation)
def __add__(self, superTag):
return self.__class__(self.__baseTag, *self.__superTags + (superTag,))
def __radd__(self, superTag):
return self.__class__(self.__baseTag, *(superTag,) + self.__superTags)
def __getitem__(self, i):
if i.__class__ is slice:
return self.__class__(self.__baseTag, *self.__superTags[i])
else:
return self.__superTags[i]
def __eq__(self, other):
return self.__superTagsClassId == other
def __ne__(self, other):
return self.__superTagsClassId != other
def __lt__(self, other):
return self.__superTagsClassId < other
def __le__(self, other):
return self.__superTagsClassId <= other
def __gt__(self, other):
return self.__superTagsClassId > other
def __ge__(self, other):
return self.__superTagsClassId >= other
def __hash__(self):
return self.__hash
def __len__(self):
return self.__lenOfSuperTags
@property
def baseTag(self):
"""Return base ASN.1 tag
Returns
-------
: :class:`~pyasn1.type.tag.Tag`
Base tag of this *TagSet*
"""
return self.__baseTag
@property
def superTags(self):
"""Return ASN.1 tags
Returns
-------
: :py:class:`tuple`
Tuple of :class:`~pyasn1.type.tag.Tag` objects that this *TagSet* contains
"""
return self.__superTags
def tagExplicitly(self, superTag):
"""Return explicitly tagged *TagSet*
Create a new *TagSet* representing callee *TagSet* explicitly tagged
with passed tag(s). With explicit tagging mode, new tags are appended
to existing tag(s).
Parameters
----------
superTag: :class:`~pyasn1.type.tag.Tag`
*Tag* object to tag this *TagSet*
Returns
-------
: :class:`~pyasn1.type.tag.TagSet`
New *TagSet* object
"""
if superTag.tagClass == tagClassUniversal:
raise error.PyAsn1Error("Can't tag with UNIVERSAL class tag")
if superTag.tagFormat != tagFormatConstructed:
superTag = Tag(superTag.tagClass, tagFormatConstructed, superTag.tagId)
return self + superTag
def tagImplicitly(self, superTag):
"""Return implicitly tagged *TagSet*
Create a new *TagSet* representing callee *TagSet* implicitly tagged
with passed tag(s). With implicit tagging mode, new tag(s) replace the
last existing tag.
Parameters
----------
superTag: :class:`~pyasn1.type.tag.Tag`
*Tag* object to tag this *TagSet*
Returns
-------
: :class:`~pyasn1.type.tag.TagSet`
New *TagSet* object
"""
if self.__superTags:
superTag = Tag(superTag.tagClass, self.__superTags[-1].tagFormat, superTag.tagId)
return self[:-1] + superTag
def isSuperTagSetOf(self, tagSet):
"""Test type relationship against given *TagSet*
The callee is considered to be a supertype of given *TagSet*
tag-wise if all tags in *TagSet* are present in the callee and
they are in the same order.
Parameters
----------
tagSet: :class:`~pyasn1.type.tag.TagSet`
*TagSet* object to evaluate against the callee
Returns
-------
: :py:class:`bool`
:obj:`True` if callee is a supertype of *tagSet*
"""
if len(tagSet) < self.__lenOfSuperTags:
return False
return self.__superTags == tagSet[:self.__lenOfSuperTags]
# Backward compatibility
def getBaseTag(self):
return self.__baseTag
def initTagSet(tag):
return TagSet(tag, tag)
+96
View File
@@ -0,0 +1,96 @@
#
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2020, Ilya Etingof <etingof@gmail.com>
# License: http://snmplabs.com/pyasn1/license.html
#
from pyasn1 import error
__all__ = ['TagMap']
class TagMap(object):
"""Map *TagSet* objects to ASN.1 types
Create an object mapping *TagSet* object to ASN.1 type.
*TagMap* objects are immutable and duck-type read-only Python
:class:`dict` objects holding *TagSet* objects as keys and ASN.1
type objects as values.
Parameters
----------
presentTypes: :py:class:`dict`
Map of :class:`~pyasn1.type.tag.TagSet` to ASN.1 objects considered
as being unconditionally present in the *TagMap*.
skipTypes: :py:class:`dict`
A collection of :class:`~pyasn1.type.tag.TagSet` objects considered
as absent in the *TagMap* even when *defaultType* is present.
defaultType: ASN.1 type object
An ASN.1 type object callee *TagMap* returns for any *TagSet* key not present
in *presentTypes* (unless given key is present in *skipTypes*).
"""
def __init__(self, presentTypes=None, skipTypes=None, defaultType=None):
self.__presentTypes = presentTypes or {}
self.__skipTypes = skipTypes or {}
self.__defaultType = defaultType
def __contains__(self, tagSet):
return (tagSet in self.__presentTypes or
self.__defaultType is not None and tagSet not in self.__skipTypes)
def __getitem__(self, tagSet):
try:
return self.__presentTypes[tagSet]
except KeyError:
if self.__defaultType is None:
raise KeyError()
elif tagSet in self.__skipTypes:
raise error.PyAsn1Error('Key in negative map')
else:
return self.__defaultType
def __iter__(self):
return iter(self.__presentTypes)
def __repr__(self):
representation = '%s object' % self.__class__.__name__
if self.__presentTypes:
representation += ', present %s' % repr(self.__presentTypes)
if self.__skipTypes:
representation += ', skip %s' % repr(self.__skipTypes)
if self.__defaultType is not None:
representation += ', default %s' % repr(self.__defaultType)
return '<%s>' % representation
@property
def presentTypes(self):
"""Return *TagSet* to ASN.1 type map present in callee *TagMap*"""
return self.__presentTypes
@property
def skipTypes(self):
"""Return *TagSet* collection unconditionally absent in callee *TagMap*"""
return self.__skipTypes
@property
def defaultType(self):
"""Return default ASN.1 type being returned for any missing *TagSet*"""
return self.__defaultType
# Backward compatibility
def getPosMap(self):
return self.presentTypes
def getNegMap(self):
return self.skipTypes
def getDef(self):
return self.defaultType
File diff suppressed because it is too large Load Diff
+189
View File
@@ -0,0 +1,189 @@
#
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2020, Ilya Etingof <etingof@gmail.com>
# License: http://snmplabs.com/pyasn1/license.html
#
import datetime
from pyasn1 import error
from pyasn1.type import char
from pyasn1.type import tag
from pyasn1.type import univ
__all__ = ['ObjectDescriptor', 'GeneralizedTime', 'UTCTime']
NoValue = univ.NoValue
noValue = univ.noValue
class ObjectDescriptor(char.GraphicString):
__doc__ = char.GraphicString.__doc__
#: Default :py:class:`~pyasn1.type.tag.TagSet` object for |ASN.1| objects
tagSet = char.GraphicString.tagSet.tagImplicitly(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 7)
)
# Optimization for faster codec lookup
typeId = char.GraphicString.getTypeId()
class TimeMixIn(object):
_yearsDigits = 4
_hasSubsecond = False
_optionalMinutes = False
_shortTZ = False
class FixedOffset(datetime.tzinfo):
"""Fixed offset in minutes east from UTC."""
# defaulted arguments required
# https: // docs.python.org / 2.3 / lib / datetime - tzinfo.html
def __init__(self, offset=0, name='UTC'):
self.__offset = datetime.timedelta(minutes=offset)
self.__name = name
def utcoffset(self, dt):
return self.__offset
def tzname(self, dt):
return self.__name
def dst(self, dt):
return datetime.timedelta(0)
UTC = FixedOffset()
@property
def asDateTime(self):
"""Create :py:class:`datetime.datetime` object from a |ASN.1| object.
Returns
-------
:
new instance of :py:class:`datetime.datetime` object
"""
text = str(self)
if text.endswith('Z'):
tzinfo = TimeMixIn.UTC
text = text[:-1]
elif '-' in text or '+' in text:
if '+' in text:
text, plusminus, tz = text.partition('+')
else:
text, plusminus, tz = text.partition('-')
if self._shortTZ and len(tz) == 2:
tz += '00'
if len(tz) != 4:
raise error.PyAsn1Error('malformed time zone offset %s' % tz)
try:
minutes = int(tz[:2]) * 60 + int(tz[2:])
if plusminus == '-':
minutes *= -1
except ValueError:
raise error.PyAsn1Error('unknown time specification %s' % self)
tzinfo = TimeMixIn.FixedOffset(minutes, '?')
else:
tzinfo = None
if '.' in text or ',' in text:
if '.' in text:
text, _, ms = text.partition('.')
else:
text, _, ms = text.partition(',')
try:
ms = int(ms) * 1000
except ValueError:
raise error.PyAsn1Error('bad sub-second time specification %s' % self)
else:
ms = 0
if self._optionalMinutes and len(text) - self._yearsDigits == 6:
text += '0000'
elif len(text) - self._yearsDigits == 8:
text += '00'
try:
dt = datetime.datetime.strptime(text, self._yearsDigits == 4 and '%Y%m%d%H%M%S' or '%y%m%d%H%M%S')
except ValueError:
raise error.PyAsn1Error('malformed datetime format %s' % self)
return dt.replace(microsecond=ms, tzinfo=tzinfo)
@classmethod
def fromDateTime(cls, dt):
"""Create |ASN.1| object from a :py:class:`datetime.datetime` object.
Parameters
----------
dt: :py:class:`datetime.datetime` object
The `datetime.datetime` object to initialize the |ASN.1| object
from
Returns
-------
:
new instance of |ASN.1| value
"""
text = dt.strftime(cls._yearsDigits == 4 and '%Y%m%d%H%M%S' or '%y%m%d%H%M%S')
if cls._hasSubsecond:
text += '.%d' % (dt.microsecond // 1000)
if dt.utcoffset():
seconds = dt.utcoffset().seconds
if seconds < 0:
text += '-'
else:
text += '+'
text += '%.2d%.2d' % (seconds // 3600, seconds % 3600)
else:
text += 'Z'
return cls(text)
class GeneralizedTime(char.VisibleString, TimeMixIn):
__doc__ = char.VisibleString.__doc__
#: Default :py:class:`~pyasn1.type.tag.TagSet` object for |ASN.1| objects
tagSet = char.VisibleString.tagSet.tagImplicitly(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 24)
)
# Optimization for faster codec lookup
typeId = char.VideotexString.getTypeId()
_yearsDigits = 4
_hasSubsecond = True
_optionalMinutes = True
_shortTZ = True
class UTCTime(char.VisibleString, TimeMixIn):
__doc__ = char.VisibleString.__doc__
#: Default :py:class:`~pyasn1.type.tag.TagSet` object for |ASN.1| objects
tagSet = char.VisibleString.tagSet.tagImplicitly(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 23)
)
# Optimization for faster codec lookup
typeId = char.VideotexString.getTypeId()
_yearsDigits = 2
_hasSubsecond = False
_optionalMinutes = False
_shortTZ = False