mirror of
https://github.com/dkmstr/openuds.git
synced 2024-12-23 17:34:17 +03:00
Refactoring UDS Exceptions
This commit is contained in:
parent
4385fdf358
commit
da823d2e6c
30
server/src/tests/REST/service_pools/__init__.py
Normal file
30
server/src/tests/REST/service_pools/__init__.py
Normal file
@ -0,0 +1,30 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2023 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.U. 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
|
||||
"""
|
73
server/src/tests/REST/service_pools/test_service_pools.py
Normal file
73
server/src/tests/REST/service_pools/test_service_pools.py
Normal file
@ -0,0 +1,73 @@
|
||||
# -*- 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.U. 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
|
||||
"""
|
||||
import typing
|
||||
import logging
|
||||
|
||||
from uds.REST.handlers import AUTH_TOKEN_HEADER
|
||||
from uds.REST.methods.actor_v3 import MANAGED, UNMANAGED, ALLOWED_FAILS
|
||||
from uds import models
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
from ...utils import rest
|
||||
from ...fixtures import rest as rest_fixtures
|
||||
|
||||
class ServicePoolTest(rest.test.RESTTestCase):
|
||||
def setUp(self) -> None:
|
||||
# Override number of items to create
|
||||
super().setUp()
|
||||
self.login()
|
||||
|
||||
def test_invalid_servicepool(self) -> None:
|
||||
url = f'servicespools/INVALID/overview'
|
||||
|
||||
response = self.client.rest_get(url)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
def test_service_pools(self) -> None:
|
||||
url = f'servicespools/overview'
|
||||
|
||||
# Now, will work
|
||||
response = self.client.rest_get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
# Get the list of service pools from DB
|
||||
db_pools_len = models.ServicePool.objects.all().count()
|
||||
re_pools: typing.List[typing.Dict[str, typing.Any]] = response.json()
|
||||
|
||||
self.assertIsInstance(re_pools, list)
|
||||
self.assertEqual(db_pools_len, len(re_pools))
|
||||
|
||||
for service_pool in re_pools:
|
||||
# Get from DB the service pool
|
||||
db_pool = models.ServicePool.objects.get(uuid=service_pool['id'])
|
||||
self.assertTrue(rest.assertions.assertServicePoolIs(db_pool, service_pool))
|
||||
|
38
server/src/tests/fixtures/rest.py
vendored
38
server/src/tests/fixtures/rest.py
vendored
@ -32,6 +32,7 @@ import typing
|
||||
|
||||
from ..utils import rest
|
||||
|
||||
|
||||
# User REST structure
|
||||
class UserRestStruct(rest.RestStruct):
|
||||
id: rest.uuid_type
|
||||
@ -45,6 +46,7 @@ class UserRestStruct(rest.RestStruct):
|
||||
mfa_data: typing.Optional[str]
|
||||
password: typing.Optional[str]
|
||||
|
||||
|
||||
# Group REST structure
|
||||
class GroupRestStruct(rest.RestStruct):
|
||||
id: rest.uuid_type
|
||||
@ -55,9 +57,45 @@ class GroupRestStruct(rest.RestStruct):
|
||||
is_meta: bool
|
||||
meta_if_any: bool
|
||||
|
||||
|
||||
# ServicePool REST structure
|
||||
class ServicePoolRestStruct(rest.RestStruct):
|
||||
id: rest.uuid_type
|
||||
name: str
|
||||
short_name: str
|
||||
tags: typing.List[str]
|
||||
parent: str
|
||||
parent_type: str
|
||||
comments: str
|
||||
state: str
|
||||
thumb: str
|
||||
account: str
|
||||
account_id: rest.uuid_type
|
||||
service_id: rest.uuid_type
|
||||
provider_id: rest.uuid_type
|
||||
image_id: rest.uuid_type
|
||||
initial_srvs: int
|
||||
cache_l1_srvs: int
|
||||
cache_l2_srvs: int
|
||||
max_srvs: int
|
||||
show_transports: bool
|
||||
visible: bool
|
||||
allow_users_remove: bool
|
||||
allow_users_reset: bool
|
||||
ignores_unused: bool
|
||||
fallbackAccess: str
|
||||
meta_member: typing.List[typing.Dict[str, rest.uuid_type]]
|
||||
calendar_message: str
|
||||
|
||||
|
||||
# Provide a "random" dictionary based on a
|
||||
def createUser(**kwargs) -> typing.Dict[str, typing.Any]:
|
||||
return UserRestStruct.random_create(**kwargs).as_dict()
|
||||
|
||||
|
||||
def createGroup(**kwargs) -> typing.Dict[str, typing.Any]:
|
||||
return GroupRestStruct.random_create(**kwargs).as_dict()
|
||||
|
||||
|
||||
def createServicePool(**kwargs) -> typing.Dict[str, typing.Any]:
|
||||
return ServicePoolRestStruct.random_create(**kwargs).as_dict()
|
||||
|
9
server/src/tests/fixtures/services.py
vendored
9
server/src/tests/fixtures/services.py
vendored
@ -64,7 +64,9 @@ def createProvider() -> models.Provider:
|
||||
return provider
|
||||
|
||||
|
||||
def createService(provider: models.Provider) -> models.Service:
|
||||
def createService(
|
||||
provider: models.Provider, useCachingVersion: bool = True
|
||||
) -> models.Service:
|
||||
from uds.services.Test.service import TestServiceCache, TestServiceNoCache
|
||||
|
||||
service = provider.services.create(
|
||||
@ -72,6 +74,10 @@ def createService(provider: models.Provider) -> models.Service:
|
||||
data_type=TestServiceCache.typeType,
|
||||
data=TestServiceCache(
|
||||
environment.Environment(str(glob['service_id'])), provider.getInstance()
|
||||
).serialize()
|
||||
if useCachingVersion
|
||||
else TestServiceNoCache(
|
||||
environment.Environment(str(glob['service_id'])), provider.getInstance()
|
||||
).serialize(),
|
||||
token=generators.random_string(16) + str(glob['service_id']),
|
||||
)
|
||||
@ -231,7 +237,6 @@ def createOneCacheTestingUserService(
|
||||
groups: typing.List['models.Group'],
|
||||
type_: typing.Union[typing.Literal['managed'], typing.Literal['unmanaged']],
|
||||
) -> 'models.UserService':
|
||||
|
||||
from uds.services.Test.service import TestServiceCache, TestServiceNoCache
|
||||
from uds.osmanagers.Test import TestOSManager
|
||||
from uds.transports.Test import TestTransport
|
||||
|
@ -40,8 +40,12 @@ from .. import ensure_data
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def assertUserIs(
|
||||
user: models.User, compare_to: typing.Mapping[str, typing.Any], compare_uuid=False, compare_password=False
|
||||
user: models.User,
|
||||
compare_to: typing.Mapping[str, typing.Any],
|
||||
compare_uuid=False,
|
||||
compare_password=False,
|
||||
) -> bool:
|
||||
ignore_fields = ['password', 'groups', 'mfa_data', 'last_access', 'role']
|
||||
|
||||
@ -51,7 +55,11 @@ def assertUserIs(
|
||||
# If last_access is present, compare it here, because it's a datetime object
|
||||
if 'last_access' in compare_to:
|
||||
if int(user.last_access.timestamp()) != compare_to['last_access']:
|
||||
logger.info('User last_access do not match: %s != %s', user.last_access.timestamp(), compare_to['last_access'])
|
||||
logger.info(
|
||||
'User last_access do not match: %s != %s',
|
||||
user.last_access.timestamp(),
|
||||
compare_to['last_access'],
|
||||
)
|
||||
return False
|
||||
|
||||
if ensure_data(user, compare_to, ignore_keys=ignore_fields):
|
||||
@ -61,25 +69,36 @@ def assertUserIs(
|
||||
compare_to_groups = set(compare_to['groups'])
|
||||
# Ensure groups are PART compare_to_groups
|
||||
if groups - compare_to_groups != set():
|
||||
logger.info('User groups do not match: %s != %s', groups, compare_to_groups)
|
||||
logger.info(
|
||||
'User groups do not match: %s != %s', groups, compare_to_groups
|
||||
)
|
||||
return False
|
||||
|
||||
# Compare mfa_data
|
||||
if 'mfa_data' in compare_to:
|
||||
if user.mfa_data != compare_to['mfa_data']:
|
||||
logger.info('User mfa_data do not match: %s != %s', user.mfa_data, compare_to['mfa_data'])
|
||||
logger.info(
|
||||
'User mfa_data do not match: %s != %s',
|
||||
user.mfa_data,
|
||||
compare_to['mfa_data'],
|
||||
)
|
||||
return False
|
||||
|
||||
|
||||
# Compare password
|
||||
if compare_password:
|
||||
if not cryptoManager().checkHash(compare_to['password'], user.password):
|
||||
logger.info('User password do not match: %s != %s', user.password, compare_to['password'])
|
||||
logger.info(
|
||||
'User password do not match: %s != %s',
|
||||
user.password,
|
||||
compare_to['password'],
|
||||
)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def assertGroupIs(
|
||||
group: models.Group, compare_to: typing.Mapping[str, typing.Any], compare_uuid=False
|
||||
) -> bool:
|
||||
@ -89,26 +108,68 @@ def assertGroupIs(
|
||||
ignore_fields.append('id')
|
||||
|
||||
if ensure_data(group, compare_to, ignore_keys=ignore_fields):
|
||||
|
||||
if group.is_meta:
|
||||
grps = set(i.uuid for i in group.groups.all())
|
||||
compare_to_groups = set(compare_to['groups'])
|
||||
if grps != compare_to_groups:
|
||||
logger.info('Group groups do not match: %s != %s', grps, compare_to_groups)
|
||||
logger.info(
|
||||
'Group groups do not match: %s != %s', grps, compare_to_groups
|
||||
)
|
||||
return False
|
||||
|
||||
if 'type' in compare_to:
|
||||
if group.is_meta != (compare_to['type'] == 'meta'):
|
||||
logger.info('Group type do not match: %s != %s', group.is_meta, compare_to['type'])
|
||||
logger.info(
|
||||
'Group type do not match: %s != %s',
|
||||
group.is_meta,
|
||||
compare_to['type'],
|
||||
)
|
||||
return False
|
||||
|
||||
|
||||
if 'pools' in compare_to:
|
||||
pools = set(i.uuid for i in group.deployedServices.all())
|
||||
compare_to_pools = set(compare_to['pools'])
|
||||
if pools != compare_to_pools:
|
||||
logger.info('Group pools do not match: %s != %s', pools, compare_to_pools)
|
||||
logger.info(
|
||||
'Group pools do not match: %s != %s', pools, compare_to_pools
|
||||
)
|
||||
return False
|
||||
|
||||
|
||||
return True
|
||||
|
||||
return False
|
||||
return False
|
||||
|
||||
|
||||
def assertServicePoolIs(
|
||||
pool: models.ServicePool,
|
||||
compare_to: typing.Mapping[str, typing.Any],
|
||||
compare_uuid=False,
|
||||
) -> bool:
|
||||
ignore_fields = [
|
||||
'tags',
|
||||
'parent',
|
||||
'parent_type',
|
||||
'thumb',
|
||||
'account',
|
||||
'service_id',
|
||||
'provider_id',
|
||||
'meta_member',
|
||||
'user_services_count',
|
||||
'user_services_in_preparation',
|
||||
'restrained',
|
||||
'permission',
|
||||
'info',
|
||||
'pool_group_id',
|
||||
'pool_group_name',
|
||||
'pool_group_thumb',
|
||||
'usage',
|
||||
'osmanager_id',
|
||||
]
|
||||
|
||||
if not compare_uuid:
|
||||
ignore_fields.append('id')
|
||||
|
||||
if ensure_data(pool, compare_to, ignore_keys=ignore_fields):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
@ -35,14 +35,14 @@ import typing
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Convenience imports, must be present before initializing handlers
|
||||
from .handlers import (
|
||||
from .exceptions import (
|
||||
AccessDenied,
|
||||
Handler,
|
||||
HandlerError,
|
||||
NotFound,
|
||||
NotSupportedError,
|
||||
RequestError,
|
||||
ResponseError,
|
||||
)
|
||||
from .handlers import Handler
|
||||
|
||||
from .dispatcher import Dispatcher, AUTH_TOKEN_HEADER
|
||||
|
@ -32,6 +32,7 @@
|
||||
import logging
|
||||
import sys
|
||||
import typing
|
||||
import traceback
|
||||
|
||||
from django import http
|
||||
from django.utils.decorators import method_decorator
|
||||
@ -43,15 +44,15 @@ from uds.core import VERSION, VERSION_STAMP
|
||||
from uds.core.util import modfinder
|
||||
|
||||
from . import processors, log
|
||||
from .handlers import (
|
||||
from .exceptions import (
|
||||
AccessDenied,
|
||||
Handler,
|
||||
HandlerError,
|
||||
NotFound,
|
||||
NotSupportedError,
|
||||
RequestError,
|
||||
ResponseError,
|
||||
)
|
||||
from .handlers import Handler
|
||||
|
||||
# Not imported at runtime, just for type checking
|
||||
if typing.TYPE_CHECKING:
|
||||
@ -203,7 +204,12 @@ class Dispatcher(View):
|
||||
return http.HttpResponseBadRequest(str(e), content_type="text/plain")
|
||||
except Exception as e:
|
||||
log.log_operation(handler, 500, log.ERROR)
|
||||
logger.exception('Error processing request')
|
||||
# Get ecxeption backtrace
|
||||
trace_back = traceback.format_exc()
|
||||
logger.error('Exception processing request: %s', full_path)
|
||||
for i in trace_back.splitlines():
|
||||
logger.error(f'* {i}')
|
||||
|
||||
return http.HttpResponseServerError(str(e), content_type="text/plain")
|
||||
|
||||
@staticmethod
|
||||
|
68
server/src/uds/REST/exceptions.py
Normal file
68
server/src/uds/REST/exceptions.py
Normal file
@ -0,0 +1,68 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2012-2021 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.U. 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
|
||||
"""
|
||||
from uds.core.exceptions import UDSException
|
||||
|
||||
class HandlerError(UDSException):
|
||||
"""
|
||||
Generic error for a REST handler
|
||||
"""
|
||||
|
||||
|
||||
class NotFound(HandlerError):
|
||||
"""
|
||||
Item not found error
|
||||
"""
|
||||
|
||||
|
||||
class AccessDenied(HandlerError):
|
||||
"""
|
||||
Access denied error
|
||||
"""
|
||||
|
||||
|
||||
class RequestError(HandlerError):
|
||||
"""
|
||||
Request is invalid error
|
||||
"""
|
||||
|
||||
|
||||
class ResponseError(HandlerError):
|
||||
"""
|
||||
Generic response error
|
||||
"""
|
||||
|
||||
|
||||
class NotSupportedError(HandlerError):
|
||||
"""
|
||||
Some elements do not support some operations (as searching over an authenticator that does not supports it)
|
||||
"""
|
||||
|
@ -42,7 +42,7 @@ from uds.core.util import net
|
||||
from uds.models import Authenticator, User
|
||||
from uds.core.managers import cryptoManager
|
||||
|
||||
from . import log
|
||||
from .exceptions import AccessDenied
|
||||
|
||||
|
||||
# Not imported at runtime, just for type checking
|
||||
@ -54,42 +54,6 @@ logger = logging.getLogger(__name__)
|
||||
AUTH_TOKEN_HEADER: typing.Final[str] = 'HTTP_X_AUTH_TOKEN' # nosec: this is not a password
|
||||
|
||||
|
||||
class HandlerError(Exception):
|
||||
"""
|
||||
Generic error for a REST handler
|
||||
"""
|
||||
|
||||
|
||||
class NotFound(HandlerError):
|
||||
"""
|
||||
Item not found error
|
||||
"""
|
||||
|
||||
|
||||
class AccessDenied(HandlerError):
|
||||
"""
|
||||
Access denied error
|
||||
"""
|
||||
|
||||
|
||||
class RequestError(HandlerError):
|
||||
"""
|
||||
Request is invalid error
|
||||
"""
|
||||
|
||||
|
||||
class ResponseError(HandlerError):
|
||||
"""
|
||||
Generic response error
|
||||
"""
|
||||
|
||||
|
||||
class NotSupportedError(HandlerError):
|
||||
"""
|
||||
Some elements do not support some operations (as searching over an authenticator that does not supports it)
|
||||
"""
|
||||
|
||||
|
||||
class Handler:
|
||||
"""
|
||||
REST requests handler base class
|
||||
|
@ -68,7 +68,7 @@ def replacePath(path: str) -> str:
|
||||
uuid = path.split(f'/{type}/')[1].split('/')[0]
|
||||
name = model.objects.get(uuid=uuid).name # type: ignore
|
||||
path = path.replace(uuid, f'[{name}]')
|
||||
except Exception:
|
||||
except Exception: # nosec: intentionally broad exception
|
||||
pass
|
||||
|
||||
return path
|
||||
|
@ -36,7 +36,7 @@ import typing
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from uds.models import ActorToken
|
||||
from uds.REST.handlers import RequestError, NotFound
|
||||
from uds.REST.exceptions import RequestError, NotFound
|
||||
from uds.REST.model import ModelHandler, OK
|
||||
from uds.core.util import permissions
|
||||
|
||||
|
@ -52,7 +52,8 @@ from uds.core.util.cache import Cache
|
||||
from uds.core.util.config import GlobalConfig
|
||||
from uds.models.service import ServiceTokenAlias
|
||||
|
||||
from ..handlers import Handler, AccessDenied, RequestError
|
||||
from ..handlers import Handler
|
||||
from ..exceptions import AccessDenied, RequestError
|
||||
|
||||
# Not imported at runtime, just for type checking
|
||||
if typing.TYPE_CHECKING:
|
||||
|
@ -38,7 +38,7 @@ from django.utils.translation import gettext as _
|
||||
|
||||
from uds import models
|
||||
|
||||
from uds.core import services
|
||||
from uds.core import exceptions
|
||||
from uds.core.util import log
|
||||
from uds.core.util import permissions
|
||||
from uds.core.util.model import processUuid
|
||||
@ -194,7 +194,7 @@ class Services(DetailHandler): # pylint: disable=too-many-public-methods
|
||||
)
|
||||
)
|
||||
raise RequestError(_('Element already exists (duplicate key error)'))
|
||||
except Module.ValidationException as e:
|
||||
except exceptions.ValidationException as e:
|
||||
if (
|
||||
not item and service
|
||||
): # Only remove partially saved element if creating new (if editing, ignore this)
|
||||
|
@ -145,7 +145,7 @@ class System(Handler):
|
||||
help_text = 'Provides system information. Must be admin to access this'
|
||||
|
||||
|
||||
def get(self):
|
||||
def get(self) -> typing.Any:
|
||||
logger.debug('args: %s', self._args)
|
||||
# Only allow admin user for global stats
|
||||
if len(self._args) == 1:
|
||||
|
@ -36,7 +36,7 @@ import typing
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from uds.models import TunnelToken
|
||||
from uds.REST.handlers import RequestError, NotFound
|
||||
from uds.REST.exceptions import RequestError, NotFound
|
||||
from uds.REST.model import ModelHandler, OK
|
||||
from uds.core.util import permissions
|
||||
|
||||
|
@ -45,12 +45,11 @@ from uds.core.ui import gui as uiGui
|
||||
from uds.core.util import log
|
||||
from uds.core.util import permissions
|
||||
from uds.core.util.model import processUuid
|
||||
from uds.core import Module
|
||||
from uds.core import Module, exceptions
|
||||
|
||||
from uds.models import Tag, TaggingMixin, ManagedObjectModel, Network
|
||||
|
||||
from .handlers import (
|
||||
Handler,
|
||||
from .exceptions import (
|
||||
HandlerError,
|
||||
NotFound,
|
||||
RequestError,
|
||||
@ -59,6 +58,8 @@ from .handlers import (
|
||||
NotSupportedError,
|
||||
)
|
||||
|
||||
from .handlers import Handler
|
||||
|
||||
# Not imported at runtime, just for type checking
|
||||
if typing.TYPE_CHECKING:
|
||||
from uds.models import User
|
||||
@ -898,10 +899,13 @@ class ModelHandler(BaseModelHandler):
|
||||
method = getattr(detail, self._operation)
|
||||
|
||||
return method()
|
||||
except KeyError:
|
||||
raise self.invalidMethodException()
|
||||
except AttributeError:
|
||||
except IndexError:
|
||||
raise self.invalidItemException()
|
||||
except (KeyError, AttributeError):
|
||||
raise self.invalidMethodException()
|
||||
except Exception as e:
|
||||
logger.error('Exception processing detail: %s', e)
|
||||
raise self.invalidRequestException()
|
||||
|
||||
def getItems(
|
||||
self, *args, **kwargs
|
||||
@ -940,7 +944,7 @@ class ModelHandler(BaseModelHandler):
|
||||
is False
|
||||
):
|
||||
continue
|
||||
if kwargs.get('overview', True):
|
||||
if overview:
|
||||
yield self.item_as_dict_overview(item)
|
||||
else:
|
||||
res = self.item_as_dict(item)
|
||||
@ -1155,7 +1159,7 @@ class ModelHandler(BaseModelHandler):
|
||||
raise NotFound('Item not found')
|
||||
except IntegrityError: # Duplicate key probably
|
||||
raise RequestError('Element already exists (duplicate key error)')
|
||||
except (SaveException, Module.ValidationException) as e:
|
||||
except (SaveException, exceptions.ValidationException) as e:
|
||||
raise RequestError(str(e))
|
||||
except (RequestError, ResponseError):
|
||||
raise
|
||||
|
@ -39,7 +39,7 @@ import ldap
|
||||
|
||||
from django.utils.translation import gettext_noop as _
|
||||
|
||||
from uds.core import auths
|
||||
from uds.core import auths, exceptions
|
||||
from uds.core.ui import gui
|
||||
from uds.core.util import ldaputil
|
||||
from uds.core.auths.auth import authLogLogin
|
||||
@ -250,7 +250,7 @@ class RegexLdap(auths.Authenticator):
|
||||
try:
|
||||
re.search(pattern, '')
|
||||
except Exception:
|
||||
raise auths.Authenticator.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
'Invalid pattern in {0}: {1}'.format(fieldLabel, line)
|
||||
)
|
||||
|
||||
|
@ -47,7 +47,7 @@ from django.utils.translation import gettext_noop as _, gettext
|
||||
|
||||
from uds.models import getSqlDatetime
|
||||
from uds.core.ui import gui
|
||||
from uds.core import auths
|
||||
from uds.core import auths, exceptions
|
||||
from uds.core.managers import cryptoManager
|
||||
from uds.core.util.decorators import allowCache
|
||||
|
||||
@ -324,7 +324,7 @@ class SAMLAuthenticator(auths.Authenticator):
|
||||
return
|
||||
|
||||
if ' ' in values['name']:
|
||||
raise auths.Authenticator.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
gettext(
|
||||
'This kind of Authenticator does not support white spaces on field NAME'
|
||||
)
|
||||
@ -338,7 +338,7 @@ class SAMLAuthenticator(auths.Authenticator):
|
||||
self.serverCertificate.value.startswith('-----BEGIN CERTIFICATE-----\n')
|
||||
is False
|
||||
):
|
||||
raise auths.Authenticator.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
gettext(
|
||||
'Server certificate should be a valid PEM (PEM certificates starts with -----BEGIN CERTIFICATE-----)'
|
||||
)
|
||||
@ -347,7 +347,7 @@ class SAMLAuthenticator(auths.Authenticator):
|
||||
try:
|
||||
cryptoManager().loadCertificate(self.serverCertificate.value)
|
||||
except Exception as e:
|
||||
raise auths.Authenticator.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
gettext('Invalid server certificate. ') + str(e)
|
||||
)
|
||||
|
||||
@ -357,7 +357,7 @@ class SAMLAuthenticator(auths.Authenticator):
|
||||
and self.privateKey.value.startswith('-----BEGIN PRIVATE KEY-----\n')
|
||||
is False
|
||||
):
|
||||
raise auths.Authenticator.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
gettext(
|
||||
'Private key should be a valid PEM (PEM private keys starts with -----BEGIN RSA PRIVATE KEY-----'
|
||||
)
|
||||
@ -366,7 +366,7 @@ class SAMLAuthenticator(auths.Authenticator):
|
||||
try:
|
||||
pk = cryptoManager().loadPrivateKey(self.privateKey.value)
|
||||
except Exception as e:
|
||||
raise auths.Authenticator.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
gettext('Invalid private key. ') + str(e)
|
||||
)
|
||||
|
||||
@ -385,7 +385,7 @@ class SAMLAuthenticator(auths.Authenticator):
|
||||
resp = requests.get(idpMetadata.split('\n')[0], verify=self.checkSSLCertificate.isTrue())
|
||||
idpMetadata = resp.content.decode()
|
||||
except Exception as e:
|
||||
raise auths.Authenticator.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
gettext('Can\'t fetch url {0}: {1}').format(
|
||||
self.idpMetadata.value, str(e)
|
||||
)
|
||||
@ -398,7 +398,7 @@ class SAMLAuthenticator(auths.Authenticator):
|
||||
xml.sax.parseString(idpMetadata, xml.sax.ContentHandler()) # type: ignore # nosec: url provided by admin
|
||||
except Exception as e:
|
||||
msg = (gettext(' (obtained from URL)') if fromUrl else '') + str(e)
|
||||
raise auths.Authenticator.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
gettext('XML does not seem valid for IDP Metadata ') + msg
|
||||
)
|
||||
|
||||
@ -531,7 +531,7 @@ class SAMLAuthenticator(auths.Authenticator):
|
||||
try:
|
||||
re.search(pattern, '')
|
||||
except:
|
||||
raise auths.Authenticator.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
'Invalid pattern at {0}: {1}'.format(field.label, line)
|
||||
)
|
||||
|
||||
|
@ -36,7 +36,7 @@ import typing
|
||||
from django.utils.translation import gettext_noop as _
|
||||
from uds.core.auths.authenticator import AuthenticationResult, AuthenticationSuccess
|
||||
from uds.core.ui import gui
|
||||
from uds.core import auths
|
||||
from uds.core import auths, exceptions
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from django.http import (
|
||||
@ -131,7 +131,7 @@ class SampleAuth(auths.Authenticator):
|
||||
# unserialization, and at this point all will be default values
|
||||
# so self.groups.value will be []
|
||||
if values and len(self.groups.value) < 2:
|
||||
raise auths.Authenticator.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
_('We need more than two groups!')
|
||||
)
|
||||
|
||||
|
47
server/src/uds/core/exceptions.py
Normal file
47
server/src/uds/core/exceptions.py
Normal file
@ -0,0 +1,47 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2023 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.U. 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
|
||||
"""
|
||||
|
||||
import typing
|
||||
|
||||
class UDSException(Exception):
|
||||
"""
|
||||
Base class for all UDS exceptions
|
||||
"""
|
||||
pass
|
||||
|
||||
class ValidationException(UDSException):
|
||||
"""
|
||||
Exception used to indicate that the params assigned are invalid
|
||||
"""
|
||||
pass
|
||||
|
@ -123,11 +123,6 @@ class Module(UserInterface, Environmentable, Serializable):
|
||||
# Not defined, but declared. If module is groupable, this value will contain to which group belongs
|
||||
group: typing.ClassVar[str]
|
||||
|
||||
class ValidationException(Exception):
|
||||
"""
|
||||
Exception used to indicate that the params assigned are invalid
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def name(cls: typing.Type['Module']) -> str:
|
||||
"""
|
||||
|
@ -39,13 +39,14 @@ import typing
|
||||
import logging
|
||||
import enum
|
||||
from collections import abc
|
||||
import re
|
||||
|
||||
|
||||
from django.utils.translation import get_language, gettext as _, gettext_noop
|
||||
from django.conf import settings
|
||||
|
||||
from uds.core.managers.crypto import CryptoManager, UDSK
|
||||
from uds.core.util.decorators import deprecatedClassValue
|
||||
from uds.core.util import serializer
|
||||
from uds.core.util import serializer, validators
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -463,6 +464,12 @@ class gui:
|
||||
"""Unserialize value from an string"""
|
||||
self.value = value
|
||||
|
||||
def validate(self) -> bool:
|
||||
"""
|
||||
Validates the value of this field.
|
||||
"""
|
||||
return True
|
||||
|
||||
class TextField(InputField):
|
||||
"""
|
||||
This represents a text field.
|
||||
@ -494,16 +501,52 @@ class gui:
|
||||
tooltip = _('Other info'), rdonly = True)
|
||||
|
||||
"""
|
||||
class PatternTypes:
|
||||
IPV4 = 'ipv4'
|
||||
IPV6 = 'ipv6'
|
||||
MAC = 'mac'
|
||||
URL = 'url'
|
||||
EMAIL = 'email'
|
||||
FQDN = 'fqdn'
|
||||
HOSTNAME = 'hostname'
|
||||
HOST = 'host'
|
||||
PATH = 'path'
|
||||
NONE = ''
|
||||
|
||||
def __init__(self, **options) -> None:
|
||||
super().__init__(**options, type=gui.InputField.Types.TEXT)
|
||||
multiline = int(options.get('multiline', 0))
|
||||
if multiline > 8:
|
||||
multiline = 8
|
||||
self._data['multiline'] = multiline
|
||||
self._data['multiline'] = min(max(int(options.get('multiline', 0)), 0), 8)
|
||||
# Pattern to validate the value
|
||||
# Can contain an regex or this special values: (empty string means no validation)
|
||||
# - 'ipv4' # IPv4 address
|
||||
# - 'ipv6' # IPv6 address
|
||||
# - 'mac' # MAC address
|
||||
# - 'url' # URL
|
||||
# - 'email' # Email
|
||||
# - 'fqdn' # Fully qualified domain name
|
||||
# - 'hostname' # Hostname (without domain)
|
||||
# - 'host' # Hostname with or without domain or IP address
|
||||
# - 'path' # Path (absolute or relative, Windows or Unix)
|
||||
# Note:
|
||||
# Checks are performed on admin side, so they are not 100% reliable.
|
||||
self._data['pattern'] = options.get('pattern', gui.TextField.PatternTypes.NONE)
|
||||
|
||||
def cleanStr(self):
|
||||
return str(self.value).strip()
|
||||
|
||||
def validate(self) -> bool:
|
||||
return super().validate() and self._validatePattern()
|
||||
|
||||
def _validatePattern(self) -> bool:
|
||||
if isinstance(self._data['pattern'], gui.TextField.PatternTypes):
|
||||
pattern: gui.TextField.PatternTypes = self._data['pattern']
|
||||
if pattern == gui.TextField.PatternTypes.IPV4:
|
||||
pass
|
||||
elif isinstance(self._data['pattern'], str):
|
||||
# It's a regex
|
||||
return re.match(self._data['pattern'], self.value) is not None
|
||||
return True # No pattern, so it's valid
|
||||
|
||||
|
||||
class TextAutocompleteField(TextField):
|
||||
"""
|
||||
|
@ -41,7 +41,7 @@ from django.utils import formats
|
||||
from django.utils.translation import gettext
|
||||
import django.template.defaultfilters as filters
|
||||
|
||||
from uds.core import services
|
||||
from uds.core import exceptions
|
||||
|
||||
|
||||
class CaseInsensitiveDict(dict):
|
||||
@ -141,41 +141,6 @@ def secondsToTimeString(seconds: int) -> str:
|
||||
return gettext('{} days {:d}:{:02d}:{:02d}').format(days, hours, minutes, seconds)
|
||||
|
||||
|
||||
def checkValidBasename(baseName: str, length: int = -1) -> None:
|
||||
""" "Checks if the basename + length is valid for services. Raises an exception if not valid"
|
||||
|
||||
Arguments:
|
||||
baseName {str} -- basename to check
|
||||
|
||||
Keyword Arguments:
|
||||
length {int} -- length to check, if -1 do not checm (default: {-1})
|
||||
|
||||
Raises:
|
||||
services.Service.ValidationException: If anything goes wrong
|
||||
Returns:
|
||||
None -- [description]
|
||||
"""
|
||||
if re.match(r'^[a-zA-Z0-9][a-zA-Z0-9-]*$', baseName) is None:
|
||||
raise services.Service.ValidationException(
|
||||
gettext('The basename is not a valid for a hostname')
|
||||
)
|
||||
|
||||
if length == 0:
|
||||
raise services.Service.ValidationException(
|
||||
gettext('The length of basename plus length must be greater than 0')
|
||||
)
|
||||
|
||||
if length != -1 and len(baseName) + length > 15:
|
||||
raise services.Service.ValidationException(
|
||||
gettext('The length of basename plus length must not be greater than 15')
|
||||
)
|
||||
|
||||
if baseName.isdigit():
|
||||
raise services.Service.ValidationException(
|
||||
gettext('The machine name can\'t be only numbers')
|
||||
)
|
||||
|
||||
|
||||
def removeControlCharacters(s: str) -> str:
|
||||
"""
|
||||
Removes control characters from an unicode string
|
||||
|
@ -35,7 +35,8 @@ import logging
|
||||
import typing
|
||||
|
||||
from django.utils.translation import gettext as _
|
||||
from uds.core.module import Module
|
||||
from django.core import validators as dj_validators
|
||||
from uds.core import exceptions
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -53,7 +54,7 @@ def validateNumeric(
|
||||
:param maxValue: If not None, max value that must be the numeric or exception is thrown
|
||||
:param returnAsInteger: if True, returs value as integer (default), else returns as string
|
||||
:param fieldName: If present, the name of the field for "Raising" exceptions, defaults to "Numeric value"
|
||||
:return: Raises Module.Validation exception if is invalid, else return the value "fixed"
|
||||
:return: Raises exceptions.Validation exception if is invalid, else return the value "fixed"
|
||||
"""
|
||||
value = value.replace(' ', '')
|
||||
fieldName = fieldName or _('Numeric')
|
||||
@ -61,7 +62,7 @@ def validateNumeric(
|
||||
try:
|
||||
numeric = int(value)
|
||||
if minValue is not None and numeric < minValue:
|
||||
raise Module.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
_(
|
||||
'{0} must be greater than or equal to {1}'.format(
|
||||
fieldName, minValue
|
||||
@ -70,14 +71,14 @@ def validateNumeric(
|
||||
)
|
||||
|
||||
if maxValue is not None and numeric > maxValue:
|
||||
raise Module.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
_('{0} must be lower than or equal to {1}'.format(fieldName, maxValue))
|
||||
)
|
||||
|
||||
value = str(numeric)
|
||||
|
||||
except ValueError:
|
||||
raise Module.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
_('{0} contains invalid characters').format(fieldName)
|
||||
)
|
||||
|
||||
@ -86,7 +87,7 @@ def validateNumeric(
|
||||
|
||||
def validateHostname(hostname: str, maxLength: int, asPattern: bool) -> str:
|
||||
if len(hostname) > maxLength:
|
||||
raise Module.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
_('{} exceeds maximum host name length.').format(hostname)
|
||||
)
|
||||
|
||||
@ -99,19 +100,33 @@ def validateHostname(hostname: str, maxLength: int, asPattern: bool) -> str:
|
||||
allowed = re.compile(r'(?!-)[A-Z\d-]{1,63}(?<!-)$', re.IGNORECASE)
|
||||
|
||||
if not all(allowed.match(x) for x in hostname.split(".")):
|
||||
raise Module.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
_('{} is not a valid hostname').format(hostname)
|
||||
)
|
||||
|
||||
return hostname
|
||||
|
||||
def validateUrl(url: str, maxLength: int = 1024) -> str:
|
||||
if len(url) > maxLength:
|
||||
raise exceptions.ValidationException(
|
||||
_('{} exceeds maximum url length.').format(url)
|
||||
)
|
||||
|
||||
validator = dj_validators.URLValidator(['http', 'https'])
|
||||
try:
|
||||
validator(url)
|
||||
except Exception as e:
|
||||
raise exceptions.ValidationException(str(e))
|
||||
|
||||
return url
|
||||
|
||||
|
||||
def validatePort(portStr: str) -> int:
|
||||
"""
|
||||
Validates that a port number is valid
|
||||
:param portStr: port to validate, as string
|
||||
:param returnAsInteger: if True, returns value as integer, if not, as string
|
||||
:return: Raises Module.Validation exception if is invalid, else return the value "fixed"
|
||||
:return: Raises exceptions.Validation exception if is invalid, else return the value "fixed"
|
||||
"""
|
||||
return validateNumeric(portStr, minValue=0, maxValue=65535, fieldName='Port')
|
||||
|
||||
@ -121,13 +136,13 @@ def validateHostPortPair(hostPortPair: str) -> typing.Tuple[str, int]:
|
||||
Validates that a host:port pair is valid
|
||||
:param hostPortPair: host:port pair to validate
|
||||
:param returnAsInteger: if True, returns value as integer, if not, as string
|
||||
:return: Raises Module.Validation exception if is invalid, else return the value "fixed"
|
||||
:return: Raises exceptions.Validation exception if is invalid, else return the value "fixed"
|
||||
"""
|
||||
try:
|
||||
host, port = hostPortPair.split(':')
|
||||
return validateHostname(host, 255, False), validatePort(port)
|
||||
except Exception:
|
||||
raise Module.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
_('{} is not a valid host:port pair').format(hostPortPair)
|
||||
)
|
||||
|
||||
@ -137,54 +152,91 @@ def validateTimeout(timeOutStr: str) -> int:
|
||||
Validates that a timeout value is valid
|
||||
:param timeOutStr: timeout to validate
|
||||
:param returnAsInteger: if True, returns value as integer, if not, as string
|
||||
:return: Raises Module.Validation exception if is invalid, else return the value "fixed"
|
||||
:return: Raises exceptions.Validation exception if is invalid, else return the value "fixed"
|
||||
"""
|
||||
return validateNumeric(timeOutStr, minValue=0, fieldName='Timeout')
|
||||
|
||||
|
||||
def validateMacRange(macRange: str) -> str:
|
||||
def validateMac(mac: str) -> str:
|
||||
"""
|
||||
Corrects mac range (uppercase, without spaces), and checks that is range is valid
|
||||
:param macRange: Range to fix
|
||||
:return: Raises Module.Validation exception if is invalid, else return the value "fixed"
|
||||
Validates that a mac address is valid
|
||||
:param mac: mac address to validate
|
||||
:return: Raises exceptions.Validation exception if is invalid, else return the value "fixed"
|
||||
"""
|
||||
# Removes white spaces and all to uppercase
|
||||
macRange = macRange.upper().replace(' ', '')
|
||||
mac = mac.upper().replace(' ', '')
|
||||
|
||||
macRE = re.compile(
|
||||
r'^([0-9A-F]{2}[:]){5}([0-9A-F]{2})$'
|
||||
) # In fact, it could be XX-XX-XX-XX-XX-XX, but we use - as range separator
|
||||
|
||||
if macRE.match(mac) is None:
|
||||
raise exceptions.ValidationException(_('{} is not a valid MAC address').format(mac))
|
||||
|
||||
return mac
|
||||
|
||||
def validateMacRange(macRange: str) -> str:
|
||||
"""
|
||||
Corrects mac range (uppercase, without spaces), and checks that is range is valid
|
||||
:param macRange: Range to fix
|
||||
:return: Raises exceptions.Validation exception if is invalid, else return the value "fixed"
|
||||
"""
|
||||
try:
|
||||
macRangeStart, macRangeEnd = macRange.split('-')
|
||||
|
||||
if macRE.match(macRangeStart) is None or macRE.match(macRangeEnd) is None:
|
||||
raise Exception()
|
||||
if macRangeStart > macRangeEnd:
|
||||
raise Exception()
|
||||
validateMac(macRangeStart)
|
||||
validateMac(macRangeEnd)
|
||||
except Exception:
|
||||
raise Module.ValidationException(
|
||||
_(
|
||||
'Invalid mac range. Mac range must be in format XX:XX:XX:XX:XX:XX-XX:XX:XX:XX:XX:XX'
|
||||
)
|
||||
raise exceptions.ValidationException(
|
||||
_('{} is not a valid MAC range').format(macRange)
|
||||
)
|
||||
|
||||
return macRange
|
||||
|
||||
|
||||
def validateEmail(email: str) -> str:
|
||||
"""
|
||||
Validates that an email is valid
|
||||
:param email: email to validate
|
||||
:return: Raises Module.Validation exception if is invalid, else return the value "fixed"
|
||||
:return: Raises exceptions.Validation exception if is invalid, else return the value "fixed"
|
||||
"""
|
||||
if len(email) > 254:
|
||||
raise Module.ValidationException(
|
||||
_('Email address is too long')
|
||||
)
|
||||
raise exceptions.ValidationException(_('Email address is too long'))
|
||||
|
||||
if not re.match(r"[^@]+@[^@]+\.[^@]+", email):
|
||||
raise Module.ValidationException(
|
||||
_('Email address is not valid')
|
||||
)
|
||||
raise exceptions.ValidationException(_('Email address is not valid'))
|
||||
|
||||
return email
|
||||
|
||||
def validateBasename(baseName: str, length: int = -1) -> None:
|
||||
""" "Checks if the basename + length is valid for services. Raises an exception if not valid"
|
||||
|
||||
Arguments:
|
||||
baseName {str} -- basename to check
|
||||
|
||||
Keyword Arguments:
|
||||
length {int} -- length to check, if -1 do not checm (default: {-1})
|
||||
|
||||
Raises:
|
||||
exceptions.ValidationException: If anything goes wrong
|
||||
Returns:
|
||||
None -- [description]
|
||||
"""
|
||||
if re.match(r'^[a-zA-Z0-9][a-zA-Z0-9-]*$', baseName) is None:
|
||||
raise exceptions.ValidationException(
|
||||
_('The basename is not a valid for a hostname')
|
||||
)
|
||||
|
||||
if length == 0:
|
||||
raise exceptions.ValidationException(
|
||||
_('The length of basename plus length must be greater than 0')
|
||||
)
|
||||
|
||||
if length != -1 and len(baseName) + length > 15:
|
||||
raise exceptions.ValidationException(
|
||||
_('The length of basename plus length must not be greater than 15')
|
||||
)
|
||||
|
||||
if baseName.isdigit():
|
||||
raise exceptions.ValidationException(
|
||||
_('The machine name can\'t be only numbers')
|
||||
)
|
||||
|
@ -40,7 +40,7 @@ import logging
|
||||
from django.utils.translation import gettext_noop as _, gettext
|
||||
|
||||
from uds import models
|
||||
from uds.core import mfas
|
||||
from uds.core import mfas, exceptions
|
||||
from uds.core.ui import gui
|
||||
from uds.core.util import validators, decorators
|
||||
|
||||
@ -165,7 +165,7 @@ class EmailMFA(mfas.MFA):
|
||||
# if hostname is not valid, we will raise an exception
|
||||
hostname = self.hostname.cleanStr()
|
||||
if not hostname:
|
||||
raise EmailMFA.ValidationException(_('Invalid SMTP hostname'))
|
||||
raise exceptions.ValidationException(_('Invalid SMTP hostname'))
|
||||
|
||||
# Now check is valid format
|
||||
if ':' in hostname:
|
||||
|
@ -39,7 +39,7 @@ import typing
|
||||
|
||||
from django.utils.translation import gettext_noop as _
|
||||
|
||||
from uds.core import messaging
|
||||
from uds.core import messaging, exceptions
|
||||
from uds.core.ui import gui
|
||||
from uds.core.util import validators
|
||||
|
||||
@ -147,7 +147,7 @@ class EmailNotifier(messaging.Notifier):
|
||||
# if hostname is not valid, we will raise an exception
|
||||
hostname = self.hostname.cleanStr()
|
||||
if not hostname:
|
||||
raise messaging.Notifier.ValidationException(_('Invalid SMTP hostname'))
|
||||
raise exceptions.ValidationException(_('Invalid SMTP hostname'))
|
||||
|
||||
# Now check is valid format
|
||||
if ':' in hostname:
|
||||
|
@ -38,7 +38,7 @@ import typing
|
||||
|
||||
from django.utils.translation import gettext_noop as _
|
||||
from uds.core.ui import gui
|
||||
from uds.core import osmanagers
|
||||
from uds.core import exceptions
|
||||
from uds.core.util import log
|
||||
|
||||
from .linux_osmanager import LinuxOsManager
|
||||
@ -77,7 +77,7 @@ class LinuxRandomPassManager(LinuxOsManager):
|
||||
super(LinuxRandomPassManager, self).__init__(environment, values)
|
||||
if values is not None:
|
||||
if values['userAccount'] == '':
|
||||
raise osmanagers.OSManager.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
_('Must provide an user account!!!')
|
||||
)
|
||||
self._userAccount = values['userAccount']
|
||||
|
@ -13,7 +13,7 @@ import logging
|
||||
import typing
|
||||
|
||||
from django.utils.translation import gettext_noop as _, gettext_lazy
|
||||
from uds.core import osmanagers
|
||||
from uds.core import osmanagers, exceptions
|
||||
from uds.core.services import types as serviceTypes
|
||||
from uds.core.ui import gui
|
||||
from uds.core.managers import userServiceManager
|
||||
@ -95,11 +95,11 @@ class WindowsOsManager(osmanagers.OSManager):
|
||||
try:
|
||||
length = int(length)
|
||||
except Exception:
|
||||
raise osmanagers.OSManager.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
_('Length must be numeric!!')
|
||||
)
|
||||
if length > 6 or length < 1:
|
||||
raise osmanagers.OSManager.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
_('Length must be betwen 1 and 6')
|
||||
)
|
||||
return length
|
||||
|
@ -41,7 +41,7 @@ import ldap
|
||||
from django.utils.translation import gettext_noop as _
|
||||
from uds.core.ui import gui
|
||||
from uds.core.managers import cryptoManager
|
||||
from uds.core import osmanagers
|
||||
from uds.core import exceptions
|
||||
from uds.core.util import log
|
||||
from uds.core.util import ldaputil
|
||||
|
||||
@ -146,21 +146,19 @@ class WinDomainOsManager(WindowsOsManager):
|
||||
super().__init__(environment, values)
|
||||
if values:
|
||||
if values['domain'] == '':
|
||||
raise osmanagers.OSManager.ValidationException(
|
||||
_('Must provide a domain!')
|
||||
)
|
||||
raise exceptions.ValidationException(_('Must provide a domain!'))
|
||||
# if values['domain'].find('.') == -1:
|
||||
# raise osmanagers.OSManager.ValidationException(_('Must provide domain in FQDN'))
|
||||
# raise exceptions.ValidationException(_('Must provide domain in FQDN'))
|
||||
if values['account'] == '':
|
||||
raise osmanagers.OSManager.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
_('Must provide an account to add machines to domain!')
|
||||
)
|
||||
if values['account'].find('\\') != -1:
|
||||
raise osmanagers.OSManager.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
_('DOM\\USER form is not allowed!')
|
||||
)
|
||||
if values['password'] == '':
|
||||
raise osmanagers.OSManager.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
_('Must provide a password for the account!')
|
||||
)
|
||||
self._domain = values['domain']
|
||||
@ -172,12 +170,12 @@ class WinDomainOsManager(WindowsOsManager):
|
||||
self._ssl = 'y' if values['ssl'] else 'n'
|
||||
self._removeOnExit = 'y' if values['removeOnExit'] else 'n'
|
||||
else:
|
||||
self._domain = ""
|
||||
self._ou = ""
|
||||
self._account = ""
|
||||
self._password = ""
|
||||
self._group = ""
|
||||
self._serverHint = ""
|
||||
self._domain = ''
|
||||
self._ou = ''
|
||||
self._account = ''
|
||||
self._password = '' # nosec: no encoded password
|
||||
self._group = ''
|
||||
self._serverHint = ''
|
||||
self._removeOnExit = 'n'
|
||||
self._ssl = 'n'
|
||||
|
||||
@ -191,10 +189,15 @@ class WinDomainOsManager(WindowsOsManager):
|
||||
if self._serverHint != '':
|
||||
yield (self._serverHint, 389)
|
||||
|
||||
server: typing.Any
|
||||
|
||||
def key(server: typing.Any) -> int:
|
||||
return server.priority * 10000 + server.weight
|
||||
|
||||
for server in reversed(
|
||||
sorted(
|
||||
dns.resolver.query('_ldap._tcp.' + self._domain, 'SRV'),
|
||||
key=lambda i: i.priority * 10000 + i.weight,
|
||||
iter(dns.resolver.resolve('_ldap._tcp.' + self._domain, 'SRV')),
|
||||
key=key,
|
||||
)
|
||||
):
|
||||
yield (str(server.target)[:-1], server.port)
|
||||
|
@ -40,7 +40,7 @@ import typing
|
||||
from django.utils.translation import gettext_noop as _
|
||||
from uds.core.ui import gui
|
||||
from uds.core.managers import cryptoManager
|
||||
from uds.core import osmanagers
|
||||
from uds.core import exceptions
|
||||
from uds.core.util import log
|
||||
|
||||
from .windows import WindowsOsManager
|
||||
@ -88,11 +88,11 @@ class WinRandomPassManager(WindowsOsManager):
|
||||
super().__init__(environment, values)
|
||||
if values:
|
||||
if values['userAccount'] == '':
|
||||
raise osmanagers.OSManager.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
_('Must provide an user account!!!')
|
||||
)
|
||||
if values['password'] == '':
|
||||
raise osmanagers.OSManager.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
_('Must provide a password for the account!!!')
|
||||
)
|
||||
self._userAccount = values['userAccount']
|
||||
|
@ -537,7 +537,7 @@ class OVirtProvider(
|
||||
# instance = Provider(env, data)
|
||||
# logger.debug('Methuselah has {0} years and is {1} :-)'
|
||||
# .format(instance.methAge.value, instance.methAlive.value))
|
||||
# except ServiceProvider.ValidationException as e:
|
||||
# except exceptions.ValidationException as e:
|
||||
# # If we say that meth is alive, instantiation will
|
||||
# return [False, str(e)]
|
||||
# except Exception as e:
|
||||
|
@ -37,8 +37,8 @@ import typing
|
||||
from django.utils.translation import gettext_noop as _
|
||||
|
||||
from uds.core.transports import protocols
|
||||
from uds.core.services import Service, types as serviceTypes
|
||||
from uds.core.util import tools
|
||||
from uds.core import services, exceptions
|
||||
from uds.core.util import validators
|
||||
from uds.core.ui import gui
|
||||
|
||||
from .publication import OVirtPublication
|
||||
@ -53,7 +53,7 @@ if typing.TYPE_CHECKING:
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OVirtLinkedService(Service): # pylint: disable=too-many-public-methods
|
||||
class OVirtLinkedService(services.Service): # pylint: disable=too-many-public-methods
|
||||
"""
|
||||
oVirt Linked clones service. This is based on creating a template from selected vm, and then use it to
|
||||
"""
|
||||
@ -105,7 +105,7 @@ class OVirtLinkedService(Service): # pylint: disable=too-many-public-methods
|
||||
deployedType = OVirtLinkedDeployment
|
||||
|
||||
allowedProtocols = protocols.GENERIC + (protocols.SPICE,)
|
||||
servicesTypeProvided = (serviceTypes.VDI,)
|
||||
servicesTypeProvided = (services.types.VDI,)
|
||||
|
||||
# Now the form part
|
||||
cluster = gui.ChoiceField(
|
||||
@ -225,9 +225,9 @@ class OVirtLinkedService(Service): # pylint: disable=too-many-public-methods
|
||||
initialized by __init__ method of base class, before invoking this.
|
||||
"""
|
||||
if values:
|
||||
tools.checkValidBasename(self.baseName.value, self.lenName.num())
|
||||
validators.validateBasename(self.baseName.value, self.lenName.num())
|
||||
if int(self.memory.value) < 256 or int(self.memoryGuaranteed.value) < 256:
|
||||
raise Service.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
_('The minimum allowed memory is 256 Mb')
|
||||
)
|
||||
if int(self.memoryGuaranteed.value) > int(self.memory.value):
|
||||
|
@ -38,7 +38,7 @@ from django.utils.translation import gettext_noop as _
|
||||
|
||||
import dns.resolver
|
||||
|
||||
from uds.core import services
|
||||
from uds.core import services, exceptions
|
||||
from uds.core.ui.user_interface import gui
|
||||
from uds.core.util import net
|
||||
from uds.core.util import log
|
||||
@ -70,7 +70,7 @@ class PhysicalMachinesProvider(services.ServiceProvider):
|
||||
values (Module.ValuesType): List of values on initialization (maybe None)
|
||||
|
||||
Raises:
|
||||
services.ServiceProvider.ValidationException
|
||||
exceptions.ValidationException
|
||||
"""
|
||||
if values is None:
|
||||
return
|
||||
@ -83,13 +83,13 @@ class PhysicalMachinesProvider(services.ServiceProvider):
|
||||
config.read_string(self.config.value)
|
||||
# Seems a valid configuration file, let's see if all se
|
||||
except Exception as e:
|
||||
raise services.ServiceProvider.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
_('Invalid advanced configuration: ') + str(e)
|
||||
)
|
||||
|
||||
for section in config.sections():
|
||||
if section not in VALID_CONFIG_SECTIONS:
|
||||
raise services.ServiceProvider.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
_('Invalid section in advanced configuration: ') + section
|
||||
)
|
||||
|
||||
@ -99,12 +99,12 @@ class PhysicalMachinesProvider(services.ServiceProvider):
|
||||
try:
|
||||
net.networksFromString(key) # Raises exception if net is invalid
|
||||
except Exception:
|
||||
raise services.ServiceProvider.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
_('Invalid network in advanced configuration: ') + key
|
||||
)
|
||||
# Now check value is an url
|
||||
if config['wol'][key][:4] != 'http':
|
||||
raise services.ServiceProvider.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
_('Invalid url in advanced configuration: ') + key
|
||||
)
|
||||
|
||||
@ -136,7 +136,7 @@ class PhysicalMachinesProvider(services.ServiceProvider):
|
||||
# Try to resolve name...
|
||||
try:
|
||||
# Prefer ipv4
|
||||
res = dns.resolver.resolve(ip)
|
||||
res: typing.Any = dns.resolver.resolve(ip)
|
||||
ip = res[0].address
|
||||
except Exception:
|
||||
# Try ipv6
|
||||
|
@ -41,7 +41,7 @@ from uds.models import getSqlDatetimeAsUnix
|
||||
from uds.core.ui import gui
|
||||
from uds.core.util import log
|
||||
from uds.core.util import net
|
||||
from uds.core import services
|
||||
from uds.core import services, exceptions
|
||||
|
||||
from .deployment import IPMachineDeployed
|
||||
from .service_base import IPServiceBase
|
||||
@ -151,7 +151,7 @@ class IPMachinesService(IPServiceBase):
|
||||
# Check that ips are valid
|
||||
for v in values['ipList']:
|
||||
if not net.isValidHost(v.split(';')[0]): # Get only IP/hostname
|
||||
raise IPServiceBase.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
gettext('Invalid value detected on servers list: "{}"').format(
|
||||
v
|
||||
)
|
||||
|
@ -37,7 +37,7 @@ from django.utils.translation import gettext_lazy as _, gettext
|
||||
|
||||
from uds.core.ui import gui
|
||||
from uds.core.util import net
|
||||
from uds.core.services import types as serviceTypes
|
||||
from uds.core import services, exceptions
|
||||
|
||||
from .deployment import IPMachineDeployed
|
||||
from .service_base import IPServiceBase
|
||||
@ -76,14 +76,14 @@ class IPSingleMachineService(IPServiceBase):
|
||||
|
||||
deployedType = IPMachineDeployed
|
||||
|
||||
servicesTypeProvided = (serviceTypes.VDI,)
|
||||
servicesTypeProvided = (services.types.VDI,)
|
||||
|
||||
def initialize(self, values: 'Module.ValuesType') -> None:
|
||||
if values is None:
|
||||
return
|
||||
|
||||
if not net.isValidHost(self.ip.value):
|
||||
raise IPServiceBase.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
gettext('Invalid server used: "{}"'.format(self.ip.value))
|
||||
)
|
||||
|
||||
|
@ -336,7 +336,7 @@ class ProxmoxProvider(
|
||||
# instance = Provider(env, data)
|
||||
# logger.debug('Methuselah has {0} years and is {1} :-)'
|
||||
# .format(instance.methAge.value, instance.methAlive.value))
|
||||
# except ServiceProvider.ValidationException as e:
|
||||
# except exceptions.ValidationException as e:
|
||||
# # If we say that meth is alive, instantiation will
|
||||
# return [False, str(e)]
|
||||
# except Exception as e:
|
||||
|
@ -186,7 +186,7 @@ class ProxmoxLinkedService(Service): # pylint: disable=too-many-public-methods
|
||||
self.baseName.value, 15, asPattern=True
|
||||
)
|
||||
# if int(self.memory.value) < 128:
|
||||
# raise Service.ValidationException(_('The minimum allowed memory is 128 Mb'))
|
||||
# raise exceptions.ValidationException(_('The minimum allowed memory is 128 Mb'))
|
||||
|
||||
def initGui(self) -> None:
|
||||
# Here we have to use "default values", cause values aren't used at form initialization
|
||||
|
@ -37,7 +37,7 @@ import typing
|
||||
|
||||
|
||||
from django.utils.translation import gettext_noop as _
|
||||
from uds.core import services
|
||||
from uds.core import services, exceptions
|
||||
from uds.core.ui import gui
|
||||
from .service import ServiceOne, ServiceTwo
|
||||
|
||||
@ -181,7 +181,7 @@ class Provider(services.ServiceProvider):
|
||||
# values are only passed from administration client. Internals
|
||||
# instantiations are always empty.
|
||||
if values and self.methAlive.isTrue():
|
||||
raise services.ServiceProvider.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
_('Methuselah is not alive!!! :-)')
|
||||
)
|
||||
|
||||
@ -222,7 +222,7 @@ class Provider(services.ServiceProvider):
|
||||
instance.methAge.value,
|
||||
instance.methAlive.value,
|
||||
)
|
||||
except services.ServiceProvider.ValidationException as e:
|
||||
except exceptions.ValidationException as e:
|
||||
# If we say that meth is alive, instantiation will
|
||||
return [False, str(e)]
|
||||
except Exception as e:
|
||||
|
@ -34,7 +34,7 @@ import logging
|
||||
import typing
|
||||
|
||||
from django.utils.translation import gettext_noop as _
|
||||
from uds.core import services
|
||||
from uds.core import services, exceptions
|
||||
from uds.core.ui import gui
|
||||
|
||||
from .publication import SamplePublication
|
||||
@ -167,7 +167,7 @@ class ServiceOne(services.Service):
|
||||
# so we only need to validate params if values is not None
|
||||
if values:
|
||||
if self.colour.value == 'nonsense':
|
||||
raise services.Service.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
'The selected colour is invalid!!!'
|
||||
)
|
||||
|
||||
|
@ -482,7 +482,7 @@ class XenProvider(ServiceProvider): # pylint: disable=too-many-public-methods
|
||||
# instance = Provider(env, data)
|
||||
# logger.debug('Methuselah has {0} years and is {1} :-)'
|
||||
# .format(instance.methAge.value, instance.methAlive.value))
|
||||
# except ServiceProvider.ValidationException as e:
|
||||
# except exceptions.ValidationException as e:
|
||||
# # If we say that meth is alive, instantiation will
|
||||
# return [False, str(e)]
|
||||
# except Exception as e:
|
||||
|
@ -33,8 +33,8 @@ import logging
|
||||
import typing
|
||||
|
||||
from django.utils.translation import gettext_noop as _
|
||||
from uds.core.services import Service, types as serviceTypes
|
||||
from uds.core.util import tools
|
||||
from uds.core import services, exceptions
|
||||
from uds.core.util import validators
|
||||
from uds.core.ui import gui
|
||||
|
||||
from .publication import XenPublication
|
||||
@ -48,7 +48,7 @@ if typing.TYPE_CHECKING:
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class XenLinkedService(Service): # pylint: disable=too-many-public-methods
|
||||
class XenLinkedService(services.Service): # pylint: disable=too-many-public-methods
|
||||
"""
|
||||
Xen Linked clones service. This is based on creating a template from selected vm, and then use it to
|
||||
|
||||
@ -101,7 +101,7 @@ class XenLinkedService(Service): # pylint: disable=too-many-public-methods
|
||||
# : Types of deploys (services in cache and/or assigned to users)
|
||||
deployedType = XenLinkedDeployment
|
||||
|
||||
servicesTypeProvided = (serviceTypes.VDI,)
|
||||
servicesTypeProvided = (services.types.VDI,)
|
||||
|
||||
# Now the form part
|
||||
datastore = gui.ChoiceField(
|
||||
@ -189,10 +189,10 @@ class XenLinkedService(Service): # pylint: disable=too-many-public-methods
|
||||
initialized by __init__ method of base class, before invoking this.
|
||||
"""
|
||||
if values:
|
||||
tools.checkValidBasename(self.baseName.value, self.lenName.num())
|
||||
validators.validateBasename(self.baseName.value, self.lenName.num())
|
||||
|
||||
if int(self.memory.value) < 256:
|
||||
raise Service.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
_('The minimum allowed memory is 256 Mb')
|
||||
)
|
||||
|
||||
|
@ -37,7 +37,7 @@ import typing
|
||||
from django.utils.translation import gettext_noop as _
|
||||
|
||||
from uds.core.ui import gui
|
||||
from uds.core import transports
|
||||
from uds.core import transports, exceptions
|
||||
from uds.core.util import os_detector as OsDetector
|
||||
from uds.core.managers import cryptoManager
|
||||
from uds import models
|
||||
@ -319,11 +319,11 @@ class HTML5RDPTransport(transports.Transport):
|
||||
# Strip spaces and all trailing '/'
|
||||
self.guacamoleServer.value = self.guacamoleServer.value.strip().rstrip('/')
|
||||
if self.guacamoleServer.value[0:4] != 'http':
|
||||
raise transports.Transport.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
_('The server must be http or https')
|
||||
)
|
||||
#if self.useEmptyCreds.isTrue() and self.security.value != 'rdp':
|
||||
# raise transports.Transport.ValidationException(
|
||||
# raise exceptions.ValidationException(
|
||||
# _(
|
||||
# 'Empty credentials (on Credentials tab) is only allowed with Security level (on Parameters tab) set to "RDP"'
|
||||
# )
|
||||
|
@ -34,12 +34,9 @@ import logging
|
||||
import typing
|
||||
|
||||
from django.utils.translation import gettext_noop as _
|
||||
from django.http import HttpResponseRedirect
|
||||
|
||||
from uds.core.ui import gui
|
||||
|
||||
from uds.core import transports
|
||||
|
||||
from uds.core import transports, exceptions
|
||||
from uds.core.util import os_detector as OsDetector
|
||||
from uds.core.managers import cryptoManager
|
||||
from uds import models
|
||||
@ -183,7 +180,7 @@ class HTML5VNCTransport(transports.Transport):
|
||||
# Remove trailing / (one or more) from url if it exists from "guacamoleServer" field
|
||||
self.guacamoleServer.value = self.guacamoleServer.value.strip().rstrip('/')
|
||||
if self.guacamoleServer.value[0:4] != 'http':
|
||||
raise transports.Transport.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
_('The server must be http or https')
|
||||
)
|
||||
|
||||
|
@ -30,7 +30,6 @@
|
||||
"""
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
"""
|
||||
import os
|
||||
import logging
|
||||
import typing
|
||||
|
||||
@ -122,6 +121,15 @@ class BaseSpiceTransport(transports.Transport):
|
||||
tab=gui.Tab.ADVANCED,
|
||||
)
|
||||
|
||||
overridedProxy = gui.TextField(
|
||||
order=10,
|
||||
label=_('Proxy'),
|
||||
tooltip=_('If not empty, this proxy will be used to connect to the service'),
|
||||
required=False,
|
||||
tab=gui.Tab.ADVANCED,
|
||||
pattern=''
|
||||
)
|
||||
|
||||
def isAvailableFor(self, userService: 'models.UserService', ip: str) -> bool:
|
||||
"""
|
||||
Checks if the transport is available for the requested destination ip
|
||||
|
@ -36,11 +36,8 @@ import typing
|
||||
from django.utils.translation import gettext_noop as _
|
||||
|
||||
from uds.core.ui import gui
|
||||
|
||||
from uds.core import transports
|
||||
|
||||
from uds.core import transports, exceptions
|
||||
from uds.core.util import os_detector as OsDetector
|
||||
from uds.core.managers import cryptoManager
|
||||
from uds import models
|
||||
|
||||
# Not imported at runtime, just for type checking
|
||||
@ -95,7 +92,7 @@ class TestTransport(transports.Transport):
|
||||
self.testURL.value.startswith('http://')
|
||||
or self.testURL.value.startswith('https://')
|
||||
):
|
||||
raise transports.Transport.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
_('The url must be http or https')
|
||||
)
|
||||
|
||||
|
@ -36,9 +36,7 @@ import typing
|
||||
from django.utils.translation import gettext_noop as _
|
||||
|
||||
from uds.core.ui import gui
|
||||
|
||||
from uds.core import transports
|
||||
|
||||
from uds.core import transports, exceptions
|
||||
from uds.core.util import os_detector as OsDetector
|
||||
from uds import models
|
||||
|
||||
@ -94,7 +92,7 @@ class URLCustomTransport(transports.Transport):
|
||||
self.urlPattern.value.startswith('http://')
|
||||
or self.urlPattern.value.startswith('https://')
|
||||
):
|
||||
raise transports.Transport.ValidationException(
|
||||
raise exceptions.ValidationException(
|
||||
_('The url must be http or https')
|
||||
)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user