Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
15a76f3b9b | ||
|
a3110d4623 |
3
.gitignore
vendored
@@ -7,7 +7,6 @@
|
||||
*_enterprise.*
|
||||
.settings/
|
||||
.ipynb_checkpoints
|
||||
.mypy_cache
|
||||
|
||||
# Debian buildings
|
||||
*.debhelper*
|
||||
@@ -165,5 +164,3 @@
|
||||
/udsService/udsgui/obj/Debug
|
||||
/udsService/udsgui/obj/Release
|
||||
/udsService/udsgui/obj/x86
|
||||
|
||||
.vscode
|
||||
|
6
actors/.gitignore
vendored
@@ -3,8 +3,6 @@ bin
|
||||
udsactor*.deb
|
||||
udsactor*.build
|
||||
udsactor*.changes
|
||||
/udsactor_*.dsc
|
||||
/udsactor_*.tar.xz
|
||||
/udsactor_*_amd64.buildinfo
|
||||
/udsactor_1.7.0.dsc
|
||||
/udsactor_1.7.0.tar.xz
|
||||
/udsactor*.rpm
|
||||
linux/debian/files
|
||||
|
@@ -69,14 +69,12 @@ install-udsactor:
|
||||
cp scripts/udsactor $(BINDIR)
|
||||
cp scripts/UDSActorConfig-pkexec $(SBINDIR)
|
||||
cp scripts/UDSActorTool-startup $(BINDIR)
|
||||
cp scripts/udsvapp ${BINDIR}
|
||||
|
||||
# Policy to run as administrator
|
||||
cp policy/org.openuds.pkexec.UDSActorConfig.policy $(POLKITDIR)
|
||||
|
||||
# Fix permissions
|
||||
chmod 755 $(BINDIR)/udsactor
|
||||
chmod 755 $(BINDIR)/udsvapp
|
||||
chmod 755 $(BINDIR)/UDSActorTool-startup
|
||||
chmod 755 $(SBINDIR)/UDSActorConfig-pkexec
|
||||
chmod 755 $(LIBDIR)/UDSActorConfig.py
|
||||
@@ -95,4 +93,4 @@ endif
|
||||
uninstall:
|
||||
rm -rf $(LIBDIR)
|
||||
# rm -f $(BINDIR)/udsactor
|
||||
rm -rf $(CFGDIR)
|
||||
rm -rf $(CFGDIR)
|
@@ -1,21 +1,3 @@
|
||||
udsactor (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
|
||||
|
||||
udsactor (2.2.0) stable; urgency=medium
|
||||
|
||||
* Upgraded to 2.2.0 release
|
||||
|
||||
-- Adolfo Gómez García <agomez@virtualcable.es> Thu, 19 Oct 2017 16:44:12 +0200
|
||||
|
||||
udsactor (2.1.0) stable; urgency=medium
|
||||
|
||||
* Fixes for 2.1.0 release
|
||||
|
||||
-- Adolfo Gómez García <agomez@virtualcable.es> Tue, 19 Jan 2017 08:00:22 +0200
|
||||
|
||||
udsactor (2.0.0) stable; urgency=medium
|
||||
|
||||
* Upgrade for 2.0.0
|
||||
|
@@ -10,8 +10,22 @@ Package: udsactor
|
||||
Section: admin
|
||||
Priority: optional
|
||||
Architecture: all
|
||||
Depends: policykit-1(>=0.100), python3-requests (>=0.8.2), python3-pyqt4 (>=4.9), python3-six(>=1.1), python3 (>=3.4), libxss1, xscreensaver, ${misc:Depends}
|
||||
Recommends: python3-prctl(>=1.1.1)
|
||||
Depends: policykit-1(>=0.100), python-requests (>=0.8.2), python-qt4 (>=4.9), python-six(>=1.1), python-prctl(>=1.1.1), python (>=2.7), libxss1, ${misc:Depends}
|
||||
Description: Actor for Universal Desktop Services (UDS) Broker
|
||||
This package provides the required components to allow this machine to work on an environment managed by UDS Broker.
|
||||
|
||||
|
||||
Package: udsactor-xrdp
|
||||
Section: x11
|
||||
Priority: optional
|
||||
Architecture: all
|
||||
Depends: xrdp (>= 0.5.0), udsactor (>= ${binary:Version}), libpam-modules-bin (>=1.0), ${misc:Depends}
|
||||
Description: UDS Actor component for xrdp
|
||||
This package provides connection between uds actor and xrdp
|
||||
|
||||
Package: udsactor-nx
|
||||
Section: x11
|
||||
Priority: optional
|
||||
Architecture: all
|
||||
Depends: nxnode (>= 3.5.0), udsactor (>= ${binary:Version}), ${misc:Depends}
|
||||
Description: UDS Actor component for nx
|
||||
This package provides connection between uds actor and nx
|
||||
|
3
actors/linux/debian/files
Normal file
@@ -0,0 +1,3 @@
|
||||
udsactor-nx_2.0.0_all.deb x11 optional
|
||||
udsactor-xrdp_2.0.0_all.deb x11 optional
|
||||
udsactor_2.0.0_all.deb admin optional
|
@@ -5,7 +5,6 @@
|
||||
set -e
|
||||
case "$1" in
|
||||
configure)
|
||||
/usr/bin/python3 -m compileall /usr/share/UDSActor > /dev/nul 2>&1
|
||||
# If new "fresh" install or if configuration file has disappeared...
|
||||
if [ "$2" = "" ] || [ ! -f /etc/udsactor/udsactor.cfg ]; then
|
||||
db_get udsactor/host
|
||||
|
@@ -8,5 +8,5 @@ Type=Application
|
||||
NoDisplay=true
|
||||
X-KDE-autostart-after=panel
|
||||
X-KDE-StartupNotify=false
|
||||
X-DBUS-StartupType=None
|
||||
X-KDE-UniqueApplet=false
|
||||
X-DBUS-StartupType=Unique
|
||||
X-KDE-UniqueApplet=true
|
||||
|
@@ -3,4 +3,4 @@
|
||||
FOLDER=/usr/share/UDSActor
|
||||
|
||||
cd $FOLDER
|
||||
exec python3 -m udsactor.linux.UDSActorService $@
|
||||
python -m udsactor.linux.UDSActorService $@
|
||||
|
@@ -1,5 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
/usr/bin/udsactor login "$USER"
|
||||
$@
|
||||
/usr/bin/udsactor logout "$USER"
|
@@ -60,7 +60,6 @@ This package provides the required components to allow this machine to work on a
|
||||
/etc/init.d/udsactor
|
||||
/usr/bin/UDSActorTool-startup
|
||||
/usr/bin/udsactor
|
||||
/usr/bin/udsvapp
|
||||
/usr/bin/UDSActorTool
|
||||
/usr/sbin/UDSActorConfig
|
||||
/usr/sbin/UDSActorConfig-pkexec
|
||||
|
2
actors/src/.gitignore
vendored
@@ -1,6 +1,4 @@
|
||||
build
|
||||
dist
|
||||
*.spec
|
||||
.idea
|
||||
*_enterprise*
|
||||
/samples/
|
||||
|
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
@@ -33,7 +33,6 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import sys
|
||||
import os
|
||||
from PyQt4 import QtCore, QtGui
|
||||
import six
|
||||
|
||||
@@ -93,13 +92,7 @@ class UDSConfigDialog(QtGui.QDialog):
|
||||
store.writeConfig(cfg)
|
||||
self.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
# If to be run as "sudo" on linux, we will need this to avoid problems
|
||||
if 'linux' in sys.platform:
|
||||
os.environ['QT_X11_NO_MITSHM'] = '1'
|
||||
|
||||
app = QtGui.QApplication(sys.argv)
|
||||
|
||||
if store.checkPermissions() is False:
|
||||
|
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
@@ -39,7 +39,6 @@ import pickle
|
||||
import time
|
||||
import datetime
|
||||
import signal
|
||||
import six
|
||||
from udsactor import ipc
|
||||
from udsactor import utils
|
||||
from udsactor.log import logger
|
||||
@@ -52,19 +51,14 @@ from udsactor import VERSION
|
||||
|
||||
trayIcon = None
|
||||
|
||||
doLogoff = False
|
||||
|
||||
TIMER_TIMEOUT = 5 # In seconds
|
||||
|
||||
|
||||
def sigTerm(sigNo, stackFrame):
|
||||
if trayIcon:
|
||||
trayIcon.quit(extra=" (by sigterm)")
|
||||
trayIcon.quit()
|
||||
|
||||
|
||||
# About dialog
|
||||
class UDSAboutDialog(QtGui.QDialog):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QtGui.QDialog.__init__(self, parent)
|
||||
self.ui = Ui_UDSAboutDialog()
|
||||
@@ -76,7 +70,6 @@ class UDSAboutDialog(QtGui.QDialog):
|
||||
|
||||
|
||||
class UDSMessageDialog(QtGui.QDialog):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QtGui.QDialog.__init__(self, parent)
|
||||
self.ui = Ui_UDSMessageDialog()
|
||||
@@ -93,13 +86,13 @@ class UDSMessageDialog(QtGui.QDialog):
|
||||
class MessagesProcessor(QtCore.QThread):
|
||||
|
||||
logoff = QtCore.pyqtSignal(name='logoff')
|
||||
displayMessage = QtCore.pyqtSignal(six.text_type, name='displayMessage')
|
||||
script = QtCore.pyqtSignal(six.text_type, name='script')
|
||||
displayMessage = QtCore.pyqtSignal(QtCore.QString, name='displayMessage')
|
||||
script = QtCore.pyqtSignal(QtCore.QString, name='script')
|
||||
exit = QtCore.pyqtSignal(name='exit')
|
||||
information = QtCore.pyqtSignal(dict, name='information')
|
||||
|
||||
def __init__(self):
|
||||
super(MessagesProcessor, self).__init__()
|
||||
super(self.__class__, self).__init__()
|
||||
# Retries connection for a while
|
||||
for _ in range(10):
|
||||
try:
|
||||
@@ -150,11 +143,11 @@ class MessagesProcessor(QtCore.QThread):
|
||||
msgId, data = msg
|
||||
logger.debug('Got Message on User Space: {}:{}'.format(msgId, data))
|
||||
if msgId == ipc.MSG_MESSAGE:
|
||||
self.displayMessage.emit(data)
|
||||
self.displayMessage.emit(QtCore.QString.fromUtf8(data))
|
||||
elif msgId == ipc.MSG_LOGOFF:
|
||||
self.logoff.emit()
|
||||
elif msgId == ipc.MSG_SCRIPT:
|
||||
self.script.emit(data)
|
||||
self.script.emit(QtCore.QString.fromUtf8(data))
|
||||
elif msgId == ipc.MSG_INFORMATION:
|
||||
self.information.emit(pickle.loads(data))
|
||||
except Exception as e:
|
||||
@@ -170,7 +163,6 @@ class MessagesProcessor(QtCore.QThread):
|
||||
|
||||
|
||||
class UDSSystemTray(QtGui.QSystemTrayIcon):
|
||||
|
||||
def __init__(self, app_, parent=None):
|
||||
self.app = app_
|
||||
|
||||
@@ -211,34 +203,20 @@ class UDSSystemTray(QtGui.QSystemTrayIcon):
|
||||
|
||||
self.counter = 0
|
||||
|
||||
self.resetTimervars()
|
||||
self.timer.start(TIMER_TIMEOUT * 1000) # Launch idle checking every 5 seconds
|
||||
self.timer.start(5000) # Launch idle checking every 5 seconds
|
||||
self.graceTimerShots = 6 # Start counting for idle after 30 seconds after login, got on windows some "instant" logout because of idle timer not being reset??
|
||||
|
||||
self.ipc.start()
|
||||
# If this is running, it's because he have logged in
|
||||
self.ipc.sendLogin(operations.getCurrentUser())
|
||||
|
||||
def resetTimervars(self):
|
||||
self.lastTimerTime = datetime.datetime.now()
|
||||
self.graceTimerShots = 6 # Start counting for idle after 30 seconds after login, got on windows some "instant" logout because of idle timer not being reset??
|
||||
|
||||
def checkTimers(self):
|
||||
# Check clock readjustment
|
||||
# This is executed
|
||||
elapsed_seconds = (datetime.datetime.now() - self.lastTimerTime).total_seconds()
|
||||
if elapsed_seconds > TIMER_TIMEOUT * 4 or elapsed_seconds < 0:
|
||||
# Clock has changed a lot, reset session variables, idle timer, etc..
|
||||
self.resetTimervars()
|
||||
return
|
||||
|
||||
self.lastTimerTime = datetime.datetime.now()
|
||||
|
||||
self.checkIdle()
|
||||
self.checkMaxSession()
|
||||
|
||||
def checkMaxSession(self):
|
||||
if self.maxSessionTime is None or self.maxSessionTime == 0:
|
||||
logger.debug('Returning because maxSessionTime is zero')
|
||||
logger.debug('Returning because maxSessionTime is cero')
|
||||
return
|
||||
|
||||
remainingTime = self.maxSessionTime - (datetime.datetime.now() - self.sessionStart).total_seconds()
|
||||
@@ -251,7 +229,7 @@ class UDSSystemTray(QtGui.QSystemTrayIcon):
|
||||
|
||||
if remainingTime <= 0:
|
||||
logger.debug('Remaining time is less than cero, exiting')
|
||||
self.quit(extra=" (max session time {} {})".format(self.maxSessionTime, self.sessionStart))
|
||||
self.quit()
|
||||
|
||||
def checkIdle(self):
|
||||
if self.maxIdleTime is None: # No idle check
|
||||
@@ -275,7 +253,7 @@ class UDSSystemTray(QtGui.QSystemTrayIcon):
|
||||
|
||||
if remainingTime <= 0:
|
||||
logger.info('User has been idle for too long, notifying Broker that service can be reclaimed')
|
||||
self.quit(logoff=True, extra=' (idle: {} vs {})'.format(idleTime, self.maxIdleTime))
|
||||
self.quit()
|
||||
|
||||
def displayMessage(self, message):
|
||||
logger.debug('Displaying message')
|
||||
@@ -312,32 +290,32 @@ class UDSSystemTray(QtGui.QSystemTrayIcon):
|
||||
def about(self):
|
||||
self.aboutDlg.exec_()
|
||||
|
||||
def quit(self, logoff=False, extra=''):
|
||||
global doLogoff # pylint: disable=global-statement
|
||||
def quit(self):
|
||||
logger.debug('Quit invoked')
|
||||
if not self.stopped:
|
||||
if self.stopped is False:
|
||||
self.stopped = True
|
||||
try:
|
||||
# If we close Client, send Logoff to Broker
|
||||
# if sys.platform != 'win32':
|
||||
self.ipc.sendLogout(operations.getCurrentUser() + extra)
|
||||
self.ipc.sendLogout(operations.getCurrentUser())
|
||||
self.timer.stop()
|
||||
self.ipc.stop()
|
||||
except Exception:
|
||||
# May we have lost connection with server, simply exit in that case
|
||||
pass
|
||||
|
||||
doLogoff = logoff
|
||||
try:
|
||||
operations.loggoff() # Invoke log off
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
self.app.quit()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QtGui.QApplication(sys.argv)
|
||||
|
||||
# if not QtGui.QSystemTrayIcon.isSystemTrayAvailable():
|
||||
# # QtGui.QMessageBox.critical(None, "Systray", "I couldn't detect any system tray on this system.")
|
||||
# sys.exit(1)
|
||||
if not QtGui.QSystemTrayIcon.isSystemTrayAvailable():
|
||||
# QtGui.QMessageBox.critical(None, "Systray", "I couldn't detect any system tray on this system.")
|
||||
sys.exit(1)
|
||||
|
||||
# This is important so our app won't close on message windows
|
||||
QtGui.QApplication.setQuitOnLastWindowClosed(False)
|
||||
@@ -349,24 +327,16 @@ if __name__ == '__main__':
|
||||
sys.exit(1)
|
||||
|
||||
# Sets a default idle duration, but will not be used unless idle is notified from server
|
||||
operations.initIdleDuration(3600 * 16)
|
||||
operations.initIdleDuration(3600 * 10)
|
||||
|
||||
trayIcon.show()
|
||||
|
||||
# Catch kill and logout user :)
|
||||
signal.signal(signal.SIGTERM, sigTerm)
|
||||
|
||||
# app.aboutToQuit.connect()
|
||||
res = app.exec_()
|
||||
|
||||
logger.debug('Exiting')
|
||||
trayIcon.quit(logoff=doLogoff) # Pass existing doLogoff
|
||||
|
||||
if doLogoff:
|
||||
try:
|
||||
time.sleep(1)
|
||||
operations.loggoff() # Invoke log off
|
||||
except Exception:
|
||||
pass
|
||||
trayIcon.quit()
|
||||
|
||||
sys.exit(res)
|
||||
|
@@ -2,7 +2,8 @@
|
||||
|
||||
# Resource object code
|
||||
#
|
||||
# Created by: The Resource Compiler for PyQt4 (Qt v4.8.7)
|
||||
# Created: Mon Apr 27 22:05:02 2015
|
||||
# by: The Resource Compiler for PyQt (Qt v4.8.6)
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
|
@@ -2,7 +2,8 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'about-dialog.ui'
|
||||
#
|
||||
# Created by: PyQt4 UI code generator 4.12.1
|
||||
# Created: Mon Apr 27 22:05:02 2015
|
||||
# by: PyQt4 UI code generator 4.11.2
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
@@ -33,8 +34,8 @@ class Ui_UDSAboutDialog(object):
|
||||
UDSAboutDialog.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates))
|
||||
UDSAboutDialog.setModal(True)
|
||||
self.vboxlayout = QtGui.QVBoxLayout(UDSAboutDialog)
|
||||
self.vboxlayout.setMargin(9)
|
||||
self.vboxlayout.setSpacing(9)
|
||||
self.vboxlayout.setMargin(9)
|
||||
self.vboxlayout.setObjectName(_fromUtf8("vboxlayout"))
|
||||
self.LogoLabel = QtGui.QLabel(UDSAboutDialog)
|
||||
self.LogoLabel.setObjectName(_fromUtf8("LogoLabel"))
|
||||
@@ -54,8 +55,8 @@ class Ui_UDSAboutDialog(object):
|
||||
self.aboutTab = QtGui.QWidget()
|
||||
self.aboutTab.setObjectName(_fromUtf8("aboutTab"))
|
||||
self.vboxlayout1 = QtGui.QVBoxLayout(self.aboutTab)
|
||||
self.vboxlayout1.setMargin(9)
|
||||
self.vboxlayout1.setSpacing(6)
|
||||
self.vboxlayout1.setMargin(9)
|
||||
self.vboxlayout1.setObjectName(_fromUtf8("vboxlayout1"))
|
||||
self.aboutBrowser = QtGui.QTextBrowser(self.aboutTab)
|
||||
self.aboutBrowser.setOpenExternalLinks(True)
|
||||
@@ -65,8 +66,8 @@ class Ui_UDSAboutDialog(object):
|
||||
self.authorsTab = QtGui.QWidget()
|
||||
self.authorsTab.setObjectName(_fromUtf8("authorsTab"))
|
||||
self.vboxlayout2 = QtGui.QVBoxLayout(self.authorsTab)
|
||||
self.vboxlayout2.setMargin(9)
|
||||
self.vboxlayout2.setSpacing(6)
|
||||
self.vboxlayout2.setMargin(9)
|
||||
self.vboxlayout2.setObjectName(_fromUtf8("vboxlayout2"))
|
||||
self.authorsBrowser = QtGui.QTextBrowser(self.authorsTab)
|
||||
self.authorsBrowser.setOpenExternalLinks(True)
|
||||
@@ -76,8 +77,8 @@ class Ui_UDSAboutDialog(object):
|
||||
self.licenseTab = QtGui.QWidget()
|
||||
self.licenseTab.setObjectName(_fromUtf8("licenseTab"))
|
||||
self.vboxlayout3 = QtGui.QVBoxLayout(self.licenseTab)
|
||||
self.vboxlayout3.setMargin(9)
|
||||
self.vboxlayout3.setSpacing(6)
|
||||
self.vboxlayout3.setMargin(9)
|
||||
self.vboxlayout3.setObjectName(_fromUtf8("vboxlayout3"))
|
||||
self.licenseBrowser = QtGui.QTextBrowser(self.licenseTab)
|
||||
self.licenseBrowser.setObjectName(_fromUtf8("licenseBrowser"))
|
||||
@@ -91,7 +92,7 @@ class Ui_UDSAboutDialog(object):
|
||||
self.vboxlayout.addWidget(self.buttonBox)
|
||||
|
||||
self.retranslateUi(UDSAboutDialog)
|
||||
self.tabWidget.setCurrentIndex(2)
|
||||
self.tabWidget.setCurrentIndex(0)
|
||||
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("clicked(QAbstractButton*)")), UDSAboutDialog.closeDialog)
|
||||
QtCore.QMetaObject.connectSlotsByName(UDSAboutDialog)
|
||||
|
||||
@@ -105,7 +106,7 @@ class Ui_UDSAboutDialog(object):
|
||||
"p, li { white-space: pre-wrap; }\n"
|
||||
"</style></head><body style=\" font-family:\'Verdana\'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
|
||||
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:\'Sans Serif\';\"><br /></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'Sans Serif\'; font-weight:600;\">(c) 2012-2016, Virtual Cable S.L.U.</span></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'Sans Serif\'; font-weight:600;\">(c) 2014, Virtual Cable S.L.U.</span></p>\n"
|
||||
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:\'Sans Serif\'; font-style:italic;\"><br /></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><a href=\"http://www.udsenterprise.com\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt; text-decoration: underline; color:#0000ff;\">http://www.udsenterprise.com</span></a></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><a href=\"http://www.openuds.org\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt; text-decoration: underline; color:#0000ff;\">http://www.openuds.org</span></a></p>\n"
|
||||
@@ -121,7 +122,7 @@ class Ui_UDSAboutDialog(object):
|
||||
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
|
||||
"p, li { white-space: pre-wrap; }\n"
|
||||
"</style></head><body style=\" font-family:\'Verdana\'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt;\">Copyright (c) 2012-2016 Virtual Cable S.L.</span></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt;\">Copyright (c) 2014 Virtual Cable S.L.</span></p>\n"
|
||||
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:\'MS Shell Dlg 2\'; font-size:8pt;\"><br /></p>\n"
|
||||
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt;\">All rights reserved.</span></p>\n"
|
||||
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:\'MS Shell Dlg 2\'; font-size:8pt;\"><br /></p>\n"
|
||||
|
@@ -2,7 +2,8 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'message-dialog.ui'
|
||||
#
|
||||
# Created by: PyQt4 UI code generator 4.12.1
|
||||
# Created: Mon Apr 27 22:05:02 2015
|
||||
# by: PyQt4 UI code generator 4.11.2
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
|
@@ -121,7 +121,7 @@
|
||||
<x>20</x>
|
||||
<y>20</y>
|
||||
<width>361</width>
|
||||
<height>166</height>
|
||||
<height>131</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
@@ -205,7 +205,7 @@
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="logLevelComboBox">
|
||||
<property name="currentIndex">
|
||||
<number>3</number>
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="frame">
|
||||
<bool>true</bool>
|
||||
@@ -220,11 +220,6 @@
|
||||
<string notr="true">INFO</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>WARN</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">ERROR</string>
|
||||
|
@@ -2,7 +2,8 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'setup-dialog.ui'
|
||||
#
|
||||
# Created by: PyQt4 UI code generator 4.12.1
|
||||
# Created: Mon Apr 27 22:05:03 2015
|
||||
# by: PyQt4 UI code generator 4.11.2
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
@@ -62,7 +63,7 @@ class Ui_UdsActorSetupDialog(object):
|
||||
self.cancelButton.setSizePolicy(sizePolicy)
|
||||
self.cancelButton.setObjectName(_fromUtf8("cancelButton"))
|
||||
self.layoutWidget = QtGui.QWidget(UdsActorSetupDialog)
|
||||
self.layoutWidget.setGeometry(QtCore.QRect(20, 20, 361, 166))
|
||||
self.layoutWidget.setGeometry(QtCore.QRect(20, 20, 361, 131))
|
||||
self.layoutWidget.setObjectName(_fromUtf8("layoutWidget"))
|
||||
self.formLayout = QtGui.QFormLayout(self.layoutWidget)
|
||||
self.formLayout.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow)
|
||||
@@ -101,14 +102,13 @@ class Ui_UdsActorSetupDialog(object):
|
||||
self.logLevelComboBox.addItem(_fromUtf8(""))
|
||||
self.logLevelComboBox.setItemText(1, _fromUtf8("INFO"))
|
||||
self.logLevelComboBox.addItem(_fromUtf8(""))
|
||||
self.logLevelComboBox.setItemText(2, _fromUtf8("ERROR"))
|
||||
self.logLevelComboBox.addItem(_fromUtf8(""))
|
||||
self.logLevelComboBox.setItemText(3, _fromUtf8("ERROR"))
|
||||
self.logLevelComboBox.addItem(_fromUtf8(""))
|
||||
self.logLevelComboBox.setItemText(4, _fromUtf8("FATAL"))
|
||||
self.logLevelComboBox.setItemText(3, _fromUtf8("FATAL"))
|
||||
self.formLayout.setWidget(3, QtGui.QFormLayout.FieldRole, self.logLevelComboBox)
|
||||
|
||||
self.retranslateUi(UdsActorSetupDialog)
|
||||
self.logLevelComboBox.setCurrentIndex(3)
|
||||
self.logLevelComboBox.setCurrentIndex(1)
|
||||
QtCore.QObject.connect(self.host, QtCore.SIGNAL(_fromUtf8("textChanged(QString)")), UdsActorSetupDialog.textChanged)
|
||||
QtCore.QObject.connect(self.masterKey, QtCore.SIGNAL(_fromUtf8("textChanged(QString)")), UdsActorSetupDialog.textChanged)
|
||||
QtCore.QObject.connect(self.cancelButton, QtCore.SIGNAL(_fromUtf8("pressed()")), UdsActorSetupDialog.cancelAndDiscard)
|
||||
@@ -139,7 +139,6 @@ class Ui_UdsActorSetupDialog(object):
|
||||
self.useSSl.setItemText(0, _translate("UdsActorSetupDialog", "Do not use SSL", None))
|
||||
self.useSSl.setItemText(1, _translate("UdsActorSetupDialog", "Use SSL", None))
|
||||
self.logLevelLabel.setText(_translate("UdsActorSetupDialog", "Log Level", None))
|
||||
self.logLevelComboBox.setItemText(2, _translate("UdsActorSetupDialog", "WARN", None))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@@ -78,7 +78,7 @@ class OsManagerError(RESTError):
|
||||
try:
|
||||
import urllib3 # @UnusedImport
|
||||
except Exception:
|
||||
from requests.packages import urllib3 # @Reimport @UnresolvedImport
|
||||
from requests.packages import urllib3 # @Reimport
|
||||
|
||||
try:
|
||||
urllib3.disable_warnings() # @UndefinedVariable
|
||||
@@ -101,7 +101,6 @@ def ensureResultIsOk(result):
|
||||
|
||||
|
||||
class Api(object):
|
||||
|
||||
def __init__(self, host, masterKey, ssl):
|
||||
self.host = host
|
||||
self.masterKey = masterKey
|
||||
@@ -113,7 +112,7 @@ class Api(object):
|
||||
self.maxSession = None
|
||||
self.secretKey = six.text_type(uuid.uuid4())
|
||||
try:
|
||||
self.newerRequestLib = requests.__version__.split('.')[0] >= '1' # @UndefinedVariable
|
||||
self.newerRequestLib = requests.__version__.split('.')[0] >= '1'
|
||||
except Exception:
|
||||
self.newerRequestLib = False # I no version, guess this must be an old requests
|
||||
|
||||
@@ -155,11 +154,7 @@ class Api(object):
|
||||
logger.debug('Requesting with old')
|
||||
r = requests.post(url, data=data, headers={'content-type': 'application/json'})
|
||||
|
||||
# From versions of requests, content maybe bytes or str. We need str for json.loads
|
||||
content = r.content
|
||||
if not isinstance(content, six.text_type):
|
||||
content = content.decode('utf8')
|
||||
r = json.loads(content) # Using instead of r.json() to make compatible with oooold rquests lib versions
|
||||
r = json.loads(r.content) # Using instead of r.json() to make compatible with oooold rquests lib versions
|
||||
except requests.exceptions.RequestException as e:
|
||||
raise ConnectionError(e)
|
||||
except Exception as e:
|
||||
@@ -206,8 +201,6 @@ class Api(object):
|
||||
raise ConnectionError('REST api has not been initialized')
|
||||
|
||||
if processData:
|
||||
if data and not isinstance(data, six.text_type):
|
||||
data = data.decode('utf8')
|
||||
data = json.dumps({'data': data})
|
||||
url = self._getUrl('/'.join([self.uuid, msg]))
|
||||
return self._request(url, data)['result']
|
||||
|
@@ -34,22 +34,21 @@ from __future__ import unicode_literals
|
||||
# On centos, old six release does not includes byte2int, nor six.PY2
|
||||
import six
|
||||
|
||||
VERSION = '2.2.1'
|
||||
VERSION = '2.0.0'
|
||||
|
||||
__title__ = 'udsactor'
|
||||
__version__ = VERSION
|
||||
__build__ = 0x010756
|
||||
__build__ = 0x010750
|
||||
__author__ = 'Adolfo Gómez <dkmaster@dkmon.com>'
|
||||
__license__ = "BSD 3-clause"
|
||||
__copyright__ = "Copyright 2014-2018 VirtualCable S.L.U."
|
||||
__copyright__ = "Copyright 2014-2016 VirtualCable S.L.U."
|
||||
|
||||
|
||||
if not hasattr(six, 'byte2int'):
|
||||
if six.PY3:
|
||||
import operator
|
||||
six.byte2int = operator.itemgetter(0)
|
||||
else:
|
||||
|
||||
def _byte2int(bs):
|
||||
return ord(bs[0])
|
||||
|
||||
six.byte2int = _byte2int
|
||||
|
@@ -116,8 +116,8 @@ class HTTPServerHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
|
||||
try:
|
||||
HTTPServerHandler.lock.acquire()
|
||||
length = int(self.headers.get('content-length'))
|
||||
content = self.rfile.read(length).decode('utf8')
|
||||
length = int(self.headers.getheader('content-length'))
|
||||
content = self.rfile.read(length)
|
||||
logger.debug('length: {}, content >>{}<<'.format(length, content))
|
||||
params = json.loads(content)
|
||||
|
||||
@@ -181,7 +181,7 @@ class HTTPServerHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
logger.error('HTTP ' + fmt % args)
|
||||
|
||||
def log_message(self, fmt, *args):
|
||||
logger.debug('HTTP ' + fmt % args)
|
||||
logger.info('HTTP ' + fmt % args)
|
||||
|
||||
|
||||
class HTTPServerThread(threading.Thread):
|
||||
@@ -196,22 +196,13 @@ class HTTPServerThread(threading.Thread):
|
||||
|
||||
self.initiateServer(address)
|
||||
|
||||
def getPort(self):
|
||||
return self.address[1]
|
||||
|
||||
def getIp(self):
|
||||
return self.address[0]
|
||||
|
||||
def initiateServer(self, address):
|
||||
self.address = (address[0], address[1]) # Copy address & keep it for future reference...
|
||||
|
||||
addr = ('0.0.0.0', address[1]) # Adapt to listen on 0.0.0.0
|
||||
|
||||
self.server = socketserver.TCPServer(addr, HTTPServerHandler)
|
||||
self.server = socketserver.TCPServer(address, HTTPServerHandler)
|
||||
self.server.socket = ssl.wrap_socket(self.server.socket, certfile=self.certFile, server_side=True)
|
||||
|
||||
def getServerUrl(self):
|
||||
return 'https://{}:{}/{}'.format(self.getIp(), self.getPort(), HTTPServerHandler.uuid)
|
||||
return 'https://{}:{}/{}'.format(self.server.server_address[0], self.server.server_address[1], HTTPServerHandler.uuid)
|
||||
|
||||
def stop(self):
|
||||
logger.debug('Stopping REST Service')
|
||||
@@ -220,14 +211,11 @@ class HTTPServerThread(threading.Thread):
|
||||
def restart(self, address=None):
|
||||
|
||||
if address is None:
|
||||
# address = self.server.server_address
|
||||
address = self.address
|
||||
address = self.server.server_address
|
||||
|
||||
self.address = (address[0], self.address[1]) # Copy address & keep it for future reference, port is never changed once assigned on init
|
||||
self.stop()
|
||||
|
||||
# Listening on 0.0.0.0, does not need to restart listener..
|
||||
# self.stop()
|
||||
# self.initiateServer(address)
|
||||
self.initiateServer(address)
|
||||
|
||||
def run(self):
|
||||
self.server.serve_forever()
|
||||
|
@@ -33,11 +33,9 @@ from __future__ import unicode_literals
|
||||
import socket
|
||||
import threading
|
||||
import sys
|
||||
import six
|
||||
import traceback
|
||||
import pickle
|
||||
import errno
|
||||
import time
|
||||
import six
|
||||
|
||||
from udsactor.utils import toUnicode
|
||||
from udsactor.log import logger
|
||||
@@ -89,9 +87,11 @@ REV_DICT = {
|
||||
|
||||
MAGIC = b'\x55\x44\x53\x00' # UDS in hexa with a padded 0 to the right
|
||||
|
||||
|
||||
# Allows notifying login/logout from client for linux platform
|
||||
ALLOW_LOG_METHODS = sys.platform != 'win32'
|
||||
|
||||
|
||||
# States for client processor
|
||||
ST_SECOND_BYTE = 0x01
|
||||
ST_RECEIVING = 0x02
|
||||
@@ -99,9 +99,8 @@ ST_PROCESS_MESSAGE = 0x02
|
||||
|
||||
|
||||
class ClientProcessor(threading.Thread):
|
||||
|
||||
def __init__(self, parent, clientSocket):
|
||||
super(ClientProcessor, self).__init__()
|
||||
super(self.__class__, self).__init__()
|
||||
self.parent = parent
|
||||
self.clientSocket = clientSocket
|
||||
self.running = False
|
||||
@@ -132,7 +131,6 @@ class ClientProcessor(threading.Thread):
|
||||
if b == b'':
|
||||
# Client disconnected
|
||||
self.running = False
|
||||
# self.processRequest(REQ_LOGOUT, 'CLIENT_CONNECTION_LOST')
|
||||
break
|
||||
buf = six.byte2int(b) # Empty buffer, this is set as non-blocking
|
||||
if state is None:
|
||||
@@ -187,8 +185,8 @@ class ClientProcessor(threading.Thread):
|
||||
|
||||
try:
|
||||
m = msg[1] if msg[1] is not None else b''
|
||||
ln = len(m)
|
||||
data = MAGIC + six.int2byte(msg[0]) + six.int2byte(ln & 0xFF) + six.int2byte(ln >> 8) + m
|
||||
l = len(m)
|
||||
data = MAGIC + six.int2byte(msg[0]) + six.int2byte(l & 0xFF) + six.int2byte(l >> 8) + m
|
||||
try:
|
||||
self.clientSocket.sendall(data)
|
||||
except socket.error as e:
|
||||
@@ -208,7 +206,7 @@ class ClientProcessor(threading.Thread):
|
||||
class ServerIPC(threading.Thread):
|
||||
|
||||
def __init__(self, listenPort, clientMessageProcessor=None):
|
||||
super(ServerIPC, self).__init__()
|
||||
super(self.__class__, self).__init__()
|
||||
self.port = listenPort
|
||||
self.running = False
|
||||
self.serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
@@ -291,7 +289,6 @@ class ServerIPC(threading.Thread):
|
||||
|
||||
|
||||
class ClientIPC(threading.Thread):
|
||||
|
||||
def __init__(self, listenPort):
|
||||
super(ClientIPC, self).__init__()
|
||||
self.port = listenPort
|
||||
@@ -321,8 +318,8 @@ class ClientIPC(threading.Thread):
|
||||
if isinstance(data, six.text_type): # Convert to bytes if necessary
|
||||
data = data.encode('utf-8')
|
||||
|
||||
ln = len(data)
|
||||
msg = six.int2byte(msg) + six.int2byte(ln & 0xFF) + six.int2byte(ln >> 8) + data
|
||||
l = len(data)
|
||||
msg = six.int2byte(msg) + six.int2byte(l & 0xFF) + six.int2byte(l >> 8) + data
|
||||
self.clientSocket.sendall(msg)
|
||||
|
||||
def requestInformation(self):
|
||||
@@ -410,11 +407,8 @@ class ClientIPC(threading.Thread):
|
||||
self.messageReceived()
|
||||
|
||||
except socket.error as e:
|
||||
if e.errno == errno.EINTR:
|
||||
time.sleep(1) #
|
||||
continue # Ignore interrupted system call
|
||||
logger.error('Communication with server got an error: {}'.format(toUnicode(e.strerror)))
|
||||
# self.running = False
|
||||
self.running = False
|
||||
return
|
||||
except Exception as e:
|
||||
tb = traceback.format_exc()
|
||||
|
@@ -31,37 +31,28 @@
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import sys
|
||||
import os
|
||||
import stat
|
||||
import subprocess
|
||||
|
||||
from udsactor import operations
|
||||
|
||||
from udsactor.service import CommonService
|
||||
from udsactor.service import initCfg
|
||||
from udsactor.service import IPC_PORT
|
||||
|
||||
from udsactor import ipc
|
||||
from udsactor import store
|
||||
|
||||
from udsactor.log import logger
|
||||
|
||||
from udsactor.linux.daemon import Daemon
|
||||
from udsactor.linux import renamer
|
||||
|
||||
POST_CMD = '/etc/udsactor/post'
|
||||
|
||||
import sys
|
||||
import time
|
||||
try:
|
||||
from prctl import set_proctitle # @UnresolvedImport
|
||||
from prctl import set_proctitle
|
||||
except Exception: # Platform may not include prctl, so in case it's not available, we let the "name" as is
|
||||
|
||||
def set_proctitle(_):
|
||||
pass
|
||||
|
||||
|
||||
class UDSActorSvc(Daemon, CommonService):
|
||||
rebootMachineAfterOp = False
|
||||
|
||||
def __init__(self, args=None):
|
||||
Daemon.__init__(self, '/var/run/udsa.pid')
|
||||
CommonService.__init__(self)
|
||||
@@ -71,12 +62,6 @@ class UDSActorSvc(Daemon, CommonService):
|
||||
Renames the computer, and optionally sets a password for an user
|
||||
before this
|
||||
'''
|
||||
hostName = operations.getComputerName()
|
||||
|
||||
if hostName.lower() == name.lower():
|
||||
logger.info('Computer name is already {}'.format(hostName))
|
||||
self.setReady()
|
||||
return
|
||||
|
||||
# Check for password change request for an user
|
||||
if user is not None:
|
||||
@@ -90,48 +75,13 @@ class UDSActorSvc(Daemon, CommonService):
|
||||
'Could not change password for user {} (maybe invalid current password is configured at broker): {} '.format(user, unicode(e)))
|
||||
|
||||
renamer.rename(name)
|
||||
|
||||
if self.rebootMachineAfterOp is False:
|
||||
self.setReady()
|
||||
else:
|
||||
logger.info('Rebooting computer to activate new name {}'.format(name))
|
||||
self.reboot()
|
||||
self.setReady()
|
||||
|
||||
def joinDomain(self, name, domain, ou, account, password):
|
||||
logger.fatal('Join domain is not supported on linux platforms right now')
|
||||
|
||||
def preConnect(self, user, protocol):
|
||||
'''
|
||||
Invoked when received a PRE Connection request via REST
|
||||
'''
|
||||
# Execute script in /etc/udsactor/post after interacting with broker, if no reboot is requested ofc
|
||||
# This will be executed only when machine gets "ready"
|
||||
try:
|
||||
pre_cmd = store.preApplication()
|
||||
if os.path.isfile(pre_cmd):
|
||||
if (os.stat(pre_cmd).st_mode & stat.S_IXUSR) != 0:
|
||||
subprocess.call([pre_cmd, user, protocol])
|
||||
else:
|
||||
logger.info('PRECONNECT file exists but it it is not executable (needs execution permission by root)')
|
||||
else:
|
||||
logger.info('PRECONNECT file not found & not executed')
|
||||
except Exception:
|
||||
# Ignore output of execution command
|
||||
logger.error('Executing preconnect command give')
|
||||
|
||||
return 'ok'
|
||||
|
||||
def run(self):
|
||||
cfg = initCfg() # Gets a local copy of config to get "reboot"
|
||||
|
||||
logger.debug('CFG: {}'.format(cfg))
|
||||
|
||||
if cfg is not None:
|
||||
self.rebootMachineAfterOp = cfg.get('reboot', True)
|
||||
else:
|
||||
self.rebootMachineAfterOp = False
|
||||
|
||||
logger.info('Reboot after is {}'.format(self.rebootMachineAfterOp))
|
||||
initCfg()
|
||||
|
||||
logger.debug('Running Daemon')
|
||||
set_proctitle('UDSActorDaemon')
|
||||
@@ -156,21 +106,6 @@ class UDSActorSvc(Daemon, CommonService):
|
||||
logger.debug('Reboot has been requested, stopping service')
|
||||
return
|
||||
|
||||
# Execute script in /etc/udsactor/post after interacting with broker, if no reboot is requested ofc
|
||||
# This will be executed only when machine gets "ready"
|
||||
try:
|
||||
|
||||
if os.path.isfile(POST_CMD):
|
||||
if (os.stat(POST_CMD).st_mode & stat.S_IXUSR) != 0:
|
||||
subprocess.call([POST_CMD, ])
|
||||
else:
|
||||
logger.info('POST file exists but it it is not executable (needs execution permission by root)')
|
||||
else:
|
||||
logger.info('POST file not found & not executed')
|
||||
except Exception as e:
|
||||
# Ignore output of execution command
|
||||
logger.error('Executing post command give')
|
||||
|
||||
self.initIPC()
|
||||
|
||||
# *********************
|
||||
@@ -196,7 +131,6 @@ def usage():
|
||||
sys.stderr.write("usage: {} start|stop|restart|login 'username'|logout 'username'\n".format(sys.argv[0]))
|
||||
sys.exit(2)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logger.setLevel(20000)
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014-2018 Virtual Cable S.L.
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
@@ -46,7 +46,6 @@ class Daemon:
|
||||
|
||||
Usage: subclass the Daemon class and override the run() method
|
||||
"""
|
||||
|
||||
def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
|
||||
self.stdin = stdin
|
||||
self.stdout = stdout
|
||||
@@ -89,8 +88,8 @@ class Daemon:
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
si = open(self.stdin, 'r')
|
||||
so = open(self.stdout, 'ab+')
|
||||
se = open(self.stderr, 'ab+', 0)
|
||||
so = open(self.stdout, 'a+')
|
||||
se = open(self.stderr, 'a+', 0)
|
||||
os.dup2(si.fileno(), sys.stdin.fileno())
|
||||
os.dup2(so.fileno(), sys.stdout.fileno())
|
||||
os.dup2(se.fileno(), sys.stderr.fileno())
|
||||
|
@@ -122,7 +122,7 @@ def getComputerName():
|
||||
def getNetworkInfo():
|
||||
for ifname in _getInterfaces():
|
||||
ip, mac = _getIpAndMac(ifname)
|
||||
if mac != '00:00:00:00:00:00' and ip.startswith('169.254') is False: # Skips local interfaces & interfaces with no dhcp IPs
|
||||
if mac != '00:00:00:00:00:00': # Skips local interfaces
|
||||
yield utils.Bunch(name=ifname, mac=mac, ip=ip)
|
||||
|
||||
|
||||
@@ -232,7 +232,7 @@ def getIdleDuration():
|
||||
xss.XScreenSaverQueryInfo(display, xlib.XDefaultRootWindow(display), info)
|
||||
|
||||
# Centos seems to set state to 1?? (weird, but it's happening don't know why... will try this way)
|
||||
if info.contents.state == 1:
|
||||
if info.contents.state != 0 and 'centos' not in platform.linux_distribution()[0].lower().strip():
|
||||
return 3600 * 100 * 1000 # If screen saver is active, return a high enough value
|
||||
|
||||
return info.contents.idle / 1000.0
|
||||
|
@@ -30,13 +30,13 @@
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
|
||||
|
||||
import six
|
||||
import os
|
||||
|
||||
DEBUG = False
|
||||
|
||||
CONFIGFILE = '/etc/udsactor/udsactor.cfg' if DEBUG is False else '/tmp/udsactor.cfg'
|
||||
PRECONNECT_CMD = '/etc/udsactor/pre'
|
||||
|
||||
|
||||
def checkPermissions():
|
||||
@@ -78,16 +78,3 @@ def writeConfig(data):
|
||||
cfg.write(f)
|
||||
|
||||
os.chmod(CONFIGFILE, 0o0600)
|
||||
|
||||
|
||||
def useOldJoinSystem():
|
||||
return False
|
||||
|
||||
|
||||
# Right now, we do not really need an application to be run on "startup" as could ocur with windows
|
||||
def runApplication():
|
||||
return None
|
||||
|
||||
|
||||
def preApplication():
|
||||
return PRECONNECT_CMD
|
||||
|
@@ -45,7 +45,6 @@ OTHER, DEBUG, INFO, WARN, ERROR, FATAL = (10000 * (x + 1) for x in six.moves.xra
|
||||
|
||||
|
||||
class Logger(object):
|
||||
|
||||
def __init__(self):
|
||||
self.logLevel = INFO
|
||||
self.logger = LocalLogger()
|
||||
|
@@ -44,10 +44,6 @@ from .utils import exceptionToMessage
|
||||
import socket
|
||||
import time
|
||||
import random
|
||||
import os
|
||||
import subprocess
|
||||
import shlex
|
||||
import stat
|
||||
|
||||
IPC_PORT = 39188
|
||||
|
||||
@@ -74,11 +70,8 @@ def initCfg():
|
||||
cfg = None
|
||||
break
|
||||
|
||||
return cfg
|
||||
|
||||
|
||||
class CommonService(object):
|
||||
|
||||
def __init__(self):
|
||||
self.isAlive = True
|
||||
self.api = None
|
||||
@@ -86,31 +79,11 @@ class CommonService(object):
|
||||
self.httpServer = None
|
||||
self.rebootRequested = False
|
||||
self.knownIps = []
|
||||
self.loggedIn = False
|
||||
socket.setdefaulttimeout(20)
|
||||
|
||||
def reboot(self):
|
||||
self.rebootRequested = True
|
||||
|
||||
def execute(self, cmdLine, section): # pylint: disable=no-self-use
|
||||
cmd = shlex.split(cmdLine, posix=False)
|
||||
|
||||
if os.path.isfile(cmd[0]):
|
||||
if (os.stat(cmd[0]).st_mode & stat.S_IXUSR) != 0:
|
||||
try:
|
||||
res = subprocess.check_call(cmd)
|
||||
except Exception as e:
|
||||
logger.error('Got exception executing: {} - {}'.format(cmdLine, e))
|
||||
return False
|
||||
logger.info('Result of executing cmd was {}'.format(res))
|
||||
return True
|
||||
else:
|
||||
logger.error('{} file exists but it it is not executable (needs execution permission by admin/root)'.format(section))
|
||||
else:
|
||||
logger.error('{} file not found & not executed'.format(section))
|
||||
|
||||
return False
|
||||
|
||||
def setReady(self):
|
||||
self.api.setReady([(v.mac, v.ip) for v in operations.getNetworkInfo()])
|
||||
|
||||
@@ -163,14 +136,6 @@ class CommonService(object):
|
||||
# Wait a bit before next check
|
||||
self.doWait(5000)
|
||||
|
||||
# Now try to run the "runonce" element
|
||||
runOnce = store.runApplication()
|
||||
if runOnce is not None:
|
||||
logger.info('Executing runOnce app: {}'.format(runOnce))
|
||||
if self.execute(runOnce, 'RunOnce') is True:
|
||||
# operations.reboot()
|
||||
return False
|
||||
|
||||
# Broker connection is initialized, now get information about what to
|
||||
# do
|
||||
counter = 0
|
||||
@@ -245,7 +210,7 @@ class CommonService(object):
|
||||
self.knownIps = dict(((v.mac, v.ip) for v in netInfo))
|
||||
|
||||
# And notify new listening address to broker
|
||||
address = (self.knownIps[self.api.mac], self.httpServer.getPort())
|
||||
address = (self.knownIps[self.api.mac], random.randrange(43900, 44000))
|
||||
# And new listening address
|
||||
self.httpServer.restart(address)
|
||||
# sends notification
|
||||
@@ -261,15 +226,13 @@ class CommonService(object):
|
||||
return
|
||||
|
||||
if msg == ipc.REQ_LOGIN:
|
||||
self.loggedIn = True
|
||||
res = self.api.login(data).split('\t')
|
||||
# third parameter, if exists, sets maxSession duration to this.
|
||||
# First & second parameters are ip & hostname of connection source
|
||||
if len(res) >= 3:
|
||||
self.api.maxSession = int(res[2]) # Third parameter is max session duration
|
||||
msg = ipc.REQ_INFORMATION # Senf information, requested or not, to client on login notification
|
||||
if msg == ipc.REQ_LOGOUT and self.loggedIn is True:
|
||||
self.loggedIn = False
|
||||
if msg == ipc.REQ_LOGOUT:
|
||||
self.api.logout(data)
|
||||
self.onLogout(data)
|
||||
if msg == ipc.REQ_INFORMATION:
|
||||
@@ -312,14 +275,11 @@ class CommonService(object):
|
||||
def endAPI(self):
|
||||
if self.api is not None:
|
||||
try:
|
||||
if self.loggedIn:
|
||||
self.loggedIn = False
|
||||
self.api.logout('service_stopped')
|
||||
self.api.notifyComm(None)
|
||||
except Exception as e:
|
||||
logger.error('Couln\'t remove comms url from broker: {}'.format(e))
|
||||
except Exception:
|
||||
logger.error('Couln\'t remove comms url from broker')
|
||||
|
||||
# self.notifyStop()
|
||||
self.notifyStop()
|
||||
|
||||
# ***************************************************
|
||||
# Methods that ARE overriden by linux & windows Actor
|
||||
|
@@ -32,10 +32,6 @@
|
||||
from __future__ import unicode_literals
|
||||
# pylint: disable=unused-wildcard-import, wildcard-import
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
import stat
|
||||
|
||||
import win32serviceutil # @UnresolvedImport, pylint: disable=import-error
|
||||
import win32service # @UnresolvedImport, pylint: disable=import-error
|
||||
import win32security # @UnresolvedImport, pylint: disable=import-error
|
||||
@@ -44,9 +40,9 @@ import win32event # @UnresolvedImport, pylint: disable=import-error
|
||||
import win32com.client # @UnresolvedImport, @UnusedImport, pylint: disable=import-error
|
||||
import pythoncom # @UnresolvedImport, pylint: disable=import-error
|
||||
import servicemanager # @UnresolvedImport, pylint: disable=import-error
|
||||
import os
|
||||
|
||||
from udsactor import operations
|
||||
from udsactor import store
|
||||
from udsactor.service import CommonService
|
||||
from udsactor.service import initCfg
|
||||
|
||||
@@ -59,8 +55,6 @@ from .SENS import SENSGUID_PUBLISHER
|
||||
from .SENS import PROGID_EventSubscription
|
||||
from .SENS import PROGID_EventSystem
|
||||
|
||||
POST_CMD = 'c:\\windows\\post-uds.bat'
|
||||
|
||||
|
||||
class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
|
||||
'''
|
||||
@@ -119,7 +113,7 @@ class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
|
||||
|
||||
operations.renameComputer(name)
|
||||
# Reboot just after renaming
|
||||
logger.info('Rebooting computer to activate new name {}'.format(name))
|
||||
logger.info('Rebooting computer got activate new name {}'.format(name))
|
||||
self.reboot()
|
||||
|
||||
def oneStepJoin(self, name, domain, ou, account, password):
|
||||
@@ -164,15 +158,12 @@ class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
|
||||
ver = ver[0] * 10 + ver[1]
|
||||
logger.debug('Starting joining domain {} with name {} (detected operating version: {})'.format(
|
||||
domain, name, ver))
|
||||
# If file c:\compat.bin exists, joind domain in two steps instead one
|
||||
|
||||
# Accepts one step joinDomain, also remember XP is no more supported by
|
||||
# microsoft, but this also must works with it because will do a "multi
|
||||
# step" join
|
||||
if ver >= 60 and store.useOldJoinSystem() is False:
|
||||
if ver >= 60:
|
||||
self.oneStepJoin(name, domain, ou, account, password)
|
||||
else:
|
||||
logger.info('Using multiple step join because configuration requests to do so')
|
||||
self.multiStepJoin(name, domain, ou, account, password)
|
||||
|
||||
def preConnect(self, user, protocol):
|
||||
@@ -189,7 +180,7 @@ class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
|
||||
resumeHandle = 0
|
||||
while True:
|
||||
users, _, resumeHandle = win32net.NetLocalGroupGetMembers(None, groupName, 1, resumeHandle, 32768)
|
||||
if user.lower() in [u['name'].lower() for u in users]:
|
||||
if user in [u['name'] for u in users]:
|
||||
useraAlreadyInGroup = True
|
||||
break
|
||||
if resumeHandle == 0:
|
||||
@@ -207,20 +198,6 @@ class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
|
||||
self._user = None
|
||||
logger.debug('User {} already in group'.format(user))
|
||||
|
||||
# Now try to run pre connect command
|
||||
try:
|
||||
pre_cmd = store.preApplication()
|
||||
if os.path.isfile(pre_cmd):
|
||||
if (os.stat(pre_cmd).st_mode & stat.S_IXUSR) != 0:
|
||||
subprocess.call([pre_cmd, user, protocol])
|
||||
else:
|
||||
logger.info('PRECONNECT file exists but it it is not executable (needs execution permission by root)')
|
||||
else:
|
||||
logger.info('PRECONNECT file not found & not executed')
|
||||
except Exception as e:
|
||||
# Ignore output of execution command
|
||||
logger.error('Executing preconnect command give {}'.format(e))
|
||||
|
||||
return 'ok'
|
||||
|
||||
def onLogout(self, user):
|
||||
@@ -239,7 +216,7 @@ class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
|
||||
except Exception as e:
|
||||
logger.error('Exception removing user from Remote Desktop Users: {}'.format(e))
|
||||
|
||||
def SvcDoRun(self): # pylint: disable=too-many-statements, too-many-branches
|
||||
def SvcDoRun(self):
|
||||
'''
|
||||
Main service loop
|
||||
'''
|
||||
@@ -315,17 +292,6 @@ class UDSActorSvc(win32serviceutil.ServiceFramework, CommonService):
|
||||
|
||||
logger.debug('Registered SENS, running main loop')
|
||||
|
||||
# Execute script in c:\\windows\\post-uds.bat after interacting with broker, if no reboot is requested ofc
|
||||
# This will be executed only when machine gets "ready"
|
||||
try:
|
||||
if os.path.isfile(POST_CMD):
|
||||
subprocess.call([POST_CMD, ])
|
||||
else:
|
||||
logger.info('POST file not found & not executed')
|
||||
except Exception as e:
|
||||
# Ignore output of execution command
|
||||
logger.error('Executing post command give')
|
||||
|
||||
# *********************
|
||||
# * Main Service loop *
|
||||
# *********************
|
||||
|
@@ -37,7 +37,7 @@ import os
|
||||
import tempfile
|
||||
|
||||
# Valid logging levels, from UDS Broker (uds.core.utils.log)
|
||||
OTHER, DEBUG, INFO, WARN, ERROR, FATAL = (10000 * (x + 1) for x in range(6))
|
||||
OTHER, DEBUG, INFO, WARN, ERROR, FATAL = (10000 * (x + 1) for x in xrange(6))
|
||||
|
||||
|
||||
class LocalLogger(object):
|
||||
@@ -58,7 +58,7 @@ class LocalLogger(object):
|
||||
# our loglevels are 10000 (other), 20000 (debug), ....
|
||||
# logging levels are 10 (debug), 20 (info)
|
||||
# OTHER = logging.NOTSET
|
||||
self.logger.log(level // 1000 - 10, message)
|
||||
self.logger.log(level / 1000 - 10, message)
|
||||
|
||||
if level < INFO or self.serviceLogger is False: # Only information and above will be on event log
|
||||
return
|
||||
|
@@ -91,7 +91,6 @@ def getDomainName():
|
||||
def getWindowsVersion():
|
||||
return win32api.GetVersionEx()
|
||||
|
||||
|
||||
EWX_LOGOFF = 0x00000000
|
||||
EWX_SHUTDOWN = 0x00000001
|
||||
EWX_REBOOT = 0x00000002
|
||||
@@ -122,7 +121,6 @@ def renameComputer(newName):
|
||||
computerName = win32api.GetComputerNameEx(win32con.ComputerNamePhysicalDnsHostname)
|
||||
raise Exception('Error renaming computer from {} to {}: {}'.format(computerName, newName, error))
|
||||
|
||||
|
||||
NETSETUP_JOIN_DOMAIN = 0x00000001
|
||||
NETSETUP_ACCT_CREATE = 0x00000002
|
||||
NETSETUP_ACCT_DELETE = 0x00000004
|
||||
@@ -189,8 +187,8 @@ def changeUserPassword(user, oldPassword, newPassword):
|
||||
|
||||
if res != 0:
|
||||
# Log the error, and raise exception to parent
|
||||
error = getErrorMessage(res)
|
||||
raise Exception('Error changing password for user {}: {} {}'.format(user.value, res, error))
|
||||
error = getErrorMessage()
|
||||
raise Exception('Error changing password for user {}: {}'.format(user.value, error))
|
||||
|
||||
|
||||
class LASTINPUTINFO(ctypes.Structure):
|
||||
@@ -208,21 +206,11 @@ def initIdleDuration(atLeastSeconds):
|
||||
|
||||
|
||||
def getIdleDuration():
|
||||
try:
|
||||
lastInputInfo = LASTINPUTINFO()
|
||||
lastInputInfo.cbSize = ctypes.sizeof(lastInputInfo)
|
||||
if ctypes.windll.user32.GetLastInputInfo(ctypes.byref(lastInputInfo)) == 0:
|
||||
return 0
|
||||
# if lastInputInfo.dwTime > 1000000000: # Value toooo high, nonsense...
|
||||
# return 0
|
||||
current = ctypes.c_uint(ctypes.windll.kernel32.GetTickCount())
|
||||
millis = current.value - lastInputInfo.dwTime # @UndefinedVariable
|
||||
if millis < 0:
|
||||
return 0
|
||||
return millis / 1000.0
|
||||
except Exception as e:
|
||||
logger.error('Getting idle duration: {}'.format(e))
|
||||
return 0
|
||||
lastInputInfo = LASTINPUTINFO()
|
||||
lastInputInfo.cbSize = ctypes.sizeof(lastInputInfo)
|
||||
ctypes.windll.user32.GetLastInputInfo(ctypes.byref(lastInputInfo))
|
||||
millis = ctypes.windll.kernel32.GetTickCount() - lastInputInfo.dwTime # @UndefinedVariable
|
||||
return millis / 1000.0
|
||||
|
||||
|
||||
def getCurrentUser():
|
||||
|
@@ -31,13 +31,10 @@
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import pickle
|
||||
from win32com.shell import shell # @UnresolvedImport, pylint: disable=import-error
|
||||
try:
|
||||
import winreg as wreg
|
||||
except ImportError: # Python 2.7 fallback
|
||||
import _winreg as wreg # @UnresolvedImport, pylint: disable=import-error
|
||||
import _winreg as wreg # @UnresolvedImport, pylint: disable=import-error
|
||||
import win32security # @UnresolvedImport, pylint: disable=import-error
|
||||
import cPickle
|
||||
|
||||
DEBUG = False
|
||||
|
||||
@@ -50,7 +47,6 @@ def encoder(data):
|
||||
def decoder(data):
|
||||
return data.decode('bz2')
|
||||
|
||||
|
||||
path = 'Software\\UDSActor'
|
||||
baseKey = wreg.HKEY_CURRENT_USER if DEBUG is True else wreg.HKEY_LOCAL_MACHINE # @UndefinedVariable
|
||||
|
||||
@@ -82,7 +78,7 @@ def readConfig():
|
||||
key = wreg.OpenKey(baseKey, path, 0, wreg.KEY_QUERY_VALUE) # @UndefinedVariable
|
||||
data, _ = wreg.QueryValueEx(key, '') # @UndefinedVariable
|
||||
wreg.CloseKey(key) # @UndefinedVariable
|
||||
return pickle.loads(decoder(data))
|
||||
return cPickle.loads(decoder(data))
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
@@ -95,49 +91,5 @@ def writeConfig(data, fixPermissions=True):
|
||||
if fixPermissions is True:
|
||||
fixRegistryPermissions(key.handle)
|
||||
|
||||
wreg.SetValueEx(key, "", 0, wreg.REG_BINARY, encoder(pickle.dumps(data))) # @UndefinedVariable
|
||||
wreg.SetValueEx(key, "", 0, wreg.REG_BINARY, encoder(cPickle.dumps(data))) # @UndefinedVariable
|
||||
wreg.CloseKey(key) # @UndefinedVariable
|
||||
|
||||
|
||||
def useOldJoinSystem():
|
||||
try:
|
||||
key = wreg.OpenKey(baseKey, 'Software\\UDSEnterpriseActor', 0, wreg.KEY_QUERY_VALUE) # @UndefinedVariable
|
||||
try:
|
||||
data, _ = wreg.QueryValueEx(key, 'join') # @UndefinedVariable
|
||||
except Exception:
|
||||
data = ''
|
||||
wreg.CloseKey(key) # @UndefinedVariable
|
||||
except:
|
||||
data = ''
|
||||
|
||||
return data == 'old'
|
||||
|
||||
|
||||
# Gives the oportunity to run an application ONE TIME (because, the registry key "run" will be deleted after read)
|
||||
def runApplication():
|
||||
try:
|
||||
key = wreg.OpenKey(baseKey, 'Software\\UDSEnterpriseActor', 0, wreg.KEY_ALL_ACCESS) # @UndefinedVariable
|
||||
try:
|
||||
data, _ = wreg.QueryValueEx(key, 'run') # @UndefinedVariable
|
||||
wreg.DeleteValue(key, 'run') # @UndefinedVariable
|
||||
except Exception:
|
||||
data = None
|
||||
wreg.CloseKey(key) # @UndefinedVariable
|
||||
except Exception:
|
||||
data = None
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def preApplication():
|
||||
try:
|
||||
key = wreg.OpenKey(baseKey, 'Software\\UDSEnterpriseActor', 0, wreg.KEY_ALL_ACCESS) # @UndefinedVariable
|
||||
try:
|
||||
data, _ = wreg.QueryValueEx(key, 'pre') # @UndefinedVariable
|
||||
except Exception:
|
||||
data = None
|
||||
wreg.CloseKey(key) # @UndefinedVariable
|
||||
except Exception:
|
||||
data = None
|
||||
|
||||
return data
|
||||
|
@@ -1,2 +0,0 @@
|
||||
udsclient_2.2.1_all.deb admin optional
|
||||
udsclient_2.2.1_amd64.buildinfo admin optional
|
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
VERSION=`cat ../../../VERSION`
|
||||
VERSION=`cat ../../VERSION`
|
||||
RELEASE=1
|
||||
# Debian based
|
||||
dpkg-buildpackage -b
|
@@ -1,21 +1,3 @@
|
||||
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
|
@@ -10,6 +10,6 @@ Package: udsclient
|
||||
Section: admin
|
||||
Priority: optional
|
||||
Architecture: all
|
||||
Depends: python-paramiko (>=0.8.2), python-qt4 (>=4.9), python-six(>=1.1), python (>=2.7), freerdp2-x11 | freerdp-x11, desktop-file-utils, ${misc:Depends}
|
||||
Depends: python-paramiko (>=0.8.2), python-qt4 (>=4.9), python-six(>=1.1), python (>=2.7), rdesktop | 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
client/linux/debian/files
Normal file
@@ -0,0 +1 @@
|
||||
udsclient_2.0.0_all.deb admin optional
|
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python2.7
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014-2017 Virtual Cable S.L.
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
@@ -43,15 +43,9 @@ from uds import tools
|
||||
from uds import VERSION
|
||||
|
||||
import webbrowser
|
||||
import json
|
||||
import sys
|
||||
import six
|
||||
|
||||
from UDSWindow import Ui_MainWindow
|
||||
|
||||
# Server before this version uses "unsigned" scripts
|
||||
OLD_METHOD_VERSION = '2.4.0'
|
||||
|
||||
class RetryException(Exception):
|
||||
pass
|
||||
|
||||
@@ -63,7 +57,6 @@ class UDSClient(QtGui.QMainWindow):
|
||||
animTimer = None
|
||||
anim = 0
|
||||
animInverted = False
|
||||
serverVersion = 'X.Y.Z' # Will be overwriten on getVersion
|
||||
|
||||
def __init__(self):
|
||||
QtGui.QMainWindow.__init__(self)
|
||||
@@ -153,8 +146,6 @@ class UDSClient(QtGui.QMainWindow):
|
||||
webbrowser.open(data['result']['downloadUrl'])
|
||||
self.closeWindow()
|
||||
return
|
||||
|
||||
self.serverVersion = data['result']['requiredVersion']
|
||||
self.getTransportData()
|
||||
|
||||
except RetryException as e:
|
||||
@@ -162,7 +153,6 @@ class UDSClient(QtGui.QMainWindow):
|
||||
QtCore.QTimer.singleShot(1000, self.getVersion)
|
||||
|
||||
except Exception as e:
|
||||
logger.exception('Version')
|
||||
self.showError(e)
|
||||
|
||||
|
||||
@@ -182,20 +172,7 @@ class UDSClient(QtGui.QMainWindow):
|
||||
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:
|
||||
raise Exception('Invalid UDS code signature. Please, report to administrator')
|
||||
script = data['result'].decode('base64').decode('bz2')
|
||||
|
||||
self.stopAnim()
|
||||
|
||||
@@ -205,14 +182,7 @@ class UDSClient(QtGui.QMainWindow):
|
||||
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.')
|
||||
logger.debug('Script: {}'.format(script))
|
||||
six.exec_(script, globals(), {'parent': self, 'sp': params})
|
||||
six.exec_(script, globals(), {'parent': self})
|
||||
|
||||
except RetryException as e:
|
||||
self.ui.info.setText(six.text_type(e) + ', retrying access...')
|
||||
@@ -254,7 +224,7 @@ def done(data):
|
||||
QtGui.QMessageBox.critical(None, 'Notice', six.text_type(data.data), QtGui.QMessageBox.Ok)
|
||||
sys.exit(0)
|
||||
|
||||
# Ask user to approve endpoint
|
||||
# Ask user to aprobe endpoint
|
||||
def approveHost(host, parentWindow=None):
|
||||
settings = QtCore.QSettings()
|
||||
settings.beginGroup('endpoints')
|
||||
@@ -271,7 +241,6 @@ def approveHost(host, parentWindow=None):
|
||||
settings.endGroup()
|
||||
return approved
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
logger.debug('Initializing connector')
|
||||
# Initialize app
|
||||
@@ -312,7 +281,7 @@ if __name__ == "__main__":
|
||||
|
||||
# Setup REST api endpoint
|
||||
RestRequest.restApiUrl = '{}://{}/rest/client'.format(['http', 'https'][ssl], host)
|
||||
logger.debug('Setting request URL to {}'.format(RestRequest.restApiUrl))
|
||||
logger.debug('Setting requert URL to {}'.format(RestRequest.restApiUrl))
|
||||
# RestRequest.restApiUrl = 'https://172.27.0.1/rest/client'
|
||||
|
||||
try:
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 9.4 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 137 KiB After Width: | Height: | Size: 137 KiB |
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2014-2017 Virtual Cable S.L.
|
||||
# Copyright (c) 2014 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
@@ -34,11 +34,11 @@ from __future__ import unicode_literals
|
||||
# On centos, old six release does not includes byte2int, nor six.PY2
|
||||
import six
|
||||
|
||||
VERSION = '2.2.0'
|
||||
VERSION = '2.0.0'
|
||||
|
||||
__title__ = 'udclient'
|
||||
__version__ = VERSION
|
||||
__build__ = 0x010760
|
||||
__build__ = 0x010750
|
||||
__author__ = 'Adolfo Gómez'
|
||||
__license__ = "BSD 3-clause"
|
||||
__copyright__ = "Copyright 2014-2017 VirtualCable S.L.U."
|
||||
__copyright__ = "Copyright 2014-2015 VirtualCable S.L.U."
|
@@ -33,17 +33,10 @@ from __future__ import unicode_literals
|
||||
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
if sys.platform.startswith('linux'):
|
||||
from os.path import expanduser
|
||||
logFile = expanduser('~/udsclient.log')
|
||||
else:
|
||||
logFile = os.path.join(tempfile.gettempdir(), b'udsclient.log')
|
||||
|
||||
logging.basicConfig(
|
||||
filename=logFile,
|
||||
filename=os.path.join(tempfile.gettempdir(), b'udsclient.log'),
|
||||
filemode='a',
|
||||
format='%(levelname)s %(asctime)s %(message)s',
|
||||
level=logging.DEBUG
|
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2017 Virtual Cable S.L.
|
||||
# Copyright (c) 2015 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2017 Virtual Cable S.L.
|
||||
# Copyright (c) 2015 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
@@ -32,8 +32,6 @@
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from base64 import b64decode
|
||||
|
||||
import tempfile
|
||||
import string
|
||||
import random
|
||||
@@ -50,25 +48,9 @@ _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 = b''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(16))
|
||||
@@ -86,7 +68,6 @@ def saveTempFile(content, filename=None):
|
||||
logger.info('Returning filename')
|
||||
return filename
|
||||
|
||||
|
||||
def readTempFile(filename):
|
||||
if 'win32' in sys.platform:
|
||||
filename = filename.encode('utf-8')
|
||||
@@ -98,7 +79,6 @@ def readTempFile(filename):
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def testServer(host, port, timeOut=4):
|
||||
try:
|
||||
sock = socket.create_connection((host, int(port)), timeOut)
|
||||
@@ -180,24 +160,3 @@ def addExecBeforeExit(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,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,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<?eclipse-pydev version="1.0"?><pydev_project>
|
||||
<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
|
||||
<path>/${PROJECT_DIR_NAME}/src</path>
|
||||
</pydev_pathproperty>
|
||||
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
|
||||
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
|
||||
</pydev_project>
|
@@ -1,158 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2017 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from uds import ui
|
||||
from uds.rest import RestRequest, RetryException
|
||||
from uds.forward import forward
|
||||
from uds import VERSION
|
||||
from uds.log import logger # @UnresolvedImport
|
||||
from uds import tools
|
||||
|
||||
import six
|
||||
import sys
|
||||
import pickle
|
||||
|
||||
|
||||
def approveHost(host):
|
||||
from os.path import expanduser
|
||||
hostsFile = expanduser('~/.udsclient.hosts')
|
||||
|
||||
try:
|
||||
with open(hostsFile, 'r') as f:
|
||||
approvedHosts = f.read().splitlines()
|
||||
except Exception:
|
||||
approvedHosts = []
|
||||
|
||||
host = host.lower()
|
||||
|
||||
if host in approvedHosts:
|
||||
return True
|
||||
|
||||
errorString = 'The server {} must be approved:\n'.format(host)
|
||||
errorString += 'Only approve UDS servers that you trust to avoid security issues.'
|
||||
|
||||
approved = ui.question("ACCESS Warning", errorString)
|
||||
|
||||
if approved:
|
||||
approvedHosts.append(host)
|
||||
logger.debug('Host was approved, saving to approvedHosts file')
|
||||
try:
|
||||
with open(hostsFile, 'w') as f:
|
||||
f.write('\n'.join(approvedHosts))
|
||||
except Exception:
|
||||
logger.warn('Got exception writing to {}'.format(hostsFile))
|
||||
|
||||
return approved
|
||||
|
||||
|
||||
def getWithRetry(rest, url, params=None):
|
||||
while True:
|
||||
try:
|
||||
res = rest.get(url, params)
|
||||
return res
|
||||
except RetryException as e:
|
||||
if ui.question('Service not available', 'Error {}.\nPlease, wait a minute and press "OK" to retry, or "CANCEL" to abort'.format(e)) is True:
|
||||
continue
|
||||
raise Exception('Cancelled by user')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
logger.debug('Initializing connector')
|
||||
|
||||
if six.PY3 is False:
|
||||
logger.debug('Fixing threaded execution of commands')
|
||||
import threading
|
||||
threading._DummyThread._Thread__stop = lambda x: 42
|
||||
|
||||
# First parameter must be url
|
||||
try:
|
||||
uri = sys.argv[1]
|
||||
|
||||
if uri == '--test':
|
||||
sys.exit(0)
|
||||
|
||||
logger.debug('URI: {}'.format(uri))
|
||||
if uri[:6] != 'uds://' and uri[:7] != 'udss://':
|
||||
raise Exception()
|
||||
|
||||
ssl = uri[3] == 's'
|
||||
host, ticket, scrambler = uri.split('//')[1].split('/')
|
||||
logger.debug('ssl: {}, host:{}, ticket:{}, scrambler:{}'.format(ssl, host, ticket, scrambler))
|
||||
|
||||
except Exception:
|
||||
logger.debug('Detected execution without valid URI, exiting')
|
||||
ui.message('UDS Client', 'UDS Client Version {}'.format(VERSION))
|
||||
sys.exit(1)
|
||||
|
||||
rest = RestRequest(host, ssl)
|
||||
logger.debug('Setting request URL to {}'.format(rest.restApiUrl))
|
||||
|
||||
# Main requests part
|
||||
# First, get version
|
||||
try:
|
||||
res = getWithRetry(rest, '')
|
||||
|
||||
logger.debug('Got information {}'.format(res))
|
||||
|
||||
if res['requiredVersion'] > VERSION:
|
||||
ui.message("New UDS Client available", "A new uds version is needed in order to access this version of UDS.\nPlease, download and install it")
|
||||
sys.exit(1)
|
||||
|
||||
res = getWithRetry(rest, '/{}/{}'.format(ticket, scrambler), params={'hostname': tools.getHostName(), 'version': VERSION})
|
||||
|
||||
script = res.decode('base64').decode('bz2')
|
||||
|
||||
logger.debug('Script: {}'.format(script))
|
||||
|
||||
six.exec_(script, globals(), {'parent': None})
|
||||
except Exception as e:
|
||||
error = 'ERROR: {}'.format(e)
|
||||
logger.error(error)
|
||||
ui.message('Error', error)
|
||||
sys.exit(2)
|
||||
|
||||
# Finalize
|
||||
try:
|
||||
tools.waitForTasks()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
tools.unlinkFiles()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
tools.execBeforeExit()
|
||||
except Exception:
|
||||
pass
|
@@ -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,86 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2015 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
'''
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import requests
|
||||
from . import VERSION
|
||||
|
||||
import json
|
||||
import six
|
||||
import osDetector
|
||||
|
||||
from .log import logger
|
||||
|
||||
|
||||
class RetryException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class RestRequest(object):
|
||||
|
||||
restApiUrl = ''
|
||||
|
||||
def __init__(self, host, ssl=True): # parent not used
|
||||
super(RestRequest, self).__init__()
|
||||
|
||||
self.host = host
|
||||
self.ssl = ssl
|
||||
self.restApiUrl = '{}://{}/rest/client'.format(['http', 'https'][ssl], host)
|
||||
|
||||
def get(self, url, params=None):
|
||||
url = self.restApiUrl + url
|
||||
if params is not None:
|
||||
url += '?' + '&'.join('{}={}'.format(k, six.moves.urllib.parse.quote(six.text_type(v).encode('utf8'))) for k, v in params.iteritems()) # @UndefinedVariable
|
||||
|
||||
logger.debug('Requesting {}'.format(url))
|
||||
|
||||
try:
|
||||
r = requests.get(url, headers={'Content-type': 'application/json', 'User-Agent': osDetector.getOs() + " - UDS Connector " + VERSION }, verify=False)
|
||||
except requests.exceptions.ConnectionError as e:
|
||||
raise Exception('Error connecting to UDS Server at {}'.format(self.restApiUrl[0:-11]))
|
||||
|
||||
if r.ok:
|
||||
logger.debug('Request was OK. {}'.format(r.text))
|
||||
data = json.loads(r.text)
|
||||
if not 'error' in data:
|
||||
return data['result']
|
||||
# Has error
|
||||
if data.get('retryable', '0') == '1':
|
||||
raise RetryException(data['error'])
|
||||
|
||||
raise Exception(data['error'])
|
||||
else:
|
||||
logger.error('Error requesting {}: {}, {}'.format(url, r.code. r.text))
|
||||
raise Exception('Error {}: {}'.format(r.code, r.text))
|
||||
|
||||
return data
|
@@ -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 $@
|