mirror of
https://github.com/dkmstr/openuds.git
synced 2025-01-08 21:18:00 +03:00
Merged changes to 2.1
This commit is contained in:
commit
e8ecf3d057
@ -32,10 +32,12 @@
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from PyQt4 import QtCore, QtGui # @UnresolvedImport
|
||||
import sys
|
||||
from PyQt4 import QtCore, QtGui
|
||||
import six
|
||||
|
||||
from uds.rest import RestRequest
|
||||
from uds.forward import forward # @UnusedImport
|
||||
from uds.forward import forward
|
||||
from uds.log import logger
|
||||
from uds import tools
|
||||
from uds import VERSION
|
||||
@ -308,7 +310,7 @@ if __name__ == "__main__":
|
||||
|
||||
# Setup REST api endpoint
|
||||
RestRequest.restApiUrl = '{}://{}/rest/client'.format(['http', 'https'][ssl], host)
|
||||
logger.debug('Setting requert URL to {}'.format(RestRequest.restApiUrl))
|
||||
logger.debug('Setting request URL to {}'.format(RestRequest.restApiUrl))
|
||||
# RestRequest.restApiUrl = 'https://172.27.0.1/rest/client'
|
||||
|
||||
try:
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2015 Virtual Cable S.L.
|
||||
# Copyright (c) 2017 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2015 Virtual Cable S.L.
|
||||
# Copyright (c) 2017 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
|
140
client/thin/src/UDSClient.py
Normal file
140
client/thin/src/UDSClient.py
Normal file
@ -0,0 +1,140 @@
|
||||
# -*- 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 import browser
|
||||
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 webbrowser
|
||||
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):
|
||||
while True:
|
||||
try:
|
||||
res = rest.get(url)
|
||||
return res
|
||||
except RetryException as e:
|
||||
if ui.question('Service not available', '{}\nPlease, wait a minute and press "OK" to retry, or CANCEL to abort') 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('{}://{}/rest/client'.format(['http', 'https'][ssl], host))
|
||||
logger.debug('Setting request URL to {}'.format(rest.restApiUrl))
|
||||
|
||||
# Main requests part
|
||||
# First, get version
|
||||
try:
|
||||
res = getWithRetry(rest, '')
|
||||
|
||||
if res['requiredVersion'] > VERSION:
|
||||
ui.message("New UDS Client available", "A new uds version is needed in order to access this version of UDS. A browser will be openend for this download.")
|
||||
webbrowser.open(res['downloadUrl'])
|
||||
sys.exit(1)
|
||||
|
||||
# Now get ticket
|
||||
res = getWithRetry(rest, '/{}/{}'.format(ticket, scrambler), params={'hostname': tools.getHostName(), 'version': VERSION})
|
||||
|
||||
except Exception as e:
|
||||
error = 'ERROR: {}'.format(e)
|
||||
logger.error(error)
|
||||
ui.message('Error', error)
|
||||
sys.exit(2)
|
58
client/thin/src/uds/browser.py
Normal file
58
client/thin/src/uds/browser.py
Normal file
@ -0,0 +1,58 @@
|
||||
# -*- 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)
|
1
client/thin/src/uds/log.py
Symbolic link
1
client/thin/src/uds/log.py
Symbolic link
@ -0,0 +1 @@
|
||||
../../../full/src/uds/log.py
|
82
client/thin/src/uds/rest.py
Normal file
82
client/thin/src/uds/rest.py
Normal file
@ -0,0 +1,82 @@
|
||||
# -*- 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 urllib
|
||||
|
||||
|
||||
from .log import logger
|
||||
|
||||
class RetryException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class RestRequest(object):
|
||||
|
||||
restApiUrl = ''
|
||||
|
||||
def __init__(self, restURL): # parent not used
|
||||
super(RestRequest, self).__init__()
|
||||
self.restApiUrl = restURL
|
||||
|
||||
def get(self, url, params=None):
|
||||
url = self.restApiUrl + url
|
||||
if params is not None:
|
||||
url += '?' + '&'.join('{}={}'.format(k, urllib.quote(six.text_type(v).encode('utf8'))) for k, v in params.iteritems())
|
||||
|
||||
logger.debug('Requesting {}'.format(url))
|
||||
try:
|
||||
r = requests.get(url, headers={'Content-type': 'application/json'})
|
||||
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
|
44
client/thin/src/uds/ui/__init__.py
Normal file
44
client/thin/src/uds/ui/__init__.py
Normal file
@ -0,0 +1,44 @@
|
||||
# -*- 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
|
||||
|
||||
def message(title, message):
|
||||
theUI.message(title, message)
|
||||
|
||||
def question(title, message):
|
||||
return theUI.question(title, message)
|
||||
|
41
client/thin/src/uds/ui/consoleui.py
Normal file
41
client/thin/src/uds/ui/consoleui.py
Normal file
@ -0,0 +1,41 @@
|
||||
# -*- 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
|
||||
from uds.log import logger
|
||||
|
||||
def message(title, message):
|
||||
sys.stderr.write("** {} **\n {}\n".format(title, message))
|
||||
|
||||
def question(title, message):
|
||||
sys.stderr.write("** {} **\n{}\nReturned YES\n".format(title, message))
|
||||
return True
|
39
client/thin/src/uds/ui/gtkui.py
Normal file
39
client/thin/src/uds/ui/gtkui.py
Normal file
@ -0,0 +1,39 @@
|
||||
# -*- 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 pygtk
|
||||
pygtk.require('2.0')
|
||||
import gtk
|
||||
|
||||
|
||||
raise Exception('not available')
|
@ -1,3 +1,5 @@
|
||||
base
|
||||
#add your own dependancies to this file, base should always be included.
|
||||
python
|
||||
pygtk
|
||||
freerdp
|
||||
|
@ -23,7 +23,7 @@ BASE_DIR = '/'.join(os.path.dirname(os.path.abspath(__file__)).split('/')[:-1])
|
||||
DEBUG = True
|
||||
|
||||
# USE_X_FORWARDED_HOST = True
|
||||
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', 'https') # For testing behind a reverse proxy
|
||||
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') # For testing begind a reverse proxy
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
@ -246,6 +246,9 @@ TRACEFILE = 'trace.log'
|
||||
LOGLEVEL = DEBUG and 'DEBUG' or 'INFO'
|
||||
ROTATINGSIZE = 32 * 1024 * 1024 # 32 Megabytes before rotating files
|
||||
|
||||
# Tests runner is default tests runner
|
||||
TEST_RUNNER = 'django.test.runner.DiscoverRunner'
|
||||
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': True,
|
||||
|
@ -51,7 +51,7 @@ import requests
|
||||
import json
|
||||
import logging
|
||||
|
||||
__updated__ = '2017-05-18'
|
||||
__updated__ = '2017-05-19'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
traceLogger = logging.getLogger('traceLog')
|
||||
@ -213,17 +213,19 @@ class UserServiceManager(object):
|
||||
@return: the uService removed (marked for removal)
|
||||
'''
|
||||
with transaction.atomic():
|
||||
uService = UserService.objects.get(id=uService.id)
|
||||
uService = UserService.objects.select_for_update().get(id=uService.id)
|
||||
logger.debug('Removing uService {0}'.format(uService))
|
||||
if uService.isUsable() is False and State.isRemovable(uService.state) is False:
|
||||
raise OperationException(_('Can\'t remove a non active element'))
|
||||
|
||||
ci = uService.getInstance()
|
||||
state = ci.destroy()
|
||||
uService.setState(State.REMOVING)
|
||||
logger.debug("**** The state now is {}".format(uService.state))
|
||||
logger.debug("***** The state now is {}".format(State.toString(uService.state)))
|
||||
uService.setInUse(False) # For accounting, ensure that it is not in use right now
|
||||
UserServiceOpChecker.makeUnique(uService, ci, state)
|
||||
uService.save()
|
||||
|
||||
ci = uService.getInstance()
|
||||
state = ci.destroy()
|
||||
|
||||
UserServiceOpChecker.makeUnique(uService, ci, state)
|
||||
|
||||
def removeOrCancel(self, uService):
|
||||
if uService.isUsable() or State.isRemovable(uService.state):
|
||||
@ -466,14 +468,18 @@ class UserServiceManager(object):
|
||||
This method is used by UserService when a request for setInUse(False) is made
|
||||
This checks that the service can continue existing or not
|
||||
'''
|
||||
remove = False
|
||||
# uService = UserService.objects.get(id=uService.id)
|
||||
with transaction.atomic():
|
||||
uService = UserService.objects.get(id=uService.id)
|
||||
uService = UserService.objects.select_for_update().get(id=uService.id)
|
||||
if uService.publication is None:
|
||||
return
|
||||
if uService.publication.id != uService.deployed_service.activePublication().id:
|
||||
logger.debug('Old revision of user service, marking as removable: {0}'.format(uService))
|
||||
uService.remove()
|
||||
remove = True
|
||||
|
||||
if remove:
|
||||
uService.remove()
|
||||
|
||||
def notifyReadyFromOsManager(self, uService, data):
|
||||
try:
|
||||
|
@ -34,6 +34,7 @@
|
||||
from uds.core.Serializable import Serializable
|
||||
import pickle
|
||||
import timeit
|
||||
import six
|
||||
|
||||
|
||||
class Attribute(object):
|
||||
@ -88,12 +89,12 @@ class AutoAttributes(Serializable):
|
||||
|
||||
def declare(self, **kwargs):
|
||||
d = {}
|
||||
for key, typ in kwargs.iteritems():
|
||||
for key, typ in six.iteritems(kwargs):
|
||||
d[key] = Attribute(typ)
|
||||
self.dict = d
|
||||
|
||||
def marshal(self):
|
||||
return '\2'.join(['%s\1%s' % (k, pickle.dumps(v)) for k, v in self.dict.iteritems()]).encode(AutoAttributes.ACODEC)
|
||||
return '\2'.join(['%s\1%s' % (k, pickle.dumps(v)) for k, v in six.iteritems(self.dict)]).encode(AutoAttributes.ACODEC)
|
||||
|
||||
def unmarshal(self, data):
|
||||
if data == '': # Can be empty
|
||||
@ -105,6 +106,6 @@ class AutoAttributes(Serializable):
|
||||
|
||||
def __str__(self):
|
||||
str_ = '<AutoAttribute '
|
||||
for k, v in self.dict.iteritems():
|
||||
for k, v in six.iteritems(self.dict):
|
||||
str_ += "%s (%s) = %s" % (k, v.getType(), v.getStrValue())
|
||||
return str_ + '>'
|
||||
|
@ -102,14 +102,17 @@ class Cache(object):
|
||||
try:
|
||||
uds.models.Cache.objects.create(owner=self._owner, key=key, value=value, created=now, validity=validity) # @UndefinedVariable
|
||||
except Exception:
|
||||
# Already exists, modify it
|
||||
c = uds.models.Cache.objects.get(pk=key) # @UndefinedVariable
|
||||
c.owner = self._owner
|
||||
c.key = key
|
||||
c.value = value
|
||||
c.created = datetime.now()
|
||||
c.validity = validity
|
||||
c.save()
|
||||
try:
|
||||
# Already exists, modify it
|
||||
c = uds.models.Cache.objects.get(pk=key) # @UndefinedVariable
|
||||
c.owner = self._owner
|
||||
c.key = key
|
||||
c.value = value
|
||||
c.created = datetime.now()
|
||||
c.validity = validity
|
||||
c.save()
|
||||
except transaction.TransactionManagementError:
|
||||
logger.debug('Transaction in course, cannot store value')
|
||||
|
||||
def refresh(self, skey):
|
||||
# logger.debug('Refreshing key "%s" for cache "%s"' % (skey, self._owner,))
|
||||
|
@ -322,6 +322,9 @@ class GlobalConfig(object):
|
||||
# Custom message for error when limiting by calendar
|
||||
LIMITED_BY_CALENDAR_TEXT = Config.section(GLOBAL_SECTION).value('Calendar access denied text', '', type=Config.TEXT_FIELD) # Defaults to Nothing
|
||||
|
||||
# This is used so templates can change "styles" from admin interface
|
||||
LOWERCASE_USERNAME = Config.section(SECURITY_SECTION).value('Convert username to lowercase', '1', type=Config.BOOLEAN_FIELD)
|
||||
|
||||
initDone = False
|
||||
|
||||
@staticmethod
|
||||
|
@ -65,7 +65,8 @@ class UserServiceInfoItemsCleaner(Job):
|
||||
|
||||
|
||||
class UserServiceRemover(Job):
|
||||
frecuency = GlobalConfig.REMOVAL_CHECK.getInt() # Request run cache "info" cleaner every configued seconds. If config value is changed, it will be used at next reload
|
||||
frecuency = 31
|
||||
frecuency_cfg = GlobalConfig.REMOVAL_CHECK # Request run cache "info" cleaner every configued seconds. If config value is changed, it will be used at next reload
|
||||
friendly_name = 'User Service Cleaner'
|
||||
|
||||
removeAtOnce = GlobalConfig.USER_SERVICE_CLEAN_NUMBER.getInt() # Same, it will work at reload
|
||||
@ -74,10 +75,12 @@ class UserServiceRemover(Job):
|
||||
super(UserServiceRemover, self).__init__(environment)
|
||||
|
||||
def run(self):
|
||||
removeFrom = getSqlDatetime() - timedelta(seconds=10) # We keep at least 10 seconds the machine before removing it, so we avoid connections errors
|
||||
removables = UserService.objects.filter(state=State.REMOVABLE, state_date__lt=removeFrom,
|
||||
deployed_service__service__provider__maintenance_mode=False)[0:UserServiceRemover.removeAtOnce]
|
||||
with transaction.atomic():
|
||||
removeFrom = getSqlDatetime() - timedelta(seconds=10) # We keep at least 10 seconds the machine before removing it, so we avoid connections errors
|
||||
removables = UserService.objects.filter(state=State.REMOVABLE, state_date__lt=removeFrom,
|
||||
deployed_service__service__provider__maintenance_mode=False)[0:UserServiceRemover.removeAtOnce]
|
||||
for us in removables:
|
||||
logger.debug('Checking removal of {}'.format(us))
|
||||
try:
|
||||
if managers.userServiceManager().canRemoveServiceFromDeployedService(us.deployed_service) is True:
|
||||
managers.userServiceManager().remove(us)
|
||||
|
@ -33,7 +33,7 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models
|
||||
from django.db import models, transaction
|
||||
from django.db.models import signals
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
|
||||
@ -62,7 +62,7 @@ from datetime import datetime, timedelta
|
||||
import logging
|
||||
import pickle
|
||||
|
||||
__updated__ = '2017-05-10'
|
||||
__updated__ = '2017-05-19'
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -335,6 +335,7 @@ class DeployedService(UUIDModel, TaggingMixin):
|
||||
Args:
|
||||
activePub: Active publication used as "current" publication to make checks
|
||||
'''
|
||||
logger.debug('Marking old user services as removable...')
|
||||
now = getSqlDatetime()
|
||||
if activePub is None:
|
||||
logger.error('No active publication, don\'t know what to erase!!! (ds = {0})'.format(self))
|
||||
@ -342,8 +343,9 @@ class DeployedService(UUIDModel, TaggingMixin):
|
||||
for ap in self.publications.exclude(id=activePub.id):
|
||||
for u in ap.userServices.filter(state=states.userService.PREPARING):
|
||||
u.cancel()
|
||||
ap.userServices.exclude(cache_level=0).filter(state=states.userService.USABLE).update(state=states.userService.REMOVABLE, state_date=now)
|
||||
ap.userServices.filter(cache_level=0, state=states.userService.USABLE, in_use=False).update(state=states.userService.REMOVABLE, state_date=now)
|
||||
with transaction.atomic():
|
||||
ap.userServices.exclude(cache_level=0).filter(state=states.userService.USABLE).update(state=states.userService.REMOVABLE, state_date=now)
|
||||
ap.userServices.filter(cache_level=0, state=states.userService.USABLE, in_use=False).update(state=states.userService.REMOVABLE, state_date=now)
|
||||
|
||||
def validateGroups(self, grps):
|
||||
'''
|
||||
|
@ -57,7 +57,7 @@ import six
|
||||
import pickle
|
||||
import logging
|
||||
|
||||
__updated__ = '2017-05-18'
|
||||
__updated__ = '2017-05-19'
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -319,7 +319,8 @@ class UserService(UUIDModel):
|
||||
save: Defaults to true. If false, record will not be saved to db, just modified
|
||||
|
||||
'''
|
||||
logger.debug(' *** Setting state to {} from {} for {}--{}'.format(state, self.state, self.id, self.friendly_name))
|
||||
logger.debug(' *** Setting state to {} from {} for {}'.format(State.toString(state), State.toString(self.state), self))
|
||||
|
||||
if state != self.state:
|
||||
self.state_date = getSqlDatetime()
|
||||
self.state = state
|
||||
@ -362,7 +363,7 @@ class UserService(UUIDModel):
|
||||
self.in_use = state
|
||||
self.in_use_date = getSqlDatetime()
|
||||
|
||||
# Start/stop accouting
|
||||
# Start/stop accounting
|
||||
if state is True:
|
||||
self.startUsageAccounting()
|
||||
else:
|
||||
|
@ -43,7 +43,7 @@ import six
|
||||
import pickle
|
||||
import logging
|
||||
|
||||
__updated__ = '2017-05-18'
|
||||
__updated__ = '2017-05-19'
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -149,7 +149,7 @@ class OGDeployment(UserDeployment):
|
||||
return self.__error('Error checking machine: {}'.format(e))
|
||||
|
||||
# possible status are ("off", "oglive", "busy", "linux", "windows", "macos" o "unknown").
|
||||
if status['status'] != 'off':
|
||||
if status['status'] in ("linux", "windows", "macos"):
|
||||
return State.FINISHED
|
||||
|
||||
return State.RUNNING
|
||||
|
@ -48,7 +48,7 @@ import logging
|
||||
import six
|
||||
|
||||
|
||||
__updated__ = '2017-05-18'
|
||||
__updated__ = '2017-05-23'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -98,6 +98,7 @@ class OGProvider(ServiceProvider):
|
||||
checkCert = gui.CheckBoxField(label=_('Check Cert.'), order=3, tooltip=_('If checked, ssl certificate of OpenGnsys server must be valid, not self signed)'))
|
||||
username = gui.TextField(length=32, label=_('Username'), order=4, tooltip=_('User with valid privileges on OpenGnsys'), required=True)
|
||||
password = gui.PasswordField(lenth=32, label=_('Password'), order=5, tooltip=_('Password of the user of OpenGnsys'), required=True)
|
||||
udsServerAccessUrl = gui.TextField(length=32, label=_('UDS Server URL'), order=6, tooltip=_('URL used by OpenGnsys to access UDS. If empty, UDS will guess it.'), required=False, tab=gui.PARAMETERS_TAB)
|
||||
|
||||
maxPreparingServices = gui.NumericField(length=3, label=_('Creation concurrency'), defvalue='10', minValue=1, maxValue=65536, order=50, tooltip=_('Maximum number of concurrently creating VMs'), required=True, tab=gui.ADVANCED_TAB)
|
||||
maxRemovingServices = gui.NumericField(length=3, label=_('Removal concurrency'), defvalue='5', minValue=1, maxValue=65536, order=51, tooltip=_('Maximum number of concurrently removing VMs'), required=True, tab=gui.ADVANCED_TAB)
|
||||
@ -123,7 +124,6 @@ class OGProvider(ServiceProvider):
|
||||
def endpoint(self):
|
||||
return 'https://{}:{}/rest'.format(self.host.value, self.port.value)
|
||||
|
||||
|
||||
@property
|
||||
def api(self):
|
||||
if self._api is None:
|
||||
|
@ -37,7 +37,7 @@ import random
|
||||
import six
|
||||
import logging
|
||||
|
||||
__updated__ = '2017-05-18'
|
||||
__updated__ = '2017-05-19'
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -212,8 +212,7 @@ def get(path, errMsg):
|
||||
return []
|
||||
elif path[-6:] == 'status':
|
||||
rnd = random.randint(0, 100)
|
||||
logger.debug('Random generated: {}'.format(rnd))
|
||||
if rnd < 95:
|
||||
if rnd < 25:
|
||||
return STATUS_READY_LINUX
|
||||
return STATUS_OFF
|
||||
|
||||
|
@ -74,7 +74,10 @@ gui.authenticators.link = (event) ->
|
||||
$select.empty()
|
||||
gui.doLog data
|
||||
$.each data, (undefined_, value) ->
|
||||
$select.append "<option value=\"" + value.id + "\">" + value.id + " (" + value.name + ")</option>"
|
||||
$select.append($('<option>',
|
||||
value: value.id
|
||||
text: value.id + " (" + value.name + ")"
|
||||
))
|
||||
return
|
||||
|
||||
return
|
||||
|
@ -195,8 +195,8 @@ uds.launch = (el, url, alt) ->
|
||||
alert data.error
|
||||
else
|
||||
# Fix access provided in url in case of https
|
||||
# if window.location.protocol is 'https:'
|
||||
# data.url = data.url.replace('uds://', 'udss://') # Ensures that protocol is https also for plugin, fixing if needed UDS provided info
|
||||
if window.location.protocol is 'https:'
|
||||
data.url = data.url.replace('uds://', 'udss://') # Ensures that protocol is https also for plugin, fixing if needed UDS provided info
|
||||
if bypassPluginDetection is false
|
||||
uds.doLaunch el, data.url, alt
|
||||
else
|
||||
|
@ -68,7 +68,7 @@
|
||||
<select multiple name="groups" class="selectpicker show-menu-arrow show-tick modal_field_data" data-style="btn-default" data-width="100%" id="id_state">
|
||||
{{# each groups_all }}
|
||||
{{# ifequals type 'group' }}
|
||||
<option value="{{ id }}"{{# ifbelongs id ../groups }} selected{{/ ifbelongs}}>{{ name }}</option>
|
||||
<option value="{{ id }}"{{# ifbelongs id ../groups }} selected{{/ ifbelongs}}>{{ name }} ({{ comments }})</option>
|
||||
{{/ ifequals }}
|
||||
{{/ each }}
|
||||
</select>
|
||||
|
@ -1,3 +1,5 @@
|
||||
# This is a template
|
||||
# Saved as .py for easier editing
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# pylint: disable=import-error, no-name-in-module
|
||||
@ -9,8 +11,15 @@ from uds import tools # @UnresolvedImport
|
||||
|
||||
import six
|
||||
|
||||
try:
|
||||
thePass = six.binary_type('{m.password}'.encode('UTF-16LE'))
|
||||
password = win32crypt.CryptProtectData(thePass, None, None, None, None, 0x01).encode('hex')
|
||||
except Exception:
|
||||
logger.info('Cannot encrypt for user, trying for machine')
|
||||
password = win32crypt.CryptProtectData(thePass, None, None, None, None, 0x05).encode('hex')
|
||||
|
||||
# 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 = sp['as_file'].format(password=win32crypt.CryptProtectData(six.binary_type(sp['password'].encode('UTF-16LE')), None, None, None, None, 0x01).encode('hex')) # @UndefinedVariable
|
||||
theFile = '''{m.r.as_file}'''.format(password=password)
|
||||
|
||||
filename = tools.saveTempFile(theFile)
|
||||
executable = tools.findApp('mstsc.exe')
|
||||
|
@ -8,21 +8,29 @@ import win32crypt # @UnresolvedImport
|
||||
import os
|
||||
import subprocess
|
||||
from uds.forward import forward # @UnresolvedImport
|
||||
from uds.log import logger # @UnresolvedImport
|
||||
|
||||
from uds import tools # @UnresolvedImport
|
||||
|
||||
import six
|
||||
|
||||
forwardThread, port = forward(sp['tunHost'], sp['tunPort'], sp['tunUser'], sp['tunPass'], sp['ip'], 3389, sp['tunWait']) # @UndefinedVariable
|
||||
forwardThread, port = forward(sp['tunHost'], sp['tunPort'], sp['tunUser'], sp['tunPass'], sp['ip'], 3389, waitTime=sp['tunWait']) # @UndefinedVariable
|
||||
|
||||
if forwardThread.status == 2:
|
||||
raise Exception('Unable to open tunnel')
|
||||
|
||||
tools.addTaskToWait(forwardThread)
|
||||
|
||||
try:
|
||||
thePass = six.binary_type('{m.password}'.encode('UTF-16LE'))
|
||||
password = win32crypt.CryptProtectData(thePass, None, None, None, None, 0x01).encode('hex')
|
||||
except Exception:
|
||||
logger.info('Cannot encrypt for user, trying for machine')
|
||||
password = win32crypt.CryptProtectData(thePass, None, None, None, None, 0x05).encode('hex')
|
||||
|
||||
# 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 = sp['as_file'].format(# @UndefinedVariable
|
||||
password=win32crypt.CryptProtectData(six.binary_type(sp['password'].encode('UTF-16LE')), None, None, None, None, 0x01).encode('hex'), # @UndefinedVariable
|
||||
password=password,
|
||||
address='127.0.0.1:{}'.format(port)
|
||||
)
|
||||
|
||||
|
@ -48,7 +48,7 @@ import uds.web.errors as errors
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
__updated__ = '2017-04-19'
|
||||
__updated__ = '2017-06-01'
|
||||
|
||||
# Allow cross-domain login
|
||||
# @csrf_exempt
|
||||
@ -91,6 +91,8 @@ def login(request, tag=None):
|
||||
except Exception:
|
||||
authenticator = Authenticator()
|
||||
userName = form.cleaned_data['user']
|
||||
if GlobalConfig.LOWERCASE_USERNAME.getBool(True) is True:
|
||||
userName = userName.lower()
|
||||
|
||||
cache = Cache('auth')
|
||||
cacheKey = str(authenticator.id) + userName
|
||||
|
Loading…
Reference in New Issue
Block a user