mirror of
https://github.com/dkmstr/openuds.git
synced 2025-01-11 05:17:55 +03:00
Adding user interface tests and refactoring user interface
This commit is contained in:
parent
284508632c
commit
adb4b5326a
84
server/src/tests/core/ui/test_gui.py
Normal file
84
server/src/tests/core/ui/test_gui.py
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2022 Virtual Cable S.L.U.
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
# are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# * Redistributions of source code must retain the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer.
|
||||||
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer in the documentation
|
||||||
|
# and/or other materials provided with the distribution.
|
||||||
|
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||||
|
# may be used to endorse or promote products derived from this software
|
||||||
|
# without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||||
|
"""
|
||||||
|
# We use commit/rollback
|
||||||
|
from ...utils.test import UDSTestCase
|
||||||
|
from uds.core.ui.user_interface import (
|
||||||
|
gui,
|
||||||
|
UDSB,
|
||||||
|
UDSK
|
||||||
|
)
|
||||||
|
import time
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
|
class GuiTest(UDSTestCase):
|
||||||
|
|
||||||
|
def test_globals(self):
|
||||||
|
self.assertEqual(UDSK, settings.SECRET_KEY[8:24].encode())
|
||||||
|
self.assertEqual(UDSB, b'udsprotect')
|
||||||
|
|
||||||
|
def test_convert_to_choices(self) -> None:
|
||||||
|
# Several cases
|
||||||
|
# 1. Empty list
|
||||||
|
# 2.- single string
|
||||||
|
# 3.- A list of strings
|
||||||
|
# 4.- A list of dictinaries, must be {'id': 'xxxx', 'text': 'yyy'}
|
||||||
|
# 5.- A Dictionary, Keys will be used in 'id' and values in 'text'
|
||||||
|
self.assertEqual(gui.convertToChoices([]), [])
|
||||||
|
self.assertEqual(gui.convertToChoices('aaaa'), [{'id': 'aaaa', 'text': 'aaaa'}])
|
||||||
|
self.assertEqual(gui.convertToChoices(['a', 'b']), [{'id': 'a', 'text': 'a'}, {'id': 'b', 'text': 'b'}])
|
||||||
|
self.assertEqual(gui.convertToChoices({'a': 'b', 'c': 'd'}), [{'id': 'a', 'text': 'b'}, {'id': 'c', 'text': 'd'}])
|
||||||
|
self.assertEqual(gui.convertToChoices({'a': 'b', 'c': 'd'}), [{'id': 'a', 'text': 'b'}, {'id': 'c', 'text': 'd'}])
|
||||||
|
# Expect an exception if we pass a list of dictionaries without id or text
|
||||||
|
self.assertRaises(ValueError, gui.convertToChoices, [{'a': 'b', 'c': 'd'}])
|
||||||
|
# Also if we pass a list of dictionaries with id and text, but not all of them
|
||||||
|
self.assertRaises(ValueError, gui.convertToChoices, [{'id': 'a', 'text': 'b'}, {'id': 'c', 'text': 'd'}, {'id': 'e'}])
|
||||||
|
|
||||||
|
|
||||||
|
def test_convert_to_list(self) -> None:
|
||||||
|
# Several cases
|
||||||
|
# 1. Empty list
|
||||||
|
# 2.- single string
|
||||||
|
# 3.- A list of strings
|
||||||
|
self.assertEqual(gui.convertToList([]), [])
|
||||||
|
self.assertEqual(gui.convertToList('aaaa'), ['aaaa'])
|
||||||
|
self.assertEqual(gui.convertToList(['a', 'b']), ['a', 'b'])
|
||||||
|
self.assertEqual(gui.convertToList(1), ['1'])
|
||||||
|
|
||||||
|
def test_choice_image(self) -> None:
|
||||||
|
# id, text, and base64 image
|
||||||
|
self.assertEqual(gui.choiceImage('id', 'text', 'image'), {'id': 'id', 'text': 'text', 'img': 'image'})
|
||||||
|
|
||||||
|
|
48
server/src/tests/core/ui/test_userinterface.py
Normal file
48
server/src/tests/core/ui/test_userinterface.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2022 Virtual Cable S.L.U.
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
# are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# * Redistributions of source code must retain the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer.
|
||||||
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer in the documentation
|
||||||
|
# and/or other materials provided with the distribution.
|
||||||
|
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||||
|
# may be used to endorse or promote products derived from this software
|
||||||
|
# without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||||
|
"""
|
||||||
|
# We use commit/rollback
|
||||||
|
from ...utils.test import UDSTransactionTestCase
|
||||||
|
from uds.core.ui.user_interface import (
|
||||||
|
gui,
|
||||||
|
UserInterface
|
||||||
|
)
|
||||||
|
import time
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
|
class UserinterfaceTest(UDSTransactionTestCase):
|
||||||
|
|
||||||
|
def test_userinterface(self):
|
||||||
|
pass
|
@ -42,6 +42,7 @@ from collections import abc
|
|||||||
|
|
||||||
from django.utils.translation import get_language, gettext as _, gettext_noop
|
from django.utils.translation import get_language, gettext as _, gettext_noop
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from numpy import isin
|
||||||
|
|
||||||
from uds.core.managers import cryptoManager
|
from uds.core.managers import cryptoManager
|
||||||
from uds.core.util.decorators import deprecatedClassValue
|
from uds.core.util.decorators import deprecatedClassValue
|
||||||
@ -99,19 +100,21 @@ class gui:
|
|||||||
|
|
||||||
# Values dict type
|
# Values dict type
|
||||||
ValuesType = typing.Optional[typing.Dict[str, str]]
|
ValuesType = typing.Optional[typing.Dict[str, str]]
|
||||||
|
|
||||||
|
class ChoiceType(typing.TypedDict):
|
||||||
|
id: str
|
||||||
|
text: str
|
||||||
|
|
||||||
ValuesDictType = typing.Dict[
|
ValuesDictType = typing.Dict[
|
||||||
str,
|
str,
|
||||||
typing.Union[str, bool, typing.List[str], typing.List[typing.Dict[str, str]]],
|
typing.Union[str, bool, typing.List[str], typing.List[ChoiceType]],
|
||||||
]
|
]
|
||||||
ChoiceType = typing.Dict[str, str]
|
|
||||||
|
|
||||||
|
|
||||||
# : True string value
|
# : True string value
|
||||||
TRUE: typing.ClassVar[str] = 'true'
|
TRUE: typing.ClassVar[str] = 'true'
|
||||||
# : False string value
|
# : False string value
|
||||||
FALSE: typing.ClassVar[str] = 'false'
|
FALSE: typing.ClassVar[str] = 'false'
|
||||||
|
|
||||||
|
|
||||||
class Tab(enum.Enum):
|
class Tab(enum.Enum):
|
||||||
ADVANCED = gettext_noop('Advanced')
|
ADVANCED = gettext_noop('Advanced')
|
||||||
PARAMETERS = gettext_noop('Parameters')
|
PARAMETERS = gettext_noop('Parameters')
|
||||||
@ -123,24 +126,28 @@ class gui:
|
|||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return str(self.value)
|
return str(self.value)
|
||||||
|
|
||||||
|
|
||||||
# : For backward compatibility, will be removed in future versions
|
# : For backward compatibility, will be removed in future versions
|
||||||
# For now, will log an warning if used
|
# For now, will log an warning if used
|
||||||
@deprecatedClassValue('gui.Tab.ADVANCED')
|
@deprecatedClassValue('gui.Tab.ADVANCED')
|
||||||
def ADVANCED_TAB(cls) -> str:
|
def ADVANCED_TAB(cls) -> str:
|
||||||
return str(gui.Tab.ADVANCED)
|
return str(gui.Tab.ADVANCED)
|
||||||
|
|
||||||
@deprecatedClassValue('gui.Tab.PARAMETERS')
|
@deprecatedClassValue('gui.Tab.PARAMETERS')
|
||||||
def PARAMETERS_TAB(cls) -> str:
|
def PARAMETERS_TAB(cls) -> str:
|
||||||
return str(gui.Tab.PARAMETERS)
|
return str(gui.Tab.PARAMETERS)
|
||||||
|
|
||||||
@deprecatedClassValue('gui.Tab.CREDENTIALS')
|
@deprecatedClassValue('gui.Tab.CREDENTIALS')
|
||||||
def CREDENTIALS_TAB(cls) -> str:
|
def CREDENTIALS_TAB(cls) -> str:
|
||||||
return str(gui.Tab.CREDENTIALS)
|
return str(gui.Tab.CREDENTIALS)
|
||||||
|
|
||||||
@deprecatedClassValue('gui.Tab.TUNNEL')
|
@deprecatedClassValue('gui.Tab.TUNNEL')
|
||||||
def TUNNEL_TAB(cls) -> str:
|
def TUNNEL_TAB(cls) -> str:
|
||||||
return str(gui.Tab.TUNNEL)
|
return str(gui.Tab.TUNNEL)
|
||||||
|
|
||||||
@deprecatedClassValue('gui.Tab.DISPLAY')
|
@deprecatedClassValue('gui.Tab.DISPLAY')
|
||||||
def DISPLAY_TAB(cls) -> str:
|
def DISPLAY_TAB(cls) -> str:
|
||||||
return str(gui.Tab.DISPLAY)
|
return str(gui.Tab.DISPLAY)
|
||||||
|
|
||||||
@deprecatedClassValue('gui.Tab.MFA')
|
@deprecatedClassValue('gui.Tab.MFA')
|
||||||
def MFA_TAB(cls) -> str:
|
def MFA_TAB(cls) -> str:
|
||||||
return str(gui.Tab.MFA)
|
return str(gui.Tab.MFA)
|
||||||
@ -151,42 +158,10 @@ class gui:
|
|||||||
typing.Callable[[typing.Dict[str, str]], typing.List[typing.Dict[str, str]]],
|
typing.Callable[[typing.Dict[str, str]], typing.List[typing.Dict[str, str]]],
|
||||||
] = {}
|
] = {}
|
||||||
|
|
||||||
# Helpers
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def convertToChoices(
|
def choiceItem(
|
||||||
vals: typing.Union[typing.Iterable[typing.Union[str, typing.Dict[str, str]]], typing.Dict[str, str]]
|
id_: typing.Union[str, int], text: typing.Union[str, int]
|
||||||
) -> typing.List[typing.Dict[str, str]]:
|
) -> 'gui.ChoiceType':
|
||||||
"""
|
|
||||||
Helper to convert from array of strings (or dictionaries) to the same dict used in choice,
|
|
||||||
multichoice, ..
|
|
||||||
"""
|
|
||||||
if not vals:
|
|
||||||
return []
|
|
||||||
# Helper to convert an item to a dict
|
|
||||||
def choiceFromValue(val: typing.Union[str, typing.Dict[str, str]]) -> typing.Dict[str, str]:
|
|
||||||
if isinstance(val, str):
|
|
||||||
return {'id': val, 'text': val}
|
|
||||||
return copy.deepcopy(val)
|
|
||||||
|
|
||||||
# If is a dict
|
|
||||||
if isinstance(vals, abc.Mapping):
|
|
||||||
return [{'id': str(k), 'text': v} for k, v in vals.items()]
|
|
||||||
|
|
||||||
# If is an iterator
|
|
||||||
if isinstance(vals, abc.Iterable):
|
|
||||||
return [choiceFromValue(v) for v in vals]
|
|
||||||
|
|
||||||
|
|
||||||
raise ValueError('Invalid type for convertToChoices: {}'.format(type(vals)))
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def convertToList(vals: typing.Iterable[str]) -> typing.List[str]:
|
|
||||||
if vals:
|
|
||||||
return [str(v) for v in vals]
|
|
||||||
return []
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def choiceItem(id_: typing.Union[str, int], text: str) -> 'gui.ChoiceType':
|
|
||||||
"""
|
"""
|
||||||
Helper method to create a single choice item.
|
Helper method to create a single choice item.
|
||||||
|
|
||||||
@ -204,6 +179,58 @@ class gui:
|
|||||||
"""
|
"""
|
||||||
return {'id': str(id_), 'text': str(text)}
|
return {'id': str(id_), 'text': str(text)}
|
||||||
|
|
||||||
|
# Helpers
|
||||||
|
@staticmethod
|
||||||
|
def convertToChoices(
|
||||||
|
vals: typing.Union[
|
||||||
|
typing.Iterable[typing.Union[str, typing.Dict[str, str]]],
|
||||||
|
typing.Dict[str, str],
|
||||||
|
None,
|
||||||
|
]
|
||||||
|
) -> typing.List['gui.ChoiceType']:
|
||||||
|
"""
|
||||||
|
Helper to convert from array of strings (or dictionaries) to the same dict used in choice,
|
||||||
|
multichoice, ..
|
||||||
|
"""
|
||||||
|
if not vals:
|
||||||
|
return []
|
||||||
|
|
||||||
|
# Helper to convert an item to a dict
|
||||||
|
def choiceFromValue(
|
||||||
|
val: typing.Union[str, int, typing.Dict[str, str]]
|
||||||
|
) -> 'gui.ChoiceType':
|
||||||
|
if isinstance(val, dict):
|
||||||
|
if 'id' not in val or 'text' not in val:
|
||||||
|
raise ValueError('Invalid choice dict: {}'.format(val))
|
||||||
|
return gui.choiceItem(val['id'], val['text'])
|
||||||
|
# If val is not a dict, and it has not 'id' and 'text', raise an exception
|
||||||
|
return gui.choiceItem(val, val)
|
||||||
|
|
||||||
|
# If is a dict
|
||||||
|
if isinstance(vals, abc.Mapping):
|
||||||
|
return [gui.choiceItem(str(k), v) for k, v in vals.items()]
|
||||||
|
|
||||||
|
# if single value, convert to list
|
||||||
|
if not isinstance(vals, abc.Iterable) or isinstance(vals, str):
|
||||||
|
vals = [vals]
|
||||||
|
|
||||||
|
# If is an iterable
|
||||||
|
if isinstance(vals, abc.Iterable):
|
||||||
|
return [choiceFromValue(v) for v in vals]
|
||||||
|
|
||||||
|
# This should never happen
|
||||||
|
raise RuntimeError('Invalid type for convertToChoices: {}'.format(type(vals)))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def convertToList(
|
||||||
|
vals: typing.Union[str, int, typing.Iterable]
|
||||||
|
) -> typing.List[str]:
|
||||||
|
if vals:
|
||||||
|
if isinstance(vals, (str, int)):
|
||||||
|
return [str(vals)]
|
||||||
|
return [str(v) for v in vals]
|
||||||
|
return []
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def choiceImage(
|
def choiceImage(
|
||||||
id_: typing.Union[str, int], text: str, img: str
|
id_: typing.Union[str, int], text: str, img: str
|
||||||
@ -211,7 +238,7 @@ class gui:
|
|||||||
return {'id': str(id_), 'text': str(text), 'img': img}
|
return {'id': str(id_), 'text': str(text), 'img': img}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def sortedChoices(choices):
|
def sortedChoices(choices: typing.Iterable):
|
||||||
return sorted(choices, key=lambda item: item['text'].lower())
|
return sorted(choices, key=lambda item: item['text'].lower())
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -287,6 +314,7 @@ class gui:
|
|||||||
so if you use both, the used one will be "value". This is valid for
|
so if you use both, the used one will be "value". This is valid for
|
||||||
all form fields.
|
all form fields.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class Types(enum.Enum):
|
class Types(enum.Enum):
|
||||||
TEXT = 'text'
|
TEXT = 'text'
|
||||||
TEXT_AUTOCOMPLETE = 'text-autocomplete'
|
TEXT_AUTOCOMPLETE = 'text-autocomplete'
|
||||||
@ -312,7 +340,9 @@ class gui:
|
|||||||
|
|
||||||
def __init__(self, **options) -> None:
|
def __init__(self, **options) -> None:
|
||||||
# Added defaultValue as alias for defvalue
|
# Added defaultValue as alias for defvalue
|
||||||
defvalue = options.get('defvalue', options.get('defaultValue', options.get('defValue', '')))
|
defvalue = options.get(
|
||||||
|
'defvalue', options.get('defaultValue', options.get('defValue', ''))
|
||||||
|
)
|
||||||
if callable(defvalue):
|
if callable(defvalue):
|
||||||
defvalue = defvalue()
|
defvalue = defvalue()
|
||||||
self._data = {
|
self._data = {
|
||||||
@ -604,9 +634,7 @@ class gui:
|
|||||||
datetime.date: the date that this object holds, or "min" | "max" on error
|
datetime.date: the date that this object holds, or "min" | "max" on error
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return datetime.datetime.strptime(
|
return datetime.datetime.strptime(self.value, '%Y-%m-%d') # ISO Format
|
||||||
self.value, '%Y-%m-%d'
|
|
||||||
) # ISO Format
|
|
||||||
except Exception:
|
except Exception:
|
||||||
return datetime.datetime.min if min else datetime.datetime.max
|
return datetime.datetime.min if min else datetime.datetime.max
|
||||||
|
|
||||||
@ -827,10 +855,7 @@ class gui:
|
|||||||
|
|
||||||
def __init__(self, **options):
|
def __init__(self, **options):
|
||||||
super().__init__(**options)
|
super().__init__(**options)
|
||||||
vals = options.get('values')
|
self._data['values'] = gui.convertToChoices(options.get('values'))
|
||||||
if vals and isinstance(vals, (dict, list, tuple)):
|
|
||||||
options['values'] = gui.convertToChoices(options['values'])
|
|
||||||
self._data['values'] = options.get('values', [])
|
|
||||||
if 'fills' in options:
|
if 'fills' in options:
|
||||||
# Save fnc to register as callback
|
# Save fnc to register as callback
|
||||||
fills = options['fills']
|
fills = options['fills']
|
||||||
@ -840,7 +865,7 @@ class gui:
|
|||||||
gui.callbacks[fills['callbackName']] = fnc
|
gui.callbacks[fills['callbackName']] = fnc
|
||||||
self._type(gui.InputField.Types.CHOICE)
|
self._type(gui.InputField.Types.CHOICE)
|
||||||
|
|
||||||
def setValues(self, values: typing.List[typing.Dict[str, typing.Any]]):
|
def setValues(self, values: typing.List['gui.ChoiceType']):
|
||||||
"""
|
"""
|
||||||
Set the values for this choice field
|
Set the values for this choice field
|
||||||
"""
|
"""
|
||||||
@ -1177,15 +1202,13 @@ class UserInterface(metaclass=UserInterfaceType):
|
|||||||
if k in self._gui:
|
if k in self._gui:
|
||||||
try:
|
try:
|
||||||
if v.startswith(MULTIVALUE_FIELD):
|
if v.startswith(MULTIVALUE_FIELD):
|
||||||
val = pickle.loads(v[1:]) # nosec: secure pickled by us for sure
|
val = pickle.loads( # nosec: safe pickle, controlled
|
||||||
|
v[1:]
|
||||||
|
) # nosec: secure pickled by us for sure
|
||||||
elif v.startswith(OLD_PASSWORD_FIELD):
|
elif v.startswith(OLD_PASSWORD_FIELD):
|
||||||
val = cryptoManager().AESDecrypt(v[1:], UDSB, True).decode()
|
val = cryptoManager().AESDecrypt(v[1:], UDSB, True).decode()
|
||||||
elif v.startswith(PASSWORD_FIELD):
|
elif v.startswith(PASSWORD_FIELD):
|
||||||
val = (
|
val = cryptoManager().AESDecrypt(v[1:], UDSK, True).decode()
|
||||||
cryptoManager()
|
|
||||||
.AESDecrypt(v[1:], UDSK, True)
|
|
||||||
.decode()
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
val = v
|
val = v
|
||||||
# Ensure "legacy bytes" values are loaded correctly as unicode
|
# Ensure "legacy bytes" values are loaded correctly as unicode
|
||||||
|
Loading…
Reference in New Issue
Block a user