Removed all 2.7 client due to "portables" clients being available
@ -1,5 +0,0 @@
|
||||
Old Python 2.7 Code
|
||||
===================
|
||||
|
||||
Warning: This code will be not used anymore on UDS, and will be removed from repository soon.
|
||||
Please, do not use this, use instead client-py3 client.
|
@ -1,2 +0,0 @@
|
||||
PYTHONPATH=./src:${PYTHONPATH}
|
||||
|
4
client/full/.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
/bin
|
||||
/udsclient_*
|
||||
/udsclient-*.tar.gz
|
||||
/*.rpm
|
@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>UDSclient</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>
|
@ -1,14 +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">system-2.7</pydev_property>
|
||||
|
||||
</pydev_project>
|
4
client/full/linux/.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
/udsclient-opensuse-[0-9]*.spec
|
||||
/udsclient-[0-9]*.spec
|
||||
/debian/udsclient
|
||||
/targz
|
@ -1,51 +0,0 @@
|
||||
#!/usr/bin/make -f
|
||||
# -*- makefile -*-
|
||||
|
||||
# Version
|
||||
# VERSION := 1.7.5
|
||||
|
||||
# Directories
|
||||
SOURCEDIR := ../src
|
||||
LIBDIR := $(DESTDIR)/usr/lib/UDSClient
|
||||
BINDIR := $(DESTDIR)/usr/bin
|
||||
SBINDIR = $(DESTDIR)/usr/sbin
|
||||
APPSDIR := $(DESTDIR)/usr/share/applications
|
||||
|
||||
PYC := $(shell find $(SOURCEDIR) -name '*.py[co]')
|
||||
CACHES := $(shell find $(SOURCEDIR) -name '__pycache__')
|
||||
|
||||
clean:
|
||||
rm -rf $(PYC) $(CACHES) $(DESTDIR)
|
||||
install:
|
||||
rm -rf $(DESTDIR)
|
||||
mkdir -p $(LIBDIR)
|
||||
#mkdir -p $(BINDIR)
|
||||
#mkdir -p $(SBINDIR)
|
||||
mkdir -p $(APPSDIR)
|
||||
|
||||
mkdir $(LIBDIR)/uds
|
||||
|
||||
# Cleans up .pyc and cache folders
|
||||
rm -f $(PYC) $(CACHES)
|
||||
|
||||
cp $(SOURCEDIR)/uds/*.py $(LIBDIR)/uds
|
||||
|
||||
cp $(SOURCEDIR)/UDS*.py $(LIBDIR)
|
||||
|
||||
|
||||
# URL Catchers elements for gnome/kde
|
||||
cp desktop/UDSClient.desktop $(APPSDIR)
|
||||
|
||||
chmod 755 $(LIBDIR)/UDSClient.py
|
||||
|
||||
ifeq ($(DISTRO),targz)
|
||||
cp installer.sh $(DESTDIR)/install.sh
|
||||
tar czvf ../udsclient-$(VERSION).tar.gz -C $(DESTDIR) .
|
||||
endif
|
||||
|
||||
|
||||
# chmod 0755 $(BINDIR)/udsclient
|
||||
uninstall:
|
||||
rm -rf $(LIBDIR)
|
||||
# rm -f $(BINDIR)/udsclient
|
||||
# rm -rf $(CFGDIR)
|
@ -1,36 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
VERSION=`cat ../../../VERSION`
|
||||
RELEASE=1
|
||||
# Debian based
|
||||
dpkg-buildpackage -b
|
||||
|
||||
# Now rpm based
|
||||
top=`pwd`
|
||||
|
||||
cat udsclient-template.spec |
|
||||
sed -e s/"version 0.0.0"/"version ${VERSION}"/g |
|
||||
sed -e s/"release 1"/"release ${RELEASE}"/g > udsclient-$VERSION.spec
|
||||
|
||||
# Now fix dependencies for opensuse
|
||||
cat udsclient-template.spec |
|
||||
sed -e s/"version 0.0.0"/"version ${VERSION}"/g |
|
||||
sed -e s/"name udsclient"/"name udsclient-opensuse"/g |
|
||||
sed -e s/"PyQt4"/"python-qt4"/g |
|
||||
sed -e s/"libXScrnSaver"/"libXss1"/g > udsclient-opensuse-$VERSION.spec
|
||||
|
||||
|
||||
# Right now, udsactor-xrdp-.spec is not needed
|
||||
for pkg in udsclient-$VERSION.spec udsclient-opensuse-$VERSION.spec; do
|
||||
|
||||
rm -rf rpm
|
||||
for folder in SOURCES BUILD RPMS SPECS SRPMS; do
|
||||
mkdir -p rpm/$folder
|
||||
done
|
||||
|
||||
rpmbuild -v -bb --clean --buildroot=$top/rpm/BUILD/$pkg-root --target noarch $pkg 2>&1
|
||||
done
|
||||
|
||||
#rm udsclient-$VERSION
|
||||
|
||||
make DESTDIR=targz DISTRO=targz VERSION=${VERSION} install
|
3
client/full/linux/debian/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
/udsactor/
|
||||
/udsactor-xrdp/
|
||||
/udsactor-nx/
|
@ -1,53 +0,0 @@
|
||||
udsclient (3.5.0) stable; urgency=medium
|
||||
|
||||
* Upgraded to 3.0.0 release
|
||||
|
||||
-- Adolfo Gómez García <agomez@virtualcable.es> Fri, 23 Jul 2020 8:00:00 +0200
|
||||
|
||||
udsclient (3.0.0) stable; urgency=medium
|
||||
|
||||
* Upgraded to 3.0.0 release
|
||||
|
||||
-- Adolfo Gómez García <agomez@virtualcable.es> Wed, 10 Jul 2019 9:24:10 +0200
|
||||
|
||||
udsclient (2.2.1) stable; urgency=medium
|
||||
|
||||
* Upgraded to 2.2.1 release
|
||||
|
||||
-- Adolfo Gómez García <agomez@virtualcable.es> Thu, 2 Oct 2018 12:44:12 +0200
|
||||
|
||||
udsclient (2.2.0) stable; urgency=medium
|
||||
|
||||
* Updated release
|
||||
|
||||
-- Adolfo Gómez García <agomez@virtualcable.es> Thu, 27 Aug 2017 14:18:18 +0200
|
||||
|
||||
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
|
||||
|
||||
* Release upgrade
|
||||
|
||||
-- Adolfo Gómez García <agomez@virtualcable.es> Tue, 01 Mar 2016 09:33:18 +0100
|
||||
|
||||
udsclient (1.9.1) stable; urgency=medium
|
||||
|
||||
* Minor fixes & making version match UDS version
|
||||
|
||||
-- Adolfo Gómez García <agomez@virtualcable.es> Tue, 01 Mar 2016 03:02:37 +0100
|
||||
|
||||
udsclient (1.9.0) stable; urgency=medium
|
||||
|
||||
* Minor fixes & making version match UDS version
|
||||
|
||||
-- Adolfo Gómez García <agomez@virtualcable.es> Tue, 05 May 2015 07:03:47 +0200
|
||||
|
||||
udsclient (1.7.5) stable; urgency=medium
|
||||
|
||||
* Initial release.
|
||||
|
||||
-- Adolfo Gómez García <agomez@virtualcable.es> Fri, 10 Apr 2015 05:32:41 +0100
|
@ -1 +0,0 @@
|
||||
9
|
@ -1,15 +0,0 @@
|
||||
Source: udsclient
|
||||
Section: admin
|
||||
Priority: optional
|
||||
Maintainer: Adolfo Gómez García <agomez@virtualcable.es>
|
||||
Build-Depends: debhelper (>= 7), po-debconf
|
||||
Standards-Version: 3.9.2
|
||||
Homepage: http://www.virtualcable.es
|
||||
|
||||
Package: udsclient
|
||||
Section: admin
|
||||
Priority: optional
|
||||
Architecture: all
|
||||
Depends: python-paramiko (>=0.8.2), python-crypto, python-qt4 (>=4.9), python-six(>=1.1), python (>=2.7), freerdp2-x11 | freerdp-x11, desktop-file-utils, ${misc:Depends}
|
||||
Description: Client connector for Universal Desktop Services (UDS) Broker
|
||||
This package provides the required components to allow this machine to connect to services provided by UDS Broker.
|
@ -1,26 +0,0 @@
|
||||
Format-Specification: http://svn.debian.org/wsvn/dep/web/deps/dep5.mdwn?op=file&rev=135
|
||||
Name: udsclient
|
||||
Maintainer: Adolfo Gómez García
|
||||
Source: http://www.udsenterprise.com/
|
||||
|
||||
Copyright: 2014 Virtual Cable S.L.U.
|
||||
License: BSD-3-clause
|
||||
|
||||
License: GPL-2+
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
.
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
.
|
||||
On Debian systems, the full text of the GNU General Public
|
||||
License version 2 can be found in the file
|
||||
`/usr/share/common-licenses/GPL-2'.
|
@ -1 +0,0 @@
|
||||
readme.txt
|
@ -1,2 +0,0 @@
|
||||
udsclient_3.5.0_all.deb admin optional
|
||||
udsclient_3.5.0_amd64.buildinfo admin optional
|
@ -1,44 +0,0 @@
|
||||
#!/usr/bin/make -f
|
||||
# -*- makefile -*-
|
||||
configure: configure-stamp
|
||||
configure-stamp:
|
||||
dh_testdir
|
||||
touch configure-stamp
|
||||
build: build-arch build-indep
|
||||
build-arch: build-stamp
|
||||
build-indep: build-stamp
|
||||
build-stamp: configure-stamp
|
||||
dh_testdir
|
||||
$(MAKE)
|
||||
touch $@
|
||||
clean:
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
rm -f build-stamp configure-stamp
|
||||
dh_clean
|
||||
install: build
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
dh_prep
|
||||
dh_installdirs
|
||||
$(MAKE) DESTDIR=$(CURDIR)/debian/udsclient install
|
||||
binary-arch: build install
|
||||
# emptyness
|
||||
binary-indep: build install
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
dh_installchangelogs
|
||||
dh_installdocs
|
||||
dh_installdebconf
|
||||
dh_installinit --no-start
|
||||
dh_python2=python
|
||||
dh_compress
|
||||
dh_link
|
||||
dh_fixperms
|
||||
dh_installdeb
|
||||
dh_shlibdeps
|
||||
dh_gencontrol
|
||||
dh_md5sums
|
||||
dh_builddeb
|
||||
binary: binary-indep
|
||||
.PHONY: build clean binary-indep binary install configure
|
@ -1,17 +0,0 @@
|
||||
dh_prep
|
||||
dh_installdirs
|
||||
dh_installchangelogs
|
||||
dh_installdocs
|
||||
dh_installdebconf
|
||||
dh_installinit
|
||||
dh_compress
|
||||
dh_link
|
||||
dh_fixperms
|
||||
dh_installdeb
|
||||
dh_shlibdeps
|
||||
dh_gencontrol
|
||||
dh_md5sums
|
||||
dh_builddeb
|
||||
dh_builddeb
|
||||
dh_builddeb
|
||||
dh_builddeb
|
@ -1,21 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
. /usr/share/debconf/confmodule
|
||||
|
||||
set -e
|
||||
case "$1" in
|
||||
configure)
|
||||
;;
|
||||
|
||||
abort-upgrade|abort-remove|abort-deconfigure)
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "postinst called with unknown argument \`$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
#DEBHELPER#
|
||||
|
||||
exit 0
|
@ -1,6 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
. /usr/share/debconf/confmodule
|
||||
|
||||
set -e
|
||||
|
@ -1 +0,0 @@
|
||||
#! /bin/bash -e
|
@ -1,20 +0,0 @@
|
||||
Template: udsactor/host
|
||||
Type: string
|
||||
Default:
|
||||
Description: UDS Server address:
|
||||
The actor needs the address of the server in order to communicate with it.
|
||||
Provide here full address (or i) of the UDS server
|
||||
|
||||
Template: udsactor/secure
|
||||
Type: boolean
|
||||
Default: true
|
||||
Description: Use secure (https) connection to communicate with UDS server?
|
||||
If selected, the communication will be done using https.
|
||||
If not selected, the communication will be done using http
|
||||
|
||||
Template: udsactor/masterKey
|
||||
Type: string
|
||||
Default:
|
||||
Description: Master Key:
|
||||
This key is available on UDS Administration interface.
|
||||
Look for it under configuration, on Security tab.
|
@ -1,11 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Name=UDSClient
|
||||
Comment=UDS Helper
|
||||
Keywords=uds;client;vdi;
|
||||
Exec=/usr/lib/UDSClient/UDSClient.py %u
|
||||
Icon=help-browser
|
||||
StartupNotify=true
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Utility;
|
||||
MimeType=x-scheme-handler/uds;x-scheme-handler/udss;
|
@ -1,14 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cp -r usr/lib/UDSClient /usr/lib/UDSClient
|
||||
cp -r usr/share/applications /usr/lib/applications -R
|
||||
update-desktop-database
|
||||
|
||||
echo "Installation process done."
|
||||
echo "Remembar that the following packages must be installed on system:"
|
||||
echo "* Python paramiko"
|
||||
echo "* Python pyqt4"
|
||||
echo "Theese packages (as their names), are dependent on your platform, so you must locate and install them"
|
||||
echo "You can install them directly on any platform with pip, using this simple command: "
|
||||
echo "pip install PyQt4 paramiko"
|
||||
|
@ -1,3 +0,0 @@
|
||||
UDSClient is the client connector needed to get acccess to services managed by UDS Broker.
|
||||
|
||||
Please, visit http://www.udsenterprise.com for more information
|
@ -1,52 +0,0 @@
|
||||
%define _topdir %(echo $PWD)/rpm
|
||||
%define name udsclient
|
||||
%define version 0.0.0
|
||||
%define release 1
|
||||
%define buildroot %{_topdir}/%{name}-%{version}-%{release}-root
|
||||
|
||||
BuildRoot: %{buildroot}
|
||||
Name: %{name}
|
||||
Version: %{version}
|
||||
Release: %{release}
|
||||
Summary: Client for Universal Desktop Services (UDS) Broker
|
||||
License: BSD3
|
||||
Group: Applications/Productivity
|
||||
Requires: python-six python-paramiko PyQt4
|
||||
Vendor: Virtual Cable S.L.U.
|
||||
URL: http://www.udsenterprise.com
|
||||
Provides: udsclient
|
||||
|
||||
%define _rpmdir ../
|
||||
%define _rpmfilename %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm
|
||||
|
||||
|
||||
%install
|
||||
curdir=`pwd`
|
||||
cd ../..
|
||||
make DESTDIR=$RPM_BUILD_ROOT DISTRO=rh install
|
||||
cd $curdir
|
||||
|
||||
%post
|
||||
/usr/bin/update-desktop-database
|
||||
if [ ! -d /media ]; then mkdir /media; echo "/media created for compatibility"; fi
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
curdir=`pwd`
|
||||
cd ../..
|
||||
make DESTDIR=$RPM_BUILD_ROOT DISTRO=rh clean
|
||||
cd $curdir
|
||||
|
||||
|
||||
%postun
|
||||
# And, posibly, the .pyc leaved behind on /usr/share/UDSActor
|
||||
rm -rf /usr/share/UDClient > /dev/null 2>&1
|
||||
/usr/bin/update-desktop-database
|
||||
|
||||
%description
|
||||
This package provides the required components to allow connection to services offered by UDS Broker.
|
||||
|
||||
%files
|
||||
%defattr(-,root,root)
|
||||
/usr/lib/UDSClient/*
|
||||
/usr/share/applications/UDSClient.desktop
|
4
client/full/src/.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
/build
|
||||
/dist
|
||||
UDSClient.dmg
|
||||
UDSClient.pkg
|
@ -1,339 +0,0 @@
|
||||
#!/usr/bin/env python2.7
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014-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
|
||||
'''
|
||||
# pylint: disable=c-extension-no-member
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import sys
|
||||
import webbrowser
|
||||
import json
|
||||
|
||||
from PyQt4 import QtCore, QtGui # @UnresolvedImport
|
||||
import six
|
||||
|
||||
from uds.rest import RestRequest
|
||||
from uds.forward import forward # pylint: disable=unused-import
|
||||
from uds.tunnel import forward as f2 # pylint: disable=unused-import
|
||||
from uds.log import logger
|
||||
from uds import tools
|
||||
from uds import VERSION
|
||||
|
||||
from UDSWindow import Ui_MainWindow
|
||||
|
||||
# Server before this version uses "unsigned" scripts
|
||||
OLD_METHOD_VERSION = '2.4.0'
|
||||
|
||||
class RetryException(Exception):
|
||||
pass
|
||||
|
||||
class UDSClient(QtGui.QMainWindow):
|
||||
|
||||
ticket = None
|
||||
scrambler = None
|
||||
withError = False
|
||||
animTimer = None
|
||||
anim = 0
|
||||
animInverted = False
|
||||
serverVersion = 'X.Y.Z' # Will be overwriten on getVersion
|
||||
req = None
|
||||
|
||||
def __init__(self):
|
||||
QtGui.QMainWindow.__init__(self)
|
||||
self.setWindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.WindowStaysOnTopHint)
|
||||
|
||||
self.ui = Ui_MainWindow()
|
||||
self.ui.setupUi(self)
|
||||
|
||||
self.ui.progressBar.setValue(0)
|
||||
self.ui.cancelButton.clicked.connect(self.cancelPushed)
|
||||
|
||||
self.ui.info.setText('Initializing...')
|
||||
|
||||
screen = QtGui.QDesktopWidget().screenGeometry()
|
||||
mysize = self.geometry()
|
||||
hpos = (screen.width() - mysize.width()) / 2
|
||||
vpos = (screen.height() - mysize.height() - mysize.height()) / 2
|
||||
self.move(hpos, vpos)
|
||||
|
||||
self.animTimer = QtCore.QTimer()
|
||||
QtCore.QObject.connect(self.animTimer, QtCore.SIGNAL('timeout()'), self.updateAnim)
|
||||
|
||||
self.activateWindow()
|
||||
|
||||
self.startAnim()
|
||||
|
||||
|
||||
def closeWindow(self):
|
||||
self.close()
|
||||
|
||||
def processError(self, data):
|
||||
if 'error' in data:
|
||||
# QtGui.QMessageBox.critical(self, 'Request error {}'.format(data.get('retryable', '0')), data['error'], QtGui.QMessageBox.Ok)
|
||||
if data.get('retryable', '0') == '1':
|
||||
raise RetryException(data['error'])
|
||||
|
||||
raise Exception(data['error'])
|
||||
# QtGui.QMessageBox.critical(self, 'Request error', rest.data['error'], QtGui.QMessageBox.Ok)
|
||||
# self.closeWindow()
|
||||
# return
|
||||
|
||||
def showError(self, error):
|
||||
logger.error('got error: %s', error)
|
||||
self.stopAnim()
|
||||
self.ui.info.setText('UDS Plugin Error') # In fact, main window is hidden, so this is not visible... :)
|
||||
self.closeWindow()
|
||||
QtGui.QMessageBox.critical(None, 'UDS Plugin Error', '{}'.format(error), QtGui.QMessageBox.Ok)
|
||||
self.withError = True
|
||||
|
||||
def cancelPushed(self):
|
||||
self.close()
|
||||
|
||||
@QtCore.pyqtSlot()
|
||||
def updateAnim(self):
|
||||
self.anim += 2
|
||||
if self.anim > 99:
|
||||
self.animInverted = not self.animInverted
|
||||
self.ui.progressBar.setInvertedAppearance(self.animInverted)
|
||||
self.anim = 0
|
||||
|
||||
self.ui.progressBar.setValue(self.anim)
|
||||
|
||||
def startAnim(self):
|
||||
self.ui.progressBar.invertedAppearance = False
|
||||
self.anim = 0
|
||||
self.animInverted = False
|
||||
self.ui.progressBar.setInvertedAppearance(self.animInverted)
|
||||
self.animTimer.start(40)
|
||||
|
||||
def stopAnim(self):
|
||||
self.ui.progressBar.invertedAppearance = False
|
||||
self.animTimer.stop()
|
||||
|
||||
@QtCore.pyqtSlot()
|
||||
def getVersion(self):
|
||||
self.req = RestRequest('', self, self.version)
|
||||
self.req.get()
|
||||
|
||||
@QtCore.pyqtSlot(dict)
|
||||
def version(self, data):
|
||||
try:
|
||||
self.processError(data)
|
||||
self.ui.info.setText('Processing...')
|
||||
|
||||
if data['result']['requiredVersion'] > VERSION:
|
||||
QtGui.QMessageBox.critical(self, 'Upgrade required', 'A newer connector version is required.\nA browser will be opened to download it.', QtGui.QMessageBox.Ok)
|
||||
webbrowser.open(data['result']['downloadUrl'])
|
||||
self.closeWindow()
|
||||
return
|
||||
|
||||
self.serverVersion = data['result']['requiredVersion']
|
||||
self.getTransportData()
|
||||
|
||||
except RetryException as e:
|
||||
self.ui.info.setText(six.text_type(e))
|
||||
QtCore.QTimer.singleShot(1000, self.getVersion)
|
||||
|
||||
except Exception as e:
|
||||
self.showError(e)
|
||||
|
||||
|
||||
@QtCore.pyqtSlot()
|
||||
def getTransportData(self):
|
||||
try:
|
||||
self.req = RestRequest('/{}/{}'.format(self.ticket, self.scrambler), self, self.transportDataReceived, params={'hostname': tools.getHostName(), 'version': VERSION})
|
||||
self.req.get()
|
||||
except Exception as e:
|
||||
logger.exception('Got exception on getTransportData')
|
||||
raise e
|
||||
|
||||
|
||||
@QtCore.pyqtSlot(dict)
|
||||
def transportDataReceived(self, data):
|
||||
logger.debug('Transport data received')
|
||||
try:
|
||||
self.processError(data)
|
||||
|
||||
params = None
|
||||
|
||||
if self.serverVersion <= OLD_METHOD_VERSION:
|
||||
script = data['result'].decode('base64').decode('bz2')
|
||||
else:
|
||||
res = data['result']
|
||||
# We have three elements on result:
|
||||
# * Script
|
||||
# * Signature
|
||||
# * Script data
|
||||
# We test that the Script has correct signature, and them execute it with the parameters
|
||||
script, signature, params = res['script'].decode('base64').decode('bz2'), res['signature'], json.loads(res['params'].decode('base64').decode('bz2'))
|
||||
if tools.verifySignature(script, signature) is False:
|
||||
logger.error('Signature is invalid')
|
||||
|
||||
raise Exception('Invalid UDS code signature. Please, report to administrator')
|
||||
|
||||
self.stopAnim()
|
||||
|
||||
if 'darwin' in sys.platform:
|
||||
self.showMinimized()
|
||||
|
||||
QtCore.QTimer.singleShot(3000, self.endScript)
|
||||
self.hide()
|
||||
|
||||
# if self.serverVersion <= OLD_METHOD_VERSION:
|
||||
# errorString = '<p>The server <b>{}</b> runs an old version of UDS:</p>'.format(host)
|
||||
# errorString += '<p>To avoid security issues, you must approve old UDS Version access.</p>'
|
||||
#
|
||||
# if QtGui.QMessageBox.warning(None, 'ACCESS Warning', errorString, QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) == QtGui.QMessageBox.No:
|
||||
# raise Exception('Server not approved. Access denied.')
|
||||
|
||||
six.exec_(script, globals(), {'parent': self, 'sp': params})
|
||||
|
||||
except RetryException as e:
|
||||
self.ui.info.setText(six.text_type(e) + ', retrying access...')
|
||||
# Retry operation in ten seconds
|
||||
QtCore.QTimer.singleShot(10000, self.getTransportData)
|
||||
|
||||
except Exception as e:
|
||||
#logger.exception('Got exception executing script:')
|
||||
self.showError(e)
|
||||
|
||||
def endScript(self):
|
||||
# After running script, wait for stuff
|
||||
try:
|
||||
tools.waitForTasks()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
tools.unlinkFiles()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
tools.execBeforeExit()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
self.closeWindow()
|
||||
|
||||
def start(self):
|
||||
'''
|
||||
Starts proccess by requesting version info
|
||||
'''
|
||||
self.ui.info.setText('Initializing...')
|
||||
QtCore.QTimer.singleShot(100, self.getVersion)
|
||||
|
||||
|
||||
def done(data):
|
||||
QtGui.QMessageBox.critical(None, 'Notice', six.text_type(data.data), QtGui.QMessageBox.Ok)
|
||||
sys.exit(0)
|
||||
|
||||
# Ask user to approve endpoint
|
||||
def approveHost(hostName, parentWindow=None):
|
||||
settings = QtCore.QSettings()
|
||||
settings.beginGroup('endpoints')
|
||||
|
||||
approved = settings.value(hostName, False).toBool()
|
||||
|
||||
errorString = '<p>The server <b>{}</b> must be approved:</p>'.format(hostName)
|
||||
errorString += '<p>Only approve UDS servers that you trust to avoid security issues.</p>'
|
||||
|
||||
if approved or QtGui.QMessageBox.warning(parentWindow, 'ACCESS Warning', errorString, QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) == QtGui.QMessageBox.Yes:
|
||||
settings.setValue(hostName, True)
|
||||
approved = True
|
||||
|
||||
settings.endGroup()
|
||||
return approved
|
||||
|
||||
if __name__ == "__main__":
|
||||
logger.debug('Initializing connector')
|
||||
# Initialize app
|
||||
app = QtGui.QApplication(sys.argv)
|
||||
|
||||
# Set several info for settings
|
||||
QtCore.QCoreApplication.setOrganizationName('Virtual Cable S.L.U.')
|
||||
QtCore.QCoreApplication.setApplicationName('UDS Connector')
|
||||
|
||||
if 'darwin' not in sys.platform:
|
||||
logger.debug('Mac OS *NOT* Detected')
|
||||
app.setStyle('plastique')
|
||||
|
||||
if six.PY3 is False:
|
||||
logger.debug('Fixing threaded execution of commands')
|
||||
import threading
|
||||
threading._DummyThread._Thread__stop = lambda x: 42 # type: ignore pylint: disable=protected-access
|
||||
|
||||
# First parameter must be url
|
||||
try:
|
||||
uri = sys.argv[1]
|
||||
|
||||
if uri == '--test':
|
||||
sys.exit(0)
|
||||
|
||||
logger.debug('URI: %s', uri)
|
||||
if uri[:6] != 'uds://' and uri[:7] != 'udss://':
|
||||
raise Exception()
|
||||
|
||||
ssl = uri[3] == 's'
|
||||
host, UDSClient.ticket, UDSClient.scrambler = uri.split('//')[1].split('/') # type: ignore
|
||||
logger.debug('ssl:%s, host:%s, ticket:%s, scrambler:%s', ssl, host, UDSClient.ticket, UDSClient.scrambler)
|
||||
except Exception:
|
||||
logger.debug('Detected execution without valid URI, exiting')
|
||||
QtGui.QMessageBox.critical(None, 'Notice', 'UDS Client Version {}'.format(VERSION), QtGui.QMessageBox.Ok)
|
||||
sys.exit(1)
|
||||
|
||||
# Setup REST api endpoint
|
||||
RestRequest.restApiUrl = '{}://{}/rest/client'.format(['http', 'https'][ssl], host)
|
||||
logger.debug('Setting request URL to %s', RestRequest.restApiUrl)
|
||||
# RestRequest.restApiUrl = 'https://172.27.0.1/rest/client'
|
||||
|
||||
try:
|
||||
logger.debug('Starting execution')
|
||||
|
||||
# Approbe before going on
|
||||
if approveHost(host) is False:
|
||||
raise Exception('Host {} was not approved'.format(host))
|
||||
|
||||
win = UDSClient()
|
||||
win.show()
|
||||
|
||||
win.start()
|
||||
|
||||
exitVal = app.exec_()
|
||||
logger.debug('Execution finished correctly')
|
||||
|
||||
except Exception as e:
|
||||
logger.exception('Got an exception executing client:')
|
||||
exitVal = 128
|
||||
QtGui.QMessageBox.critical(None, 'Error', six.text_type(e), QtGui.QMessageBox.Ok)
|
||||
|
||||
logger.debug('Exiting')
|
||||
sys.exit(exitVal)
|
@ -1,6 +0,0 @@
|
||||
<RCC>
|
||||
<qresource prefix="images">
|
||||
<file alias="logo-uds-small">images/logo-uds-small.png</file>
|
||||
<file alias="logo-uds-big">images/logo-uds.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
@ -1,105 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'UDSWindow.ui'
|
||||
#
|
||||
# Created: Mon Apr 27 21:41:43 2015
|
||||
# by: PyQt4 UI code generator 4.11.2
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
try:
|
||||
_fromUtf8 = QtCore.QString.fromUtf8
|
||||
except AttributeError:
|
||||
def _fromUtf8(s):
|
||||
return s
|
||||
|
||||
try:
|
||||
_encoding = QtGui.QApplication.UnicodeUTF8
|
||||
def _translate(context, text, disambig):
|
||||
return QtGui.QApplication.translate(context, text, disambig, _encoding)
|
||||
except AttributeError:
|
||||
def _translate(context, text, disambig):
|
||||
return QtGui.QApplication.translate(context, text, disambig)
|
||||
|
||||
class Ui_MainWindow(object):
|
||||
def setupUi(self, MainWindow):
|
||||
MainWindow.setObjectName(_fromUtf8("MainWindow"))
|
||||
MainWindow.setWindowModality(QtCore.Qt.NonModal)
|
||||
MainWindow.resize(259, 185)
|
||||
MainWindow.setCursor(QtGui.QCursor(QtCore.Qt.BusyCursor))
|
||||
icon = QtGui.QIcon()
|
||||
icon.addPixmap(QtGui.QPixmap(_fromUtf8(":/images/logo-uds-small")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
MainWindow.setWindowIcon(icon)
|
||||
MainWindow.setWindowOpacity(1.0)
|
||||
self.centralwidget = QtGui.QWidget(MainWindow)
|
||||
self.centralwidget.setAutoFillBackground(True)
|
||||
self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
|
||||
self.verticalLayout_2 = QtGui.QVBoxLayout(self.centralwidget)
|
||||
self.verticalLayout_2.setSpacing(4)
|
||||
self.verticalLayout_2.setMargin(4)
|
||||
self.verticalLayout_2.setObjectName(_fromUtf8("verticalLayout_2"))
|
||||
self.frame = QtGui.QFrame(self.centralwidget)
|
||||
self.frame.setFrameShape(QtGui.QFrame.StyledPanel)
|
||||
self.frame.setFrameShadow(QtGui.QFrame.Raised)
|
||||
self.frame.setObjectName(_fromUtf8("frame"))
|
||||
self.verticalLayout_3 = QtGui.QVBoxLayout(self.frame)
|
||||
self.verticalLayout_3.setSpacing(4)
|
||||
self.verticalLayout_3.setMargin(4)
|
||||
self.verticalLayout_3.setObjectName(_fromUtf8("verticalLayout_3"))
|
||||
self.verticalLayout = QtGui.QVBoxLayout()
|
||||
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
|
||||
self.image = QtGui.QLabel(self.frame)
|
||||
self.image.setMinimumSize(QtCore.QSize(0, 24))
|
||||
self.image.setAutoFillBackground(True)
|
||||
self.image.setText(_fromUtf8(""))
|
||||
self.image.setPixmap(QtGui.QPixmap(_fromUtf8(":/images/logo-uds-small")))
|
||||
self.image.setScaledContents(False)
|
||||
self.image.setAlignment(QtCore.Qt.AlignCenter)
|
||||
self.image.setObjectName(_fromUtf8("image"))
|
||||
self.verticalLayout.addWidget(self.image)
|
||||
self.info = QtGui.QLabel(self.frame)
|
||||
self.info.setMaximumSize(QtCore.QSize(16777215, 16))
|
||||
self.info.setObjectName(_fromUtf8("info"))
|
||||
self.verticalLayout.addWidget(self.info)
|
||||
self.progressBar = QtGui.QProgressBar(self.frame)
|
||||
self.progressBar.setProperty("value", 24)
|
||||
self.progressBar.setTextVisible(False)
|
||||
self.progressBar.setObjectName(_fromUtf8("progressBar"))
|
||||
self.verticalLayout.addWidget(self.progressBar)
|
||||
self.horizontalLayout = QtGui.QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
|
||||
spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
|
||||
self.horizontalLayout.addItem(spacerItem)
|
||||
self.cancelButton = QtGui.QPushButton(self.frame)
|
||||
self.cancelButton.setDefault(True)
|
||||
self.cancelButton.setFlat(False)
|
||||
self.cancelButton.setObjectName(_fromUtf8("cancelButton"))
|
||||
self.horizontalLayout.addWidget(self.cancelButton)
|
||||
spacerItem1 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
|
||||
self.horizontalLayout.addItem(spacerItem1)
|
||||
self.verticalLayout.addLayout(self.horizontalLayout)
|
||||
self.verticalLayout_3.addLayout(self.verticalLayout)
|
||||
self.verticalLayout_2.addWidget(self.frame)
|
||||
MainWindow.setCentralWidget(self.centralwidget)
|
||||
|
||||
self.retranslateUi(MainWindow)
|
||||
QtCore.QMetaObject.connectSlotsByName(MainWindow)
|
||||
|
||||
def retranslateUi(self, MainWindow):
|
||||
MainWindow.setWindowTitle(_translate("MainWindow", "UDS Connection", None))
|
||||
self.info.setText(_translate("MainWindow", "TextLabel", None))
|
||||
self.cancelButton.setText(_translate("MainWindow", "Cancel", None))
|
||||
|
||||
import UDSResources_rc
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
app = QtGui.QApplication(sys.argv)
|
||||
MainWindow = QtGui.QMainWindow()
|
||||
ui = Ui_MainWindow()
|
||||
ui.setupUi(MainWindow)
|
||||
MainWindow.show()
|
||||
sys.exit(app.exec_())
|
||||
|
@ -1,160 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::NonModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>259</width>
|
||||
<height>185</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="cursor">
|
||||
<cursorShape>BusyCursor</cursorShape>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>UDS Connection</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset resource="UDSResources.qrc">
|
||||
<normaloff>:/images/logo-uds-small</normaloff>:/images/logo-uds-small</iconset>
|
||||
</property>
|
||||
<property name="windowOpacity">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<property name="autoFillBackground">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<property name="spacing">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="image">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="UDSResources.qrc">:/images/logo-uds-small</pixmap>
|
||||
</property>
|
||||
<property name="scaledContents">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="info">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="progressBar">
|
||||
<property name="value">
|
||||
<number>24</number>
|
||||
</property>
|
||||
<property name="textVisible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="cancelButton">
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="UDSResources.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
Before Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 9.4 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 137 KiB |
@ -1,41 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014-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
|
||||
|
||||
VERSION = '3.5.0'
|
||||
|
||||
__title__ = 'udclient'
|
||||
__version__ = VERSION
|
||||
__build__ = 0x010780
|
||||
__author__ = 'Adolfo Gómez'
|
||||
__license__ = "BSD 3-clause"
|
||||
__copyright__ = "Copyright 2014-2021 VirtualCable S.L.U."
|
@ -1,211 +0,0 @@
|
||||
# Based on forward.py from paramiko
|
||||
# Copyright (C) 2003-2007 Robey Pointer <robeypointer@gmail.com>
|
||||
# https://github.com/paramiko/paramiko/blob/master/demos/forward.py
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from binascii import hexlify
|
||||
import threading
|
||||
import random
|
||||
import time
|
||||
import select
|
||||
|
||||
import paramiko
|
||||
import six
|
||||
|
||||
from .log import logger
|
||||
|
||||
if six.PY2:
|
||||
import SocketServer as socketserver # pylint: disable=import-error
|
||||
else:
|
||||
import socketserver
|
||||
|
||||
class CheckfingerPrints(paramiko.MissingHostKeyPolicy):
|
||||
def __init__(self, fingerPrints):
|
||||
super(CheckfingerPrints, self).__init__()
|
||||
self.fingerPrints = fingerPrints
|
||||
|
||||
def missing_host_key(self, client, hostname, key):
|
||||
if self.fingerPrints:
|
||||
remotefingerPrints = hexlify(key.get_fingerprint()).decode().lower()
|
||||
logger.debug('Checking keys {} against {}'.format(remotefingerPrints, self.fingerPrints))
|
||||
if remotefingerPrints not in self.fingerPrints.split(','):
|
||||
logger.error("Server {!r} has invalid fingerPrints. ({} vs {})".format(hostname, remotefingerPrints, self.fingerPrints))
|
||||
raise paramiko.SSHException(
|
||||
"Server {!r} has invalid fingerPrints".format(hostname)
|
||||
)
|
||||
|
||||
|
||||
class ForwardServer(socketserver.ThreadingTCPServer):
|
||||
daemon_threads = True
|
||||
allow_reuse_address = True
|
||||
|
||||
|
||||
class Handler(socketserver.BaseRequestHandler):
|
||||
|
||||
def handle(self):
|
||||
self.thread.currentConnections += 1
|
||||
|
||||
try:
|
||||
chan = self.ssh_transport.open_channel('direct-tcpip',
|
||||
(self.chain_host, self.chain_port),
|
||||
self.request.getpeername())
|
||||
except Exception as e:
|
||||
logger.exception('Incoming request to %s:%d failed: %s', self.chain_host, self.chain_port, repr(e))
|
||||
return
|
||||
if chan is None:
|
||||
logger.error('Incoming request to %s:%d was rejected by the SSH server.', self.chain_host, self.chain_port)
|
||||
return
|
||||
|
||||
logger.debug('Connected! Tunnel open %r -> %r -> %r', self.request.getpeername(), chan.getpeername(), (self.chain_host, self.chain_port))
|
||||
try:
|
||||
while self.event.is_set() is False:
|
||||
r, _w, _x = select.select([self.request, chan], [], [], 1) # pylint: disable=unused-variable
|
||||
|
||||
if self.request in r:
|
||||
data = self.request.recv(1024)
|
||||
if not data:
|
||||
break
|
||||
chan.send(data)
|
||||
if chan in r:
|
||||
data = chan.recv(1024)
|
||||
if not data:
|
||||
break
|
||||
self.request.send(data)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
peername = self.request.getpeername()
|
||||
chan.close()
|
||||
self.request.close()
|
||||
logger.debug('Tunnel closed from %r', peername,)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
self.thread.currentConnections -= 1
|
||||
|
||||
if self.thread.stoppable is True and self.thread.currentConnections == 0:
|
||||
self.thread.stop()
|
||||
|
||||
|
||||
class ForwardThread(threading.Thread):
|
||||
status = 0 # Connecting
|
||||
|
||||
def __init__(self, server, port, username, password, localPort, redirectHost, redirectPort, waitTime, fingerPrints):
|
||||
threading.Thread.__init__(self)
|
||||
self.client = None
|
||||
self.fs = None
|
||||
|
||||
self.server = server
|
||||
self.port = int(port)
|
||||
self.username = username
|
||||
self.password = password
|
||||
|
||||
self.localPort = int(localPort)
|
||||
self.redirectHost = redirectHost
|
||||
self.redirectPort = redirectPort
|
||||
|
||||
self.waitTime = waitTime
|
||||
|
||||
self.fingerPrints = fingerPrints
|
||||
|
||||
self.stopEvent = threading.Event()
|
||||
|
||||
self.timer = None
|
||||
self.currentConnections = 0
|
||||
self.stoppable = False
|
||||
self.client = None
|
||||
|
||||
def clone(self, redirectHost, redirectPort, localPort=None):
|
||||
if localPort is None:
|
||||
localPort = random.randrange(33000, 52000)
|
||||
|
||||
ft = ForwardThread(self.server, self.port, self.username, self.password, localPort, redirectHost, redirectPort, self.waitTime, self.fingerPrints)
|
||||
ft.client = self.client
|
||||
self.client.useCount += 1 # One more using this client
|
||||
ft.start()
|
||||
|
||||
while ft.status == 0:
|
||||
time.sleep(0.1)
|
||||
|
||||
return (ft, localPort)
|
||||
|
||||
|
||||
def _timerFnc(self):
|
||||
self.timer = None
|
||||
logger.debug('Timer fnc: %s', self.currentConnections)
|
||||
self.stoppable = True
|
||||
if self.currentConnections <= 0:
|
||||
self.stop()
|
||||
|
||||
def run(self):
|
||||
if self.client is None:
|
||||
try:
|
||||
self.client = paramiko.SSHClient()
|
||||
self.client.useCount = 1 # Custom added variable, to keep track on when to close tunnel
|
||||
# self.client.load_system_host_keys()
|
||||
self.client.set_missing_host_key_policy(CheckfingerPrints(self.fingerPrints))
|
||||
|
||||
logger.debug('Connecting to ssh host %s:%d ...', self.server, self.port)
|
||||
|
||||
self.client.connect(self.server, self.port, username=self.username, password=self.password, timeout=5)
|
||||
except Exception:
|
||||
logger.exception('Exception connecting: ')
|
||||
self.status = 2 # Error
|
||||
return
|
||||
|
||||
class SubHandler(Handler):
|
||||
chain_host = self.redirectHost
|
||||
chain_port = self.redirectPort
|
||||
ssh_transport = self.client.get_transport()
|
||||
event = self.stopEvent
|
||||
thread = self
|
||||
|
||||
logger.debug('Wait Time: %s', self.waitTime)
|
||||
self.timer = threading.Timer(self.waitTime, self._timerFnc)
|
||||
self.timer.start()
|
||||
|
||||
self.status = 1 # Ok, listening
|
||||
|
||||
self.fs = ForwardServer(('', self.localPort), SubHandler)
|
||||
self.fs.serve_forever()
|
||||
|
||||
def stop(self):
|
||||
try:
|
||||
if self.timer:
|
||||
self.timer.cancel()
|
||||
|
||||
self.stopEvent.set()
|
||||
self.fs.shutdown()
|
||||
|
||||
if self.client is not None:
|
||||
self.client.useCount -= 1
|
||||
if self.client.useCount == 0:
|
||||
self.client.close()
|
||||
self.client = None # Clean up
|
||||
except Exception:
|
||||
logger.exception('Exception stopping')
|
||||
|
||||
|
||||
def forward(server, port, username, password, redirectHost, redirectPort, localPort=None, waitTime=10, fingerPrints=None):
|
||||
'''
|
||||
Instantiates an ssh connection to server:port
|
||||
Returns the Thread created and the local redirected port as a list: (thread, port)
|
||||
'''
|
||||
port, redirectPort = int(port), int(redirectPort)
|
||||
|
||||
if localPort is None:
|
||||
localPort = random.randrange(33000, 52000)
|
||||
|
||||
logger.debug('Connecting to %s:%s using %s/%s redirecting to %s:%s, listening on 127.0.0.1:%s',
|
||||
server, port, username, password, redirectHost, redirectPort, localPort)
|
||||
|
||||
ft = ForwardThread(server, port, username, password, localPort, redirectHost, redirectPort, waitTime, fingerPrints)
|
||||
|
||||
ft.start()
|
||||
|
||||
while ft.status == 0:
|
||||
time.sleep(0.1)
|
||||
|
||||
return (ft, localPort)
|
@ -1,55 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 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 logging
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
if sys.platform.startswith('linux'):
|
||||
from os.path import expanduser # pylint: disable=ungrouped-imports
|
||||
logFile = expanduser('~/udsclient.log')
|
||||
else:
|
||||
logFile = os.path.join(tempfile.gettempdir(), b'udsclient.log')
|
||||
|
||||
try:
|
||||
logging.basicConfig(
|
||||
filename=logFile,
|
||||
filemode='a',
|
||||
format='%(levelname)s %(asctime)s %(message)s',
|
||||
level=logging.INFO
|
||||
)
|
||||
except Exception:
|
||||
logging.basicConfig(format='%(levelname)s %(asctime)s %(message)s', level=logging.INFO)
|
||||
|
||||
logger = logging.getLogger('udsclient')
|
@ -1,48 +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
|
||||
|
||||
LINUX = 'Linux'
|
||||
WINDOWS = 'Windows'
|
||||
MAC_OS_X = 'Mac os x'
|
||||
|
||||
def getOs():
|
||||
if sys.platform.startswith('linux'):
|
||||
return LINUX
|
||||
if sys.platform.startswith('win'):
|
||||
return WINDOWS
|
||||
if sys.platform.startswith('darwin'):
|
||||
return MAC_OS_X
|
||||
return 'other'
|
@ -1,123 +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
|
||||
'''
|
||||
# pylint: disable=c-extension-no-member,no-name-in-module
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import json
|
||||
import urllib
|
||||
|
||||
import six
|
||||
|
||||
from PyQt4.QtCore import pyqtSignal, pyqtSlot
|
||||
from PyQt4.QtCore import QObject, QUrl, QSettings
|
||||
from PyQt4.QtCore import Qt
|
||||
from PyQt4.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply, QSslCertificate
|
||||
from PyQt4.QtGui import QMessageBox
|
||||
|
||||
from . import osDetector
|
||||
|
||||
from . import VERSION
|
||||
|
||||
|
||||
|
||||
class RestRequest(QObject):
|
||||
|
||||
restApiUrl = '' #
|
||||
|
||||
done = pyqtSignal(dict, name='done')
|
||||
|
||||
def __init__(self, url, parentWindow, done, params=None): # parent not used
|
||||
super(RestRequest, self).__init__()
|
||||
# private
|
||||
self._manager = QNetworkAccessManager()
|
||||
if params is not None:
|
||||
url += '?' + '&'.join('{}={}'.format(k, urllib.quote(six.text_type(v).encode('utf8'))) for k, v in params.iteritems())
|
||||
|
||||
self.url = QUrl(RestRequest.restApiUrl + url)
|
||||
|
||||
# connect asynchronous result, when a request finishes
|
||||
self._manager.finished.connect(self._finished)
|
||||
self._manager.sslErrors.connect(self._sslError)
|
||||
self._parentWindow = parentWindow
|
||||
|
||||
self.done.connect(done, Qt.QueuedConnection)
|
||||
|
||||
# private slot, no need to declare as slot
|
||||
@pyqtSlot(QNetworkReply)
|
||||
def _finished(self, reply):
|
||||
'''
|
||||
Handle signal 'finished'. A network request has finished.
|
||||
'''
|
||||
try:
|
||||
if reply.error() != QNetworkReply.NoError:
|
||||
raise Exception(reply.errorString())
|
||||
data = six.text_type(reply.readAll())
|
||||
data = json.loads(data)
|
||||
except Exception as e:
|
||||
data = {
|
||||
'result': None,
|
||||
'error': six.text_type(e)
|
||||
}
|
||||
|
||||
self.done.emit(data)
|
||||
|
||||
reply.deleteLater() # schedule for delete from main event loop
|
||||
|
||||
@pyqtSlot(QNetworkReply, list)
|
||||
def _sslError(self, reply, errors):
|
||||
# reply.ignoreSslErrors()
|
||||
|
||||
settings = QSettings()
|
||||
settings.beginGroup('ssl')
|
||||
cert = errors[0].certificate()
|
||||
digest = six.text_type(cert.digest().toHex())
|
||||
|
||||
approved = settings.value(digest, False).toBool()
|
||||
|
||||
errorString = '<p>Please, accept the certificate for <b>{}</b></p>'.format(cert.subjectInfo(QSslCertificate.CommonName))
|
||||
|
||||
# for err in errors:
|
||||
# errorString += '<li>' + err.errorString() + '</li>'
|
||||
|
||||
# errorString += '</ul>'
|
||||
|
||||
if approved or QMessageBox.warning(self._parentWindow, 'SSL Warning', errorString, QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes:
|
||||
settings.setValue(digest, True)
|
||||
reply.ignoreSslErrors()
|
||||
|
||||
settings.endGroup()
|
||||
|
||||
def get(self):
|
||||
request = QNetworkRequest(self.url)
|
||||
request.setRawHeader('User-Agent', osDetector.getOs() + " - UDS Connector " + VERSION)
|
||||
self._manager.get(request)
|
@ -1,205 +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
|
||||
|
||||
from base64 import b64decode
|
||||
|
||||
import tempfile
|
||||
import string
|
||||
import random
|
||||
import os
|
||||
import socket
|
||||
import stat
|
||||
import sys
|
||||
import time
|
||||
|
||||
import six
|
||||
|
||||
from .log import logger
|
||||
|
||||
_unlinkFiles = []
|
||||
_tasksToWait = []
|
||||
_execBeforeExit = []
|
||||
|
||||
sys_fs_enc = sys.getfilesystemencoding() or 'mbcs'
|
||||
|
||||
# Public key for scripts
|
||||
PUBLIC_KEY = '''-----BEGIN PUBLIC KEY-----
|
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuNURlGjBpqbglkTTg2lh
|
||||
dU5qPbg9Q+RofoDDucGfrbY0pjB9ULgWXUetUWDZhFG241tNeKw+aYFTEorK5P+g
|
||||
ud7h9KfyJ6huhzln9eyDu3k+kjKUIB1PLtA3lZLZnBx7nmrHRody1u5lRaLVplsb
|
||||
FmcnptwYD+3jtJ2eK9ih935DYAkYS4vJFi2FO+npUQdYBZHPG/KwXLjP4oGOuZp0
|
||||
pCTLiCXWGjqh2GWsTECby2upGS/ZNZ1r4Ymp4V2A6DZnN0C0xenHIY34FWYahbXF
|
||||
ZGdr4DFBPdYde5Rb5aVKJQc/pWK0CV7LK6Krx0/PFc7OGg7ItdEuC7GSfPNV/ANt
|
||||
5BEQNF5w2nUUsyN8ziOrNih+z6fWQujAAUZfpCCeV9ekbwXGhbRtdNkbAryE5vH6
|
||||
eCE0iZ+cFsk72VScwLRiOhGNelMQ7mIMotNck3a0P15eaGJVE2JV0M/ag/Cnk0Lp
|
||||
wI1uJQRAVqz9ZAwvF2SxM45vnrBn6TqqxbKnHCeiwstLDYG4fIhBwFxP3iMH9EqV
|
||||
2+QXqdJW/wLenFjmXfxrjTRr+z9aYMIdtIkSpADIlbaJyTtuQpEdWnrlDS2b1IGd
|
||||
Okbm65EebVzOxfje+8dRq9Uqwip8f/qmzFsIIsx3wPSvkKawFwb0G5h2HX5oJrk0
|
||||
nVgtClKcDDlSaBsO875WDR0CAwEAAQ==
|
||||
-----END PUBLIC KEY-----'''
|
||||
|
||||
|
||||
def saveTempFile(content, filename=None):
|
||||
if filename is None:
|
||||
filename = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(16))
|
||||
filename = filename + '.uds'
|
||||
|
||||
if 'win32' in sys.platform:
|
||||
logger.info('Fixing for win32')
|
||||
filename = filename.encode(sys_fs_enc)
|
||||
|
||||
filename = os.path.join(tempfile.gettempdir(), filename)
|
||||
|
||||
with open(filename, 'w') as f:
|
||||
f.write(content)
|
||||
|
||||
logger.info('Returning filename')
|
||||
return filename
|
||||
|
||||
|
||||
def readTempFile(filename):
|
||||
if 'win32' in sys.platform:
|
||||
filename = filename.encode('utf-8')
|
||||
|
||||
filename = os.path.join(tempfile.gettempdir(), filename)
|
||||
try:
|
||||
with open(filename, 'r') as f:
|
||||
return f.read()
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def testServer(host, port, timeOut=4):
|
||||
try:
|
||||
sock = socket.create_connection((host, int(port)), timeOut)
|
||||
sock.close()
|
||||
except Exception:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def findApp(appName, extraPath=None):
|
||||
if 'win32' in sys.platform and isinstance(appName, six.text_type):
|
||||
appName = appName.encode(sys_fs_enc)
|
||||
searchPath = os.environ['PATH'].split(os.pathsep)
|
||||
if extraPath is not None:
|
||||
searchPath += list(extraPath)
|
||||
|
||||
for path in searchPath:
|
||||
fileName = os.path.join(path, appName)
|
||||
if os.path.isfile(fileName) and (os.stat(fileName).st_mode & stat.S_IXUSR) != 0:
|
||||
return fileName
|
||||
return None
|
||||
|
||||
|
||||
def getHostName():
|
||||
'''
|
||||
Returns current host name
|
||||
In fact, it's a wrapper for socket.gethostname()
|
||||
'''
|
||||
hostname = socket.gethostname()
|
||||
if 'win32' in sys.platform:
|
||||
hostname = hostname.decode(sys_fs_enc)
|
||||
|
||||
hostname = six.text_type(hostname)
|
||||
logger.info('Hostname: %s', hostname)
|
||||
return hostname
|
||||
|
||||
# Queing operations (to be executed before exit)
|
||||
|
||||
|
||||
def addFileToUnlink(filename):
|
||||
'''
|
||||
Adds a file to the wait-and-unlink list
|
||||
'''
|
||||
_unlinkFiles.append(filename)
|
||||
|
||||
|
||||
def unlinkFiles():
|
||||
'''
|
||||
Removes all wait-and-unlink files
|
||||
'''
|
||||
if _unlinkFiles:
|
||||
time.sleep(5) # Wait 5 seconds before deleting anything
|
||||
|
||||
for f in _unlinkFiles:
|
||||
try:
|
||||
os.unlink(f)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def addTaskToWait(taks):
|
||||
_tasksToWait.append(taks)
|
||||
|
||||
|
||||
def waitForTasks():
|
||||
for t in _tasksToWait:
|
||||
try:
|
||||
if hasattr(t, 'join'):
|
||||
t.join()
|
||||
elif hasattr(t, 'wait'):
|
||||
t.wait()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def addExecBeforeExit(fnc):
|
||||
_execBeforeExit.append(fnc)
|
||||
|
||||
|
||||
def execBeforeExit():
|
||||
for fnc in _execBeforeExit:
|
||||
fnc.__call__()
|
||||
|
||||
|
||||
def verifySignature(script, signature):
|
||||
'''
|
||||
Verifies with a public key from whom the data came that it was indeed
|
||||
signed by their private key
|
||||
param: public_key_loc Path to public key
|
||||
param: signature String signature to be verified
|
||||
return: Boolean. True if the signature is valid; False otherwise.
|
||||
'''
|
||||
# For signature checking
|
||||
from Crypto.PublicKey import RSA
|
||||
from Crypto.Signature import PKCS1_v1_5
|
||||
from Crypto.Hash import SHA256
|
||||
|
||||
rsakey = RSA.importKey(PUBLIC_KEY)
|
||||
signer = PKCS1_v1_5.new(rsakey)
|
||||
digest = SHA256.new(script) # Script is "binary string" here
|
||||
if signer.verify(digest, b64decode(signature)):
|
||||
return True
|
||||
return False
|
@ -1,249 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2021 Virtual Cable S.L.U.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L.U. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import socket
|
||||
import ssl
|
||||
import threading
|
||||
import time
|
||||
import random
|
||||
import select
|
||||
import logging
|
||||
|
||||
import six
|
||||
|
||||
if six.PY2:
|
||||
import SocketServer as socketserver # pylint: disable=import-error
|
||||
else:
|
||||
import socketserver # pylint: disable=import-error
|
||||
|
||||
HANDSHAKE_V1 = b'\x5AMGB\xA5\x01\x00'
|
||||
BUFFER_SIZE = 1024 * 16 # Max buffer length
|
||||
DEBUG = True
|
||||
LISTEN_ADDRESS = '0.0.0.0' if DEBUG else '127.0.0.1'
|
||||
|
||||
# ForwarServer states
|
||||
TUNNEL_LISTENING, TUNNEL_OPENING, TUNNEL_PROCESSING, TUNNEL_ERROR = 0, 1, 2, 3
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ForwardServer(socketserver.ThreadingTCPServer):
|
||||
daemon_threads = True
|
||||
allow_reuse_address = True
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
remote,
|
||||
ticket,
|
||||
timeout,
|
||||
local_port,
|
||||
check_certificate,
|
||||
):
|
||||
|
||||
local_port = local_port or random.randrange(33000, 53000)
|
||||
|
||||
socketserver.ThreadingTCPServer.__init__(
|
||||
self,
|
||||
server_address=(LISTEN_ADDRESS, local_port),
|
||||
RequestHandlerClass=Handler
|
||||
)
|
||||
self.remote = remote
|
||||
self.ticket = ticket
|
||||
# Negative values for timeout, means "accept always connections"
|
||||
# "but if no connection is stablished on timeout (positive)"
|
||||
# "stop the listener"
|
||||
self.timeout = int(time.time()) + timeout if timeout > 0 else 0
|
||||
self.check_certificate = check_certificate
|
||||
self.stop_flag = threading.Event() # False initial
|
||||
self.current_connections = 0
|
||||
|
||||
self.status = TUNNEL_LISTENING
|
||||
self.can_stop = False
|
||||
|
||||
timeout = abs(timeout) or 60
|
||||
self.timer = threading.Timer(
|
||||
abs(timeout), ForwardServer.__checkStarted, args=(self,)
|
||||
)
|
||||
self.timer.start()
|
||||
|
||||
def stop(self):
|
||||
if not self.stop_flag.is_set():
|
||||
logger.debug('Stopping servers')
|
||||
self.stop_flag.set()
|
||||
if self.timer:
|
||||
self.timer.cancel()
|
||||
self.timer = None
|
||||
self.shutdown()
|
||||
|
||||
def connect(self):
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as rsocket:
|
||||
logger.info('CONNECT to %s', self.remote)
|
||||
|
||||
rsocket.connect(self.remote)
|
||||
|
||||
context = ssl.create_default_context()
|
||||
|
||||
# Do not "recompress" data, use only "base protocol" compression
|
||||
context.options |= ssl.OP_NO_COMPRESSION
|
||||
|
||||
# If ignore remote certificate
|
||||
if self.check_certificate is False:
|
||||
context.check_hostname = False
|
||||
context.verify_mode = ssl.CERT_NONE
|
||||
logger.warning('Certificate checking is disabled!')
|
||||
|
||||
return context.wrap_socket(rsocket, server_hostname=self.remote[0])
|
||||
|
||||
def check(self):
|
||||
if self.status == TUNNEL_ERROR:
|
||||
return False
|
||||
|
||||
try:
|
||||
with self.connect() as ssl_socket:
|
||||
ssl_socket.sendall(HANDSHAKE_V1 + b'TEST')
|
||||
resp = ssl_socket.recv(2)
|
||||
if resp != b'OK':
|
||||
raise Exception({'Invalid tunnelresponse: {resp}'})
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
'Error connecting to tunnel server %s: %s', self.server_address, e
|
||||
)
|
||||
return False
|
||||
|
||||
@property
|
||||
def stoppable(self):
|
||||
logger.debug('Is stoppable: %s', self.can_stop)
|
||||
return self.can_stop or (self.timeout != 0 and int(time.time()) > self.timeout)
|
||||
|
||||
@staticmethod
|
||||
def __checkStarted(fs):
|
||||
logger.debug('New connection limit reached')
|
||||
fs.timer = None
|
||||
fs.can_stop = True
|
||||
if fs.current_connections <= 0:
|
||||
fs.stop()
|
||||
|
||||
|
||||
class Handler(socketserver.BaseRequestHandler):
|
||||
# server: ForwardServer
|
||||
def handle(self):
|
||||
self.server.status = TUNNEL_OPENING
|
||||
|
||||
# If server processing is over time
|
||||
if self.server.stoppable:
|
||||
self.server.status = TUNNEL_ERROR
|
||||
logger.info('Rejected timedout connection')
|
||||
self.request.close() # End connection without processing it
|
||||
return
|
||||
|
||||
self.server.current_connections += 1
|
||||
|
||||
# Open remote connection
|
||||
try:
|
||||
logger.debug('Ticket %s', self.server.ticket)
|
||||
with self.server.connect() as ssl_socket:
|
||||
# Send handhshake + command + ticket
|
||||
ssl_socket.sendall(HANDSHAKE_V1 + b'OPEN' + self.server.ticket.encode())
|
||||
# Check response is OK
|
||||
data = ssl_socket.recv(2)
|
||||
if data != b'OK':
|
||||
data += ssl_socket.recv(128)
|
||||
raise Exception(
|
||||
'Error received: {}'.format(data.decode(errors="ignore"))
|
||||
) # Notify error
|
||||
|
||||
# All is fine, now we can tunnel data
|
||||
self.process(remote=ssl_socket)
|
||||
except Exception as e:
|
||||
logger.error('Error connecting to %s', self.server.remote)
|
||||
self.server.status = TUNNEL_ERROR
|
||||
self.server.stop()
|
||||
finally:
|
||||
self.server.current_connections -= 1
|
||||
|
||||
if self.server.current_connections <= 0 and self.server.stoppable:
|
||||
self.server.stop()
|
||||
|
||||
# Processes data forwarding
|
||||
def process(self, remote):
|
||||
self.server.status = TUNNEL_PROCESSING
|
||||
logger.debug('Processing tunnel with ticket %s', self.server.ticket)
|
||||
# Process data until stop requested or connection closed
|
||||
try:
|
||||
while not self.server.stop_flag.is_set():
|
||||
r, _w, _x = select.select([self.request, remote], [], [], 1.0)
|
||||
if self.request in r:
|
||||
data = self.request.recv(BUFFER_SIZE)
|
||||
if not data:
|
||||
break
|
||||
remote.sendall(data)
|
||||
if remote in r:
|
||||
data = remote.recv(BUFFER_SIZE)
|
||||
if not data:
|
||||
break
|
||||
self.request.sendall(data)
|
||||
logger.debug('Finished tunnel with ticekt %s', self.server.ticket)
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
|
||||
def _run(server):
|
||||
logger.debug(
|
||||
'Starting forwarder: %s -> %s, timeout: %d',
|
||||
server.server_address,
|
||||
server.remote,
|
||||
server.timeout,
|
||||
)
|
||||
server.serve_forever()
|
||||
logger.debug('Stoped forwarder %s -> %s', server.server_address, server.remote)
|
||||
|
||||
|
||||
def forward(
|
||||
remote,
|
||||
ticket,
|
||||
timeout=0,
|
||||
local_port=0,
|
||||
check_certificate=True,
|
||||
):
|
||||
|
||||
fs = ForwardServer(
|
||||
remote=remote,
|
||||
ticket=ticket,
|
||||
timeout=timeout,
|
||||
local_port=local_port,
|
||||
check_certificate=check_certificate,
|
||||
)
|
||||
# Starts a new thread
|
||||
threading.Thread(target=_run, args=(fs,)).start()
|
||||
|
||||
return fs
|
@ -1,15 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
|
||||
function process {
|
||||
for a in *.ui; do
|
||||
pyuic4 $a -o `basename $a .ui`.py -x
|
||||
done
|
||||
}
|
||||
|
||||
pyrcc4 -py3 UDSResources.qrc -o UDSResources_rc.py
|
||||
|
||||
|
||||
# process current directory ui's
|
||||
process
|
||||
|
@ -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>
|
@ -1,14 +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">system-2.7</pydev_property>
|
||||
|
||||
</pydev_project>
|
@ -1,174 +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 json
|
||||
|
||||
import six
|
||||
|
||||
from uds import ui
|
||||
from uds.rest import RestRequest, RetryException
|
||||
from uds.forward import forward # pylint: disable=unused-import
|
||||
from uds import VERSION
|
||||
from uds.log import logger # @UnresolvedImport
|
||||
from uds import tools
|
||||
|
||||
|
||||
# Server before this version uses "unsigned" scripts
|
||||
OLD_METHOD_VERSION = '2.4.0'
|
||||
|
||||
def approveHost(hostName):
|
||||
from os.path import expanduser
|
||||
hostsFile = expanduser('~/.udsclient.hosts')
|
||||
|
||||
try:
|
||||
with open(hostsFile, 'r') as f:
|
||||
approvedHosts = f.read().splitlines()
|
||||
except Exception:
|
||||
approvedHosts = []
|
||||
|
||||
hostName = hostName.lower()
|
||||
|
||||
if hostName in approvedHosts:
|
||||
return True
|
||||
|
||||
errorString = 'The server {} must be approved:\n'.format(hostName)
|
||||
errorString += 'Only approve UDS servers that you trust to avoid security issues.'
|
||||
|
||||
approved = ui.question("ACCESS Warning", errorString)
|
||||
|
||||
if approved:
|
||||
approvedHosts.append(hostName)
|
||||
logger.debug('Host was approved, saving to approvedHosts file')
|
||||
try:
|
||||
with open(hostsFile, 'w') as f:
|
||||
f.write('\n'.join(approvedHosts))
|
||||
except Exception:
|
||||
logger.warning('Got exception writing to %s', hostsFile)
|
||||
|
||||
return approved
|
||||
|
||||
|
||||
def getWithRetry(api, url, parameters=None):
|
||||
while True:
|
||||
try:
|
||||
return api.get(url, parameters)
|
||||
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 # type: ignore, pylint:disable=protected-access
|
||||
|
||||
# First parameter must be url
|
||||
try:
|
||||
uri = sys.argv[1]
|
||||
|
||||
if uri == '--test':
|
||||
sys.exit(0)
|
||||
|
||||
logger.debug('URI: %s', 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: %s, host:%s, ticket:%s, scrambler:%s', 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 %s', rest.restApiUrl)
|
||||
|
||||
# Main requests part
|
||||
# First, get version
|
||||
try:
|
||||
res = getWithRetry(rest, '')
|
||||
|
||||
logger.debug('Got information %s', res)
|
||||
requiredVersion = res['requiredVersion']
|
||||
|
||||
if 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), parameters={'hostname': tools.getHostName(), 'version': VERSION})
|
||||
|
||||
params = None
|
||||
|
||||
if requiredVersion <= OLD_METHOD_VERSION:
|
||||
script = res.decode('base64').decode('bz2')
|
||||
else:
|
||||
# We have three elements on result:
|
||||
# * Script
|
||||
# * Signature
|
||||
# * Script data
|
||||
# We test that the Script has correct signature, and them execute it with the parameters
|
||||
script, signature, params = res['script'].decode('base64').decode('bz2'), res['signature'], json.loads(res['params'].decode('base64').decode('bz2'))
|
||||
if tools.verifySignature(script, signature) is False:
|
||||
logger.error('Signature is invalid')
|
||||
|
||||
raise Exception('Invalid UDS code signature. Please, report to administrator')
|
||||
|
||||
logger.debug('Script: %s', script)
|
||||
six.exec_(script, globals(), {'parent': None, 'sp': params})
|
||||
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
|
@ -1 +0,0 @@
|
||||
../../../full/src/uds/__init__.py
|
@ -1 +0,0 @@
|
||||
../../../full/src/uds/forward.py
|
@ -1 +0,0 @@
|
||||
../../../full/src/uds/log.py
|
@ -1 +0,0 @@
|
||||
../../../full/src/uds/osDetector.py
|
@ -1,84 +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 %s', url)
|
||||
|
||||
try:
|
||||
r = requests.get(url, headers={'Content-type': 'application/json', 'User-Agent': osDetector.getOs() + " - UDS Connector " + VERSION}, verify=False)
|
||||
except requests.exceptions.ConnectionError:
|
||||
raise Exception('Error connecting to UDS Server at {}'.format(self.restApiUrl[0:-11]))
|
||||
|
||||
if r.ok:
|
||||
logger.debug('Request was OK. %s', 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'])
|
||||
|
||||
logger.error('Error requesting %s: %s, %s', url, r.code, r.text)
|
||||
raise Exception('Error {}: {}'.format(r.code, r.text))
|
@ -1 +0,0 @@
|
||||
../../../full/src/uds/tools.py
|
@ -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)
|
||||
|
@ -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)
|
@ -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
|
@ -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
|
@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd /lib/UDSClient
|
||||
exec python UDSClient.pyc $@
|
@ -1,11 +0,0 @@
|
||||
Steps:
|
||||
1.- If building from repository, full copy (recursive) the "src" folder of "client/thin" (from openuds project) inside the "udsclient" folder here (so we will have an client/thin/udsclient/src folder, with the source code of thin client). If building from the .tar.gz, simply ignore 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!!!
|
2
client/thin/thinstation/udsclient/.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
lib
|
||||
src
|
@ -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;
|
@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd /lib/UDSClient
|
||||
exec python UDSClient.pyc $@
|
@ -1,13 +0,0 @@
|
||||
#!/bin/sh
|
||||
pip install paramiko requests six pycrypto
|
||||
rm -rf lib
|
||||
mkdir -p lib/python2.7/site-packages
|
||||
for a in requests paramiko pyasn1 cryptography packaging idna asn1crypto six enum ipaddress cffi Crypto; 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
|
@ -1,5 +0,0 @@
|
||||
base
|
||||
#add your own dependancies to this file, base should always be included.
|
||||
python
|
||||
pygtk
|
||||
freerdp
|
@ -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
|
@ -1 +0,0 @@
|
||||
CMD_FULLSCREEN="example -FULLSCREEN"
|
@ -1 +0,0 @@
|
||||
CMD_GLOBAL="example -startapp"
|
@ -1 +0,0 @@
|
||||
Place a 0 length file in here as the same name as the package if your application is a Console App
|
@ -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
|
@ -1 +0,0 @@
|
||||
/etc/init.d/your_start_up_script
|