1
0
mirror of https://github.com/dkmstr/openuds.git synced 2025-10-07 15:33:51 +03:00

14 Commits

Author SHA1 Message Date
Adolfo Gómez García
1417a66b21 Small fixes on OpenNebula complains 2021-07-02 12:45:16 +02:00
Adolfo Gómez García
9ba4234313 Removed NX 2021-07-02 11:06:23 +02:00
Adolfo Gómez García
e85e4c4e54 Merge remote-tracking branch 'origin/v3.0' 2021-07-02 11:02:11 +02:00
Adolfo Gómez García
693d14cd81 small typo fixes 2021-07-02 11:01:31 +02:00
Adolfo Gómez García
4be9e9ea69 Added more info to UDSClient and small typo fixed 2021-07-01 22:04:24 +02:00
Adolfo Gómez García
e38cd73f30 Added user agent 2021-07-01 21:46:00 +02:00
Adolfo Gómez García
43b785eb73 Added more info on ticket error 2021-07-01 21:42:25 +02:00
Adolfo Gómez García
9c4a4ed35c Fixed RDP for MacOS 2021-07-01 21:38:21 +02:00
Adolfo Gómez García
02737c0e8d Fixed guacamole auth url 2021-06-29 16:57:01 +02:00
Adolfo Gómez García
8bbd897cd0 Added ticket check 2021-06-29 16:26:10 +02:00
Adolfo Gómez García
c98933b6ed Fixed guacamole urls && small pam fix 2021-06-29 14:48:04 +02:00
Adolfo Gómez García
6e0292e76e Fixed guacamole new url && added 0000... as admin alias for auths 2021-06-29 13:02:09 +02:00
Adolfo Gómez García
8e6fced2ac Added second-log to login in case invalid username/password is detected 2021-06-29 11:33:58 +02:00
Adolfo Gómez García
c5a02686c4 added "auth_id" as alias for "authId" on login
Changed "uds_auth" to "uds_token"
2021-06-28 19:02:44 +02:00
47 changed files with 215 additions and 1329 deletions

View File

@@ -128,11 +128,13 @@ class UDSClient(QtWidgets.QMainWindow):
self.anim = 0
self.animInverted = False
self.ui.progressBar.setInvertedAppearance(self.animInverted)
self.animTimer.start(40)
if self.animTimer:
self.animTimer.start(40)
def stopAnim(self):
self.ui.progressBar.invertedAppearance = False # type: ignore
self.animTimer.stop()
if self.animTimer:
self.animTimer.stop()
def getVersion(self):
try:

View File

@@ -93,6 +93,7 @@ class Handler(socketserver.BaseRequestHandler):
class ForwardThread(threading.Thread):
status = 0 # Connecting
client: typing.Optional[paramiko.SSHClient]
fs: typing.Optional[ForwardServer]
def __init__(self, server, port, username, password, localPort, redirectHost, redirectPort, waitTime, fingerPrints):
threading.Thread.__init__(self)
@@ -180,7 +181,9 @@ class ForwardThread(threading.Thread):
self.timer.cancel()
self.stopEvent.set()
self.fs.shutdown()
if self.fs:
self.fs.shutdown()
if self.client is not None:
self.client.useCount -= 1 # type: ignore

View File

@@ -132,12 +132,15 @@ class ForwardServer(socketserver.ThreadingTCPServer):
if self.status == TUNNEL_ERROR:
return False
logger.debug('Checking tunnel availability')
try:
with self.connect() as ssl_socket:
ssl_socket.sendall(HANDSHAKE_V1 + b'TEST')
resp = ssl_socket.recv(2)
if resp != b'OK':
raise Exception({'Invalid tunnelresponse: {resp}'})
logger.debug('Tunnel is available!')
return True
except Exception as e:
logger.error(
@@ -220,7 +223,7 @@ class Handler(socketserver.BaseRequestHandler):
if not data:
break
self.request.sendall(data)
logger.debug('Finished tunnel with ticekt %s', self.server.ticket)
logger.debug('Finished tunnel with ticket %s', self.server.ticket)
except Exception as e:
pass

View File

@@ -112,11 +112,11 @@ class Login(Handler):
logger.info('Access to REST API %s is blocked for %s seconds since last fail', self._request.ip, GlobalConfig.LOGIN_BLOCK.getInt())
try:
if 'authId' not in self._params and 'authSmallName' not in self._params and 'auth' not in self._params:
if 'auth_id' not in self._params and 'authId' not in self._params and 'authSmallName' not in self._params and 'auth' not in self._params:
raise RequestError('Invalid parameters (no auth)')
scrambler: str = ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(32)) # @UndefinedVariable
authId: typing.Optional[str] = self._params.get('authId', None)
authId: typing.Optional[str] = self._params.get('authId', self._params.get('auth_id', None))
authSmallName: typing.Optional[str] = self._params.get('authSmallName', None)
authName: typing.Optional[str] = self._params.get('auth', None)
platform: str = self._params.get('platform', self._request.os)
@@ -126,7 +126,7 @@ class Login(Handler):
username, password = self._params['username'], self._params['password']
locale: str = self._params.get('locale', 'en')
if authName == 'admin' or authSmallName == 'admin':
if authName == 'admin' or authSmallName == 'admin' or authId == '00000000-0000-0000-0000-000000000000':
if GlobalConfig.SUPER_USER_LOGIN.get(True) == username and GlobalConfig.SUPER_USER_PASS.get(True) == password:
self.genAuthToken(-1, username, password, locale, platform, True, True, scrambler)
return Login.result(result='ok', token=self.getAuthToken())

View File

@@ -38,9 +38,8 @@ from uds.core import managers
from uds.REST import Handler
from uds.REST import AccessDenied
from uds.core.auths.auth import isTrustedSource
from uds.core.util import log, net
from uds.core.util import log, net, request
from uds.core.util.stats import events
from uds.models.util import getSqlDatetime
logger = logging.getLogger(__name__)
@@ -71,9 +70,12 @@ class TunnelTicket(Handler):
# Invalid requests
raise AccessDenied()
# If args is 3, the last one is the authId
authId = self._args[2][:48]
# TODO: Check auth Id
# Take token from url
token = self._args[2][:48]
if not models.TunnelToken.validateToken(token):
logger.error('Invalid token %s from %s', token, self._request.ip)
raise AccessDenied()
# Try to get ticket from DB
try:

View File

@@ -37,8 +37,8 @@ import typing
from django.utils.translation import ugettext_noop as _
from uds.core import auths
from uds.core.util import net
from uds.core.util.request import getRequest
from uds.core.ui import gui
from uds.core.util.request import getRequest
# Not imported at runtime, just for type checking
if typing.TYPE_CHECKING:
@@ -72,7 +72,7 @@ class IPAuth(auths.Authenticator):
blockUserOnLoginFailures = False
def getIp(self) -> str:
ip = getRequest().ip_proxy if self.acceptProxy.isTrue() else getRequest().ip # pylint: disable=maybe-no-member
ip = getRequest().ip_proxy if self.acceptProxy.isTrue() else getRequest().ip
logger.debug('Client IP: %s', ip)
return ip
@@ -88,7 +88,6 @@ class IPAuth(auths.Authenticator):
def authenticate(self, username: str, credentials: str, groupsManager: 'auths.GroupsManager') -> bool:
# If credentials is a dict, that can't be sent directly from web interface, we allow entering
# We use this "trick" so authenticators
if username == self.getIp():
self.getGroups(username, groupsManager)
return True

View File

@@ -44,6 +44,7 @@ from uds.core.ui import gui
from uds.core.managers import cryptoManager
from uds.core.util.state import State
from uds.core.util.request import getRequest
from uds.core.auths.auth import authLogLogin
# Not imported at runtime, just for type checking
if typing.TYPE_CHECKING:
@@ -135,6 +136,7 @@ class InternalDBAuth(auths.Authenticator):
try:
user: 'models.User' = dbAuth.users.get(name=username, state=State.ACTIVE)
except Exception:
authLogLogin(getRequest(), self.dbAuthenticator(), username, 'Invalid user')
return False
if user.parent: # Direct auth not allowed for "derived" users
@@ -144,6 +146,7 @@ class InternalDBAuth(auths.Authenticator):
if cryptoManager().checkHash(credentials, user.password):
groupsManager.validate([g.name for g in user.groups.all()])
return True
authLogLogin(getRequest(), self.dbAuthenticator(), username, 'Invalid password')
return False
def getGroups(self, username: str, groupsManager: 'auths.GroupsManager'):

View File

@@ -34,16 +34,17 @@ import logging
import typing
from django.utils.translation import ugettext_noop as _
from uds.core.ui import gui
from uds.core import auths
from uds.core.managers import cryptoManager
from uds.core.auths.auth import authLogLogin
from uds.core.util.request import getRequest
from . import client
if typing.TYPE_CHECKING:
from django.http import (
HttpRequest
)
pass
logger = logging.getLogger(__name__)
@@ -131,6 +132,7 @@ class RadiusAuth(auths.Authenticator):
connection = self.radiusClient()
groups = connection.authenticate(username=username, password=credentials)
except Exception:
authLogLogin(getRequest(), self.dbAuthenticator(), username, 'Access denied by Raiuds')
return False
if self.globalGroup.value.strip():

View File

@@ -38,9 +38,12 @@ import typing
import ldap
from django.utils.translation import ugettext_noop as _
from uds.core import auths
from uds.core.ui import gui
from uds.core.util import ldaputil
from uds.core.auths.auth import authLogLogin
from uds.core.util.request import getRequest
try:
# pylint: disable=no-name-in-module
@@ -498,12 +501,17 @@ class RegexLdap(auths.Authenticator):
usr = self.__getUser(username)
if usr is None:
authLogLogin(getRequest(), self.dbAuthenticator(), username, 'Invalid user')
return False
# Let's see first if it credentials are fine
self.__connectAs(
usr['dn'], credentials
) # Will raise an exception if it can't connect
try:
# Let's see first if it credentials are fine
self.__connectAs(
usr['dn'], credentials
) # Will raise an exception if it can't connect
except:
authLogLogin(getRequest(), self.dbAuthenticator(), username, 'Invalid password')
return False
groupsManager.validate(self.__getGroups(usr))

View File

@@ -37,9 +37,12 @@ import ldap.filter
import ldap
from django.utils.translation import ugettext_noop as _
from uds.core.ui import gui
from uds.core import auths
from uds.core.util import ldaputil
from uds.core.auths.auth import authLogLogin
from uds.core.util.request import getRequest
# Not imported at runtime, just for type checking
if typing.TYPE_CHECKING:
@@ -398,12 +401,17 @@ class SimpleLDAPAuthenticator(auths.Authenticator):
user = self.__getUser(username)
if user is None:
authLogLogin(getRequest(), self.dbAuthenticator(), username, 'Invalid user')
return False
# Let's see first if it credentials are fine
self.__connectAs(
user['dn'], credentials
) # Will raise an exception if it can't connect
try:
# Let's see first if it credentials are fine
self.__connectAs(
user['dn'], credentials
) # Will raise an exception if it can't connect
except:
authLogLogin(getRequest(), self.dbAuthenticator(), username, 'Invalid password')
return False
groupsManager.validate(self.__getGroups(user))

View File

@@ -51,7 +51,6 @@ from uds.core import auths
from uds.core.util import log
from uds.core.util import net
from uds.core.util.config import GlobalConfig
from uds.core.util.decorators import deprecated
from uds.core.util.stats import events
from uds.core.util.state import State
from uds.core.managers import cryptoManager
@@ -378,7 +377,7 @@ def webLogin(
manager_id,
user.name,
password,
get_language(),
get_language() or '',
request.os['OS'],
user.is_admin,
user.staff_member,

View File

@@ -31,13 +31,11 @@
@author: Adolfo Gómez, dkmaster at dkmon dot com
"""
from django.conf.urls import url
from .views import guacamole
from .views import guacamole, guacamole_authenticated
urlpatterns = [
# Old, compat
url(r'^guacamole/(?P<tunnelId>.+)$', guacamole, name='dispatcher.guacamole'),
# New path
url(r'^uds/guacamole/(?P<tunnelId>.+)$', guacamole, name='dispatcher.guacamole'),
# Authenticated path
url(r'^uds/guacamole/auth/(?P<authId>.+)/(?P<tunnelId>.+)$', guacamole, name='dispatcher.guacamole'),
url(r'^uds/guacamole/auth/(?P<token>[^/]+)/(?P<tunnelId>.+)$', guacamole_authenticated, name='dispatcher.guacamole'),
# Non authenticated path. Disabled
# url(r'^uds/guacamole/(?P<tunnelId>.+)$', guacamole, name='dispatcher.guacamole.noauth'),
]

View File

@@ -34,10 +34,10 @@ import logging
from django.http import HttpResponse, HttpRequest
from uds.models import TicketStore, UserService
from uds.models import TicketStore, UserService, TunnelToken
from uds.core.auths import auth
from uds.core.managers import cryptoManager
from uds.core.util.request import ExtendedHttpRequestWithUser
logger = logging.getLogger(__name__)
@@ -52,7 +52,7 @@ def dict2resp(dct):
@auth.trustedSourceRequired
def guacamole(request: HttpRequest, tunnelId: str) -> HttpResponse:
def guacamole(request: ExtendedHttpRequestWithUser, tunnelId: str) -> HttpResponse:
logger.debug('Received credentials request for tunnel id %s', tunnelId)
try:
@@ -85,7 +85,9 @@ def guacamole(request: HttpRequest, tunnelId: str) -> HttpResponse:
return HttpResponse(response, content_type=CONTENT_TYPE)
@auth.trustedSourceRequired
def guacamole_authenticated(request: HttpRequest, authId: str, tunnelId: str) -> HttpResponse:
authId = authId[:48]
def guacamole_authenticated(request: ExtendedHttpRequestWithUser, token: str, tunnelId: str) -> HttpResponse:
if not TunnelToken.validateToken(token):
logger.error('Invalid token %s from %s', token, request.ip)
return HttpResponse(ERROR, content_type=CONTENT_TYPE)
# TODO: Check the authId validity
return guacamole(request, tunnelId)

View File

@@ -35,6 +35,7 @@ import logging
from django.http import HttpResponseNotAllowed, HttpResponse, HttpRequest
from uds.models import TicketStore
from uds.core.auths import auth
from uds.core.util.request import ExtendedHttpRequestWithUser
logger = logging.getLogger(__name__)
@@ -42,7 +43,7 @@ logger = logging.getLogger(__name__)
@auth.trustedSourceRequired
def pam(request: HttpRequest) -> HttpResponse:
def pam(request: ExtendedHttpRequestWithUser) -> HttpResponse:
response = ''
if request.method == 'POST':
return HttpResponseNotAllowed(['GET'])

View File

@@ -28,8 +28,10 @@
'''
.. moduleauthor:: Adolfo Gómez, dkmaster at dkmon dot com
'''
from django.db import models
import typing
from django.db import models
from uds.core.util.request import ExtendedHttpRequest
class TunnelToken(models.Model):
"""
@@ -52,7 +54,18 @@ class TunnelToken(models.Model):
constraints = [
models.UniqueConstraint(fields=['ip', 'hostname'], name='tt_ip_hostname')
]
@staticmethod
def validateToken(token: str, request: typing.Optional[ExtendedHttpRequest] = None) -> bool:
try:
tt = TunnelToken.objects.get(token=token)
# We could check the request ip here
if request and request.ip != tt.ip:
raise Exception('Invalid ip')
return True
except TunnelToken.DoesNotExist:
pass
return False
def __str__(self):
return '<TunnelToken {} created on {} by {} from {}/{}>'.format(

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2012-2019 Virtual Cable S.L.
# Copyright (c) 2012-2021 Virtual Cable S.L.U.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
@@ -12,7 +12,7 @@
# * 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
# * 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.
#
@@ -49,6 +49,7 @@ def ensureConnected(fnc: typing.Callable[..., RT]) -> typing.Callable[..., RT]:
def inner(*args, **kwargs) -> RT:
args[0].connect()
return fnc(*args, **kwargs)
return inner
@@ -113,10 +114,14 @@ class OpenNebulaClient: # pylint: disable=too-many-public-methods
def enumStorage(self, storageType: int = 0) -> typing.Iterable[types.StorageType]:
sstorageType = str(storageType) # Ensure it is an string
# Invoke datastore pools info, no parameters except connection string
result, _ = checkResult(self.connection.one.datastorepool.info(self.sessionString))
result, _ = checkResult(
self.connection.one.datastorepool.info(self.sessionString)
)
for ds in asIterable(result['DATASTORE_POOL']['DATASTORE']):
if ds['TYPE'] == sstorageType:
yield types.StorageType(ds['ID'], ds['NAME'], int(ds['TOTAL_MB']), int(ds['FREE_MB']), None)
yield types.StorageType(
ds['ID'], ds['NAME'], int(ds['TOTAL_MB']), int(ds['FREE_MB']), None
)
@ensureConnected
def enumTemplates(self) -> typing.Iterable[types.TemplateType]:
@@ -127,10 +132,14 @@ class OpenNebulaClient: # pylint: disable=too-many-public-methods
3.- When the next parameter is >= -1 this is the Range start ID. Can be -1. For smaller values this is the offset used for pagination.
4.- For values >= -1 this is the Range end ID. Can be -1 to get until the last ID. For values < -1 this is the page size used for pagination.
"""
result, _ = checkResult(self.connection.one.templatepool.info(self.sessionString, -1, -1, -1))
result, _ = checkResult(
self.connection.one.templatepool.info(self.sessionString, -1, -1, -1)
)
for ds in asIterable(result['VMTEMPLATE_POOL']['VMTEMPLATE']):
try:
yield types.TemplateType(ds['ID'], ds['NAME'], int(ds['TEMPLATE']['MEMORY']), None)
yield types.TemplateType(
ds['ID'], ds['NAME'], int(ds['TEMPLATE']['MEMORY']), None
)
except Exception: # Maybe no memory? (then template is not usable)
pass
@@ -143,7 +152,9 @@ class OpenNebulaClient: # pylint: disable=too-many-public-methods
3.- When the next parameter is >= -1 this is the Range start ID. Can be -1. For smaller values this is the offset used for pagination.
4.- For values >= -1 this is the Range end ID. Can be -1 to get until the last ID. For values < -1 this is the page size used for pagination.
"""
result, _ = checkResult(self.connection.one.imagepool.info(self.sessionString, -1, -1, -1))
result, _ = checkResult(
self.connection.one.imagepool.info(self.sessionString, -1, -1, -1)
)
for ds in asIterable(result['IMAGE_POOL']['IMAGE']):
yield types.ImageType(
ds['ID'],
@@ -152,22 +163,38 @@ class OpenNebulaClient: # pylint: disable=too-many-public-methods
ds.get('PERSISTENT', '0') != '0',
int(ds.get('RUNNING_VMS', '0')),
types.ImageState.fromState(ds['STATE']),
None
None,
)
@ensureConnected
def templateInfo(self, templateId: str, extraInfo: bool = False) -> types.TemplateType:
def templateInfo(
self, templateId: str, extraInfo: bool = False
) -> types.TemplateType:
"""
Returns a list
first element is a dictionary (built from XML)
second is original XML
"""
result = self.connection.one.template.info(self.sessionString, int(templateId), extraInfo)
result = self.connection.one.template.info(
self.sessionString, int(templateId), extraInfo
)
ds, xml = checkResult(result)
return types.TemplateType(ds['VMTEMPLATE']['ID'], ds['VMTEMPLATE']['NAME'], int(ds['VMTEMPLATE']['TEMPLATE']['MEMORY']), xml)
return types.TemplateType(
ds['VMTEMPLATE']['ID'],
ds['VMTEMPLATE']['NAME'],
int(ds['VMTEMPLATE']['TEMPLATE']['MEMORY']),
xml,
)
@ensureConnected
def instantiateTemplate(self, templateId: str, vmName: str, createHold: bool = False, templateToMerge: str = '', privatePersistent: bool = False) -> str:
def instantiateTemplate(
self,
templateId: str,
vmName: str,
createHold: bool = False,
templateToMerge: str = '',
privatePersistent: bool = False,
) -> str:
"""
Instantiates a template (compatible with open nebula 4 & 5)
1.- Session string
@@ -178,15 +205,26 @@ class OpenNebulaClient: # pylint: disable=too-many-public-methods
6.- true to create a private persistent copy of the template plus any image defined in DISK, and instantiate that copy.
Note: This parameter is ignored on version 4, it is new for version 5.
"""
if self.version[0] == '4': # Version 4 has one less parameter than version 5
result = self.connection.one.template.instantiate(self.sessionString, int(templateId), vmName, createHold, templateToMerge)
if self.version[0] == '4': # type: ignore # Version 4 has one less parameter than version 5
result = self.connection.one.template.instantiate(
self.sessionString, int(templateId), vmName, createHold, templateToMerge
)
else:
result = self.connection.one.template.instantiate(self.sessionString, int(templateId), vmName, createHold, templateToMerge, privatePersistent)
result = self.connection.one.template.instantiate(
self.sessionString,
int(templateId),
vmName,
createHold,
templateToMerge,
privatePersistent,
)
return checkResultRaw(result)
@ensureConnected
def updateTemplate(self, templateId: str, templateData: str, updateType: int = 0) -> str:
def updateTemplate(
self, templateId: str, templateData: str, updateType: int = 0
) -> str:
"""
Updates the template with the templateXml
1.- Session string
@@ -194,7 +232,9 @@ class OpenNebulaClient: # pylint: disable=too-many-public-methods
3.- The new template contents. Syntax can be the usual attribute=value or XML.
4.- Update type. 0 replace the whole template, 1 merge with the existing one
"""
result = self.connection.one.template.update(self.sessionString, int(templateId), templateData, int(updateType))
result = self.connection.one.template.update(
self.sessionString, int(templateId), templateData, int(updateType)
)
return checkResultRaw(result)
@ensureConnected
@@ -202,10 +242,14 @@ class OpenNebulaClient: # pylint: disable=too-many-public-methods
"""
Clones the template
"""
if self.version[0] == '4':
result = self.connection.one.template.clone(self.sessionString, int(templateId), name)
if self.version[0] == '4': # type: ignore
result = self.connection.one.template.clone(
self.sessionString, int(templateId), name
)
else:
result = self.connection.one.template.clone(self.sessionString, int(templateId), name, False) # This works as previous version clone
result = self.connection.one.template.clone(
self.sessionString, int(templateId), name, False
) # This works as previous version clone
return checkResultRaw(result)
@@ -214,15 +258,21 @@ class OpenNebulaClient: # pylint: disable=too-many-public-methods
"""
Deletes the template (not images)
"""
result = self.connection.one.template.delete(self.sessionString, int(templateId))
result = self.connection.one.template.delete(
self.sessionString, int(templateId)
)
return checkResultRaw(result)
@ensureConnected
def cloneImage(self, srcId: str, name: str, datastoreId: typing.Union[str, int] = -1) -> str:
def cloneImage(
self, srcId: str, name: str, datastoreId: typing.Union[str, int] = -1
) -> str:
"""
Clones the image.
"""
result = self.connection.one.image.clone(self.sessionString, int(srcId), name, int(datastoreId))
result = self.connection.one.image.clone(
self.sessionString, int(srcId), name, int(datastoreId)
)
return checkResultRaw(result)
@ensureConnected
@@ -230,7 +280,9 @@ class OpenNebulaClient: # pylint: disable=too-many-public-methods
"""
Clones the image.
"""
result = self.connection.one.image.persistent(self.sessionString, int(imageId), persistent)
result = self.connection.one.image.persistent(
self.sessionString, int(imageId), persistent
)
return checkResultRaw(result)
@ensureConnected
@@ -248,7 +300,9 @@ class OpenNebulaClient: # pylint: disable=too-many-public-methods
first element is a dictionary (built from XML)
second is original XML
"""
result, xml = checkResult(self.connection.one.image.info(self.sessionString, int(imageInfo)))
result, xml = checkResult(
self.connection.one.image.info(self.sessionString, int(imageInfo))
)
ds = result['IMAGE']
return types.ImageType(
ds['ID'],
@@ -257,7 +311,7 @@ class OpenNebulaClient: # pylint: disable=too-many-public-methods
ds.get('PERSISTENT', '0') != '0',
int(ds.get('RUNNING_VMS', '0')),
types.ImageState.fromState(ds['STATE']),
xml
xml,
)
@ensureConnected
@@ -270,10 +324,18 @@ class OpenNebulaClient: # pylint: disable=too-many-public-methods
4.- For values >= -1 this is the Range end ID. Can be -1 to get until the last ID. For values < -1 this is the page size used for pagination.
5.- VM state to filter by. (-2 = any state including DONE, -1 = any state EXCEPT DONE)
"""
result, _ = checkResult(self.connection.one.vmpool.info(self.sessionString, -1, -1, -1, -1))
result, _ = checkResult(
self.connection.one.vmpool.info(self.sessionString, -1, -1, -1, -1)
)
if result['VM_POOL']:
for ds in asIterable(result['VM_POOL'].get('VM', [])):
yield types.VirtualMachineType(ds['ID'], ds['NAME'], int(ds.get('MEMORY', '0')), types.VmState.fromState(ds['STATE']), None)
yield types.VirtualMachineType(
ds['ID'],
ds['NAME'],
int(ds.get('MEMORY', '0')),
types.VmState.fromState(ds['STATE']),
None,
)
@ensureConnected
def VMInfo(self, vmId: str) -> types.VirtualMachineType:
@@ -282,16 +344,24 @@ class OpenNebulaClient: # pylint: disable=too-many-public-methods
first element is a dictionary (built from XML)
second is original XML
"""
result, xml = checkResult(self.connection.one.vm.info(self.sessionString, int(vmId)))
result, xml = checkResult(
self.connection.one.vm.info(self.sessionString, int(vmId))
)
ds = result['VM']
return types.VirtualMachineType(ds['ID'], ds['NAME'], int(ds.get('MEMORY', '0')), types.VmState.fromState(ds['STATE']), xml)
return types.VirtualMachineType(
ds['ID'],
ds['NAME'],
int(ds.get('MEMORY', '0')),
types.VmState.fromState(ds['STATE']),
xml,
)
@ensureConnected
def deleteVM(self, vmId: str) -> str:
"""
Deletes an vm
"""
if self.version[0] == '4':
if self.version[0] == '4': # type: ignore
return self.VMAction(vmId, 'delete')
# Version 5

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2012-2019 Virtual Cable S.L.
# Copyright (c) 2012-2021 Virtual Cable S.L.U.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
@@ -12,7 +12,7 @@
# * 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
# * 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.
#

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,42 +0,0 @@
# -*- 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. 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
"""
# Disabled OLD NX. Will be removed soon
# from django.utils.translation import ugettext_noop as _
# from uds.core.managers.user_preferences import UserPrefsManager, CommonPrefs
# from uds.core.util.config import Config
# from .nxtransport import NXTransport
# from .nxtunneltransport import TSNXTransport
# Config.section('NX').value('downloadUrl', 'http://sourceforge.net/projects/opennx/files/opennx/CI-win32/OpenNX-0.16.0.725-Setup.exe/download').get()
# Config.section('NX').value('downloadUrlMACOS', 'http://opennx.net/download.html').get()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

View File

@@ -1,74 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2012-2019 Virtual Cable S.L.
# 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.
'''
Created on Apr 29, 2019
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
import os
import logging
import typing
from uds.core import transports
# Not imported at runtime, just for type checking
if typing.TYPE_CHECKING:
from uds import models
logger = logging.getLogger(__name__)
READY_CACHE_TIMEOUT = 30
class BaseNXTransport(transports.Transport):
_listenPort: str = ''
def isAvailableFor(self, userService: 'models.UserService', ip: str) -> bool:
"""
Checks if the transport is available for the requested destination ip
Override this in yours transports
"""
logger.debug('Checking availability for %s', ip)
ready = self.cache.get(ip)
if not ready:
# Check again for readyness
if self.testServer(userService, ip, self._listenPort) is True:
self.cache.put(ip, 'Y', READY_CACHE_TIMEOUT)
return True
self.cache.put(ip, 'N', READY_CACHE_TIMEOUT)
return ready == 'Y'
def getScript(self, scriptNameTemplate: str, osName: str, params: typing.Dict[str, typing.Any]) -> typing.Tuple[str, str, typing.Dict[str, typing.Any]]:
# Reads script
scriptNameTemplate = scriptNameTemplate.format(osName)
with open(os.path.join(os.path.dirname(__file__), scriptNameTemplate)) as f:
script = f.read()
# Reads signature
with open(os.path.join(os.path.dirname(__file__), scriptNameTemplate + '.signature')) as f:
signature = f.read()
return script, signature, params

View File

@@ -1,220 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2012-2019 Virtual Cable S.L.
# 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.
"""
Created on Jul 29, 2011
@author: Adolfo Gómez, dkmaster at dkmon dot com
"""
from .nxpassword import NXPassword
EMPTY_PASSWORD = "EMPTY_PASSWORD"
NXTEMPLATE = (
"<!DOCTYPE NXClientSettings>\n"
"<NXClientSettings application=\"nxclient\" version=\"1.3\" >\n"
" <group name=\"Advanced\" >\n"
" <option key=\"Cache size\" value=\"{CACHEMEM}\" />\n"
" <option key=\"Cache size on disk\" value=\"{CACHEDISK}\" />\n"
" <option key=\"Current keyboard\" value=\"true\" />\n"
" <option key=\"Custom keyboard layout\" value=\"{KEYLAYOUT}\" />\n"
" <option key=\"Disable ZLIB stream compression\" value=\"false\" />\n"
" <option key=\"Disable TCP no-delay\" value=\"false\" />\n" +
" <option key=\"Disable deferred updates\" value=\"false\" />\n"
" <option key=\"Enable HTTP proxy\" value=\"false\" />\n"
" <option key=\"Enable SSL encryption\" value=\"true\" />\n"
" <option key=\"Enable response time optimisations\" value=\"true\" />\n"
" <option key=\"Grab keyboard\" value=\"false\" />\n"
" <option key=\"HTTP proxy host\" value=\"\" />\n"
" <option key=\"HTTP proxy port\" value=\"8080\" />\n"
" <option key=\"HTTP proxy username\" value=\"\" />\n"
" <option key=\"Remember HTTP proxy password\" value=\"false\" />\n"
" <option key=\"Restore cache\" value=\"true\" />\n"
" <option key=\"StreamCompression\" value=\"\" />\n"
" </group>\n"
" <group name=\"Environment\" >\n"
" <option key=\"Font server host\" value=\"\" />\n"
" <option key=\"Font server port\" value=\"7100\" />\n"
" <option key=\"Use font server\" value=\"false\" />\n"
" </group>\n"
" <group name=\"General\" >\n"
" <option key=\"Automatic reconnect\" value=\"true\" />\n"
" <option key=\"Disable SHM\" value=\"false\" />\n"
" <option key=\"Disable emulate shared pixmaps\" value=\"false\" />\n"
" <option key=\"Link speed\" value=\"{LINKSPEED}\" />\n"
" <option key=\"Remember password\" value=\"{REMEMBERPASS}\" />\n"
" <option key=\"Resolution\" value=\"{RESOLUTION}\" />\n"
" <option key=\"Resolution width\" value=\"{WIDTH}\" />\n"
" <option key=\"Resolution height\" value=\"{HEIGHT}\" />\n"
" <option key=\"Server host\" value=\"{HOST}\" />\n"
" <option key=\"Server port\" value=\"{PORT}\" />\n"
" <option key=\"Session\" value=\"unix\" />\n"
" <option key=\"Desktop\" value=\"{DESKTOP}\" />\n"
" <option key=\"Use default image encoding\" value=\"1\" />\n"
" <option key=\"Use render\" value=\"false\" />\n"
" <option key=\"Use taint\" value=\"true\" />\n"
" <option key=\"Virtual desktop\" value=\"false\" />\n"
" <option key=\"XAgent encoding\" value=\"true\" />\n"
" <option key=\"displaySaveOnExit\" value=\"true\" />\n"
" <option key=\"xdm broadcast port\" value=\"177\" />\n"
" <option key=\"xdm list host\" value=\"localhost\" />\n"
" <option key=\"xdm list port\" value=\"177\" />\n"
" <option key=\"xdm mode\" value=\"server decide\" />\n"
" <option key=\"xdm query host\" value=\"localhost\" />\n"
" <option key=\"xdm query port\" value=\"177\" />\n"
" </group>\n"
" <group name=\"Images\" >\n"
" <option key=\"Disable JPEG Compression\" value=\"0\" />\n"
" <option key=\"Disable all image optimisations\" value=\"false\" />\n"
" <option key=\"Disable backingstore\" value=\"false\" />\n"
" <option key=\"Disable composite\" value=\"false\" />\n"
" <option key=\"Image Compression Type\" value=\"3\" />\n"
" <option key=\"Image Encoding Type\" value=\"0\" />\n"
" <option key=\"Image JPEG Encoding\" value=\"false\" />\n"
" <option key=\"JPEG Quality\" value=\"6\" />\n"
" <option key=\"RDP Image Encoding\" value=\"3\" />\n"
" <option key=\"RDP JPEG Quality\" value=\"6\" />\n"
" <option key=\"RDP optimization for low-bandwidth link\" value=\"false\" />\n"
" <option key=\"Reduce colors to\" value=\"\" />\n"
" <option key=\"Use PNG Compression\" value=\"true\" />\n"
" <option key=\"VNC JPEG Quality\" value=\"6\" />\n"
" <option key=\"VNC images compression\" value=\"3\" />\n"
" </group>\n"
" <group name=\"Login\" >\n"
" <option key=\"User\" value=\"{USERNAME}\" />\n"
" <option key=\"Auth\" value=\"{PASSWORD}\" />\n"
" <option key=\"Guest Mode\" value=\"false\" />\n"
" <option key=\"Guest password\" value=\"\" />\n"
" <option key=\"Guest username\" value=\"\" />\n"
" <option key=\"Login Method\" value=\"nx\" />\n"
" <option key=\"Public Key\" value=\"-----BEGIN DSA PRIVATE KEY-----\n"
"MIIBuwIBAAKBgQCXv9AzQXjxvXWC1qu3CdEqskX9YomTfyG865gb4D02ZwWuRU/9\n"
"C3I9/bEWLdaWgJYXIcFJsMCIkmWjjeSZyTmeoypI1iLifTHUxn3b7WNWi8AzKcVF\n"
"aBsBGiljsop9NiD1mEpA0G+nHHrhvTXz7pUvYrsrXcdMyM6rxqn77nbbnwIVALCi\n"
"xFdHZADw5KAVZI7r6QatEkqLAoGBAI4L1TQGFkq5xQ/nIIciW8setAAIyrcWdK/z\n"
"5/ZPeELdq70KDJxoLf81NL/8uIc4PoNyTRJjtT3R4f8Az1TsZWeh2+ReCEJxDWgG\n"
"fbk2YhRqoQTtXPFsI4qvzBWct42WonWqyyb1bPBHk+JmXFscJu5yFQ+JUVNsENpY\n"
"+Gkz3HqTAoGANlgcCuA4wrC+3Cic9CFkqiwO/Rn1vk8dvGuEQqFJ6f6LVfPfRTfa\n"
"QU7TGVLk2CzY4dasrwxJ1f6FsT8DHTNGnxELPKRuLstGrFY/PR7KeafeFZDf+fJ3\n"
"mbX5nxrld3wi5titTnX+8s4IKv29HJguPvOK/SI7cjzA+SqNfD7qEo8CFDIm1xRf\n"
"8xAPsSKs6yZ6j1FNklfu\n"
"-----END DSA PRIVATE KEY-----\n"
"\" />\n"
" </group>\n"
" <group name=\"Services\" >\n"
" <option key=\"Audio\" value=\"true\" />\n"
" <option key=\"IPPPort\" value=\"631\" />\n"
" <option key=\"IPPPrinting\" value=\"false\" />\n"
" <option key=\"Shares\" value=\"false\" />\n"
" </group>\n"
" <group name=\"VNC Session\" >\n"
" <option key=\"Display\" value=\"0\" />\n"
" <option key=\"Remember\" value=\"false\" />\n"
" <option key=\"Server\" value=\"\" />\n"
" </group>\n"
" <group name=\"Windows Session\" >\n"
" <option key=\"Application\" value=\"\" />\n"
" <option key=\"Authentication\" value=\"2\" />\n"
" <option key=\"Color Depth\" value=\"16\" />\n"
" <option key=\"Domain\" value=\"\" />\n"
" <option key=\"Image Cache\" value=\"true\" />\n"
" <option key=\"Password\" value=\"EMPTY_PASSWORD\" />\n"
" <option key=\"Remember\" value=\"true\" />\n"
" <option key=\"Run application\" value=\"false\" />\n"
" <option key=\"Server\" value=\"\" />\n"
" <option key=\"User\" value=\"\" />\n"
" </group>\n"
" <group name=\"share chosen\" >\n"
" <option key=\"Share number\" value=\"0\" />\n"
" </group>\n"
"</NXClientSettings>"
)
class NXFile:
fullScreen: bool = False
width: int = 800
height: int = 600
cachemem: str = '4'
cachedisk: str = '32'
keyboardLayout: str = ''
linkSpeed: str = 'wan'
host: str = ''
port: str = ''
username: str = ''
password: str = ''
desktop: str = 'gnome'
def __init__(self, username: str = '', password: str = '', width: int = 1024, height: int = 768):
self.fullScreen = width == -1 or height == -1
self.width = int(width)
self.height = int(height)
self.username = username
self.password = password
@property
def as_file(self):
return self.get()
@property
def as_file_for_format(self):
return self.get(True)
def get(self, processPassword=False):
rememberPass = 'true'
password = NXPassword.scrambleString(self.password)
if processPassword:
password = password.replace('{', '{{')
password = password.replace('}', '}}')
if password == '':
rememberPass = "false"
password = EMPTY_PASSWORD
resolution = '{}x{}'.format(self.width, self.height)
if self.fullScreen:
resolution = "fullscreen"
return NXTEMPLATE.format(
CACHEMEM=self.cachemem,
CACHEDISK=self.cachedisk,
KEYLAYOUT=self.keyboardLayout,
LINKSPEED=self.linkSpeed,
REMEMBERPASS=rememberPass,
RESOLUTION=resolution,
WIDTH=self.width,
HEIGHT=self.height,
HOST=self.host,
PORT=self.port,
DESKTOP=self.desktop,
USERNAME=self.username,
PASSWORD=password
)

View File

@@ -1,110 +0,0 @@
# -*- 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. 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.
"""
Created on Apr 20, 2015
@author: Adolfo Gómez, dkmaster at dkmon dot com
"""
class NXPassword: # pylint: disable=too-few-public-methods
# Encoding method extracted from nomachine web site:
# http://www.nomachine.com/ar/view.php?ar_id=AR01C00125
dummyString = "{{{{"
numValidCharList = 85
validCharList = [
'!', '#', '$', '%', '&', '(', ')', '*', '+', '-',
'.', '0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', ':', ';', '<', '>', '?', '@', 'A', 'B', 'C',
'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
'X', 'Y', 'Z', '[', ']', '_', 'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z', '{', '|', '}'
]
@staticmethod
def _encodePassword(p):
sPass = ':'
if p == '':
return ''
for i, ch in enumerate(p):
sPass += '{}:'.format(ord(ch) + i + 1)
return sPass
@staticmethod
def _findCharInList(c):
try:
return NXPassword.validCharList.index(c)
except ValueError:
return -1
@staticmethod
def _getRandomValidCharFromList():
# k = random.randint(0, NXPassword.numValidCharList)
k = 0
return NXPassword.validCharList[k]
@staticmethod
def scrambleString(s):
if s is None or s == '':
return ''
_str = NXPassword._encodePassword(s)
if len(_str) < 32:
_str += NXPassword.dummyString
password = _str[::-1] # Reversed string
if len(password) < 32:
password += NXPassword.dummyString
startChar = NXPassword._getRandomValidCharFromList()
l = ord(startChar) + len(password) - 2
pw = startChar
for i1, ch in enumerate(password):
j = NXPassword._findCharInList(ch)
if j == -1:
return s
i = (j + l * (i1 + 2)) % NXPassword.numValidCharList
pw += NXPassword.validCharList[i]
pw += chr(ord(NXPassword._getRandomValidCharFromList()) + 2)
return pw.replace('&', '&amp;').replace('<', '&lt;').replace('"', '&quot;').replace('\'', '&apos;') # .replace('$', '\\$')

View File

@@ -1,243 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2012-2019 Virtual Cable S.L.
# 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.
"""
Created on Jul 29, 2011
@author: Adolfo Gómez, dkmaster at dkmon dot com
"""
import logging
import typing
from django.utils.translation import ugettext_noop as _, ugettext_lazy
from uds.core.managers.user_preferences import CommonPrefs
from uds.core.ui import gui
from uds.core import transports
from uds.core.util import os_detector as OsDetector
from .nxbase import BaseNXTransport
from .nxfile import NXFile
# Not imported at runtime, just for type checking
if typing.TYPE_CHECKING:
from uds.core import Module
from uds import models
from django.http import HttpRequest # pylint: disable=ungrouped-imports
logger = logging.getLogger(__name__)
READY_CACHE_TIMEOUT = 30
class NXTransport(BaseNXTransport):
"""
Provides access via NX to service.
This transport can use an domain. If username processed by authenticator contains '@', it will split it and left-@-part will be username, and right password
"""
typeName = _('NX v3.5 (DEPRECATED)')
typeType = 'NXTransport'
typeDescription = _('NX Protocol v3.5. Direct connection.')
iconFile = 'nx.png'
protocol = transports.protocols.NX
useEmptyCreds = gui.CheckBoxField(label=_('Empty creds'), order=1, tooltip=_('If checked, the credentials used to connect will be emtpy'), tab=gui.CREDENTIALS_TAB)
fixedName = gui.TextField(label=_('Username'), order=2, tooltip=_('If not empty, this username will be always used as credential'), tab=gui.CREDENTIALS_TAB)
fixedPassword = gui.PasswordField(label=_('Password'), order=3, tooltip=_('If not empty, this password will be always used as credential'), tab=gui.CREDENTIALS_TAB)
listenPort = gui.NumericField(label=_('Listening port'), length=5, order=4, tooltip=_('Listening port of NX (ssh) at client machine'), defvalue='22')
connection = gui.ChoiceField(
label=_('Connection'),
order=6,
tooltip=_('Connection speed for this transport (quality)'),
values=[
{'id': 'modem', 'text': 'modem'},
{'id': 'isdn', 'text': 'isdn'},
{'id': 'adsl', 'text': 'adsl'},
{'id': 'wan', 'text': 'wan'},
{'id': 'lan', 'text': 'lan'}
],
tab=gui.PARAMETERS_TAB
)
session = gui.ChoiceField(
label=_('Session'),
order=7,
tooltip=_('Desktop session'),
values=[
{'id': 'gnome', 'text': 'gnome'},
{'id': 'kde', 'text': 'kde'},
{'id': 'cde', 'text': 'cde'},
],
tab=gui.PARAMETERS_TAB
)
cacheDisk = gui.ChoiceField(
label=_('Disk Cache'),
order=8,
tooltip=_('Cache size en Mb stored at disk'),
values=[
{'id': '0', 'text': '0 Mb'},
{'id': '32', 'text': '32 Mb'},
{'id': '64', 'text': '64 Mb'},
{'id': '128', 'text': '128 Mb'},
{'id': '256', 'text': '256 Mb'},
{'id': '512', 'text': '512 Mb'},
],
tab=gui.PARAMETERS_TAB
)
cacheMem = gui.ChoiceField(
label=_('Memory Cache'),
order=9,
tooltip=_('Cache size en Mb kept at memory'),
values=[
{'id': '4', 'text': '4 Mb'},
{'id': '8', 'text': '8 Mb'},
{'id': '16', 'text': '16 Mb'},
{'id': '32', 'text': '32 Mb'},
{'id': '64', 'text': '64 Mb'},
{'id': '128', 'text': '128 Mb'},
],
tab=gui.PARAMETERS_TAB
)
screenSize = gui.ChoiceField(
label=_('Screen size'),
order=10,
tooltip=_('Screen size'),
defvalue=CommonPrefs.SZ_FULLSCREEN,
values=[
{'id': CommonPrefs.SZ_640x480, 'text': '640x480'},
{'id': CommonPrefs.SZ_800x600, 'text': '800x600'},
{'id': CommonPrefs.SZ_1024x768, 'text': '1024x768'},
{'id': CommonPrefs.SZ_1366x768, 'text': '1366x768'},
{'id': CommonPrefs.SZ_1920x1080, 'text': '1920x1080'},
{'id': CommonPrefs.SZ_FULLSCREEN, 'text': ugettext_lazy('Full Screen')}
],
tab=gui.PARAMETERS_TAB
)
_useEmptyCreds: bool = False
_fixedName: str = ''
_fixedPassword: str = ''
_listenPort: str = ''
_connection: str = ''
_session: str = ''
_cacheDisk: str = ''
_cacheMem: str = ''
_screenSize: str = ''
def initialize(self, values: 'Module.ValuesType'):
if values:
self._useEmptyCreds = gui.strToBool(values['useEmptyCreds'])
self._fixedName = values['fixedName']
self._fixedPassword = values['fixedPassword']
self._listenPort = values['listenPort']
self._connection = values['connection']
self._session = values['session']
self._cacheDisk = values['cacheDisk']
self._cacheMem = values['cacheMem']
self._screenSize = values['screenSize']
def marshal(self) -> bytes:
"""
Serializes the transport data so we can store it in database
"""
return str.join('\t', [
'v2', gui.boolToStr(self._useEmptyCreds), self._fixedName, self._fixedPassword, self._listenPort,
self._connection, self._session, self._cacheDisk, self._cacheMem, self._screenSize
]).encode('utf8')
def unmarshal(self, data: bytes) -> None:
values = data.decode('utf8').split('\t')
if values[0] in ('v1', 'v2'):
self._useEmptyCreds = gui.strToBool(values[1])
self._fixedName, self._fixedPassword, self._listenPort, self._connection, self._session, self._cacheDisk, self._cacheMem = values[2:9]
self._screenSize = values[9] if values[0] == 'v2' else CommonPrefs.SZ_FULLSCREEN
def valuesDict(self) -> gui.ValuesDictType:
return {
'useEmptyCreds': gui.boolToStr(self._useEmptyCreds),
'fixedName': self._fixedName,
'fixedPassword': self._fixedPassword,
'listenPort': self._listenPort,
'connection': self._connection,
'session': self._session,
'cacheDisk': self._cacheDisk,
'cacheMem': self._cacheMem
}
def getUDSTransportScript( # pylint: disable=too-many-locals
self,
userService: 'models.UserService',
transport: 'models.Transport',
ip: str,
os: typing.Dict[str, str],
user: 'models.User',
password: str,
request: 'HttpRequest'
) -> typing.Tuple[str, str, typing.Mapping[str, typing.Any]]:
username = user.getUsernameForAuth()
proc = username.split('@')
username = proc[0]
if self._fixedName:
username = self._fixedName
if self._fixedPassword:
password = self._fixedPassword
if self._useEmptyCreds:
username, password = '', ''
# We have the credentials right now, let os manager
width, height = CommonPrefs.getWidthHeight(self._screenSize)
# Fix username/password acording to os manager
username, password = userService.processUserPassword(username, password)
r = NXFile(username=username, password=password, width=width, height=height)
r.host = ip
r.port = self._listenPort
r.linkSpeed = self._connection
r.desktop = self._session
r.cachedisk = self._cacheDisk
r.cachemem = self._cacheMem
osName = {
OsDetector.Windows: 'windows',
OsDetector.Linux: 'linux',
OsDetector.Macintosh: 'macosx'
}.get(os['OS'])
if osName is None:
return super().getUDSTransportScript(userService, transport, ip, os, user, password, request)
sp = {
'as_file': r.as_file,
}
return self.getScript('scripts/{}/direct.py', osName, sp)

View File

@@ -1,359 +0,0 @@
# -*- 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. 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.
"""
Created on Jul 29, 2011
@author: Adolfo Gómez, dkmaster at dkmon dot com
"""
import random
import string
import logging
import typing
from django.utils.translation import ugettext_noop as _, ugettext_lazy
from uds.core.managers.user_preferences import CommonPrefs
from uds.core.ui import gui
from uds.core import transports
from uds.models import TicketStore
from uds.core.util import os_detector as OsDetector
from .nxfile import NXFile
from .nxbase import BaseNXTransport
logger = logging.getLogger(__name__)
# Not imported at runtime, just for type checking
if typing.TYPE_CHECKING:
from uds.core import Module
from uds import models
from django.http import HttpRequest # pylint: disable=ungrouped-imports
class TSNXTransport(BaseNXTransport):
"""
Provides access via NX to service.
This transport can use an domain. If username processed by authenticator contains '@', it will split it and left-@-part will be username, and right password
"""
typeName = _('NX v3.5 (DEPRECATED)')
typeType = 'TSNXTransport'
typeDescription = _('NX protocol v3.5. Tunneled connection.')
iconFile = 'nx.png'
protocol = transports.protocols.NX
group = transports.TUNNELED_GROUP
tunnelServer = gui.TextField(
label=_('Tunnel server'),
order=1,
tooltip=_(
'IP or Hostname of tunnel server sent to client device ("public" ip) and port. (use HOST:PORT format)'
),
tab=gui.TUNNEL_TAB,
)
tunnelWait = gui.NumericField(
length=3,
label=_('Tunnel wait time'),
defvalue='30',
minValue=5,
maxValue=3600 * 24,
order=2,
tooltip=_('Maximum time to wait before closing the tunnel listener'),
required=True,
tab=gui.TUNNEL_TAB,
)
verifyCertificate = gui.CheckBoxField(
label=_('Force SSL certificate verification'),
order=23,
tooltip=_(
'If enabled, the certificate of tunnel server will be verified (recommended).'
),
defvalue=gui.FALSE,
tab=gui.TUNNEL_TAB,
)
useEmptyCreds = gui.CheckBoxField(
label=_('Empty creds'),
order=3,
tooltip=_('If checked, the credentials used to connect will be emtpy'),
tab=gui.CREDENTIALS_TAB,
)
fixedName = gui.TextField(
label=_('Username'),
order=4,
tooltip=_('If not empty, this username will be always used as credential'),
tab=gui.CREDENTIALS_TAB,
)
fixedPassword = gui.PasswordField(
label=_('Password'),
order=5,
tooltip=_('If not empty, this password will be always used as credential'),
tab=gui.CREDENTIALS_TAB,
)
listenPort = gui.NumericField(
label=_('Listening port'),
length=5,
order=6,
tooltip=_('Listening port of NX (ssh) at client machine'),
defvalue='22',
)
connection = gui.ChoiceField(
label=_('Connection'),
order=7,
tooltip=_('Connection speed for this transport (quality)'),
values=[
{'id': 'modem', 'text': 'modem'},
{'id': 'isdn', 'text': 'isdn'},
{'id': 'adsl', 'text': 'adsl'},
{'id': 'wan', 'text': 'wan'},
{'id': 'lan', 'text': 'lan'},
],
tab=gui.PARAMETERS_TAB,
)
session = gui.ChoiceField(
label=_('Session'),
order=8,
tooltip=_('Desktop session'),
values=[
{'id': 'gnome', 'text': 'gnome'},
{'id': 'kde', 'text': 'kde'},
{'id': 'cde', 'text': 'cde'},
],
tab=gui.PARAMETERS_TAB,
)
cacheDisk = gui.ChoiceField(
label=_('Disk Cache'),
order=9,
tooltip=_('Cache size en Mb stored at disk'),
values=[
{'id': '0', 'text': '0 Mb'},
{'id': '32', 'text': '32 Mb'},
{'id': '64', 'text': '64 Mb'},
{'id': '128', 'text': '128 Mb'},
{'id': '256', 'text': '256 Mb'},
{'id': '512', 'text': '512 Mb'},
],
tab=gui.PARAMETERS_TAB,
)
cacheMem = gui.ChoiceField(
label=_('Memory Cache'),
order=10,
tooltip=_('Cache size en Mb kept at memory'),
values=[
{'id': '4', 'text': '4 Mb'},
{'id': '8', 'text': '8 Mb'},
{'id': '16', 'text': '16 Mb'},
{'id': '32', 'text': '32 Mb'},
{'id': '64', 'text': '64 Mb'},
{'id': '128', 'text': '128 Mb'},
],
tab=gui.PARAMETERS_TAB,
)
screenSize = gui.ChoiceField(
label=_('Screen size'),
order=10,
tooltip=_('Screen size'),
defvalue=CommonPrefs.SZ_FULLSCREEN,
values=[
{'id': CommonPrefs.SZ_640x480, 'text': '640x480'},
{'id': CommonPrefs.SZ_800x600, 'text': '800x600'},
{'id': CommonPrefs.SZ_1024x768, 'text': '1024x768'},
{'id': CommonPrefs.SZ_1366x768, 'text': '1366x768'},
{'id': CommonPrefs.SZ_1920x1080, 'text': '1920x1080'},
{'id': CommonPrefs.SZ_FULLSCREEN, 'text': ugettext_lazy('Full Screen')},
],
tab=gui.PARAMETERS_TAB,
)
_tunnelServer: str = ''
_tunnelCheckServer: str = ''
_useEmptyCreds: bool = False
_fixedName: str = ''
_fixedPassword: str = ''
_listenPort: str = ''
_connection: str = ''
_session: str = ''
_cacheDisk: str = ''
_cacheMem: str = ''
_screenSize: str = ''
_tunnelWait: int = 30
_verifyCertificate: bool = False
def initialize(self, values: 'Module.ValuesType'):
if values:
if values['tunnelServer'].find(':') == -1:
raise transports.Transport.ValidationException(
_('Must use HOST:PORT in Tunnel Server Field')
)
self._tunnelServer = values['tunnelServer']
self._tunnelWait = int(values['tunnelWait'])
self._verifyCertificate = gui.strToBool(values['verifyCertificate'])
self._tunnelCheckServer = ''
self._useEmptyCreds = gui.strToBool(values['useEmptyCreds'])
self._fixedName = values['fixedName']
self._fixedPassword = values['fixedPassword']
self._listenPort = values['listenPort']
self._connection = values['connection']
self._session = values['session']
self._cacheDisk = values['cacheDisk']
self._cacheMem = values['cacheMem']
self._screenSize = values['screenSize']
def marshal(self) -> bytes:
"""
Serializes the transport data so we can store it in database
"""
val = str.join(
'\t',
[
'v3',
gui.boolToStr(self._useEmptyCreds),
self._fixedName,
self._fixedPassword,
self._listenPort,
self._connection,
self._session,
self._cacheDisk,
self._cacheMem,
self._tunnelServer,
self._tunnelCheckServer,
self._screenSize,
str(self._tunnelWait),
gui.boolToStr(self._verifyCertificate),
],
)
logger.debug('Values: %s', val)
return val.encode('utf8')
def unmarshal(self, data: bytes) -> None:
values = data.decode('utf8').split('\t')
if values[0] in ('v1', 'v2', 'v3'):
self._useEmptyCreds = gui.strToBool(values[1])
(
self._fixedName,
self._fixedPassword,
self._listenPort,
self._connection,
self._session,
self._cacheDisk,
self._cacheMem,
self._tunnelServer,
self._tunnelCheckServer,
) = values[2:11]
self._screenSize = (
values[11] if values[0] == 'v2' else CommonPrefs.SZ_FULLSCREEN
)
if values[0] == 'v3':
self._tunnelWait, self._verifyCertificate = (
int(values[12]),
gui.strToBool(values[13]),
)
def valuesDict(self) -> gui.ValuesDictType:
return {
'useEmptyCreds': gui.boolToStr(self._useEmptyCreds),
'fixedName': self._fixedName,
'fixedPassword': self._fixedPassword,
'listenPort': self._listenPort,
'connection': self._connection,
'session': self._session,
'cacheDisk': self._cacheDisk,
'cacheMem': self._cacheMem,
'tunnelServer': self._tunnelServer,
'tunnelWait': str(self._tunnelWait),
'verifyCertificate': gui.boolToStr(self._verifyCertificate),
}
def getUDSTransportScript( # pylint: disable=too-many-locals
self,
userService: 'models.UserService',
transport: 'models.Transport',
ip: str,
os: typing.Dict[str, str],
user: 'models.User',
password: str,
request: 'HttpRequest',
) -> typing.Tuple[str, str, typing.Mapping[str, typing.Any]]:
prefs = self.screenSize.value
username = user.getUsernameForAuth()
proc = username.split('@')
username = proc[0]
if self._fixedName is not '':
username = self._fixedName
if self._fixedPassword is not '':
password = self._fixedPassword
if self._useEmptyCreds is True:
usernamsizerd = '', ''
ticket = TicketStore.create_for_tunnel(
userService=userService,
port=int(self._listenPort),
validity=self._tunnelWait + 60, # Ticket overtime
)
tunHost, tunPort = self.tunnelServer.value.split(':')
width, height = CommonPrefs.getWidthHeight(prefs)
# Fix username/password acording to os manager
username, password = userService.processUserPassword(username, password)
r = NXFile(username=username, password=password, width=width, height=height)
r.host = '{address}'
r.port = '{port}'
r.linkSpeed = self._connection
r.desktop = self._session
r.cachedisk = self._cacheDisk
r.cachemem = self._cacheMem
osName = {
OsDetector.Windows: 'windows',
OsDetector.Linux: 'linux',
OsDetector.Macintosh: 'macosx',
}.get(os['OS'])
if osName is None:
return super().getUDSTransportScript(
userService, transport, ip, os, user, password, request
)
sp = {
'ip': ip,
'tunHost': tunHost,
'tunPort': tunPort,
'tunWait': self._tunnelWait,
'tunChk': self._verifyCertificate,
'ticket': ticket,
'as_file_for_format': r.as_file_for_format,
}
return self.getScript('scripts/{}/tunnel.py', osName, sp)

View File

@@ -1,23 +0,0 @@
# This is a template
# Saved as .py for easier editing
from __future__ import unicode_literals
# pylint: disable=import-error, no-name-in-module, undefined-variable
import subprocess
from uds import tools # type: ignore
try:
cmd = tools.findApp('nxclient', ['/usr/NX/bin/'])
if cmd is None:
raise Exception()
except Exception:
raise Exception('''<p>You need to have installed NX Client version 3.5 in order to connect to this UDS service.</p>
<p>Please, install appropriate package for your system.</p>
''')
filename = tools.saveTempFile(sp['as_file']) # type: ignore
tools.addTaskToWait(subprocess.Popen([cmd, '--session', filename]))
tools.addFileToUnlink(filename)

View File

@@ -1 +0,0 @@
DyRlBsF1FK0/lXx/GVmKZNpnXh4sS0sdQJ4eKKDbEvzUeU1OKAAyONpvtpk9SKYHDKcvriiynp+kAE690XFYjPnaVrYc8BenjLVqcvlv7hLzc1kvNVmJve9RtVYOfIFCPfQN3sGseREV4aQ7JBuN4T+Paw8j+6YmeborIAfrmfFUhtx5IdUjF5SUnLAok+3aaJCOpKItRIxg4zxp9VfGdnF39KqTWLrgscX9mxe5YEc9DzQTpUm6bw7eUjG4OiloeMwXTxK3/tXEsEDTFF40w0NlSMOOmIQSWTUfhjDzwx9dJX4mE8mtOOO2U//cxGQ4DOQDoRHLIjwC0auKumjKrvdMzYU8H2tLmJwarRS43fu58Ir0NRydolB9vuRSA7aGziK+TtwYpKOUlge/7BY26lIANlCsnGnPvyT52UZXxILUkmHGCt98lMnJ2I+zXYIkjj8jvP02/eQuCdYWIS55ou1JJKGTazgn5Nu6cPMn6mAL20vWd3t8eUwU5F8KNavCcal903tDn2gen6QRf28ZVEWmEVc7vl4p9+iDkAZT855tVHHt4gz45C8XrwMBFBNZ1iiJtnzCiRsWAfoALJfJH9+gyKywZa67lQZWlmUnEDBqj/WT61+NJHPIFO+74xgdTEyfbeLWJjz6ecFa+TQcAiTGIqdTZmzu640kthQYBfs=

View File

@@ -1,36 +0,0 @@
# This is a template
# Saved as .py for easier editing
from __future__ import unicode_literals
# pylint: disable=import-error, no-name-in-module, undefined-variable
import subprocess
from uds.tunnel import forward # type: ignore
from uds import tools # type: ignore
try:
cmd = tools.findApp('nxclient', ['/usr/NX/bin/'])
if cmd is None:
raise Exception()
except Exception:
raise Exception('''<p>You need to have installed NX Client version 3.5 in order to connect to this UDS service.</p>
<p>Please, install appropriate package for your system.</p>
''')
# Open tunnel
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
# Check that tunnel works..
if fs.check() is False:
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
theFile = sp['as_file_for_format'].format( # type: ignore
address='127.0.0.1',
port=fs.server_address[1]
)
filename = tools.saveTempFile(theFile)
cmd = cmd.replace('%1', filename)
tools.addTaskToWait(subprocess.Popen([cmd, '--session', filename]))
tools.addFileToUnlink(filename)

View File

@@ -1 +0,0 @@
EFxcQ0pD5IdbGBhlBdULIIPckwR0BlC2XQpWmxUngQlK/qe2s9CleQBjTcGyp6SSzy7uc6osweHA1b9N4o4opodLI0mD5X3H5+cP/92HsKcBT1QPRh1S8i+hGyGa5WO/fxdpeIM0rco9OcFDx9iloRbxCN0op3GJe3X0DwtS89r0MwaMs3rz7A913geshVGmJ/5oZM+EXf/kD6oGTRVkRagqeNkpB+Aup0LxhVET5EO6tY5TBDd2TvgCSBOqOkcA5vtavcxxb5As20lgl5/UsYDpCXuz7gGyq4EKn0nDSYHYiFeqsyJgaXWqdWW9rVQpGl8qjbm/Ndc2bC3s/3Q8bDgEjev0EQjKQ6oMUtdOJNJ89fP9TEd8Y0UKocBZRsGMxvQdcFN4Q5jMzplPcP9F3VuaCvA9W+uLZ/b1EvFPFdLrDBLhUsgUiWNoEQCqpG7FG+qz3dy0oVkmAZs9ewI6/oOxE+KaTs7uJv1mIbWpJEWhvLwzMg6j6jPSsV4bu9kbtjr3dBFwTNI5EsaW9vP9NeEg2hqD6vBOrlw4PB9SWIPBdFX0tPsT4tAgJxaUx13OepO7DWTItzA6EjT/be3BIUSJPoJuCJA7nxGj/ZOFqN4grmAlMKa8JXq8L/6++Jtqf+iSNgZjD+5cxC5j9M4yRlsBTFQaQhf+OnawjxAd1a4=

View File

@@ -1,21 +0,0 @@
# This is a template
# Saved as .py for easier editing
from __future__ import unicode_literals
# pylint: disable=import-error, no-name-in-module, too-many-format-args, undefined-variable, invalid-sequence-index
import subprocess
import os
from uds import tools # type: ignore
cmd = '/Applications/OpenNX/OpenNX.app/Contents/MacOS/OpenNXapp'
if os.path.isfile(cmd) is False:
raise Exception('''<p>You need to have installed Open NX Client in order to connect to this UDS service.</p>
<p>Please, install appropriate package for your system from <a href="http://www.opennx.net/">here</a>.</p>
''')
filename = tools.saveTempFile(sp['as_file']) # type: ignore
tools.addTaskToWait(subprocess.Popen([cmd, '--session={{}}'.format(filename), '--autologin', '--killerrors'])) # type: ignore
tools.addFileToUnlink(filename)

View File

@@ -1 +0,0 @@
hgPD0KnclF5OpaW4tIs+6pWX5tLeactCv1MGI1bk942nHoS4c/Nm87qd5dkHek51UMm1s8o2eB7xdrkJ6CVi/eOf2jnEs63luF+etmdwccHQU9BcQZjev1aId4q0q7HiQCXjXaS2vorIevH9uvf1NWl6AyPABynYhC7zvWb9nz/GTNBXO7TAqfVarGJLRXwY2KHpBXqUKEPB0H46+h3S9AWD2pHxfZnVBKdjoGgrD5/pt905aI2lrl1yCE14LFENkpssH/dBxYnaEMMYiWTuAe3lAP8MQEFlWmHBT63G7xMhDR3wc2sqC2eh8RQieEj1EoqCPLJFwMoxA1SZfS+JLhppskdJi06o+pqiJ4bzO0Is47plGn+KBodBAT+5/dOgOK/lKv+7Q8j3MS59TQUFty4TkybS6Ujk40SjlOlCwofVb6awKMSUSny853K20yKClt0gGhUjykstex3/eaXmU7hWLBBbDsFmY5W7Xhvxi1vPmrJ3uJ2M+R9WIeCM4xygLQPcMkZbY2k1bonv3NhK+AlapmY36y3IBbziL1Xv4agjRAykls3y+qrxMjE4Lx4ZUAI0OdX7COqdz7Ix7baYpMHrLgROjtkp/EJqVIfhvRSvJqMWLsZxbqCjoswNSI4zlyWFR980y4ITHhBsbP95X0yJnoRsgcN+wARNolxVL7o=

View File

@@ -1,34 +0,0 @@
# This is a template
# Saved as .py for easier editing
from __future__ import unicode_literals
# pylint: disable=import-error, no-name-in-module, too-many-format-args, undefined-variable, invalid-sequence-index
import subprocess
from uds.tunnel import forward # type: ignore
import os
from uds import tools # type: ignore
cmd = '/Applications/OpenNX/OpenNX.app/Contents/MacOS/OpenNXapp'
if os.path.isfile(cmd) is False:
raise Exception('''<p>You need to have installed Open NX Client in order to connect to this UDS service.</p>
<p>Please, install appropriate package for your system from <a href="http://www.opennx.net/">here</a>.</p>
''')
# Open tunnel
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
# Check that tunnel works..
if fs.check() is False:
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
theFile = sp['as_file_for_format'].format( # type: ignore
address='127.0.0.1',
port=fs.server_address[1]
)
filename = tools.saveTempFile(theFile)
tools.addTaskToWait(subprocess.Popen([cmd, '--session={}'.format(filename), '--autologin', '--killerrors']))
tools.addFileToUnlink(filename)

View File

@@ -1 +0,0 @@
lsChjBOL2LNJeEjnFSXjK3y9F8uPfz/j6ZlHg511XyQxakyrxPKhEnrAJ9DT7X7Py99D1SQqrMmn+A9B/lH658LmXyCLaQMKFVNLZxc1WH/0Ytl4int6ZJA3uTrt/bHYMNh91OxMsS6WPWjN8g2aCkGhgZIKHehP4oKlQmxOnI4EXSoWtHwl/aN2JaWV6pltiVDKMiyVxMHCnRm0L1KSVaOsC5OxW76DvsUWcYELXiue+bMlBx96lQN0/g4xd9UJKJFqRmA+tPnUhKYdm/gt1804xsdGQ2v2IdPiJjhBvN4riFUffkls0T67HFOEedNdoV7ox/lz8RmamlAGbs36Qz84U/hYdeEwpOZfzHvVKuq8M1EZQciboqdlaRDPDbF+o7mZHQsOCSzRTp6qBqb46pzcELuXBH4/jod/tAX9iyvz7BBxrQsTmhivHIwu3VOdjClN3bw2GrNSyhKxSYsb7wq/YiABfHWHJkHzMZnwxGOpYuYSHNNew2liH3zE3gZPX6rGnyFn7rv80rIGvbLmQV9hJmAluyzU6hQivHYqZnpnfQN1cKT5SKbDiZVCnAC9c8uPGD7VsHJZpaGR3Hi4bB/J2qyVG+zbfVVsLyRh/wDfGfucCBxt9ecY/xcZ6aebzabrEnyluhEmrehu6Ovp1lsWJQPb3mUzSHC0muN4M3s=

View File

@@ -1,26 +0,0 @@
# This is a template
# Saved as .py for easier editing
from __future__ import unicode_literals
# pylint: disable=import-error, no-name-in-module
try:
import winreg as wreg
except ImportError: # Python 2.7 fallback
import _winreg as wreg # type: ignore
import subprocess
from uds import tools # type: ignore
try:
k = wreg.OpenKey(wreg.HKEY_CURRENT_USER, 'Software\\Classes\\NXClient.session\\shell\\open\\command') # @UndefinedVariable
cmd = wreg.QueryValue(k, '') # type: ignore
wreg.CloseKey(k)
except Exception:
raise Exception('''<p>You need to have installed NX Client version 3.5 in order to connect to this UDS service.</p>
<p>Please, install appropriate package for your system.</p>
''')
filename = tools.saveTempFile(sp['as_file']) # type: ignore
cmd = cmd.replace('%1', filename)
tools.addTaskToWait(subprocess.Popen(cmd))
tools.addFileToUnlink(filename)

View File

@@ -1 +0,0 @@
isXacHwak7jQEx9QFKLUaVUTG75t5ogtWFiV7m7eMDttzBTkkS1/0hVLX1avLdaMOBCY60JTfTrPcHcd8XESfSzR3w92i1BzfccHmpV3g67lbeESZqpjsJTWC3F9kCpZHsj6DHXQICQjPPeW++tchJj8bAoETc6MyH5IHSJ/KOmbgLOBM+2x9crnX1ZWHrwF2xQyMaLn5rgntklvSX2KmOS6z0WC0C5DLFpVzZvSsDwMyfhhxd4fGNWCxUW4v5f5S1GUCM1AfzXWZEPYAWbRFgOzG2MKB2dhHasxVt25VtjeKgrD+Q5A28ihQBUkh5vZRmOtAWjtneF6K6bOM59ZL0vzjGIL1/y/6oysjyeOAG4YvagekMRAZT0folf7d4prUb1tN+8jvabZszGCxjvb0kYjfiT6zN53lxDSExLuvjBEwHkWM3CPCTkPLJ7UWiRT6Fyd8c3vJw860WhnohPYg+4q2udjf/ZgdDiyVPEyOB5AKpDnHB3HfsQr7upw+WqWUH56ylF2myWyP0uSmOrLJnUyFX1FFVx2R+/Rc0AjPmM+VE9UwPUkSSpFaRdKPP2nJxDYrReZwk/kfFmRvIqLAUz+rwSIH2JJqEB6NT//tMdxRu4lAKrpX29nqDSWCiMvew3D21OQYafzGGJ9GTn2n+Mwki3cbKpxLXxLxlCh0S8=

View File

@@ -1,41 +0,0 @@
# This is a template
# Saved as .py for easier editing
from __future__ import unicode_literals
# pylint: disable=import-error, no-name-in-module, undefined-variable
try:
import winreg as wreg
except ImportError: # Python 2.7 fallback
import _winreg as wreg # type: ignore
import subprocess
from uds.tunnel import forward # type: ignore
from uds import tools # type: ignore
try:
k = wreg.OpenKey(wreg.HKEY_CURRENT_USER, 'Software\\Classes\\NXClient.session\\shell\\open\\command')
cmd = wreg.QueryValue(k, '')
wreg.CloseKey(k)
except Exception:
raise Exception('''<p>You need to have installed NX Client version 3.5 in order to connect to this UDS service.</p>
<p>Please, install appropriate package for your system.</p>
''')
# Open tunnel
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
# Check that tunnel works..
if fs.check() is False:
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
theFile = sp['as_file_for_format'].format( # type: ignore
address='127.0.0.1',
port=fs.server_address[1]
)
filename = tools.saveTempFile(theFile)
cmd = cmd.replace('%1', filename)
tools.addTaskToWait(subprocess.Popen(cmd))
tools.addFileToUnlink(filename)

View File

@@ -1 +0,0 @@
o+152nwWH5xKg7nrK4ffYSeGjzitZS5LxvkC9Z0aa86J2D9gEIsUqDAQjh2ljuO+g4ik2s72T7Yb5HiZizhHfRfjwe22yjIj+NtK1Xoeh/VW3773bq5VCXAjfMbVU6GuGnNMndQOn4qrS/l12YLDhxXFKUkpwNU1TjRGo33ns1DFPNTf0dT7W/WpQkf/75Jlt6bMnGxFWDWYhc1wLySmwlVPj7GOKQTD9pS9MaB7eqpq/GO9gADNGWcTbz3GGs8iO8N5dxBHTnyHxO7P29aQL9bOvtrY0rxAopfy+TTcuE03qNDI6pCBjhYxCqL+GqiRrzmLJq9ZtvhNxvQ5+kvDDrw3ErFZbXoBOF4f7SeP6Tr9A6aOkLG579czsqNGSpHqkUPgvb38xXfSPv983pDvzhi3lo2GzNhAu4ZYM+/Z/Q32ssYBfst4joHAC9mcHmP37ZTKRiMfRz3hafkJlSmm2RQf5/OPYCz5ha8AAcs2CvqYMlOiJhP9Zx8AwtB9oxVlFPS+ZUJ9h/0waRVFBKQm1m70Z7odjJqT0ThTTJQEjuedfnNuxW1V5GtCi62NcwskulWOL2fXjmf9eh0u5PPn1tdqLIUmZXa9eqGU+LjZqA52w7V3sHHWoMYvfEC4SG9HXfZxd6YZdfPx12z6WYh4PnJLNUqd7bgfl4YswALJyaA=

View File

@@ -21,14 +21,17 @@ def fixResolution():
import re
import subprocess
results = str(subprocess.Popen(['system_profiler SPDisplaysDataType'],stdout=subprocess.PIPE, shell=True).communicate()[0])
res = re.search(r': \d* x \d*', results).group(0).split(' ')
width, height = str(int(res[1])-4), str(int(int(res[3])*90/100)) # Width and Height
groups = re.search(r': \d* x \d*', results)
width, height = '1024', '768' # Safe default values
if groups:
res = groups.group(0).split(' ')
width, height = str(int(res[1])-4), str(int(int(res[3])*90/100)) # Width and Height
return list(map(lambda x: x.replace('#WIDTH#', width).replace('#HEIGHT#', height), sp['as_new_xfreerdp_params'])) # type: ignore
# Check first xfreerdp, allow password redir
if os.path.isfile(xfreerdp):
if xfreerdp and os.path.isfile(xfreerdp):
executable = xfreerdp
elif os.path.isfile(msrdc) and sp['as_file']: # type: ignore
elif msrdc and os.path.isfile(msrdc) and sp['as_file']: # type: ignore
executable = msrdc
if executable is None:

View File

@@ -1 +1 @@
PFhjbkT6+Xgiq/hHE10L5KdkDFhpp4wlRUBSEvUKO0Ral/+xB/La2AUUXVwyIZrIcy9oXZ3mzlOLfzCSa9jcqpR8X3twmtqSz7mDL166avrRGSWkRXS6VFSOt2mjeAPt/pCvB3IIz+KoluMJBtaYj4JTqGzu85t9REfHwv9BF7MarMStUcrXov8tL+04sH1Ge6/daey3Y3VkdLkel2VeMaQmfhwuIcHoNQhSXHKX6Jjdtv0Vzf9Pi3Va7CK+uR4rQK0etQTP6GVmX7veJdWbZM4x81136rD1yWIdFPTcy9NnhBbBtgZiIS8eKSXzDwC1ReJq++nclyxlbPD3JJPYZ8TNBfS0LStR8kpz4TTBj7uLJzXrBselIt4Io7w1QaLvOmDEEs1wcfvmSImvNHCFu1giPQRPrzaoeq9tJyin0xb2dZQNqDlptyCZZkEFOOfIhI3dYVeL38ljhpBo4wcQ2fI1kmhAuc2yZgNnhVRj2qJePCUTxmhQXuT9OKIF8YKlG0SaNIFszRG+qRxJ0G/S4MkPTjJsHXKq+qh2zilimJhJLherackXIG0aY5mkMFZ2zGrQgzy271zFNtOjUen8KTXkvrd2ZqxXYdJeu7PM3UxuLH5Cx3vnbf+/cXHXXqs5p5iBWqogsQZHkiKVod2S7FE+TmIQIaphwyd+lvy6iOE=
g+F+FrlpXOyy2wh+BlNM/jao56WCwLWsE1ilao7muUhTCcLJGWGWpLvPkf41ooKcFMX06m0b0tIY/I7am3w20WJ/J2TwGx6iekjUwNnHu12cBXUgmlJP2oYuqIMkVIvkFT6PjTi8163+gYPufVidhQPBFCz+4LnHI5Lj/7AUPonBdf4iHpTbVAQ4g3tf4KPgQPKX6O9PuCSWOyetZZXy9LJc1IqAnRSnjCRXbUHUc/AFRZ4ERAKD1fgEGezbvtdI5C0j/umr4hQYlMlzuL63N76HI2K3c1+Nwr055WyxDtjiPECo77glJPScUe5VoI35Lvd1YQ2nlOsHpj4d9u+mOyV8InCEOEqkllw+Z3QeKeWm15PIqcLN8DpU2f8zwTi3dsSAWY64YE9iQ9VZGtLmBqo5zuel+p9N2Rutu8shI6hIr2Ivq7VFqyWhDAGcR0FoXKUtK9XFC0klbTeHPnuDkl5UdKkhyBNykYX3f367tcWA8nmC8W6tHxKkGncwTSQS0nrF3ITVwQn+ldGgRD0KrkmNx/uB6dexcEFSEuFvA8YXENmqshNgo0AeTRIVxjqp2/MrddrETduBh4+bG32VhLN82POJj61CpPRizNp4K2Nx9zdBsPdbSTUZZSN6XkNNEm+qNCbtIqdtbptN11Y/NH9L8x1Kd/O6QnMWqj9i8og=

View File

@@ -19,8 +19,11 @@ def fixResolution():
import re
import subprocess
results = str(subprocess.Popen(['system_profiler SPDisplaysDataType'],stdout=subprocess.PIPE, shell=True).communicate()[0])
res = re.search(r': \d* x \d*', results).group(0).split(' ')
width, height = str(int(res[1])-4), str(int(int(res[3])*90/100)) # Width and Height
groups = re.search(r': \d* x \d*', results)
width, height = '1024', '768' # Safe default values
if groups:
res = groups.group(0).split(' ')
width, height = str(int(res[1])-4), str(int(int(res[3])*90/100)) # Width and Height
return list(map(lambda x: x.replace('#WIDTH#', width).replace('#HEIGHT#', height), sp['as_new_xfreerdp_params'])) # type: ignore
@@ -29,9 +32,9 @@ xfreerdp = tools.findApp('xfreerdp')
executable = None
# Check first xfreerdp, allow password redir
if os.path.isfile(xfreerdp):
if xfreerdp and os.path.isfile(xfreerdp):
executable = xfreerdp
elif os.path.isfile(msrdc) and sp['as_file']: # type: ignore
elif msrdc and os.path.isfile(msrdc) and sp['as_file']: # type: ignore
executable = msrdc
if executable is None:

View File

@@ -1 +1 @@
F5BEzwTWBoM12XfwvA70K8cgB8sxXrE9APZuvHhPTpJY9+TA3+Q4wnmC+yrbUW54wPS4HPSrDkERUVDHGmulIeLuOzXnmAA1C+L86FOkO5Pmiy/10utA44p8fja/3R6K5yGW2i9tDSg5CBalaVixw0YvxKZgDpLmdL7cd5h2aWliJc68nOoDMdduWz3Tt19tyMO7TRLfhCVJUP9ETStPIHoLLr/NiyeZ6y7/KvARoi5vEQ1XkRZhOoiZoSnOPCBihzXNIoVAPDFwcS2vW8j+u8TgdFeMgLz26ANs4VLslbhMqJfNTTueejGTma9POOXgDMcbAVbhBCk9xuZjieho/QdtaEQOgPnR45JfadUm0QvrNquVW6eKeE9K6VJ/o3EF5u4qSRoSTlDbxlBo5wblnrRj2IWScvSHGpzTto1o81zOMb8KLhK0iJggxWdK6IiRGmUMbiUKAjeXR3ufvoiQpU9gB54FbPWOThenKL3zUWamVTSx7HnleDSUn+Q9Xu1KWqCamagdgBG7MkEJFkd3dChzaxR2GNBRAijHhHF31AlFcdsIfPXsokqDbqtDu92oSj9MRfjDhp9Jwrw7De4CRXHbmaBYjXfcBTomQYjVymU+cyNjyfgt1NHHWkmVoYvHxod+cUAE5ORkrD9iwZsBbzwYMgcO0TPCqcmNMOS0Mto=
fhYPwbna6zRkxA4oceHtAAbAglnf3zEr+9GzswklGScMNTjEAlF6LPw+0pPQkrgXCn6+SVxdferandVfxYyQwdmU4d0xEHhW5hVe38vKgFVYqqZxtaOfLP6feAuAYyblmE82Zk4gJB7nhTLRcub0i45de2aEtfPoi7vtqHDeTdZIcY38rddhjqtqTw/yEfzJHeW3/7sKxnrXKjFkMPcPvH+1X9OOoYpqp7RZvZyhHbtxJQVxy9wZ4PVFR2KvcNl/rg9h9uu6AnOopoC/vyMQXF+nS3E/bAR2pjoZ6Gld+5VqdgLReWhIxm7fHlvM11D57j/GmKTP1v6UOT6DifX/Ot011nATxy7SauK1VYYuyEZe8oCG5lv1EkLQYw3O7jhFog1o9Lqr/CBl5oov/l9VXceDYoMho75qXFS3XU/bCibe6sbfz31DJUzl6qf64cWXrVQMTtSSj/ChFBSwhm0R/u78w8HE/Gl1JjEBHAD/zNAzhd24B815anE16geye2fYJchnCnHDRj5FrHHwBnQtnLJ8crR8/qRJl6s+S2cCUy08kN+tOpujFY4eYihsxoxeSJB3yCO4WFuZZRI9x/TCs0aTXblzlGl3QCmXWgbjdTwCqnMqYhlzabxH2MUp5l7F3/2gX4Vrzqgov6Q70CjOtepE0tI7g+V8n+wl/9pi6RE=

View File

@@ -400,7 +400,7 @@ def enableService(request: 'ExtendedHttpRequestWithUser', idService: str, idTran
userService, trans = res[1], res[3]
userService.setProperty('accesedByClient', '0') # Reset accesed property to
userService.setProperty('accessedByClient', '0') # Reset accesed property to
typeTrans = trans.getType()

View File

@@ -58,7 +58,7 @@ class ConfigurationType(typing.NamedTuple):
ssl_dhparam: str
uds_server: str
uds_auth: str
uds_token: str
secret: str
allow: typing.Set[str]
@@ -105,7 +105,7 @@ def read() -> ConfigurationType:
ssl_ciphers=uds.get('ssl_ciphers'),
ssl_dhparam=uds.get('ssl_dhparam'),
uds_server=uds_server,
uds_auth=uds.get('uds_auth', 'unauthorized'),
uds_token=uds.get('uds_token', 'unauthorized'),
secret=secret,
allow=set(uds.get('allow', '127.0.0.1').split(',')),
)

View File

@@ -51,6 +51,8 @@ BANDWIDTH_TIME = 10
# Commands LENGTH (all same length)
COMMAND_LENGTH = 4
VERSION = 'v1.0'
# Valid commands
COMMAND_OPEN = b'OPEN'
COMMAND_TEST = b'TEST'

View File

@@ -55,14 +55,14 @@ class Proxy:
@staticmethod
def _getUdsUrl(cfg: config.ConfigurationType, ticket: bytes, msg: str) -> typing.MutableMapping[str, typing.Any]:
try:
url = cfg.uds_server + '/' + ticket.decode() + '/' + msg + '/' + cfg.uds_auth
r = requests.get(url, headers={'content-type': 'application/json'})
url = cfg.uds_server + '/' + ticket.decode() + '/' + msg + '/' + cfg.uds_token
r = requests.get(url, headers={'content-type': 'application/json', 'User-Agent': f'UDSTunnel-{consts.VERSION}'})
if not r.ok:
raise Exception(r.content)
return r.json()
except Exception as e:
raise Exception(f'TICKET COMMS ERROR: {e!s}')
raise Exception(f'TICKET COMMS ERROR: {ticket.decode()} {msg} {e!s}')
@staticmethod

View File

@@ -40,7 +40,7 @@ ssl_dhparam = /etc/certs/dhparam.pem
# http://www.example.com/uds/rest/tunnel/ticket
# https://www.example.com:14333/uds/rest/tunnel/ticket
uds_server = http://172.27.0.1:8000/uds/rest/tunnel/ticket
uds_auth = 123456789012345678901234567890123456789012345678
uds_token = 123456789012345678901234567890123456789012345678
# Secret to get access to admin commands (Currently only stats commands). No default for this.
# Admin commands and only allowed from "allow" ips