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

2 Commits
v2.1 ... v2.0

Author SHA1 Message Date
Adolfo Gómez García
15a76f3b9b Small 2.0 fix 2017-04-07 10:47:57 +02:00
Adolfo Gómez García
a3110d4623 fixed tunneld cord access 2017-03-18 11:48:52 +01:00
271 changed files with 12893 additions and 28314 deletions

View File

@@ -1 +1 @@
2.1.0 2.0.0

2
actors/.gitignore vendored
View File

@@ -6,5 +6,3 @@ udsactor*.changes
/udsactor_1.7.0.dsc /udsactor_1.7.0.dsc
/udsactor_1.7.0.tar.xz /udsactor_1.7.0.tar.xz
/udsactor*.rpm /udsactor*.rpm
/udsactor_2.1.0_amd64.buildinfo
linux/debian/files

View File

@@ -1,9 +1,3 @@
udsactor (2.1.0) stable; urgency=medium
* Fixes for 2.1.0 release
-- Adolfo Gómez García <agomez@virtualcable.es> Tue, 19 Jan 2017 08:00:22 +0200
udsactor (2.0.0) stable; urgency=medium udsactor (2.0.0) stable; urgency=medium
* Upgrade for 2.0.0 * Upgrade for 2.0.0

View File

@@ -0,0 +1,3 @@
udsactor-nx_2.0.0_all.deb x11 optional
udsactor-xrdp_2.0.0_all.deb x11 optional
udsactor_2.0.0_all.deb admin optional

View File

@@ -5,7 +5,6 @@
set -e set -e
case "$1" in case "$1" in
configure) configure)
/usr/bin/python2.7 -m compileall /usr/share/UDSActor > /dev/nul 2>&1
# If new "fresh" install or if configuration file has disappeared... # If new "fresh" install or if configuration file has disappeared...
if [ "$2" = "" ] || [ ! -f /etc/udsactor/udsactor.cfg ]; then if [ "$2" = "" ] || [ ! -f /etc/udsactor/udsactor.cfg ]; then
db_get udsactor/host db_get udsactor/host

View File

@@ -8,5 +8,5 @@ Type=Application
NoDisplay=true NoDisplay=true
X-KDE-autostart-after=panel X-KDE-autostart-after=panel
X-KDE-StartupNotify=false X-KDE-StartupNotify=false
X-DBUS-StartupType=None X-DBUS-StartupType=Unique
X-KDE-UniqueApplet=false X-KDE-UniqueApplet=true

View File

@@ -51,8 +51,6 @@ from udsactor import VERSION
trayIcon = None trayIcon = None
doLogoff = False
def sigTerm(sigNo, stackFrame): def sigTerm(sigNo, stackFrame):
if trayIcon: if trayIcon:
@@ -255,7 +253,7 @@ class UDSSystemTray(QtGui.QSystemTrayIcon):
if remainingTime <= 0: if remainingTime <= 0:
logger.info('User has been idle for too long, notifying Broker that service can be reclaimed') logger.info('User has been idle for too long, notifying Broker that service can be reclaimed')
self.quit(logoff=True) self.quit()
def displayMessage(self, message): def displayMessage(self, message):
logger.debug('Displaying message') logger.debug('Displaying message')
@@ -292,8 +290,7 @@ class UDSSystemTray(QtGui.QSystemTrayIcon):
def about(self): def about(self):
self.aboutDlg.exec_() self.aboutDlg.exec_()
def quit(self, logoff=False): def quit(self):
global doLogoff
logger.debug('Quit invoked') logger.debug('Quit invoked')
if self.stopped is False: if self.stopped is False:
self.stopped = True self.stopped = True
@@ -306,7 +303,10 @@ class UDSSystemTray(QtGui.QSystemTrayIcon):
# May we have lost connection with server, simply exit in that case # May we have lost connection with server, simply exit in that case
pass pass
doLogoff = logoff try:
operations.loggoff() # Invoke log off
except Exception:
pass
self.app.quit() self.app.quit()
@@ -339,12 +339,4 @@ if __name__ == '__main__':
logger.debug('Exiting') logger.debug('Exiting')
trayIcon.quit() trayIcon.quit()
if doLogoff:
try:
time.sleep(1)
operations.loggoff() # Invoke log off
except Exception:
pass
sys.exit(res) sys.exit(res)

View File

@@ -34,7 +34,7 @@ from __future__ import unicode_literals
# On centos, old six release does not includes byte2int, nor six.PY2 # On centos, old six release does not includes byte2int, nor six.PY2
import six import six
VERSION = '2.1.0' VERSION = '2.0.0'
__title__ = 'udsactor' __title__ = 'udsactor'
__version__ = VERSION __version__ = VERSION

View File

@@ -196,22 +196,13 @@ class HTTPServerThread(threading.Thread):
self.initiateServer(address) self.initiateServer(address)
def getPort(self):
return self.address[1]
def getIp(self):
return self.address[0]
def initiateServer(self, address): def initiateServer(self, address):
self.address = (address[0], address[1]) # Copy address & keep it for future reference... self.server = socketserver.TCPServer(address, HTTPServerHandler)
addr = ('0.0.0.0', address[1]) # Adapt to listen on 0.0.0.0
self.server = socketserver.TCPServer(addr, HTTPServerHandler)
self.server.socket = ssl.wrap_socket(self.server.socket, certfile=self.certFile, server_side=True) self.server.socket = ssl.wrap_socket(self.server.socket, certfile=self.certFile, server_side=True)
def getServerUrl(self): def getServerUrl(self):
return 'https://{}:{}/{}'.format(self.getIp(), self.getPort(), HTTPServerHandler.uuid) return 'https://{}:{}/{}'.format(self.server.server_address[0], self.server.server_address[1], HTTPServerHandler.uuid)
def stop(self): def stop(self):
logger.debug('Stopping REST Service') logger.debug('Stopping REST Service')
@@ -220,14 +211,11 @@ class HTTPServerThread(threading.Thread):
def restart(self, address=None): def restart(self, address=None):
if address is None: if address is None:
# address = self.server.server_address address = self.server.server_address
address = self.address
self.address = (address[0], self.address[1]) # Copy address & keep it for future reference, port is never changed once assigned on init self.stop()
# Listening on 0.0.0.0, does not need to restart listener.. self.initiateServer(address)
# self.stop()
# self.initiateServer(address)
def run(self): def run(self):
self.server.serve_forever() self.server.serve_forever()

View File

@@ -36,8 +36,6 @@ import sys
import six import six
import traceback import traceback
import pickle import pickle
import errno
import time
from udsactor.utils import toUnicode from udsactor.utils import toUnicode
from udsactor.log import logger from udsactor.log import logger
@@ -409,11 +407,8 @@ class ClientIPC(threading.Thread):
self.messageReceived() self.messageReceived()
except socket.error as e: except socket.error as e:
if e.errno == errno.EINTR:
time.sleep(1) #
continue # Ignore interrupted system call
logger.error('Communication with server got an error: {}'.format(toUnicode(e.strerror))) logger.error('Communication with server got an error: {}'.format(toUnicode(e.strerror)))
# self.running = False self.running = False
return return
except Exception as e: except Exception as e:
tb = traceback.format_exc() tb = traceback.format_exc()

View File

@@ -36,7 +36,6 @@ from udsactor import operations
from udsactor.service import CommonService from udsactor.service import CommonService
from udsactor.service import initCfg from udsactor.service import initCfg
from udsactor.service import IPC_PORT from udsactor.service import IPC_PORT
from udsactor import ipc from udsactor import ipc
from udsactor.log import logger from udsactor.log import logger
@@ -45,23 +44,15 @@ from udsactor.linux.daemon import Daemon
from udsactor.linux import renamer from udsactor.linux import renamer
import sys import sys
import os import time
import stat
import subprocess
POST_CMD = '/etc/udsactor/post'
PRECONNECT_CMD = '/etc/udsactor/pre'
try: try:
from prctl import set_proctitle # @UnresolvedImport from prctl import set_proctitle
except Exception: # Platform may not include prctl, so in case it's not available, we let the "name" as is except Exception: # Platform may not include prctl, so in case it's not available, we let the "name" as is
def set_proctitle(_): def set_proctitle(_):
pass pass
class UDSActorSvc(Daemon, CommonService): class UDSActorSvc(Daemon, CommonService):
rebootMachineAfterOp = False
def __init__(self, args=None): def __init__(self, args=None):
Daemon.__init__(self, '/var/run/udsa.pid') Daemon.__init__(self, '/var/run/udsa.pid')
CommonService.__init__(self) CommonService.__init__(self)
@@ -71,12 +62,6 @@ class UDSActorSvc(Daemon, CommonService):
Renames the computer, and optionally sets a password for an user Renames the computer, and optionally sets a password for an user
before this before this
''' '''
hostName = operations.getComputerName()
if hostName.lower() == name.lower():
logger.info('Computer name is already {}'.format(hostName))
self.setReady()
return
# Check for password change request for an user # Check for password change request for an user
if user is not None: if user is not None:
@@ -90,48 +75,13 @@ class UDSActorSvc(Daemon, CommonService):
'Could not change password for user {} (maybe invalid current password is configured at broker): {} '.format(user, unicode(e))) 'Could not change password for user {} (maybe invalid current password is configured at broker): {} '.format(user, unicode(e)))
renamer.rename(name) renamer.rename(name)
self.setReady()
if self.rebootMachineAfterOp is False:
self.setReady()
else:
logger.info('Rebooting computer to activate new name {}'.format(name))
self.reboot()
def joinDomain(self, name, domain, ou, account, password): def joinDomain(self, name, domain, ou, account, password):
logger.fatal('Join domain is not supported on linux platforms right now') logger.fatal('Join domain is not supported on linux platforms right now')
def preConnect(self, user, protocol):
'''
Invoked when received a PRE Connection request via REST
'''
# Execute script in /etc/udsactor/post after interacting with broker, if no reboot is requested ofc
# This will be executed only when machine gets "ready"
try:
if os.path.isfile(PRECONNECT_CMD):
if (os.stat(PRECONNECT_CMD).st_mode & stat.S_IXUSR) != 0:
subprocess.call([PRECONNECT_CMD, user, protocol])
else:
logger.info('PRECONNECT file exists but it it is not executable (needs execution permission by root)')
else:
logger.info('PRECONNECT file not found & not executed')
except Exception as e:
# Ignore output of execution command
logger.error('Executing preconnect command give')
def run(self): def run(self):
cfg = initCfg() # Gets a local copy of config to get "reboot" initCfg()
logger.debug('CFG: {}'.format(cfg))
if cfg is not None:
self.rebootMachineAfterOp = cfg.get('reboot', True)
else:
self.rebootMachineAfterOp = False
logger.info('Reboot after is {}'.format(self.rebootMachineAfterOp))
logger.debug('Running Daemon') logger.debug('Running Daemon')
set_proctitle('UDSActorDaemon') set_proctitle('UDSActorDaemon')
@@ -156,21 +106,6 @@ class UDSActorSvc(Daemon, CommonService):
logger.debug('Reboot has been requested, stopping service') logger.debug('Reboot has been requested, stopping service')
return return
# Execute script in /etc/udsactor/post after interacting with broker, if no reboot is requested ofc
# This will be executed only when machine gets "ready"
try:
if os.path.isfile(POST_CMD):
if (os.stat(POST_CMD).st_mode & stat.S_IXUSR) != 0:
subprocess.call([POST_CMD, ])
else:
logger.info('POST file exists but it it is not executable (needs execution permission by root)')
else:
logger.info('POST file not found & not executed')
except Exception as e:
# Ignore output of execution command
logger.error('Executing post command give')
self.initIPC() self.initIPC()
# ********************* # *********************

View File

@@ -122,7 +122,7 @@ def getComputerName():
def getNetworkInfo(): def getNetworkInfo():
for ifname in _getInterfaces(): for ifname in _getInterfaces():
ip, mac = _getIpAndMac(ifname) ip, mac = _getIpAndMac(ifname)
if mac != '00:00:00:00:00:00' and ip.startswith('169.254') is False: # Skips local interfaces & interfaces with no dhcp IPs if mac != '00:00:00:00:00:00': # Skips local interfaces
yield utils.Bunch(name=ifname, mac=mac, ip=ip) yield utils.Bunch(name=ifname, mac=mac, ip=ip)

View File

@@ -78,11 +78,3 @@ def writeConfig(data):
cfg.write(f) cfg.write(f)
os.chmod(CONFIGFILE, 0o0600) os.chmod(CONFIGFILE, 0o0600)
def useOldJoinSystem():
return False
# Right now, we do not really need an application to be run on "startup" as could ocur with windows
def runApplication():
return None

View File

@@ -70,8 +70,6 @@ def initCfg():
cfg = None cfg = None
break break
return cfg
class CommonService(object): class CommonService(object):
def __init__(self): def __init__(self):
@@ -86,23 +84,6 @@ class CommonService(object):
def reboot(self): def reboot(self):
self.rebootRequested = True self.rebootRequested = True
def execute(self, cmd, section):
import os
import subprocess
import stat
if os.path.isfile(cmd):
if (os.stat(cmd).st_mode & stat.S_IXUSR) != 0:
subprocess.call([cmd, ])
return True
else:
logger.info('{} file exists but it it is not executable (needs execution permission by admin/root)'.format(section))
else:
logger.info('{} file not found & not executed'.format(section))
return False
def setReady(self): def setReady(self):
self.api.setReady([(v.mac, v.ip) for v in operations.getNetworkInfo()]) self.api.setReady([(v.mac, v.ip) for v in operations.getNetworkInfo()])
@@ -155,13 +136,6 @@ class CommonService(object):
# Wait a bit before next check # Wait a bit before next check
self.doWait(5000) self.doWait(5000)
# Now try to run the "runonce" element
runOnce = store.runApplication()
if runOnce is not None:
if self.execute(runOnce, 'RunOnce') is True:
# operations.reboot()
return False
# Broker connection is initialized, now get information about what to # Broker connection is initialized, now get information about what to
# do # do
counter = 0 counter = 0
@@ -236,7 +210,7 @@ class CommonService(object):
self.knownIps = dict(((v.mac, v.ip) for v in netInfo)) self.knownIps = dict(((v.mac, v.ip) for v in netInfo))
# And notify new listening address to broker # And notify new listening address to broker
address = (self.knownIps[self.api.mac], self.httpServer.getPort()) address = (self.knownIps[self.api.mac], random.randrange(43900, 44000))
# And new listening address # And new listening address
self.httpServer.restart(address) self.httpServer.restart(address)
# sends notification # sends notification

View File

@@ -40,11 +40,9 @@ import win32event # @UnresolvedImport, pylint: disable=import-error
import win32com.client # @UnresolvedImport, @UnusedImport, pylint: disable=import-error import win32com.client # @UnresolvedImport, @UnusedImport, pylint: disable=import-error
import pythoncom # @UnresolvedImport, pylint: disable=import-error import pythoncom # @UnresolvedImport, pylint: disable=import-error
import servicemanager # @UnresolvedImport, pylint: disable=import-error import servicemanager # @UnresolvedImport, pylint: disable=import-error
import subprocess
import os import os
from udsactor import operations from udsactor import operations
from udsactor import store
from udsactor.service import CommonService from udsactor.service import CommonService
from udsactor.service import initCfg from udsactor.service import initCfg
@@ -57,8 +55,6 @@ from .SENS import SENSGUID_PUBLISHER
from .SENS import PROGID_EventSubscription from .SENS import PROGID_EventSubscription
from .SENS import PROGID_EventSystem from .SENS import PROGID_EventSystem
POST_CMD = 'c:\\windows\\post-uds.bat'
class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService): class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
''' '''
@@ -117,7 +113,7 @@ class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
operations.renameComputer(name) operations.renameComputer(name)
# Reboot just after renaming # Reboot just after renaming
logger.info('Rebooting computer to activate new name {}'.format(name)) logger.info('Rebooting computer got activate new name {}'.format(name))
self.reboot() self.reboot()
def oneStepJoin(self, name, domain, ou, account, password): def oneStepJoin(self, name, domain, ou, account, password):
@@ -162,15 +158,12 @@ class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
ver = ver[0] * 10 + ver[1] ver = ver[0] * 10 + ver[1]
logger.debug('Starting joining domain {} with name {} (detected operating version: {})'.format( logger.debug('Starting joining domain {} with name {} (detected operating version: {})'.format(
domain, name, ver)) domain, name, ver))
# If file c:\compat.bin exists, joind domain in two steps instead one
# Accepts one step joinDomain, also remember XP is no more supported by # Accepts one step joinDomain, also remember XP is no more supported by
# microsoft, but this also must works with it because will do a "multi # microsoft, but this also must works with it because will do a "multi
# step" join # step" join
if ver >= 60 and store.useOldJoinSystem() is False: if ver >= 60:
self.oneStepJoin(name, domain, ou, account, password) self.oneStepJoin(name, domain, ou, account, password)
else: else:
logger.info('Using multiple step join because configuration requests to do so')
self.multiStepJoin(name, domain, ou, account, password) self.multiStepJoin(name, domain, ou, account, password)
def preConnect(self, user, protocol): def preConnect(self, user, protocol):
@@ -299,17 +292,6 @@ class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
logger.debug('Registered SENS, running main loop') logger.debug('Registered SENS, running main loop')
# Execute script in c:\\windows\\post-uds.bat after interacting with broker, if no reboot is requested ofc
# This will be executed only when machine gets "ready"
try:
if os.path.isfile(POST_CMD):
subprocess.call([POST_CMD, ])
else:
logger.info('POST file not found & not executed')
except Exception as e:
# Ignore output of execution command
logger.error('Executing post command give')
# ********************* # *********************
# * Main Service loop * # * Main Service loop *
# ********************* # *********************

View File

@@ -82,6 +82,7 @@ def readConfig():
except Exception: except Exception:
return None return None
def writeConfig(data, fixPermissions=True): def writeConfig(data, fixPermissions=True):
try: try:
key = wreg.OpenKey(baseKey, path, 0, wreg.KEY_ALL_ACCESS) # @UndefinedVariable key = wreg.OpenKey(baseKey, path, 0, wreg.KEY_ALL_ACCESS) # @UndefinedVariable
@@ -92,32 +93,3 @@ def writeConfig(data, fixPermissions=True):
wreg.SetValueEx(key, "", 0, wreg.REG_BINARY, encoder(cPickle.dumps(data))) # @UndefinedVariable wreg.SetValueEx(key, "", 0, wreg.REG_BINARY, encoder(cPickle.dumps(data))) # @UndefinedVariable
wreg.CloseKey(key) # @UndefinedVariable wreg.CloseKey(key) # @UndefinedVariable
def useOldJoinSystem():
try:
key = wreg.OpenKey(baseKey, 'Software\\UDSEnterpriseActor', 0, wreg.KEY_QUERY_VALUE) # @UndefinedVariable
try:
data, _ = wreg.QueryValueEx(key, 'join') # @UndefinedVariable
except Exception:
data = ''
wreg.CloseKey(key) # @UndefinedVariable
except:
data = ''
return data == 'old'
# Gives the oportunity to run an application ONE TIME (because, the registry key "run" will be deleted after read)
def runApplication():
try:
key = wreg.OpenKey(baseKey, 'Software\\UDSEnterpriseActor', 0, wreg.KEY_ALL_ACCESS) # @UndefinedVariable
try:
data, _ = wreg.QueryValueEx(key, 'run') # @UndefinedVariable
wreg.DeleteValue(key, 'run') # @UndefinedVariable
except Exception:
data = None
wreg.CloseKey(key) # @UndefinedVariable
except:
data = None
return data

View File

@@ -1,2 +0,0 @@
udsclient_2.1.0_all.deb admin optional
udsclient_2.1.0_amd64.buildinfo admin optional

View File

@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
VERSION=`cat ../../../VERSION` VERSION=`cat ../../VERSION`
RELEASE=1 RELEASE=1
# Debian based # Debian based
dpkg-buildpackage -b dpkg-buildpackage -b

View File

@@ -1,9 +1,3 @@
udsclient (2.1.0) stable; urgency=medium
* Updated release
-- Adolfo Gómez García <agomez@virtualcable.es> Sun, 23 Oct 2016 21:12:23 +0200
udsclient (2.0.0) stable; urgency=medium udsclient (2.0.0) stable; urgency=medium
* Release upgrade * Release upgrade

View File

@@ -0,0 +1 @@
udsclient_2.0.0_all.deb admin optional

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (c) 2017 Virtual Cable S.L. # Copyright (c) 2014 Virtual Cable S.L.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without modification, # Redistribution and use in source and binary forms, with or without modification,
@@ -281,7 +281,7 @@ if __name__ == "__main__":
# Setup REST api endpoint # Setup REST api endpoint
RestRequest.restApiUrl = '{}://{}/rest/client'.format(['http', 'https'][ssl], host) RestRequest.restApiUrl = '{}://{}/rest/client'.format(['http', 'https'][ssl], host)
logger.debug('Setting request URL to {}'.format(RestRequest.restApiUrl)) logger.debug('Setting requert URL to {}'.format(RestRequest.restApiUrl))
# RestRequest.restApiUrl = 'https://172.27.0.1/rest/client' # RestRequest.restApiUrl = 'https://172.27.0.1/rest/client'
try: try:

View File

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

Before

Width:  |  Height:  |  Size: 137 KiB

After

Width:  |  Height:  |  Size: 137 KiB

View File

@@ -34,7 +34,7 @@ from __future__ import unicode_literals
# On centos, old six release does not includes byte2int, nor six.PY2 # On centos, old six release does not includes byte2int, nor six.PY2
import six import six
VERSION = '2.1.0' VERSION = '2.0.0'
__title__ = 'udclient' __title__ = 'udclient'
__version__ = VERSION __version__ = VERSION

View File

@@ -33,17 +33,10 @@ from __future__ import unicode_literals
import logging import logging
import os import os
import sys
import tempfile import tempfile
if sys.platform.startswith('linux'):
from os.path import expanduser
logFile = expanduser('~/udsclient.log')
else:
logFile = os.path.join(tempfile.gettempdir(), b'udsclient.log')
logging.basicConfig( logging.basicConfig(
filename=logFile, filename=os.path.join(tempfile.gettempdir(), b'udsclient.log'),
filemode='a', filemode='a',
format='%(levelname)s %(asctime)s %(message)s', format='%(levelname)s %(asctime)s %(message)s',
level=logging.DEBUG level=logging.DEBUG

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (c) 2017 Virtual Cable S.L. # Copyright (c) 2015 Virtual Cable S.L.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without modification, # Redistribution and use in source and binary forms, with or without modification,

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (c) 2017 Virtual Cable S.L. # Copyright (c) 2015 Virtual Cable S.L.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without modification, # Redistribution and use in source and binary forms, with or without modification,

View File

@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>UDSClient-Thin</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.python.pydev.PyDevBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.python.pydev.pythonNature</nature>
</natures>
</projectDescription>

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?eclipse-pydev version="1.0"?><pydev_project>
<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
<path>/${PROJECT_DIR_NAME}/src</path>
</pydev_pathproperty>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
</pydev_project>

View File

@@ -1,158 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017 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.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
from uds import ui
from uds.rest import RestRequest, RetryException
from uds.forward import forward
from uds import VERSION
from uds.log import logger # @UnresolvedImport
from uds import tools
import six
import sys
import pickle
def approveHost(host):
from os.path import expanduser
hostsFile = expanduser('~/.udsclient.hosts')
try:
with open(hostsFile, 'r') as f:
approvedHosts = f.read().splitlines()
except Exception:
approvedHosts = []
host = host.lower()
if host in approvedHosts:
return True
errorString = 'The server {} must be approved:\n'.format(host)
errorString += 'Only approve UDS servers that you trust to avoid security issues.'
approved = ui.question("ACCESS Warning", errorString)
if approved:
approvedHosts.append(host)
logger.debug('Host was approved, saving to approvedHosts file')
try:
with open(hostsFile, 'w') as f:
f.write('\n'.join(approvedHosts))
except Exception:
logger.warn('Got exception writing to {}'.format(hostsFile))
return approved
def getWithRetry(rest, url, params=None):
while True:
try:
res = rest.get(url, params)
return res
except RetryException as e:
if ui.question('Service not available', 'Error {}.\nPlease, wait a minute and press "OK" to retry, or "CANCEL" to abort'.format(e)) is True:
continue
raise Exception('Cancelled by user')
if __name__ == "__main__":
logger.debug('Initializing connector')
if six.PY3 is False:
logger.debug('Fixing threaded execution of commands')
import threading
threading._DummyThread._Thread__stop = lambda x: 42
# First parameter must be url
try:
uri = sys.argv[1]
if uri == '--test':
sys.exit(0)
logger.debug('URI: {}'.format(uri))
if uri[:6] != 'uds://' and uri[:7] != 'udss://':
raise Exception()
ssl = uri[3] == 's'
host, ticket, scrambler = uri.split('//')[1].split('/')
logger.debug('ssl: {}, host:{}, ticket:{}, scrambler:{}'.format(ssl, host, ticket, scrambler))
except Exception:
logger.debug('Detected execution without valid URI, exiting')
ui.message('UDS Client', 'UDS Client Version {}'.format(VERSION))
sys.exit(1)
rest = RestRequest(host, ssl)
logger.debug('Setting request URL to {}'.format(rest.restApiUrl))
# Main requests part
# First, get version
try:
res = getWithRetry(rest, '')
logger.debug('Got information {}'.format(res))
if res['requiredVersion'] > VERSION:
ui.message("New UDS Client available", "A new uds version is needed in order to access this version of UDS.\nPlease, download and install it")
sys.exit(1)
res = getWithRetry(rest, '/{}/{}'.format(ticket, scrambler), params={'hostname': tools.getHostName(), 'version': VERSION})
script = res.decode('base64').decode('bz2')
logger.debug('Script: {}'.format(script))
six.exec_(script, globals(), {'parent': None})
except Exception as e:
error = 'ERROR: {}'.format(e)
logger.error(error)
ui.message('Error', error)
sys.exit(2)
# Finalize
try:
tools.waitForTasks()
except Exception:
pass
try:
tools.unlinkFiles()
except Exception:
pass
try:
tools.execBeforeExit()
except Exception:
pass

View File

@@ -1 +0,0 @@
../../../full/src/uds/__init__.py

View File

@@ -1 +0,0 @@
../../../full/src/uds/forward.py

View File

@@ -1 +0,0 @@
../../../full/src/uds/log.py

View File

@@ -1 +0,0 @@
../../../full/src/uds/osDetector.py

View File

@@ -1,86 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2015 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.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
import requests
from . import VERSION
import json
import six
import osDetector
from .log import logger
class RetryException(Exception):
pass
class RestRequest(object):
restApiUrl = ''
def __init__(self, host, ssl=True): # parent not used
super(RestRequest, self).__init__()
self.host = host
self.ssl = ssl
self.restApiUrl = '{}://{}/rest/client'.format(['http', 'https'][ssl], host)
def get(self, url, params=None):
url = self.restApiUrl + url
if params is not None:
url += '?' + '&'.join('{}={}'.format(k, six.moves.urllib.parse.quote(six.text_type(v).encode('utf8'))) for k, v in params.iteritems()) # @UndefinedVariable
logger.debug('Requesting {}'.format(url))
try:
r = requests.get(url, headers={'Content-type': 'application/json', 'User-Agent': osDetector.getOs() + " - UDS Connector " + VERSION })
except requests.exceptions.ConnectionError as e:
raise Exception('Error connecting to UDS Server at {}'.format(self.restApiUrl[0:-11]))
if r.ok:
logger.debug('Request was OK. {}'.format(r.text))
data = json.loads(r.text)
if not 'error' in data:
return data['result']
# Has error
if data.get('retryable', '0') == '1':
raise RetryException(data['error'])
raise Exception(data['error'])
else:
logger.error('Error requesting {}: {}, {}'.format(url, r.code. r.text))
raise Exception('Error {}: {}'.format(r.code, r.text))
return data

View File

@@ -1 +0,0 @@
../../../full/src/uds/tools.py

View File

@@ -1,44 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017 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.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
try:
import gtkui as theUI
except Exception:
import consoleui as theUI # @Reimport
def message(title, message):
theUI.message(title, message)
def question(title, message):
return theUI.question(title, message)

View File

@@ -1,58 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017 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.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
import random
import os
import tempfile
import string
import webbrowser
TEMPLATE = '''<html>
<head>
<title>{title}</title>
</head>
<body>
<h1>{title}</h1>
<p>{message}<P>
</body>
</html>
'''
def _htmlFilename():
return os.path.join(tempfile.gettempdir(), ''.join([random.choice(string.ascii_lowercase) for i in range(22)]) + '.html')
def message(title, message):
filename = _htmlFilename()
with open(filename, 'w') as f:
f.write(TEMPLATE.format(title=title, message=message))
webbrowser.open('file://' + filename, new=0, autoraise=False)

View File

@@ -1,49 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017 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.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
import sys
import time
from uds.log import logger
counter = 0
def message(title, message):
sys.stderr.write("** {} **\n {}\n".format(title, message))
def question(title, message):
global counter
if counter > 100: # 5 minutes
return False
counter += 1
sys.stderr.write("** {} **\n{}\nReturning YES in 3 seconds. (counter is {})\n".format(title, message, counter))
time.sleep(3) # Wait 3 seconds before returning
return True

View File

@@ -1,143 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017 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.
'''
@author: Adolfo Gómez, dkmaster at dkmon dot com
'''
from __future__ import unicode_literals
import re
import pygtk
pygtk.require('2.0')
import gtk
import gobject
LINE_LEN = 65
class Dialog():
def __init__(self, title, message, timeout=-1, withCancel=True):
self.title = title
self.message = message
self.timeout = timeout
self.withCancel = withCancel
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.set_position(gtk.WIN_POS_CENTER)
# self.window.set_size_request(320, 200)
self.window.set_title(self.title)
self.create_widgets()
self.connect_signals()
self.window.show_all()
self.window.connect("destroy", self.destroy)
# Setup "auto OK" timer
if timeout != -1:
self.timerId = gobject.timeout_add(self.timeout * 1000, self.callback_timer)
else:
self.timerId = -1
self.result = False
gtk.main()
@property
def adapted_message(self):
msg = ''
for l in re.sub(r'<p[^>]*>', '', self.message).replace('</p>', '\n').split('\n'):
words = []
length = 0
for word in l.split(' '):
if length + len(word) >= LINE_LEN:
msg += ' '.join(words) + '\n'
words = []
length = 0
length += len(word) + 1
words.append(word)
msg += ' '.join(words) + '\n'
return msg
def create_widgets(self):
self.vbox = gtk.VBox(spacing=10)
self.vbox.set_size_request(490, -1)
self.messageLabel = gtk.Label()
# Fix message markup
# self.message = re.sub(r'<p[^>]*>', '<span font_weight="bold">', self.message).replace('</p>', '</span>\n' )
# Set as simple markup
self.messageLabel.set_markup('\n' + self.adapted_message + '\n')
self.messageLabel.set_alignment(xalign=0.5, yalign=1)
self.hbox = gtk.HBox(spacing=10)
self.button_ok = gtk.Button("OK")
self.hbox.pack_start(self.button_ok)
if self.withCancel:
self.button_cancel = gtk.Button("Cancel")
self.hbox.pack_start(self.button_cancel)
self.vbox.pack_start(self.messageLabel)
self.vbox.pack_start(self.hbox)
self.window.add(self.vbox)
def connect_signals(self):
self.button_ok.connect("clicked", self.callback_ok)
if self.withCancel:
self.button_cancel.connect("clicked", self.callback_cancel)
def destroy(self, widget, data=None):
self.setResult(False)
def setResult(self, val):
if self.timerId != -1:
gobject.source_remove(self.timerId)
self.timerId = -1
self.result = val
self.window.hide()
gtk.main_quit()
def callback_ok(self, widget, callback_data=None):
self.setResult(True)
def callback_cancel(self, widget, callback_data=None):
self.setResult(False)
def callback_timer(self):
self.setResult(True)
def message(title, message):
Dialog(title, message, withCancel=False)
def question(title, message):
dlg = Dialog(title, message, timeout=30, withCancel=True)
return dlg.result

View File

@@ -1,4 +0,0 @@
#!/bin/sh
cd /lib/UDSClient
exec python UDSClient.pyc $@

View File

@@ -1,11 +0,0 @@
Steps:
1.- If building from repository, full copy (recursive) the "src" folder of "udsclient/thin" inside the "udsclient" folder. If building from the .tar.gz, simply ignor4e this step
2.- Copy the folder "udsclient" to /build/packages inside the thinstation build environment
3.- enter the chroot of thinstation
4.- go to the udsclient folder (/build/packages/udsclient)
5.- Execute "build.sh"
6.- Edit the file /build/build.conf, and add this line:
package udsclient
7.- Execute the build process
Ready!!!

View File

@@ -1,2 +0,0 @@
lib
src

View File

@@ -1,11 +0,0 @@
[Desktop Entry]
Name=UDSClient
Comment=UDS Helper
Keywords=uds;client;vdi;
Exec=/bin/udsclient %u
Icon=help-browser
StartupNotify=true
Terminal=false
Type=Application
Categories=Utility;
MimeType=x-scheme-handler/uds;x-scheme-handler/udss;

View File

@@ -1,4 +0,0 @@
#!/bin/sh
cd /lib/UDSClient
exec python UDSClient.pyc $@

View File

@@ -1,13 +0,0 @@
#!/bin/sh
pip install paramiko requests six
rm -rf lib
mkdir -p lib/python2.7/site-packages
for a in requests paramiko pyasn1 cryptography packaging idna asn1crypto six enum ipaddress cffi ; do cp -r /usr/lib/python2.7/site-packages/$a* lib/python2.7/site-packages/; done
cp src/udsclient bin
chmod 755 bin/udsclient
mkdir lib/UDSClient
cp src/UDSClient.py lib/UDSClient
chmod 755 lib/UDSClient/UDSClient.py
cp -r src/uds lib/UDSClient
mkdir lib/applications
cp UDSClient.desktop lib/applications

View File

@@ -1,5 +0,0 @@
base
#add your own dependancies to this file, base should always be included.
python
pygtk
freerdp

View File

@@ -1,15 +0,0 @@
In here you place the commands to start your application if using the scripts
/etc/thinstation.packages
or /etc/thinstation.console
see examples for for information
possible types are
example.global (this is always needed)
example.menu
example.console
example.window
example.fullscreen

View File

@@ -1 +0,0 @@
CMD_FULLSCREEN="example -FULLSCREEN"

View File

@@ -1 +0,0 @@
CMD_GLOBAL="example -startapp"

View File

@@ -1 +0,0 @@
Place a 0 length file in here as the same name as the package if your application is a Console App

View File

@@ -1,34 +0,0 @@
#! /bin/sh
. /etc/thinstation.global
# note you can replace this package with a symlink to /etc/thinstation.packages
# for GUI apps, or /etc/thinstation.console for console apps
# if you do then you will need to create a seperate initilization script for
# any other parameters which need to be started at bootup
case "$1" in
init)
if ! pkg_initialized $PACKAGE; then
# Your startup instructions go here
pkg_set_init_flag $PACKAGE
fi
;;
console)
;;
window)
;;
fullscreen)
;;
help)
echo "Usage: $0 init"
;;
*)
exit 1
;;
esac
exit 0

View File

@@ -1 +0,0 @@
/etc/init.d/your_start_up_script

View File

@@ -1,13 +0,0 @@
# Backup files
*~
# Generated files
src/main/webapp/META-INF/
src/main/webapp/generated/
target/
# IDE-specific configuration
nb-configuration.xml
.classpath
.project

View File

@@ -7,7 +7,7 @@
<groupId>org.openuds.server</groupId> <groupId>org.openuds.server</groupId>
<artifactId>transport</artifactId> <artifactId>transport</artifactId>
<packaging>war</packaging> <packaging>war</packaging>
<version>2.5.0</version> <version>2.0.0</version>
<name>Guacamole Transport</name> <name>Guacamole Transport</name>
<url>https://github.com/dkmstr/openuds</url> <url>https://github.com/dkmstr/openuds</url>
@@ -81,14 +81,14 @@
<dependency> <dependency>
<groupId>org.apache.guacamole</groupId> <groupId>org.apache.guacamole</groupId>
<artifactId>guacamole-common</artifactId> <artifactId>guacamole-common</artifactId>
<version>0.9.10-incubating</version> <version>0.9.9-incubating</version>
</dependency> </dependency>
<!-- Guacamole JavaScript library --> <!-- Guacamole JavaScript library -->
<dependency> <dependency>
<groupId>org.apache.guacamole</groupId> <groupId>org.apache.guacamole</groupId>
<artifactId>guacamole-common-js</artifactId> <artifactId>guacamole-common-js</artifactId>
<version>0.9.12-incubating</version> <version>0.9.9-incubating</version>
<type>zip</type> <type>zip</type>
<scope>runtime</scope> <scope>runtime</scope>
</dependency> </dependency>

View File

@@ -2,7 +2,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<!-- <!--
Copyright (C) 2017 Glyptodon, Inc. Copyright (C) 2013 Glyptodon LLC
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@@ -147,12 +147,30 @@
<!-- guacamole-default-webapp scripts --> <!-- guacamole-default-webapp scripts -->
<script type="text/javascript" src="scripts/session.js"></script> <script type="text/javascript" src="scripts/session.js"></script>
<script type="text/javascript" src="scripts/history.js"></script>
<script type="text/javascript" src="scripts/service.js"></script>
<script type="text/javascript" src="scripts/guac-ui.js"></script> <script type="text/javascript" src="scripts/guac-ui.js"></script>
<script type="text/javascript" src="scripts/client-ui.js"></script> <script type="text/javascript" src="scripts/client-ui.js"></script>
<!-- Init --> <!-- Init -->
<script type="text/javascript"> /* <![CDATA[ */ <script type="text/javascript"> /* <![CDATA[ */
/*function getQueryParams(qs) {
qs = qs.split("+").join(" ");
var params = {}, tokens,
re = /[?&]?([^=]+)=([^&]*)/g;
while (tokens = re.exec(qs)) {
params[decodeURIComponent(tokens[1])]
= decodeURIComponent(tokens[2]);
}
return params;
}
window.query = getQueryParams(document.location.search);*/
// Adapted to 1.5 // Adapted to 1.5
function getQueryParams(qs) { function getQueryParams(qs) {
qs = qs.split("+").join(" "); qs = qs.split("+").join(" ");
@@ -169,11 +187,16 @@
window.query = getQueryParams(document.location.href); window.query = getQueryParams(document.location.href);
// Sanity check Guacamole JavaScript API version
// if (Guacamole.API_VERSION !== "0.9.1")
// GuacUI.Client.showStatus("Clear Your Cache", "An older version of Guacamole has been cached by your browser. Please clear your browser's cache and try again.");
// Start connect after control returns from onload (allow browser // Start connect after control returns from onload (allow browser
// to consider the page loaded). // to consider the page loaded).
window.onload = function() { //else
window.setTimeout(GuacUI.Client.connect, 10); window.onload = function() {
}; window.setTimeout(GuacUI.Client.connect, 10);
};
/* ]]> */ </script> /* ]]> */ </script>

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2017 Glyptodon, Inc. * Copyright (C) 2013 Glyptodon LLC
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -746,6 +746,48 @@ GuacUI.Client.Pinch = function(element) {
}; };
/**
* Flattens the attached Guacamole.Client, storing the result within the
* connection history.
*/
GuacUI.Client.updateThumbnail = function() {
var guac = GuacUI.Client.attachedClient;
if (!guac)
return;
// Do not create empty thumbnails
if (guac.getDisplay().getWidth() <= 0 || guac.getDisplay().getHeight() <= 0)
return;
// Get screenshot
var canvas = guac.getDisplay().flatten();
// Calculate scale of thumbnail (max 320x240, max zoom 100%)
var scale = Math.min(
320 / canvas.width,
240 / canvas.height,
1
);
// Create thumbnail canvas
var thumbnail = document.createElement("canvas");
thumbnail.width = canvas.width*scale;
thumbnail.height = canvas.height*scale;
// Scale screenshot to thumbnail
var context = thumbnail.getContext("2d");
context.drawImage(canvas,
0, 0, canvas.width, canvas.height,
0, 0, thumbnail.width, thumbnail.height
);
// Save thumbnail to history
var id = decodeURIComponent(window.location.search.substring(4));
GuacamoleHistory.update(id, thumbnail.toDataURL());
};
/** /**
* Sets the current display scale to the given value, where 1 is 100% (1:1 * Sets the current display scale to the given value, where 1 is 100% (1:1
* pixel ratio). Out-of-range values will be clamped in-range. * pixel ratio). Out-of-range values will be clamped in-range.
@@ -1546,11 +1588,15 @@ GuacUI.Client.attach = function(guac) {
}, false); }, false);
/* /*
* Disconnect on close * Disconnect and update thumbnail on close
*/ */
window.onunload = function() { window.onunload = function() {
GuacUI.Client.updateThumbnail();
if (GuacUI.Client.attachedClient) if (GuacUI.Client.attachedClient)
GuacUI.Client.attachedClient.disconnect(); GuacUI.Client.attachedClient.disconnect();
}; };
/* /*

Some files were not shown because too many files have changed in this diff Show More