support multi target in rdp proxy
This commit is contained in:
@@ -45,7 +45,22 @@ class ProxyServer(rdp.RDPServerObserver):
|
||||
rdp.RDPServerObserver.__init__(self, controller)
|
||||
self._credentialProvider = credentialProvider
|
||||
self._client = None
|
||||
|
||||
self._window = None
|
||||
|
||||
def showSelectView(self, machines):
|
||||
self._machines = dict([("%s:%s"%(ip, port), (ip, port)) for ip, port in machines])
|
||||
width, height = self._controller.getScreen()
|
||||
self._window = view.Window(width, height, QtGui.QColor(24, 93, 123))
|
||||
self._window.addView(view.Anchor(width / 2 - 250, 100, view.Label("Please select following server", 500, 50, QtGui.QFont('arial', 18, QtGui.QFont.Bold), backgroundColor = QtGui.QColor(24, 93, 123))))
|
||||
self._window.addView(view.Anchor(width / 2 - 250, 150, view.List(self._machines.keys(), 500, 500, self.onSelectMachine, QtGui.QColor(24, 93, 123))), True)
|
||||
self._window.update(view.RDPRenderer(self._controller, self._controller.getColorDepth()), True)
|
||||
|
||||
def onSelectMachine(self, machine):
|
||||
ip, port = self._machines[machine]
|
||||
width, height = self._controller.getScreen()
|
||||
domain, username, password = self._controller.getCredentials()
|
||||
reactor.connectTCP(ip, port, ProxyClientFactory(self, width, height, domain, username, password, "%s\\%s on %s:%s"%(domain, username, ip, port)))
|
||||
|
||||
def clientConnected(self, client):
|
||||
"""
|
||||
Event throw by client when it's ready
|
||||
@@ -54,23 +69,35 @@ class ProxyServer(rdp.RDPServerObserver):
|
||||
self._client = client
|
||||
self._controller.setColorDepth(self._client._controller.getColorDepth())
|
||||
|
||||
def showErrorMessage(self, message):
|
||||
"""
|
||||
Print a message to the client
|
||||
@param message: string
|
||||
"""
|
||||
width, height = self._controller.getScreen()
|
||||
popup = view.Window(width, height, QtGui.QColor(24, 93, 123))
|
||||
popup.addView(view.Anchor(width / 2 - 250, height / 2 - 25, view.Label(message, 500, 50, QtGui.QFont('arial', 18, QtGui.QFont.Bold), backgroundColor = QtGui.QColor(24, 93, 123))))
|
||||
popup.update(view.RDPRenderer(self._controller, self._controller.getColorDepth()), True)
|
||||
|
||||
def onReady(self):
|
||||
"""
|
||||
Event use to inform state of server stack
|
||||
Use to connect client
|
||||
On ready is not launch only on connection but after a reactivation process
|
||||
On ready is not launch only after connection sequence but after a reactivation sequence too
|
||||
"""
|
||||
if self._client is None:
|
||||
#try a connection
|
||||
domain, username, password = self._controller.getCredentials()
|
||||
try:
|
||||
ip, port = self._credentialProvider.getProxyPass(domain, username)
|
||||
except error.InvalidExpectedDataException as e:
|
||||
log.info(e.message)
|
||||
return
|
||||
machines = self._credentialProvider.getProxyPass(domain, username)
|
||||
|
||||
width, height = self._controller.getScreen()
|
||||
reactor.connectTCP(ip, port, ProxyClientFactory(self, width, height, domain, username, password, "%s\\%s on %s:%s"%(domain, username, ip, port)))
|
||||
if len(machines) == 0:
|
||||
self.showErrorMessage("No servers attach to account %s\\%s"%(domain, username))
|
||||
elif len(machines) == 1:
|
||||
ip, port = machines[0]
|
||||
width, height = self._controller.getScreen()
|
||||
reactor.connectTCP(ip, port, ProxyClientFactory(self, width, height, domain, username, password, "%s\\%s on %s:%s"%(domain, username, ip, port)))
|
||||
else:
|
||||
self.showSelectView(machines)
|
||||
else:
|
||||
#refresh client
|
||||
width, height = self._controller.getScreen()
|
||||
@@ -91,9 +118,12 @@ class ProxyServer(rdp.RDPServerObserver):
|
||||
@param isPressed: True if key is down
|
||||
"""
|
||||
#no client connected
|
||||
if self._client is None:
|
||||
return
|
||||
self._client._controller.sendKeyEventScancode(code, isPressed)
|
||||
if not self._client is None:
|
||||
self._client._controller.sendKeyEventScancode(code, isPressed)
|
||||
elif not self._window is None and isPressed:
|
||||
self._window.keyEvent(code)
|
||||
self._window.update(view.RDPRenderer(self._controller, self._controller.getColorDepth()))
|
||||
|
||||
|
||||
def onKeyEventUnicode(self, code, isPressed):
|
||||
"""
|
||||
@@ -262,10 +292,9 @@ class ProxyAdmin(rdp.RDPServerObserver):
|
||||
Init GUI view
|
||||
"""
|
||||
width, height = self._controller.getScreen()
|
||||
self._window = view.WindowView(width, height, QtGui.QColor(24, 93, 123))
|
||||
self._list = view.ListView(ProxyClient._CONNECTED_.keys(), 500, 500, self.onSelect, QtGui.QColor(24, 93, 123))
|
||||
self._window.addView(view.AnchorView(width / 2 - 250, height / 2 - 250, self._list))
|
||||
self._render = view.RDPRenderer(self._controller, self._controller.getColorDepth())
|
||||
self._window = view.Window(width, height, QtGui.QColor(24, 93, 123))
|
||||
self._window.addView(view.Anchor(width / 2 - 250, 100, view.Label("Please select following session", 500, 50, QtGui.QFont('arial', 18, QtGui.QFont.Bold), backgroundColor = QtGui.QColor(24, 93, 123))))
|
||||
self._window.addView(view.Anchor(width / 2 - 250, 150, view.List(ProxyClient._CONNECTED_.keys(), 500, 500, self.onSelect, QtGui.QColor(24, 93, 123))), True)
|
||||
|
||||
def onReady(self):
|
||||
"""
|
||||
@@ -274,7 +303,7 @@ class ProxyAdmin(rdp.RDPServerObserver):
|
||||
"""
|
||||
if self._state == ProxyAdmin.State.GUI:
|
||||
self.initView()
|
||||
self._window.update(self._render, True)
|
||||
self._window.update(view.RDPRenderer(self._controller, self._controller.getColorDepth()), True)
|
||||
elif self._state == ProxyAdmin.State.SPY:
|
||||
#refresh client
|
||||
width, height = self._controller.getScreen()
|
||||
@@ -296,7 +325,7 @@ class ProxyAdmin(rdp.RDPServerObserver):
|
||||
if not isPressed:
|
||||
return
|
||||
self._window.keyEvent(code)
|
||||
self._window.update(self._render)
|
||||
self._window.update(view.RDPRenderer(self._controller, self._controller.getColorDepth()))
|
||||
elif code == 1:
|
||||
#escape button refresh GUI
|
||||
self._state = ProxyAdmin.State.GUI
|
||||
@@ -364,20 +393,19 @@ class CredentialProvider(object):
|
||||
|
||||
def getAccount(self, domain, username):
|
||||
if not self._config.has_key(domain) or not self._config[domain].has_key(username):
|
||||
raise error.InvalidExpectedDataException("Invalid credentials %s\\%s"%(domain, username))
|
||||
|
||||
return None
|
||||
return self._config[domain][username]
|
||||
|
||||
def getProxyPass(self, domain, username):
|
||||
"""
|
||||
@param domain: domain to check
|
||||
@param username: username in domain
|
||||
@return: (ip, port) or None if error
|
||||
@return: [(ip, port)]
|
||||
"""
|
||||
account = self.getAccount(domain, username)
|
||||
if not account.has_key("ip") or not account.has_key("port"):
|
||||
raise error.InvalidExpectedDataException("Invalid credentials declaration %s\\%s"%(domain, username))
|
||||
return str(account['ip']), account['port']
|
||||
if account is None:
|
||||
return []
|
||||
return [(str(machine["ip"]), machine["port"]) for machine in account]
|
||||
|
||||
def help():
|
||||
"""
|
||||
|
||||
@@ -646,7 +646,7 @@ class DataPDU(CompositeType):
|
||||
"""
|
||||
Create object in accordance self.shareDataHeader.pduType2 value
|
||||
"""
|
||||
for c in [UpdateDataPDU, SynchronizeDataPDU, ControlDataPDU, ErrorInfoDataPDU, FontListDataPDU, FontMapDataPDU, PersistentListPDU, ClientInputEventPDU, ShutdownDeniedPDU, ShutdownRequestPDU, SuppressOutputDataPDU]:
|
||||
for c in [UpdateDataPDU, SynchronizeDataPDU, ControlDataPDU, ErrorInfoDataPDU, FontListDataPDU, FontMapDataPDU, PersistentListPDU, ClientInputEventPDU, ShutdownDeniedPDU, ShutdownRequestPDU, SupressOutputDataPDU]:
|
||||
if self.shareDataHeader.pduType2.value == c._PDUTYPE2_:
|
||||
return c()
|
||||
log.debug("unknown PDU data type : %s"%hex(self.shareDataHeader.pduType2.value))
|
||||
@@ -812,13 +812,13 @@ class InclusiveRectangle(CompositeType):
|
||||
@see: http://msdn.microsoft.com/en-us/library/cc240643.aspx
|
||||
"""
|
||||
def __init__(self, conditional = lambda:True):
|
||||
CompositeType.__init__(self)
|
||||
CompositeType.__init__(self, conditional = conditional)
|
||||
self.left = UInt16Le()
|
||||
self.top = UInt16Le()
|
||||
self.right = UInt16Le()
|
||||
self.bottom = UInt16Le()
|
||||
|
||||
class SuppressOutputDataPDU(CompositeType):
|
||||
class SupressOutputDataPDU(CompositeType):
|
||||
"""
|
||||
@see: http://msdn.microsoft.com/en-us/library/cc240648.aspx
|
||||
"""
|
||||
|
||||
@@ -86,7 +86,7 @@ class IView(object):
|
||||
raise CallPureVirtualFuntion("%s:%s defined by interface %s"%(self.__class__, "update", "IView"))
|
||||
|
||||
|
||||
class AnchorView(IView):
|
||||
class Anchor(IView):
|
||||
def __init__(self, x, y, view):
|
||||
self._x = x
|
||||
self._y = y
|
||||
@@ -103,7 +103,7 @@ class AnchorView(IView):
|
||||
self._view.update(render, force)
|
||||
render.translate(-self._x, -self._y)
|
||||
|
||||
class ListView(IView):
|
||||
class List(IView):
|
||||
"""
|
||||
List widget simulate by QT painter
|
||||
"""
|
||||
@@ -158,15 +158,17 @@ class ListView(IView):
|
||||
i += 1
|
||||
render.drawImage(drawArea)
|
||||
|
||||
class WindowView(IView):
|
||||
class Window(IView):
|
||||
def __init__(self, width, height, backgroundColor = QtCore.Qt.black):
|
||||
self._views = []
|
||||
self._focusIndex = 0
|
||||
self._width = width
|
||||
self._height = height
|
||||
self._backgroundColor = backgroundColor
|
||||
def addView(self, view):
|
||||
def addView(self, view, focus = False):
|
||||
self._views.append(view)
|
||||
if focus:
|
||||
self._focusIndex = len(self._views) - 1
|
||||
def keyEvent(self, code):
|
||||
if self._focusIndex < len(self._views):
|
||||
self._views[self._focusIndex].keyEvent(code)
|
||||
@@ -181,6 +183,43 @@ class WindowView(IView):
|
||||
render.drawImage(drawArea)
|
||||
for view in self._views:
|
||||
view.update(render, force)
|
||||
|
||||
class Label(IView):
|
||||
def __init__(self, label, width, height, font = QtGui.QFont(), fontColor = QtCore.Qt.white, backgroundColor = QtCore.Qt.black):
|
||||
self._label = label
|
||||
self._width = width
|
||||
self._height = height
|
||||
self._font = font
|
||||
self._fontColor = fontColor
|
||||
self._backgroundColor = backgroundColor
|
||||
|
||||
def keyEvent(self, code):
|
||||
"""
|
||||
Nothing to do
|
||||
"""
|
||||
pass
|
||||
|
||||
def pointerEvent(self, x, y, button):
|
||||
"""
|
||||
Nothing to do
|
||||
"""
|
||||
pass
|
||||
|
||||
def update(self, render, force = False):
|
||||
"""
|
||||
Update view
|
||||
@param render: IRender
|
||||
@param force: force update
|
||||
"""
|
||||
if not force:
|
||||
return;
|
||||
drawArea = QtGui.QImage(self._width, self._height, render.getImageFormat())
|
||||
drawArea.fill(self._backgroundColor)
|
||||
with QtGui.QPainter(drawArea) as qp:
|
||||
qp.setFont(self._font)
|
||||
qp.setPen(self._fontColor)
|
||||
qp.drawText(drawArea.rect(), QtCore.Qt.AlignCenter, self._label)
|
||||
render.drawImage(drawArea)
|
||||
|
||||
class RDPRenderer(object):
|
||||
def __init__(self, controller, colorDepth):
|
||||
@@ -192,7 +231,6 @@ class RDPRenderer(object):
|
||||
self._colorDepth = colorDepth
|
||||
self._dx = 0
|
||||
self._dy = 0
|
||||
self._renderSize = 64
|
||||
|
||||
def getImageFormat(self):
|
||||
if self._colorDepth == 15:
|
||||
@@ -212,14 +250,11 @@ class RDPRenderer(object):
|
||||
"""
|
||||
Render of widget
|
||||
"""
|
||||
nbWidth = image.width() / self._renderSize + 1
|
||||
nbHeight = image.height() / self._renderSize + 1
|
||||
for i in range(0, nbWidth):
|
||||
for j in range(0, nbHeight):
|
||||
tmp = image.copy(i * self._renderSize, j * self._renderSize, self._renderSize, self._renderSize)
|
||||
#in RDP image or bottom top encoded
|
||||
tmp = tmp.transformed(QtGui.QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0))
|
||||
ptr = tmp.bits()
|
||||
ptr.setsize(tmp.byteCount())
|
||||
self._controller.sendUpdate(i * self._renderSize + self._dx, j * self._renderSize + self._dy, min((i + 1) * self._renderSize, image.width()) + self._dx - 1, min((j + 1) * self._renderSize, image.height()) + self._dy - 1, tmp.width(), tmp.height(), self._colorDepth, False, ptr.asstring())
|
||||
padding = image.width() % 4
|
||||
for i in range(0, image.height()):
|
||||
tmp = image.copy(0, i, image.width() + padding, 1)
|
||||
#in RDP image or bottom top encoded
|
||||
ptr = tmp.bits()
|
||||
ptr.setsize(tmp.byteCount())
|
||||
self._controller.sendUpdate(self._dx, i + self._dy, image.width() + self._dx - 1, i + self._dy, tmp.width(), tmp.height(), self._colorDepth, False, ptr.asstring())
|
||||
|
||||
Reference in New Issue
Block a user