137 lines
4.2 KiB
Python
137 lines
4.2 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
def _make_tif_property(val):
|
|
"""
|
|
Helper function for generating property methods for :obj:`.TIF`
|
|
which will boolean whether a particular SQRL ``TIF`` bit is ``True``
|
|
in the ``TIF`` value.
|
|
Parameters
|
|
----------
|
|
val : int
|
|
Value with particular ``True`` bit which will be tested
|
|
within the generated property.
|
|
Returns
|
|
-------
|
|
function
|
|
Function which can be made into a property
|
|
"""
|
|
|
|
def is_bit_present(self):
|
|
"""
|
|
Property which returns boolean whether ``{hex}`` or ``{bits}``
|
|
bit is present in the TIF value.
|
|
"""
|
|
return bool(self & val)
|
|
|
|
is_bit_present.__doc__ = is_bit_present.__doc__.format(
|
|
hex=hex(val),
|
|
bits=bin(val),
|
|
)
|
|
|
|
return is_bit_present
|
|
|
|
|
|
class TIF(int):
|
|
"""
|
|
SQRL ``TIF`` ``int`` subclass which can represent SQRL ``TIF`` flags.
|
|
Example
|
|
-------
|
|
::
|
|
>>> tif = TIF(TIF.IP_MATCH | TIF.TRANSIENT_FAILURE | TIF.COMMAND_FAILED)
|
|
>>> tif.is_ip_match
|
|
True
|
|
>>> tif.is_id_match
|
|
False
|
|
>>> tif.is_transient_failure
|
|
True
|
|
>>> tif
|
|
100
|
|
>>> tif.as_hex_string()
|
|
'64'
|
|
>>> tif.breakdown() == {
|
|
... 'id_match': False,
|
|
... 'previous_id_match': False,
|
|
... 'ip_match': True,
|
|
... 'sqrl_disabled': False,
|
|
... 'not_supported': False,
|
|
... 'transient_failure': True,
|
|
... 'command_failed': True,
|
|
... 'client_failure': False,
|
|
... }
|
|
True
|
|
"""
|
|
ID_MATCH = 0x1
|
|
"""SQRL ID was found in DB"""
|
|
PREVIOUS_ID_MATCH = 0x2
|
|
"""Previous SQRL ID was found in DB"""
|
|
IP_MATCH = 0x4
|
|
"""SQRL client is used from same IP as where transaction started"""
|
|
SQRL_DISABLED = 0x8
|
|
"""SQRL auth is disabled for the found SQRL identity as per users request"""
|
|
NOT_SUPPORTED = 0x10
|
|
"""SQRL client requested SQRl operation which is not supported"""
|
|
TRANSIENT_FAILURE = 0x20
|
|
"""SQRL command failed transiently. Most likely restarting SQRL transaction should fix this"""
|
|
COMMAND_FAILED = 0x40
|
|
"""SQRL command failed for any reason"""
|
|
CLIENT_FAILURE = 0x80
|
|
"""SQRL command failed because SQRL client sent invalid data"""
|
|
BAD_ID_ASSOCIATION = 0x100
|
|
"""SQRL Identity is already a ssociated with a different account"""
|
|
|
|
is_id_match = property(_make_tif_property(ID_MATCH))
|
|
is_previous_id_match = property(_make_tif_property(PREVIOUS_ID_MATCH))
|
|
is_ip_match = property(_make_tif_property(IP_MATCH))
|
|
is_sqrl_disabled = property(_make_tif_property(SQRL_DISABLED))
|
|
is_transient_failure = property(_make_tif_property(TRANSIENT_FAILURE))
|
|
is_command_failed = property(_make_tif_property(COMMAND_FAILED))
|
|
is_client_failure = property(_make_tif_property(CLIENT_FAILURE))
|
|
is_not_supported = property(_make_tif_property(NOT_SUPPORTED))
|
|
is_bad_id_association = property(_make_tif_property(BAD_ID_ASSOCIATION))
|
|
|
|
def as_hex_string(self):
|
|
"""
|
|
Return TIF value as hex string
|
|
"""
|
|
return '{:x}'.format(self)
|
|
|
|
def breakdown(self):
|
|
"""
|
|
Returns a full breakdown of the TIF value.
|
|
Returns
|
|
-------
|
|
dict
|
|
Keys are the SQRL TIF property and values are booleans.
|
|
"""
|
|
return {
|
|
k.lower(): bool(self & v)
|
|
for k, v in vars(self.__class__).items()
|
|
if not k.startswith('_') and k.isupper()
|
|
}
|
|
|
|
def update(self, other):
|
|
"""
|
|
Return updated TIF which will contain both bits already set
|
|
in the ``self`` value as well as the ``other value.
|
|
Parameters
|
|
----------
|
|
other : int
|
|
Other ``TIF`` value which be merged with ``self`` bits
|
|
Returns
|
|
-------
|
|
TIF
|
|
New :obj:`.TIF` value which has merged bits.
|
|
"""
|
|
return type(self)(self | other)
|
|
|
|
|
|
class TIFException(Exception):
|
|
"""
|
|
Custom Exception which can be used in the views to raise
|
|
specific :obj:`.TIF` bits and immediately return appropriate response
|
|
to the user.
|
|
"""
|
|
|
|
def __init__(self, tif):
|
|
self.tif = TIF(tif)
|