Addded README
Code cleanup
This commit is contained in:
88
lib/auth/vencrypt.py
Normal file
88
lib/auth/vencrypt.py
Normal file
@@ -0,0 +1,88 @@
|
||||
from lib import log
|
||||
from time import sleep
|
||||
import ssl
|
||||
import select
|
||||
from struct import *
|
||||
|
||||
class VeNCrypt():
|
||||
|
||||
subtypes = [
|
||||
256, # Plain
|
||||
#258, # TLSVnc # FIXME: not yet implemented
|
||||
#259, # TLSPlain # FIXME: not yet implemented
|
||||
]
|
||||
|
||||
def __init__(self, sock):
|
||||
self.getbuff = lambda _: None
|
||||
self.sock = sock
|
||||
self.client_subtype = None
|
||||
self.pem_file = None
|
||||
log.debug(__name__, "initialized")
|
||||
|
||||
# send version
|
||||
version = b'\x00\x02' # 0.2
|
||||
sock.send(version)
|
||||
data = sock.recv(2)
|
||||
if data != version:
|
||||
sock.send(b'\x01')
|
||||
sock.close()
|
||||
raise Exception("unknown vencrypt version")
|
||||
|
||||
sock.send(b'\x00')
|
||||
|
||||
def send_subtypes(self):
|
||||
# send subtypes
|
||||
data = pack('!B', len(self.subtypes))
|
||||
for i in self.subtypes:
|
||||
data += pack('!I', i)
|
||||
log.debug(__name__, "subtype", i)
|
||||
|
||||
self.sock.send(data)
|
||||
|
||||
# get client choosen subtype
|
||||
data = self.sock.recv(4)
|
||||
(data,) = unpack('!I', data)
|
||||
log.debug("client subtype", data)
|
||||
self.client_subtype = data
|
||||
|
||||
def auth_plain(self, userlist={}):
|
||||
data = self.sock.recv(8)
|
||||
user_length, pass_length = unpack('!II', data)
|
||||
username = self.sock.recv(user_length).decode()
|
||||
password = self.sock.recv(pass_length).decode()
|
||||
#log.debug("user", username, password)
|
||||
|
||||
if userlist.get(username) == password:
|
||||
self.sock.send(pack("!I", 0))
|
||||
log.debug(__name__, "Auth OK")
|
||||
return True
|
||||
else:
|
||||
log.debug(__name__, "Invalid auth")
|
||||
sleep(3)
|
||||
self.sock.send(pack("!I", 1))
|
||||
return False
|
||||
|
||||
def auth_tls_plain(self, userlist={}):
|
||||
#TODO: implement TLS plain
|
||||
log.debug(__name__, 'Using TLSPlain')
|
||||
|
||||
self.sock.sendall(pack("!I", 1)) # send ACK
|
||||
|
||||
#data = self.getbuff(30)
|
||||
#print("data", data)
|
||||
|
||||
|
||||
#sslctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
|
||||
sslctx = ssl.SSLContext(protocol=ssl.PROTOCOL_TLS_SERVER)
|
||||
sslctx.protocol = ssl.PROTOCOL_TLS
|
||||
#sslctx.load_cert_chain(certfile=self.pem_file, keyfile=self.pem_file)
|
||||
# this is quite insecure...
|
||||
sslctx.set_ciphers(":aNULL:kDHE:kEDH:ADH:DH:kECDHE:kEECDH:AECDH:ECDH")
|
||||
|
||||
self.sock.settimeout(30)
|
||||
self.sock = sslctx.wrap_socket(self.sock, server_side=True)
|
||||
self.sock.settimeout(None)
|
||||
|
||||
ret = self.auth_plain(userlist=userlist)
|
||||
return ret
|
||||
|
||||
45
lib/auth/vnc_auth.py
Normal file
45
lib/auth/vnc_auth.py
Normal file
@@ -0,0 +1,45 @@
|
||||
from time import sleep
|
||||
from struct import *
|
||||
from pyDes import *
|
||||
import os
|
||||
from lib import log
|
||||
|
||||
class VNCAuth():
|
||||
|
||||
def __init__(self):
|
||||
self.getbuff = lambda _: None
|
||||
|
||||
def _mirrorBits(self, key):
|
||||
newkey = []
|
||||
for ki in range(len(key)):
|
||||
bsrc = key[ki]
|
||||
btgt = 0
|
||||
for i in range(8):
|
||||
if ord(bsrc) & (1 << i):
|
||||
btgt = btgt | (1 << 7-i)
|
||||
newkey.append(btgt)
|
||||
|
||||
return newkey
|
||||
|
||||
def auth(self, sock, password):
|
||||
# el cliente encripta el challenge con la contraseña ingresada como key
|
||||
pw = (password + '\0' * 8)[:8]
|
||||
challenge = os.urandom(16) # challenge
|
||||
sock.send(challenge) # send challenge
|
||||
# obtener desde el cliente el dato encritado
|
||||
data = self.getbuff(30)
|
||||
# la encriptacion de challenge, con pw como key debe dar data
|
||||
|
||||
k = des(self._mirrorBits(pw))
|
||||
crypted = k.encrypt(challenge)
|
||||
|
||||
if data == crypted:
|
||||
# Handshake successful
|
||||
sock.send(pack("!I", 0))
|
||||
log.debug(__name__, "Auth OK")
|
||||
return True
|
||||
else:
|
||||
log.debug(__name__, "Invalid auth")
|
||||
sleep(3)
|
||||
sock.send(pack("!I", 1))
|
||||
return False
|
||||
30
lib/clipboardctrl.py
Normal file
30
lib/clipboardctrl.py
Normal file
@@ -0,0 +1,30 @@
|
||||
from struct import *
|
||||
|
||||
class ClipboardController():
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def client_cut_text(self, sock):
|
||||
"""
|
||||
The client has new ISO 8859-1 (Latin-1) text in its cut buffer.
|
||||
Ends of lines are represented by the linefeed / newline character (value 10) alone. No carriage-return (value 13) is needed.
|
||||
|
||||
No. of bytes Type [Value] Description
|
||||
1 U8 6 message-type
|
||||
3 padding
|
||||
4 U32 length
|
||||
length U8 array text
|
||||
"""
|
||||
|
||||
# read padding
|
||||
_ = sock.recv(3)
|
||||
|
||||
# read length
|
||||
length = sock.recv(4)
|
||||
(length, ) = unpack('!I', length)
|
||||
|
||||
# read text
|
||||
text = sock.recv(length)
|
||||
|
||||
return text
|
||||
@@ -66,3 +66,9 @@ class proc:
|
||||
def waitproc(self):
|
||||
while psutil.pid_exists(self.pid):
|
||||
time.sleep(.25)
|
||||
|
||||
def reshape(a, cols):
|
||||
|
||||
for i in range(0, int(len(a)/cols), cols):
|
||||
print(i)
|
||||
print(a[i:i+cols])
|
||||
|
||||
39
lib/log.py
39
lib/log.py
@@ -15,14 +15,41 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import inspect
|
||||
import logging
|
||||
logging.basicConfig(level=logging.DEBUG, format='[%(threadName)s] %(message)s')
|
||||
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s: %(message)s')
|
||||
logger = logging.getLogger('pyvncs')
|
||||
|
||||
def _log(*args, logtype='debug'):
|
||||
|
||||
def debug(*args):
|
||||
str = ""
|
||||
func = inspect.stack()[2][3]
|
||||
if func[0] != '<':
|
||||
func = "%s():" % func
|
||||
|
||||
_str = func
|
||||
|
||||
for s in args:
|
||||
str = "%s %s" % (str, s)
|
||||
str = str.strip()
|
||||
logger.debug(str)
|
||||
_str = "%s %s" % (_str, s)
|
||||
_str = _str.strip()
|
||||
f = getattr(logger, logtype)
|
||||
#logger.debug(str)
|
||||
f(_str)
|
||||
|
||||
def __getattr__(name):
|
||||
|
||||
def method(*args):
|
||||
_str = ''
|
||||
if args:
|
||||
for s in args:
|
||||
_str = "%s %s" % (_str, s)
|
||||
_str = _str.strip()
|
||||
|
||||
_log(_str, logtype=name)
|
||||
|
||||
return method
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
109
lib/rfb_bitmap.py
Normal file
109
lib/rfb_bitmap.py
Normal file
@@ -0,0 +1,109 @@
|
||||
import numpy as np
|
||||
from PIL import Image, ImageChops, ImageDraw, ImagePalette
|
||||
from lib import bgr233_palette
|
||||
|
||||
__all__ = ['RfbBitmap']
|
||||
|
||||
class RfbBitmap():
|
||||
|
||||
def __init__(self):
|
||||
self.bpp = None
|
||||
self.depth = None
|
||||
self.truecolor = None
|
||||
self.primaryOrder = 'rgb'
|
||||
self.dither = False
|
||||
self.red_shift = None
|
||||
self.green_shift = None
|
||||
self.blue_shift = None
|
||||
|
||||
def __quantizetopalette(self, silf, palette, dither=False):
|
||||
"""Converts an RGB or L mode image to use a given P image's palette."""
|
||||
silf.load()
|
||||
|
||||
# use palette from reference image
|
||||
palette.load()
|
||||
if palette.mode != "P":
|
||||
raise ValueError("bad mode for palette image")
|
||||
if silf.mode != "RGB" and silf.mode != "L":
|
||||
raise ValueError(
|
||||
"only RGB or L mode images can be quantized to a palette"
|
||||
)
|
||||
im = silf.im.convert("P", 1 if dither else 0, palette.im)
|
||||
# the 0 above means turn OFF dithering
|
||||
|
||||
# Later versions of Pillow (4.x) rename _makeself to _new
|
||||
try:
|
||||
return silf._new(im)
|
||||
except AttributeError:
|
||||
return silf._makeself(im)
|
||||
|
||||
|
||||
def get_bitmap(self, rectangle):
|
||||
if self.bpp == 32:
|
||||
redBits = 8
|
||||
greenBits = 8
|
||||
blueBits = 8
|
||||
|
||||
# image array
|
||||
a = np.asarray(rectangle).copy()
|
||||
|
||||
redMask = ((1 << redBits) - 1) << self.red_shift
|
||||
greenMask = ((1 << greenBits) - 1) << self.green_shift
|
||||
blueMask = ((1 << blueBits) - 1) << self.blue_shift
|
||||
a[..., 0] = ( a[..., 0] ) & redMask >> self.red_shift
|
||||
a[..., 1] = ( a[..., 1] ) & greenMask >> self.green_shift
|
||||
a[..., 2] = ( a[..., 2] ) & blueMask >> self.blue_shift
|
||||
|
||||
image = Image.fromarray(a)
|
||||
if self.primaryOrder == "rgb":
|
||||
(b, g, r) = image.split()
|
||||
image = Image.merge("RGB", (r, g, b))
|
||||
del b,g,r
|
||||
image = image.convert("RGBX")
|
||||
return image
|
||||
|
||||
elif self.bpp == 16: #BGR565
|
||||
greenBits = 5
|
||||
blueBits = 6
|
||||
redBits = 5
|
||||
image = rectangle
|
||||
|
||||
if self.primaryOrder == "bgr": # FIXME: does not work
|
||||
(b, g, r) = image.split()
|
||||
image = Image.merge("RGB", (r, g, b))
|
||||
|
||||
if self.depth == 16:
|
||||
image = image.convert('BGR;16')
|
||||
if self.depth == 15:
|
||||
image = image.convert('BGR;15')
|
||||
|
||||
return image
|
||||
|
||||
elif self.bpp == 8: #bgr233
|
||||
redBits = 3
|
||||
greenBits = 3
|
||||
blueBits = 2
|
||||
image = rectangle
|
||||
|
||||
palette = bgr233_palette.palette
|
||||
if self.primaryOrder == "rgb":
|
||||
#(b, g, r) = image.split()
|
||||
#image = Image.merge("RGB", (r, g, b))
|
||||
|
||||
palette = np.reshape(palette, (-3,3))
|
||||
palette[:,[0, 2]] = palette[:,[2, 0]]
|
||||
palette = palette.flatten()
|
||||
palette = list(palette)
|
||||
|
||||
p = Image.new('P',(16,16))
|
||||
p.putpalette(palette)
|
||||
|
||||
image = self.__quantizetopalette(image, p, dither=self.dither)
|
||||
|
||||
#image = image.convert('RGB', colors=4).quantize(palette=p)
|
||||
#log.debug(image)
|
||||
return image
|
||||
|
||||
else:
|
||||
# unsupported BPP
|
||||
return None
|
||||
Reference in New Issue
Block a user