diff --git a/actors/src/udsactor/httpserver.py b/actors/src/udsactor/httpserver.py index 1c0faed7..7b4c3d16 100644 --- a/actors/src/udsactor/httpserver.py +++ b/actors/src/udsactor/httpserver.py @@ -196,6 +196,11 @@ class HTTPServerThread(threading.Thread): self.initiateServer(address) + def getPort(self): + return self.address[1] + + def getIp(self): + return self.address[0] def initiateServer(self, address): self.address = (address[0], address[1]) # Copy address & keep it for future reference... @@ -206,7 +211,7 @@ class HTTPServerThread(threading.Thread): self.server.socket = ssl.wrap_socket(self.server.socket, certfile=self.certFile, server_side=True) def getServerUrl(self): - return 'https://{}:{}/{}'.format(self.address[0], self.address[1], HTTPServerHandler.uuid) + return 'https://{}:{}/{}'.format(self.getIp(), self.getPort(), HTTPServerHandler.uuid) def stop(self): logger.debug('Stopping REST Service') @@ -218,7 +223,7 @@ class HTTPServerThread(threading.Thread): # address = self.server.server_address address = self.address - self.address = (address[0], address[1]) # Copy address & keep it for future reference + self.address = (address[0], self.address[1]) # Copy address & keep it for future reference, port is never changed once assigned on init # Listening on 0.0.0.0, does not need to restart listener.. # self.stop() diff --git a/actors/src/udsactor/service.py b/actors/src/udsactor/service.py index 282ffb07..252b94b3 100644 --- a/actors/src/udsactor/service.py +++ b/actors/src/udsactor/service.py @@ -210,7 +210,7 @@ class CommonService(object): self.knownIps = dict(((v.mac, v.ip) for v in netInfo)) # And notify new listening address to broker - address = (self.knownIps[self.api.mac], random.randrange(43900, 44000)) + address = (self.knownIps[self.api.mac], self.httpServer.getPort()) # And new listening address self.httpServer.restart(address) # sends notification diff --git a/server/src/uds/REST/methods/calendarrules.py b/server/src/uds/REST/methods/calendarrules.py index 17466666..a277f71b 100644 --- a/server/src/uds/REST/methods/calendarrules.py +++ b/server/src/uds/REST/methods/calendarrules.py @@ -110,8 +110,8 @@ class CalendarRules(DetailHandler): # pylint: disable=too-many-public-methods logger.debug('Saving rule {0} / {1}'.format(parent, item)) fields = self.readFieldsFromParams(['name', 'comments', 'frequency', 'start', 'end', 'interval', 'duration', 'duration_unit']) - if int(fields['interval']) == 0: - self.invalidItemException('Element can\'t have a 0 interval') + if int(fields['interval']) < 1: + self.invalidItemException('Repeat must be greater than zero') # Convert timestamps to datetimes fields['start'] = datetime.datetime.fromtimestamp(fields['start']) diff --git a/server/src/uds/models/CalendarRule.py b/server/src/uds/models/CalendarRule.py index 302f3062..368ee190 100644 --- a/server/src/uds/models/CalendarRule.py +++ b/server/src/uds/models/CalendarRule.py @@ -33,7 +33,7 @@ from __future__ import unicode_literals -__updated__ = '2016-04-05' +__updated__ = '2016-10-31' from django.db import models from django.utils.encoding import python_2_unicode_compatible @@ -113,6 +113,9 @@ class CalendarRule(UUIDModel): app_label = 'uds' def as_rrule(self): + if self.interval == 0: # Fix 0 intervals + self.interval = 1 + if self.frequency == WEEKDAYS: dw = [] l = self.interval diff --git a/server/src/uds/transports/X2GO/TX2GOTransport.py b/server/src/uds/transports/X2GO/TX2GOTransport.py index f6424738..bc909a6a 100644 --- a/server/src/uds/transports/X2GO/TX2GOTransport.py +++ b/server/src/uds/transports/X2GO/TX2GOTransport.py @@ -33,20 +33,20 @@ from django.utils.translation import ugettext_noop as _ from uds.core.ui.UserInterface import gui -from uds.core.transports.BaseTransport import Transport -from uds.core.transports.BaseTransport import TUNNELED_GROUP -from uds.core.transports import protocols +from uds.core.managers.UserPrefsManager import CommonPrefs from uds.core.util import OsDetector from uds.core.util import tools +from uds.core.transports.BaseTransport import TUNNELED_GROUP from uds.models import TicketStore - from .BaseX2GOTransport import BaseX2GOTransport +from . import x2gofile + import logging import random import string -__updated__ = '2016-10-23' +__updated__ = '2016-11-02' logger = logging.getLogger(__name__) @@ -58,22 +58,81 @@ class TX2GOTransport(BaseX2GOTransport): ''' typeName = _('X2Go Transport (tunneled)') typeType = 'TX2GOTransport' - typeDescription = _('X2Go Transport for tunneled connection (EXPERIMENTAL)') - protocol = protocols.SPICE + typeDescription = _('X2Go Transport for tunneled connection (EXPERIMENTAL)') group = 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) fixedName = BaseX2GOTransport.fixedName - fullScreen = BaseX2GOTransport.fullScreen + # fullScreen = BaseX2GOTransport.fullScreen desktopType = BaseX2GOTransport.desktopType + sound = BaseX2GOTransport.sound + exports = BaseX2GOTransport.exports + + soundType = BaseX2GOTransport.soundType + keyboardLayout = BaseX2GOTransport.keyboardLayout + pack = BaseX2GOTransport.pack + quality = BaseX2GOTransport.quality def initialize(self, values): if values is not None: if values['tunnelServer'].count(':') != 1: - raise Transport.ValidationException(_('Must use HOST:PORT in Tunnel Server Field')) + raise BaseX2GOTransport.ValidationException(_('Must use HOST:PORT in Tunnel Server Field')) def getUDSTransportScript(self, userService, transport, ip, os, user, password, request): - self.getAndPushKey('user', userService) - return '' + prefs = user.prefs('nx') + + priv, pub = self.getAndPushKey('user', userService) + + prefs = user.prefs('rdp') + + ci = self.getConnectionInfo(userService, user, password) + username = ci['username'] + + width, height = CommonPrefs.getWidthHeight(prefs) + xf = x2gofile.getTemplate( + pack=self.pack.value, + quality=self.quality.value, + sound=self.sound.isTrue(), + soundSystem=self.sound.value, + windowManager=self.desktopType.value, + exports=self.exports.isTrue()) + + tunpass = ''.join(random.choice(string.letters + string.digits) for _i in range(12)) + tunuser = TicketStore.create(tunpass) + + sshHost, sshPort = self.tunnelServer.value.split(':') + + # data + data = { + 'os': os['OS'], + 'ip': ip, + 'port': 22, + 'tunUser': tunuser, + 'tunPass': tunpass, + 'tunHost': sshHost, + 'tunPort': sshPort, + 'username': username, + 'key': priv, + 'width': width, + 'height': height, + 'printers': True, + 'drives': self.exports.isTrue(), + 'fullScreen': width == -1 or height == -1, + 'this_server': request.build_absolute_uri('/'), + 'xf': xf + } + + m = tools.DictAsObj(data) + + os = { + OsDetector.Windows: 'windows', + OsDetector.Linux: 'linux', + # OsDetector.Macintosh: 'macosx' + }.get(m.os) + + if os is None: + return super(BaseX2GOTransport, self).getUDSTransportScript(self, userService, transport, ip, os, user, password, request) + + return self.getScript('scripts/{}/tunnel.py'.format(os)).format(m=m) diff --git a/server/src/uds/transports/X2GO/scripts/windows/direct.py b/server/src/uds/transports/X2GO/scripts/windows/direct.py index 82288261..d0d49721 100644 --- a/server/src/uds/transports/X2GO/scripts/windows/direct.py +++ b/server/src/uds/transports/X2GO/scripts/windows/direct.py @@ -12,16 +12,20 @@ from uds import tools # @UnresolvedImport import six -# The password must be encoded, to be included in a .rdp file, as 'UTF-16LE' before protecting (CtrpyProtectData) it in order to work with mstsc keyFile = tools.saveTempFile('''{m.key}''') -theFile = '''{m.xf}'''.format(exports='c:\\', keyFile=keyFile.replace('\\', '/'), ip='{m.ip}') +theFile = '''{m.xf}'''.format(exports='c:\\', keyFile=keyFile.replace('\\', '/'), ip='{m.ip}', port='22') filename = tools.saveTempFile(theFile) x2goPath = os.environ['PROGRAMFILES(X86)'] + '\\x2goclient' executable = tools.findApp('x2goclient.exe', [x2goPath]) +if executable is None: + raise Exception('''

You must have installed latest X2GO Client in order to connect to this UDS service.

+

You can download it for windows from X2Go Site.

''') -# executable = tools.findApp('mstsc.exe') -# subprocess.Popen([executable, filename]) +# C:\Program Files (x86)\\x2goclient>x2goclient.exe --session-conf=c:/temp/sessions --session=UDS/test-session --close-disconnect --hide --no-menu + +subprocess.Popen([executable, '--session-conf={{}}'.format(filename), '--session=UDS/connect', '--close-disconnect', '--hide', '--no-menu']) # tools.addFileToUnlink(filename) +# tools.addFileToUnlink(keyFile) -QtGui.QMessageBox.critical(parent, 'Notice', executable + ' -- ' + keyFile + ', ' + filename, QtGui.QMessageBox.Ok) # @UndefinedVariable +# QtGui.QMessageBox.critical(parent, 'Notice', executable + ' -- ' + keyFile + ', ' + filename, QtGui.QMessageBox.Ok) # @UndefinedVariable diff --git a/server/src/uds/transports/X2GO/scripts/windows/tunnel.py b/server/src/uds/transports/X2GO/scripts/windows/tunnel.py index 0f29a9c9..f58908c9 100644 --- a/server/src/uds/transports/X2GO/scripts/windows/tunnel.py +++ b/server/src/uds/transports/X2GO/scripts/windows/tunnel.py @@ -21,18 +21,16 @@ if forwardThread.status == 2: tools.addTaskToWait(forwardThread) -# The password must be encoded, to be included in a .rdp file, as 'UTF-16LE' before protecting (CtrpyProtectData) it in order to work with mstsc -theFile = '''{m.r.as_file}'''.format( - password=win32crypt.CryptProtectData(six.binary_type('{m.password}'.encode('UTF-16LE')), None, None, None, None, 0x01).encode('hex'), - address='127.0.0.1:{{}}'.format(port) -) - +keyFile = tools.saveTempFile('''{m.key}''') +theFile = '''{m.xf}'''.format(exports='c:\\', keyFile=keyFile.replace('\\', '/'), ip='127.0.0.1', port=port) filename = tools.saveTempFile(theFile) -executable = tools.findApp('mstsc.exe') -if executable is None: - raise Exception('Unable to find mstsc.exe') -subprocess.Popen([executable, filename]) -tools.addFileToUnlink(filename) +x2goPath = os.environ['PROGRAMFILES(X86)'] + '\\x2goclient' +executable = tools.findApp('x2goclient.exe', [x2goPath]) +if executable is None: + raise Exception('''

You must have installed latest X2GO Client in default program file folder in order to connect to this UDS service.

+

You can download it for windows from X2Go Site.

''') + +subprocess.Popen([executable, '--session-conf={{}}'.format(filename), '--session=UDS/connect', '--close-disconnect', '--hide', '--no-menu']) # QtGui.QMessageBox.critical(parent, 'Notice', filename + ", " + executable, QtGui.QMessageBox.Ok) diff --git a/server/src/uds/transports/X2GO/x2gofile.py b/server/src/uds/transports/X2GO/x2gofile.py index 4eceb125..b814c7ea 100644 --- a/server/src/uds/transports/X2GO/x2gofile.py +++ b/server/src/uds/transports/X2GO/x2gofile.py @@ -70,7 +70,7 @@ host={{ip}} user=user key={{keyFile}} rdpport=3389 -sshport=22 +sshport={{port}} autologin=false krblogin=false krbdelegation=false