forked from shaba/openuds
Removed NX
This commit is contained in:
parent
e85e4c4e54
commit
9ba4234313
@ -1,42 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012-2021 Virtual Cable S.L.U.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. 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
|
||||
"""
|
||||
# Disabled OLD NX. Will be removed soon
|
||||
|
||||
# from django.utils.translation import ugettext_noop as _
|
||||
# from uds.core.managers.user_preferences import UserPrefsManager, CommonPrefs
|
||||
# from uds.core.util.config import Config
|
||||
# from .nxtransport import NXTransport
|
||||
# from .nxtunneltransport import TSNXTransport
|
||||
|
||||
# Config.section('NX').value('downloadUrl', 'http://sourceforge.net/projects/opennx/files/opennx/CI-win32/OpenNX-0.16.0.725-Setup.exe/download').get()
|
||||
# Config.section('NX').value('downloadUrlMACOS', 'http://opennx.net/download.html').get()
|
Binary file not shown.
Before Width: | Height: | Size: 4.5 KiB |
@ -1,74 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012-2019 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.
|
||||
'''
|
||||
Created on Apr 29, 2019
|
||||
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
'''
|
||||
import os
|
||||
import logging
|
||||
import typing
|
||||
|
||||
from uds.core import transports
|
||||
|
||||
# Not imported at runtime, just for type checking
|
||||
if typing.TYPE_CHECKING:
|
||||
from uds import models
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
READY_CACHE_TIMEOUT = 30
|
||||
|
||||
class BaseNXTransport(transports.Transport):
|
||||
_listenPort: str = ''
|
||||
|
||||
def isAvailableFor(self, userService: 'models.UserService', ip: str) -> bool:
|
||||
"""
|
||||
Checks if the transport is available for the requested destination ip
|
||||
Override this in yours transports
|
||||
"""
|
||||
logger.debug('Checking availability for %s', ip)
|
||||
ready = self.cache.get(ip)
|
||||
if not ready:
|
||||
# Check again for readyness
|
||||
if self.testServer(userService, ip, self._listenPort) is True:
|
||||
self.cache.put(ip, 'Y', READY_CACHE_TIMEOUT)
|
||||
return True
|
||||
self.cache.put(ip, 'N', READY_CACHE_TIMEOUT)
|
||||
return ready == 'Y'
|
||||
|
||||
def getScript(self, scriptNameTemplate: str, osName: str, params: typing.Dict[str, typing.Any]) -> typing.Tuple[str, str, typing.Dict[str, typing.Any]]:
|
||||
# Reads script
|
||||
scriptNameTemplate = scriptNameTemplate.format(osName)
|
||||
with open(os.path.join(os.path.dirname(__file__), scriptNameTemplate)) as f:
|
||||
script = f.read()
|
||||
# Reads signature
|
||||
with open(os.path.join(os.path.dirname(__file__), scriptNameTemplate + '.signature')) as f:
|
||||
signature = f.read()
|
||||
return script, signature, params
|
@ -1,220 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012-2019 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.
|
||||
|
||||
|
||||
"""
|
||||
Created on Jul 29, 2011
|
||||
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
|
||||
"""
|
||||
from .nxpassword import NXPassword
|
||||
|
||||
EMPTY_PASSWORD = "EMPTY_PASSWORD"
|
||||
|
||||
NXTEMPLATE = (
|
||||
"<!DOCTYPE NXClientSettings>\n"
|
||||
"<NXClientSettings application=\"nxclient\" version=\"1.3\" >\n"
|
||||
" <group name=\"Advanced\" >\n"
|
||||
" <option key=\"Cache size\" value=\"{CACHEMEM}\" />\n"
|
||||
" <option key=\"Cache size on disk\" value=\"{CACHEDISK}\" />\n"
|
||||
" <option key=\"Current keyboard\" value=\"true\" />\n"
|
||||
" <option key=\"Custom keyboard layout\" value=\"{KEYLAYOUT}\" />\n"
|
||||
" <option key=\"Disable ZLIB stream compression\" value=\"false\" />\n"
|
||||
" <option key=\"Disable TCP no-delay\" value=\"false\" />\n" +
|
||||
" <option key=\"Disable deferred updates\" value=\"false\" />\n"
|
||||
" <option key=\"Enable HTTP proxy\" value=\"false\" />\n"
|
||||
" <option key=\"Enable SSL encryption\" value=\"true\" />\n"
|
||||
" <option key=\"Enable response time optimisations\" value=\"true\" />\n"
|
||||
" <option key=\"Grab keyboard\" value=\"false\" />\n"
|
||||
" <option key=\"HTTP proxy host\" value=\"\" />\n"
|
||||
" <option key=\"HTTP proxy port\" value=\"8080\" />\n"
|
||||
" <option key=\"HTTP proxy username\" value=\"\" />\n"
|
||||
" <option key=\"Remember HTTP proxy password\" value=\"false\" />\n"
|
||||
" <option key=\"Restore cache\" value=\"true\" />\n"
|
||||
" <option key=\"StreamCompression\" value=\"\" />\n"
|
||||
" </group>\n"
|
||||
" <group name=\"Environment\" >\n"
|
||||
" <option key=\"Font server host\" value=\"\" />\n"
|
||||
" <option key=\"Font server port\" value=\"7100\" />\n"
|
||||
" <option key=\"Use font server\" value=\"false\" />\n"
|
||||
" </group>\n"
|
||||
" <group name=\"General\" >\n"
|
||||
" <option key=\"Automatic reconnect\" value=\"true\" />\n"
|
||||
" <option key=\"Disable SHM\" value=\"false\" />\n"
|
||||
" <option key=\"Disable emulate shared pixmaps\" value=\"false\" />\n"
|
||||
" <option key=\"Link speed\" value=\"{LINKSPEED}\" />\n"
|
||||
" <option key=\"Remember password\" value=\"{REMEMBERPASS}\" />\n"
|
||||
" <option key=\"Resolution\" value=\"{RESOLUTION}\" />\n"
|
||||
" <option key=\"Resolution width\" value=\"{WIDTH}\" />\n"
|
||||
" <option key=\"Resolution height\" value=\"{HEIGHT}\" />\n"
|
||||
" <option key=\"Server host\" value=\"{HOST}\" />\n"
|
||||
" <option key=\"Server port\" value=\"{PORT}\" />\n"
|
||||
" <option key=\"Session\" value=\"unix\" />\n"
|
||||
" <option key=\"Desktop\" value=\"{DESKTOP}\" />\n"
|
||||
" <option key=\"Use default image encoding\" value=\"1\" />\n"
|
||||
" <option key=\"Use render\" value=\"false\" />\n"
|
||||
" <option key=\"Use taint\" value=\"true\" />\n"
|
||||
" <option key=\"Virtual desktop\" value=\"false\" />\n"
|
||||
" <option key=\"XAgent encoding\" value=\"true\" />\n"
|
||||
" <option key=\"displaySaveOnExit\" value=\"true\" />\n"
|
||||
" <option key=\"xdm broadcast port\" value=\"177\" />\n"
|
||||
" <option key=\"xdm list host\" value=\"localhost\" />\n"
|
||||
" <option key=\"xdm list port\" value=\"177\" />\n"
|
||||
" <option key=\"xdm mode\" value=\"server decide\" />\n"
|
||||
" <option key=\"xdm query host\" value=\"localhost\" />\n"
|
||||
" <option key=\"xdm query port\" value=\"177\" />\n"
|
||||
" </group>\n"
|
||||
" <group name=\"Images\" >\n"
|
||||
" <option key=\"Disable JPEG Compression\" value=\"0\" />\n"
|
||||
" <option key=\"Disable all image optimisations\" value=\"false\" />\n"
|
||||
" <option key=\"Disable backingstore\" value=\"false\" />\n"
|
||||
" <option key=\"Disable composite\" value=\"false\" />\n"
|
||||
" <option key=\"Image Compression Type\" value=\"3\" />\n"
|
||||
" <option key=\"Image Encoding Type\" value=\"0\" />\n"
|
||||
" <option key=\"Image JPEG Encoding\" value=\"false\" />\n"
|
||||
" <option key=\"JPEG Quality\" value=\"6\" />\n"
|
||||
" <option key=\"RDP Image Encoding\" value=\"3\" />\n"
|
||||
" <option key=\"RDP JPEG Quality\" value=\"6\" />\n"
|
||||
" <option key=\"RDP optimization for low-bandwidth link\" value=\"false\" />\n"
|
||||
" <option key=\"Reduce colors to\" value=\"\" />\n"
|
||||
" <option key=\"Use PNG Compression\" value=\"true\" />\n"
|
||||
" <option key=\"VNC JPEG Quality\" value=\"6\" />\n"
|
||||
" <option key=\"VNC images compression\" value=\"3\" />\n"
|
||||
" </group>\n"
|
||||
" <group name=\"Login\" >\n"
|
||||
" <option key=\"User\" value=\"{USERNAME}\" />\n"
|
||||
" <option key=\"Auth\" value=\"{PASSWORD}\" />\n"
|
||||
" <option key=\"Guest Mode\" value=\"false\" />\n"
|
||||
" <option key=\"Guest password\" value=\"\" />\n"
|
||||
" <option key=\"Guest username\" value=\"\" />\n"
|
||||
" <option key=\"Login Method\" value=\"nx\" />\n"
|
||||
" <option key=\"Public Key\" value=\"-----BEGIN DSA PRIVATE KEY-----\n"
|
||||
"MIIBuwIBAAKBgQCXv9AzQXjxvXWC1qu3CdEqskX9YomTfyG865gb4D02ZwWuRU/9\n"
|
||||
"C3I9/bEWLdaWgJYXIcFJsMCIkmWjjeSZyTmeoypI1iLifTHUxn3b7WNWi8AzKcVF\n"
|
||||
"aBsBGiljsop9NiD1mEpA0G+nHHrhvTXz7pUvYrsrXcdMyM6rxqn77nbbnwIVALCi\n"
|
||||
"xFdHZADw5KAVZI7r6QatEkqLAoGBAI4L1TQGFkq5xQ/nIIciW8setAAIyrcWdK/z\n"
|
||||
"5/ZPeELdq70KDJxoLf81NL/8uIc4PoNyTRJjtT3R4f8Az1TsZWeh2+ReCEJxDWgG\n"
|
||||
"fbk2YhRqoQTtXPFsI4qvzBWct42WonWqyyb1bPBHk+JmXFscJu5yFQ+JUVNsENpY\n"
|
||||
"+Gkz3HqTAoGANlgcCuA4wrC+3Cic9CFkqiwO/Rn1vk8dvGuEQqFJ6f6LVfPfRTfa\n"
|
||||
"QU7TGVLk2CzY4dasrwxJ1f6FsT8DHTNGnxELPKRuLstGrFY/PR7KeafeFZDf+fJ3\n"
|
||||
"mbX5nxrld3wi5titTnX+8s4IKv29HJguPvOK/SI7cjzA+SqNfD7qEo8CFDIm1xRf\n"
|
||||
"8xAPsSKs6yZ6j1FNklfu\n"
|
||||
"-----END DSA PRIVATE KEY-----\n"
|
||||
"\" />\n"
|
||||
" </group>\n"
|
||||
" <group name=\"Services\" >\n"
|
||||
" <option key=\"Audio\" value=\"true\" />\n"
|
||||
" <option key=\"IPPPort\" value=\"631\" />\n"
|
||||
" <option key=\"IPPPrinting\" value=\"false\" />\n"
|
||||
" <option key=\"Shares\" value=\"false\" />\n"
|
||||
" </group>\n"
|
||||
" <group name=\"VNC Session\" >\n"
|
||||
" <option key=\"Display\" value=\"0\" />\n"
|
||||
" <option key=\"Remember\" value=\"false\" />\n"
|
||||
" <option key=\"Server\" value=\"\" />\n"
|
||||
" </group>\n"
|
||||
" <group name=\"Windows Session\" >\n"
|
||||
" <option key=\"Application\" value=\"\" />\n"
|
||||
" <option key=\"Authentication\" value=\"2\" />\n"
|
||||
" <option key=\"Color Depth\" value=\"16\" />\n"
|
||||
" <option key=\"Domain\" value=\"\" />\n"
|
||||
" <option key=\"Image Cache\" value=\"true\" />\n"
|
||||
" <option key=\"Password\" value=\"EMPTY_PASSWORD\" />\n"
|
||||
" <option key=\"Remember\" value=\"true\" />\n"
|
||||
" <option key=\"Run application\" value=\"false\" />\n"
|
||||
" <option key=\"Server\" value=\"\" />\n"
|
||||
" <option key=\"User\" value=\"\" />\n"
|
||||
" </group>\n"
|
||||
" <group name=\"share chosen\" >\n"
|
||||
" <option key=\"Share number\" value=\"0\" />\n"
|
||||
" </group>\n"
|
||||
"</NXClientSettings>"
|
||||
)
|
||||
|
||||
|
||||
class NXFile:
|
||||
fullScreen: bool = False
|
||||
width: int = 800
|
||||
height: int = 600
|
||||
cachemem: str = '4'
|
||||
cachedisk: str = '32'
|
||||
keyboardLayout: str = ''
|
||||
linkSpeed: str = 'wan'
|
||||
host: str = ''
|
||||
port: str = ''
|
||||
username: str = ''
|
||||
password: str = ''
|
||||
desktop: str = 'gnome'
|
||||
|
||||
def __init__(self, username: str = '', password: str = '', width: int = 1024, height: int = 768):
|
||||
self.fullScreen = width == -1 or height == -1
|
||||
self.width = int(width)
|
||||
self.height = int(height)
|
||||
self.username = username
|
||||
self.password = password
|
||||
|
||||
@property
|
||||
def as_file(self):
|
||||
return self.get()
|
||||
|
||||
@property
|
||||
def as_file_for_format(self):
|
||||
return self.get(True)
|
||||
|
||||
def get(self, processPassword=False):
|
||||
rememberPass = 'true'
|
||||
password = NXPassword.scrambleString(self.password)
|
||||
if processPassword:
|
||||
password = password.replace('{', '{{')
|
||||
password = password.replace('}', '}}')
|
||||
|
||||
if password == '':
|
||||
rememberPass = "false"
|
||||
password = EMPTY_PASSWORD
|
||||
|
||||
resolution = '{}x{}'.format(self.width, self.height)
|
||||
if self.fullScreen:
|
||||
resolution = "fullscreen"
|
||||
|
||||
return NXTEMPLATE.format(
|
||||
CACHEMEM=self.cachemem,
|
||||
CACHEDISK=self.cachedisk,
|
||||
KEYLAYOUT=self.keyboardLayout,
|
||||
LINKSPEED=self.linkSpeed,
|
||||
REMEMBERPASS=rememberPass,
|
||||
RESOLUTION=resolution,
|
||||
WIDTH=self.width,
|
||||
HEIGHT=self.height,
|
||||
HOST=self.host,
|
||||
PORT=self.port,
|
||||
DESKTOP=self.desktop,
|
||||
USERNAME=self.username,
|
||||
PASSWORD=password
|
||||
)
|
@ -1,110 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2012-2021 Virtual Cable S.L.U.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. 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.
|
||||
|
||||
|
||||
"""
|
||||
Created on Apr 20, 2015
|
||||
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
|
||||
"""
|
||||
|
||||
class NXPassword: # pylint: disable=too-few-public-methods
|
||||
# Encoding method extracted from nomachine web site:
|
||||
# http://www.nomachine.com/ar/view.php?ar_id=AR01C00125
|
||||
|
||||
dummyString = "{{{{"
|
||||
numValidCharList = 85
|
||||
validCharList = [
|
||||
'!', '#', '$', '%', '&', '(', ')', '*', '+', '-',
|
||||
'.', '0', '1', '2', '3', '4', '5', '6', '7', '8',
|
||||
'9', ':', ';', '<', '>', '?', '@', 'A', 'B', 'C',
|
||||
'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
|
||||
'X', 'Y', 'Z', '[', ']', '_', 'a', 'b', 'c', 'd',
|
||||
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
|
||||
'y', 'z', '{', '|', '}'
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def _encodePassword(p):
|
||||
sPass = ':'
|
||||
|
||||
if p == '':
|
||||
return ''
|
||||
|
||||
for i, ch in enumerate(p):
|
||||
sPass += '{}:'.format(ord(ch) + i + 1)
|
||||
|
||||
return sPass
|
||||
|
||||
@staticmethod
|
||||
def _findCharInList(c):
|
||||
try:
|
||||
return NXPassword.validCharList.index(c)
|
||||
except ValueError:
|
||||
return -1
|
||||
|
||||
@staticmethod
|
||||
def _getRandomValidCharFromList():
|
||||
# k = random.randint(0, NXPassword.numValidCharList)
|
||||
k = 0
|
||||
return NXPassword.validCharList[k]
|
||||
|
||||
@staticmethod
|
||||
def scrambleString(s):
|
||||
if s is None or s == '':
|
||||
return ''
|
||||
|
||||
_str = NXPassword._encodePassword(s)
|
||||
|
||||
if len(_str) < 32:
|
||||
_str += NXPassword.dummyString
|
||||
|
||||
password = _str[::-1] # Reversed string
|
||||
|
||||
if len(password) < 32:
|
||||
password += NXPassword.dummyString
|
||||
|
||||
startChar = NXPassword._getRandomValidCharFromList()
|
||||
l = ord(startChar) + len(password) - 2
|
||||
|
||||
pw = startChar
|
||||
|
||||
for i1, ch in enumerate(password):
|
||||
j = NXPassword._findCharInList(ch)
|
||||
if j == -1:
|
||||
return s
|
||||
|
||||
i = (j + l * (i1 + 2)) % NXPassword.numValidCharList
|
||||
pw += NXPassword.validCharList[i]
|
||||
|
||||
pw += chr(ord(NXPassword._getRandomValidCharFromList()) + 2)
|
||||
|
||||
return pw.replace('&', '&').replace('<', '<').replace('"', '"').replace('\'', ''') # .replace('$', '\\$')
|
@ -1,243 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012-2019 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.
|
||||
|
||||
"""
|
||||
Created on Jul 29, 2011
|
||||
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
"""
|
||||
import logging
|
||||
import typing
|
||||
|
||||
from django.utils.translation import ugettext_noop as _, ugettext_lazy
|
||||
from uds.core.managers.user_preferences import CommonPrefs
|
||||
from uds.core.ui import gui
|
||||
from uds.core import transports
|
||||
from uds.core.util import os_detector as OsDetector
|
||||
|
||||
from .nxbase import BaseNXTransport
|
||||
from .nxfile import NXFile
|
||||
|
||||
# Not imported at runtime, just for type checking
|
||||
if typing.TYPE_CHECKING:
|
||||
from uds.core import Module
|
||||
from uds import models
|
||||
from django.http import HttpRequest # pylint: disable=ungrouped-imports
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
READY_CACHE_TIMEOUT = 30
|
||||
|
||||
|
||||
class NXTransport(BaseNXTransport):
|
||||
"""
|
||||
Provides access via NX to service.
|
||||
This transport can use an domain. If username processed by authenticator contains '@', it will split it and left-@-part will be username, and right password
|
||||
"""
|
||||
typeName = _('NX v3.5 (DEPRECATED)')
|
||||
typeType = 'NXTransport'
|
||||
typeDescription = _('NX Protocol v3.5. Direct connection.')
|
||||
iconFile = 'nx.png'
|
||||
protocol = transports.protocols.NX
|
||||
|
||||
useEmptyCreds = gui.CheckBoxField(label=_('Empty creds'), order=1, tooltip=_('If checked, the credentials used to connect will be emtpy'), tab=gui.CREDENTIALS_TAB)
|
||||
fixedName = gui.TextField(label=_('Username'), order=2, tooltip=_('If not empty, this username will be always used as credential'), tab=gui.CREDENTIALS_TAB)
|
||||
fixedPassword = gui.PasswordField(label=_('Password'), order=3, tooltip=_('If not empty, this password will be always used as credential'), tab=gui.CREDENTIALS_TAB)
|
||||
listenPort = gui.NumericField(label=_('Listening port'), length=5, order=4, tooltip=_('Listening port of NX (ssh) at client machine'), defvalue='22')
|
||||
connection = gui.ChoiceField(
|
||||
label=_('Connection'),
|
||||
order=6,
|
||||
tooltip=_('Connection speed for this transport (quality)'),
|
||||
values=[
|
||||
{'id': 'modem', 'text': 'modem'},
|
||||
{'id': 'isdn', 'text': 'isdn'},
|
||||
{'id': 'adsl', 'text': 'adsl'},
|
||||
{'id': 'wan', 'text': 'wan'},
|
||||
{'id': 'lan', 'text': 'lan'}
|
||||
],
|
||||
tab=gui.PARAMETERS_TAB
|
||||
)
|
||||
session = gui.ChoiceField(
|
||||
label=_('Session'),
|
||||
order=7,
|
||||
tooltip=_('Desktop session'),
|
||||
values=[
|
||||
{'id': 'gnome', 'text': 'gnome'},
|
||||
{'id': 'kde', 'text': 'kde'},
|
||||
{'id': 'cde', 'text': 'cde'},
|
||||
],
|
||||
tab=gui.PARAMETERS_TAB
|
||||
)
|
||||
cacheDisk = gui.ChoiceField(
|
||||
label=_('Disk Cache'),
|
||||
order=8,
|
||||
tooltip=_('Cache size en Mb stored at disk'),
|
||||
values=[
|
||||
{'id': '0', 'text': '0 Mb'},
|
||||
{'id': '32', 'text': '32 Mb'},
|
||||
{'id': '64', 'text': '64 Mb'},
|
||||
{'id': '128', 'text': '128 Mb'},
|
||||
{'id': '256', 'text': '256 Mb'},
|
||||
{'id': '512', 'text': '512 Mb'},
|
||||
],
|
||||
tab=gui.PARAMETERS_TAB
|
||||
)
|
||||
cacheMem = gui.ChoiceField(
|
||||
label=_('Memory Cache'),
|
||||
order=9,
|
||||
tooltip=_('Cache size en Mb kept at memory'),
|
||||
values=[
|
||||
{'id': '4', 'text': '4 Mb'},
|
||||
{'id': '8', 'text': '8 Mb'},
|
||||
{'id': '16', 'text': '16 Mb'},
|
||||
{'id': '32', 'text': '32 Mb'},
|
||||
{'id': '64', 'text': '64 Mb'},
|
||||
{'id': '128', 'text': '128 Mb'},
|
||||
],
|
||||
tab=gui.PARAMETERS_TAB
|
||||
)
|
||||
screenSize = gui.ChoiceField(
|
||||
label=_('Screen size'),
|
||||
order=10,
|
||||
tooltip=_('Screen size'),
|
||||
defvalue=CommonPrefs.SZ_FULLSCREEN,
|
||||
values=[
|
||||
{'id': CommonPrefs.SZ_640x480, 'text': '640x480'},
|
||||
{'id': CommonPrefs.SZ_800x600, 'text': '800x600'},
|
||||
{'id': CommonPrefs.SZ_1024x768, 'text': '1024x768'},
|
||||
{'id': CommonPrefs.SZ_1366x768, 'text': '1366x768'},
|
||||
{'id': CommonPrefs.SZ_1920x1080, 'text': '1920x1080'},
|
||||
{'id': CommonPrefs.SZ_FULLSCREEN, 'text': ugettext_lazy('Full Screen')}
|
||||
],
|
||||
tab=gui.PARAMETERS_TAB
|
||||
)
|
||||
|
||||
_useEmptyCreds: bool = False
|
||||
_fixedName: str = ''
|
||||
_fixedPassword: str = ''
|
||||
_listenPort: str = ''
|
||||
_connection: str = ''
|
||||
_session: str = ''
|
||||
_cacheDisk: str = ''
|
||||
_cacheMem: str = ''
|
||||
_screenSize: str = ''
|
||||
|
||||
|
||||
def initialize(self, values: 'Module.ValuesType'):
|
||||
if values:
|
||||
self._useEmptyCreds = gui.strToBool(values['useEmptyCreds'])
|
||||
self._fixedName = values['fixedName']
|
||||
self._fixedPassword = values['fixedPassword']
|
||||
self._listenPort = values['listenPort']
|
||||
self._connection = values['connection']
|
||||
self._session = values['session']
|
||||
self._cacheDisk = values['cacheDisk']
|
||||
self._cacheMem = values['cacheMem']
|
||||
self._screenSize = values['screenSize']
|
||||
|
||||
def marshal(self) -> bytes:
|
||||
"""
|
||||
Serializes the transport data so we can store it in database
|
||||
"""
|
||||
return str.join('\t', [
|
||||
'v2', gui.boolToStr(self._useEmptyCreds), self._fixedName, self._fixedPassword, self._listenPort,
|
||||
self._connection, self._session, self._cacheDisk, self._cacheMem, self._screenSize
|
||||
]).encode('utf8')
|
||||
|
||||
def unmarshal(self, data: bytes) -> None:
|
||||
values = data.decode('utf8').split('\t')
|
||||
if values[0] in ('v1', 'v2'):
|
||||
self._useEmptyCreds = gui.strToBool(values[1])
|
||||
self._fixedName, self._fixedPassword, self._listenPort, self._connection, self._session, self._cacheDisk, self._cacheMem = values[2:9]
|
||||
self._screenSize = values[9] if values[0] == 'v2' else CommonPrefs.SZ_FULLSCREEN
|
||||
|
||||
def valuesDict(self) -> gui.ValuesDictType:
|
||||
return {
|
||||
'useEmptyCreds': gui.boolToStr(self._useEmptyCreds),
|
||||
'fixedName': self._fixedName,
|
||||
'fixedPassword': self._fixedPassword,
|
||||
'listenPort': self._listenPort,
|
||||
'connection': self._connection,
|
||||
'session': self._session,
|
||||
'cacheDisk': self._cacheDisk,
|
||||
'cacheMem': self._cacheMem
|
||||
}
|
||||
|
||||
def getUDSTransportScript( # pylint: disable=too-many-locals
|
||||
self,
|
||||
userService: 'models.UserService',
|
||||
transport: 'models.Transport',
|
||||
ip: str,
|
||||
os: typing.Dict[str, str],
|
||||
user: 'models.User',
|
||||
password: str,
|
||||
request: 'HttpRequest'
|
||||
) -> typing.Tuple[str, str, typing.Mapping[str, typing.Any]]:
|
||||
username = user.getUsernameForAuth()
|
||||
proc = username.split('@')
|
||||
username = proc[0]
|
||||
|
||||
if self._fixedName:
|
||||
username = self._fixedName
|
||||
if self._fixedPassword:
|
||||
password = self._fixedPassword
|
||||
if self._useEmptyCreds:
|
||||
username, password = '', ''
|
||||
|
||||
# We have the credentials right now, let os manager
|
||||
|
||||
width, height = CommonPrefs.getWidthHeight(self._screenSize)
|
||||
|
||||
# Fix username/password acording to os manager
|
||||
username, password = userService.processUserPassword(username, password)
|
||||
|
||||
r = NXFile(username=username, password=password, width=width, height=height)
|
||||
r.host = ip
|
||||
r.port = self._listenPort
|
||||
r.linkSpeed = self._connection
|
||||
r.desktop = self._session
|
||||
r.cachedisk = self._cacheDisk
|
||||
r.cachemem = self._cacheMem
|
||||
|
||||
osName = {
|
||||
OsDetector.Windows: 'windows',
|
||||
OsDetector.Linux: 'linux',
|
||||
OsDetector.Macintosh: 'macosx'
|
||||
|
||||
}.get(os['OS'])
|
||||
|
||||
if osName is None:
|
||||
return super().getUDSTransportScript(userService, transport, ip, os, user, password, request)
|
||||
|
||||
sp = {
|
||||
'as_file': r.as_file,
|
||||
}
|
||||
|
||||
return self.getScript('scripts/{}/direct.py', osName, sp)
|
@ -1,359 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2012-2021 Virtual Cable S.L.U.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
# * Neither the name of Virtual Cable S.L. 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.
|
||||
|
||||
"""
|
||||
Created on Jul 29, 2011
|
||||
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
"""
|
||||
import random
|
||||
import string
|
||||
import logging
|
||||
import typing
|
||||
|
||||
from django.utils.translation import ugettext_noop as _, ugettext_lazy
|
||||
|
||||
from uds.core.managers.user_preferences import CommonPrefs
|
||||
from uds.core.ui import gui
|
||||
from uds.core import transports
|
||||
from uds.models import TicketStore
|
||||
from uds.core.util import os_detector as OsDetector
|
||||
|
||||
from .nxfile import NXFile
|
||||
from .nxbase import BaseNXTransport
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Not imported at runtime, just for type checking
|
||||
if typing.TYPE_CHECKING:
|
||||
from uds.core import Module
|
||||
from uds import models
|
||||
from django.http import HttpRequest # pylint: disable=ungrouped-imports
|
||||
|
||||
|
||||
class TSNXTransport(BaseNXTransport):
|
||||
"""
|
||||
Provides access via NX to service.
|
||||
This transport can use an domain. If username processed by authenticator contains '@', it will split it and left-@-part will be username, and right password
|
||||
"""
|
||||
|
||||
typeName = _('NX v3.5 (DEPRECATED)')
|
||||
typeType = 'TSNXTransport'
|
||||
typeDescription = _('NX protocol v3.5. Tunneled connection.')
|
||||
iconFile = 'nx.png'
|
||||
protocol = transports.protocols.NX
|
||||
group = transports.TUNNELED_GROUP
|
||||
|
||||
tunnelServer = gui.TextField(
|
||||
label=_('Tunnel server'),
|
||||
order=1,
|
||||
tooltip=_(
|
||||
'IP or Hostname of tunnel server sent to client device ("public" ip) and port. (use HOST:PORT format)'
|
||||
),
|
||||
tab=gui.TUNNEL_TAB,
|
||||
)
|
||||
|
||||
tunnelWait = gui.NumericField(
|
||||
length=3,
|
||||
label=_('Tunnel wait time'),
|
||||
defvalue='30',
|
||||
minValue=5,
|
||||
maxValue=3600 * 24,
|
||||
order=2,
|
||||
tooltip=_('Maximum time to wait before closing the tunnel listener'),
|
||||
required=True,
|
||||
tab=gui.TUNNEL_TAB,
|
||||
)
|
||||
|
||||
verifyCertificate = gui.CheckBoxField(
|
||||
label=_('Force SSL certificate verification'),
|
||||
order=23,
|
||||
tooltip=_(
|
||||
'If enabled, the certificate of tunnel server will be verified (recommended).'
|
||||
),
|
||||
defvalue=gui.FALSE,
|
||||
tab=gui.TUNNEL_TAB,
|
||||
)
|
||||
|
||||
useEmptyCreds = gui.CheckBoxField(
|
||||
label=_('Empty creds'),
|
||||
order=3,
|
||||
tooltip=_('If checked, the credentials used to connect will be emtpy'),
|
||||
tab=gui.CREDENTIALS_TAB,
|
||||
)
|
||||
fixedName = gui.TextField(
|
||||
label=_('Username'),
|
||||
order=4,
|
||||
tooltip=_('If not empty, this username will be always used as credential'),
|
||||
tab=gui.CREDENTIALS_TAB,
|
||||
)
|
||||
fixedPassword = gui.PasswordField(
|
||||
label=_('Password'),
|
||||
order=5,
|
||||
tooltip=_('If not empty, this password will be always used as credential'),
|
||||
tab=gui.CREDENTIALS_TAB,
|
||||
)
|
||||
listenPort = gui.NumericField(
|
||||
label=_('Listening port'),
|
||||
length=5,
|
||||
order=6,
|
||||
tooltip=_('Listening port of NX (ssh) at client machine'),
|
||||
defvalue='22',
|
||||
)
|
||||
connection = gui.ChoiceField(
|
||||
label=_('Connection'),
|
||||
order=7,
|
||||
tooltip=_('Connection speed for this transport (quality)'),
|
||||
values=[
|
||||
{'id': 'modem', 'text': 'modem'},
|
||||
{'id': 'isdn', 'text': 'isdn'},
|
||||
{'id': 'adsl', 'text': 'adsl'},
|
||||
{'id': 'wan', 'text': 'wan'},
|
||||
{'id': 'lan', 'text': 'lan'},
|
||||
],
|
||||
tab=gui.PARAMETERS_TAB,
|
||||
)
|
||||
session = gui.ChoiceField(
|
||||
label=_('Session'),
|
||||
order=8,
|
||||
tooltip=_('Desktop session'),
|
||||
values=[
|
||||
{'id': 'gnome', 'text': 'gnome'},
|
||||
{'id': 'kde', 'text': 'kde'},
|
||||
{'id': 'cde', 'text': 'cde'},
|
||||
],
|
||||
tab=gui.PARAMETERS_TAB,
|
||||
)
|
||||
cacheDisk = gui.ChoiceField(
|
||||
label=_('Disk Cache'),
|
||||
order=9,
|
||||
tooltip=_('Cache size en Mb stored at disk'),
|
||||
values=[
|
||||
{'id': '0', 'text': '0 Mb'},
|
||||
{'id': '32', 'text': '32 Mb'},
|
||||
{'id': '64', 'text': '64 Mb'},
|
||||
{'id': '128', 'text': '128 Mb'},
|
||||
{'id': '256', 'text': '256 Mb'},
|
||||
{'id': '512', 'text': '512 Mb'},
|
||||
],
|
||||
tab=gui.PARAMETERS_TAB,
|
||||
)
|
||||
cacheMem = gui.ChoiceField(
|
||||
label=_('Memory Cache'),
|
||||
order=10,
|
||||
tooltip=_('Cache size en Mb kept at memory'),
|
||||
values=[
|
||||
{'id': '4', 'text': '4 Mb'},
|
||||
{'id': '8', 'text': '8 Mb'},
|
||||
{'id': '16', 'text': '16 Mb'},
|
||||
{'id': '32', 'text': '32 Mb'},
|
||||
{'id': '64', 'text': '64 Mb'},
|
||||
{'id': '128', 'text': '128 Mb'},
|
||||
],
|
||||
tab=gui.PARAMETERS_TAB,
|
||||
)
|
||||
screenSize = gui.ChoiceField(
|
||||
label=_('Screen size'),
|
||||
order=10,
|
||||
tooltip=_('Screen size'),
|
||||
defvalue=CommonPrefs.SZ_FULLSCREEN,
|
||||
values=[
|
||||
{'id': CommonPrefs.SZ_640x480, 'text': '640x480'},
|
||||
{'id': CommonPrefs.SZ_800x600, 'text': '800x600'},
|
||||
{'id': CommonPrefs.SZ_1024x768, 'text': '1024x768'},
|
||||
{'id': CommonPrefs.SZ_1366x768, 'text': '1366x768'},
|
||||
{'id': CommonPrefs.SZ_1920x1080, 'text': '1920x1080'},
|
||||
{'id': CommonPrefs.SZ_FULLSCREEN, 'text': ugettext_lazy('Full Screen')},
|
||||
],
|
||||
tab=gui.PARAMETERS_TAB,
|
||||
)
|
||||
|
||||
_tunnelServer: str = ''
|
||||
_tunnelCheckServer: str = ''
|
||||
_useEmptyCreds: bool = False
|
||||
_fixedName: str = ''
|
||||
_fixedPassword: str = ''
|
||||
_listenPort: str = ''
|
||||
_connection: str = ''
|
||||
_session: str = ''
|
||||
_cacheDisk: str = ''
|
||||
_cacheMem: str = ''
|
||||
_screenSize: str = ''
|
||||
_tunnelWait: int = 30
|
||||
_verifyCertificate: bool = False
|
||||
|
||||
def initialize(self, values: 'Module.ValuesType'):
|
||||
if values:
|
||||
if values['tunnelServer'].find(':') == -1:
|
||||
raise transports.Transport.ValidationException(
|
||||
_('Must use HOST:PORT in Tunnel Server Field')
|
||||
)
|
||||
self._tunnelServer = values['tunnelServer']
|
||||
self._tunnelWait = int(values['tunnelWait'])
|
||||
self._verifyCertificate = gui.strToBool(values['verifyCertificate'])
|
||||
self._tunnelCheckServer = ''
|
||||
self._useEmptyCreds = gui.strToBool(values['useEmptyCreds'])
|
||||
self._fixedName = values['fixedName']
|
||||
self._fixedPassword = values['fixedPassword']
|
||||
self._listenPort = values['listenPort']
|
||||
self._connection = values['connection']
|
||||
self._session = values['session']
|
||||
self._cacheDisk = values['cacheDisk']
|
||||
self._cacheMem = values['cacheMem']
|
||||
self._screenSize = values['screenSize']
|
||||
|
||||
def marshal(self) -> bytes:
|
||||
"""
|
||||
Serializes the transport data so we can store it in database
|
||||
"""
|
||||
val = str.join(
|
||||
'\t',
|
||||
[
|
||||
'v3',
|
||||
gui.boolToStr(self._useEmptyCreds),
|
||||
self._fixedName,
|
||||
self._fixedPassword,
|
||||
self._listenPort,
|
||||
self._connection,
|
||||
self._session,
|
||||
self._cacheDisk,
|
||||
self._cacheMem,
|
||||
self._tunnelServer,
|
||||
self._tunnelCheckServer,
|
||||
self._screenSize,
|
||||
str(self._tunnelWait),
|
||||
gui.boolToStr(self._verifyCertificate),
|
||||
],
|
||||
)
|
||||
logger.debug('Values: %s', val)
|
||||
return val.encode('utf8')
|
||||
|
||||
def unmarshal(self, data: bytes) -> None:
|
||||
values = data.decode('utf8').split('\t')
|
||||
if values[0] in ('v1', 'v2', 'v3'):
|
||||
self._useEmptyCreds = gui.strToBool(values[1])
|
||||
(
|
||||
self._fixedName,
|
||||
self._fixedPassword,
|
||||
self._listenPort,
|
||||
self._connection,
|
||||
self._session,
|
||||
self._cacheDisk,
|
||||
self._cacheMem,
|
||||
self._tunnelServer,
|
||||
self._tunnelCheckServer,
|
||||
) = values[2:11]
|
||||
self._screenSize = (
|
||||
values[11] if values[0] == 'v2' else CommonPrefs.SZ_FULLSCREEN
|
||||
)
|
||||
if values[0] == 'v3':
|
||||
self._tunnelWait, self._verifyCertificate = (
|
||||
int(values[12]),
|
||||
gui.strToBool(values[13]),
|
||||
)
|
||||
|
||||
def valuesDict(self) -> gui.ValuesDictType:
|
||||
return {
|
||||
'useEmptyCreds': gui.boolToStr(self._useEmptyCreds),
|
||||
'fixedName': self._fixedName,
|
||||
'fixedPassword': self._fixedPassword,
|
||||
'listenPort': self._listenPort,
|
||||
'connection': self._connection,
|
||||
'session': self._session,
|
||||
'cacheDisk': self._cacheDisk,
|
||||
'cacheMem': self._cacheMem,
|
||||
'tunnelServer': self._tunnelServer,
|
||||
'tunnelWait': str(self._tunnelWait),
|
||||
'verifyCertificate': gui.boolToStr(self._verifyCertificate),
|
||||
}
|
||||
|
||||
def getUDSTransportScript( # pylint: disable=too-many-locals
|
||||
self,
|
||||
userService: 'models.UserService',
|
||||
transport: 'models.Transport',
|
||||
ip: str,
|
||||
os: typing.Dict[str, str],
|
||||
user: 'models.User',
|
||||
password: str,
|
||||
request: 'HttpRequest',
|
||||
) -> typing.Tuple[str, str, typing.Mapping[str, typing.Any]]:
|
||||
prefs = self.screenSize.value
|
||||
|
||||
username = user.getUsernameForAuth()
|
||||
proc = username.split('@')
|
||||
username = proc[0]
|
||||
if self._fixedName is not '':
|
||||
username = self._fixedName
|
||||
if self._fixedPassword is not '':
|
||||
password = self._fixedPassword
|
||||
if self._useEmptyCreds is True:
|
||||
usernamsizerd = '', ''
|
||||
|
||||
ticket = TicketStore.create_for_tunnel(
|
||||
userService=userService,
|
||||
port=int(self._listenPort),
|
||||
validity=self._tunnelWait + 60, # Ticket overtime
|
||||
)
|
||||
|
||||
tunHost, tunPort = self.tunnelServer.value.split(':')
|
||||
|
||||
width, height = CommonPrefs.getWidthHeight(prefs)
|
||||
# Fix username/password acording to os manager
|
||||
username, password = userService.processUserPassword(username, password)
|
||||
|
||||
r = NXFile(username=username, password=password, width=width, height=height)
|
||||
r.host = '{address}'
|
||||
r.port = '{port}'
|
||||
r.linkSpeed = self._connection
|
||||
r.desktop = self._session
|
||||
r.cachedisk = self._cacheDisk
|
||||
r.cachemem = self._cacheMem
|
||||
|
||||
osName = {
|
||||
OsDetector.Windows: 'windows',
|
||||
OsDetector.Linux: 'linux',
|
||||
OsDetector.Macintosh: 'macosx',
|
||||
}.get(os['OS'])
|
||||
|
||||
if osName is None:
|
||||
return super().getUDSTransportScript(
|
||||
userService, transport, ip, os, user, password, request
|
||||
)
|
||||
|
||||
sp = {
|
||||
'ip': ip,
|
||||
'tunHost': tunHost,
|
||||
'tunPort': tunPort,
|
||||
'tunWait': self._tunnelWait,
|
||||
'tunChk': self._verifyCertificate,
|
||||
'ticket': ticket,
|
||||
'as_file_for_format': r.as_file_for_format,
|
||||
}
|
||||
|
||||
return self.getScript('scripts/{}/tunnel.py', osName, sp)
|
@ -1,23 +0,0 @@
|
||||
# This is a template
|
||||
# Saved as .py for easier editing
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# pylint: disable=import-error, no-name-in-module, undefined-variable
|
||||
import subprocess
|
||||
|
||||
from uds import tools # type: ignore
|
||||
|
||||
|
||||
try:
|
||||
cmd = tools.findApp('nxclient', ['/usr/NX/bin/'])
|
||||
if cmd is None:
|
||||
raise Exception()
|
||||
|
||||
except Exception:
|
||||
raise Exception('''<p>You need to have installed NX Client version 3.5 in order to connect to this UDS service.</p>
|
||||
<p>Please, install appropriate package for your system.</p>
|
||||
''')
|
||||
|
||||
filename = tools.saveTempFile(sp['as_file']) # type: ignore
|
||||
tools.addTaskToWait(subprocess.Popen([cmd, '--session', filename]))
|
||||
tools.addFileToUnlink(filename)
|
@ -1 +0,0 @@
|
||||
DyRlBsF1FK0/lXx/GVmKZNpnXh4sS0sdQJ4eKKDbEvzUeU1OKAAyONpvtpk9SKYHDKcvriiynp+kAE690XFYjPnaVrYc8BenjLVqcvlv7hLzc1kvNVmJve9RtVYOfIFCPfQN3sGseREV4aQ7JBuN4T+Paw8j+6YmeborIAfrmfFUhtx5IdUjF5SUnLAok+3aaJCOpKItRIxg4zxp9VfGdnF39KqTWLrgscX9mxe5YEc9DzQTpUm6bw7eUjG4OiloeMwXTxK3/tXEsEDTFF40w0NlSMOOmIQSWTUfhjDzwx9dJX4mE8mtOOO2U//cxGQ4DOQDoRHLIjwC0auKumjKrvdMzYU8H2tLmJwarRS43fu58Ir0NRydolB9vuRSA7aGziK+TtwYpKOUlge/7BY26lIANlCsnGnPvyT52UZXxILUkmHGCt98lMnJ2I+zXYIkjj8jvP02/eQuCdYWIS55ou1JJKGTazgn5Nu6cPMn6mAL20vWd3t8eUwU5F8KNavCcal903tDn2gen6QRf28ZVEWmEVc7vl4p9+iDkAZT855tVHHt4gz45C8XrwMBFBNZ1iiJtnzCiRsWAfoALJfJH9+gyKywZa67lQZWlmUnEDBqj/WT61+NJHPIFO+74xgdTEyfbeLWJjz6ecFa+TQcAiTGIqdTZmzu640kthQYBfs=
|
@ -1,36 +0,0 @@
|
||||
# This is a template
|
||||
# Saved as .py for easier editing
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# pylint: disable=import-error, no-name-in-module, undefined-variable
|
||||
import subprocess
|
||||
from uds.tunnel import forward # type: ignore
|
||||
|
||||
from uds import tools # type: ignore
|
||||
|
||||
try:
|
||||
cmd = tools.findApp('nxclient', ['/usr/NX/bin/'])
|
||||
if cmd is None:
|
||||
raise Exception()
|
||||
except Exception:
|
||||
raise Exception('''<p>You need to have installed NX Client version 3.5 in order to connect to this UDS service.</p>
|
||||
<p>Please, install appropriate package for your system.</p>
|
||||
''')
|
||||
|
||||
# Open tunnel
|
||||
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
|
||||
|
||||
# Check that tunnel works..
|
||||
if fs.check() is False:
|
||||
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
|
||||
|
||||
theFile = sp['as_file_for_format'].format( # type: ignore
|
||||
address='127.0.0.1',
|
||||
port=fs.server_address[1]
|
||||
)
|
||||
|
||||
filename = tools.saveTempFile(theFile)
|
||||
|
||||
cmd = cmd.replace('%1', filename)
|
||||
tools.addTaskToWait(subprocess.Popen([cmd, '--session', filename]))
|
||||
tools.addFileToUnlink(filename)
|
@ -1 +0,0 @@
|
||||
EFxcQ0pD5IdbGBhlBdULIIPckwR0BlC2XQpWmxUngQlK/qe2s9CleQBjTcGyp6SSzy7uc6osweHA1b9N4o4opodLI0mD5X3H5+cP/92HsKcBT1QPRh1S8i+hGyGa5WO/fxdpeIM0rco9OcFDx9iloRbxCN0op3GJe3X0DwtS89r0MwaMs3rz7A913geshVGmJ/5oZM+EXf/kD6oGTRVkRagqeNkpB+Aup0LxhVET5EO6tY5TBDd2TvgCSBOqOkcA5vtavcxxb5As20lgl5/UsYDpCXuz7gGyq4EKn0nDSYHYiFeqsyJgaXWqdWW9rVQpGl8qjbm/Ndc2bC3s/3Q8bDgEjev0EQjKQ6oMUtdOJNJ89fP9TEd8Y0UKocBZRsGMxvQdcFN4Q5jMzplPcP9F3VuaCvA9W+uLZ/b1EvFPFdLrDBLhUsgUiWNoEQCqpG7FG+qz3dy0oVkmAZs9ewI6/oOxE+KaTs7uJv1mIbWpJEWhvLwzMg6j6jPSsV4bu9kbtjr3dBFwTNI5EsaW9vP9NeEg2hqD6vBOrlw4PB9SWIPBdFX0tPsT4tAgJxaUx13OepO7DWTItzA6EjT/be3BIUSJPoJuCJA7nxGj/ZOFqN4grmAlMKa8JXq8L/6++Jtqf+iSNgZjD+5cxC5j9M4yRlsBTFQaQhf+OnawjxAd1a4=
|
@ -1,21 +0,0 @@
|
||||
# This is a template
|
||||
# Saved as .py for easier editing
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# pylint: disable=import-error, no-name-in-module, too-many-format-args, undefined-variable, invalid-sequence-index
|
||||
import subprocess
|
||||
import os
|
||||
|
||||
from uds import tools # type: ignore
|
||||
|
||||
|
||||
cmd = '/Applications/OpenNX/OpenNX.app/Contents/MacOS/OpenNXapp'
|
||||
if os.path.isfile(cmd) is False:
|
||||
raise Exception('''<p>You need to have installed Open NX Client in order to connect to this UDS service.</p>
|
||||
<p>Please, install appropriate package for your system from <a href="http://www.opennx.net/">here</a>.</p>
|
||||
''')
|
||||
|
||||
|
||||
filename = tools.saveTempFile(sp['as_file']) # type: ignore
|
||||
tools.addTaskToWait(subprocess.Popen([cmd, '--session={{}}'.format(filename), '--autologin', '--killerrors'])) # type: ignore
|
||||
tools.addFileToUnlink(filename)
|
@ -1 +0,0 @@
|
||||
hgPD0KnclF5OpaW4tIs+6pWX5tLeactCv1MGI1bk942nHoS4c/Nm87qd5dkHek51UMm1s8o2eB7xdrkJ6CVi/eOf2jnEs63luF+etmdwccHQU9BcQZjev1aId4q0q7HiQCXjXaS2vorIevH9uvf1NWl6AyPABynYhC7zvWb9nz/GTNBXO7TAqfVarGJLRXwY2KHpBXqUKEPB0H46+h3S9AWD2pHxfZnVBKdjoGgrD5/pt905aI2lrl1yCE14LFENkpssH/dBxYnaEMMYiWTuAe3lAP8MQEFlWmHBT63G7xMhDR3wc2sqC2eh8RQieEj1EoqCPLJFwMoxA1SZfS+JLhppskdJi06o+pqiJ4bzO0Is47plGn+KBodBAT+5/dOgOK/lKv+7Q8j3MS59TQUFty4TkybS6Ujk40SjlOlCwofVb6awKMSUSny853K20yKClt0gGhUjykstex3/eaXmU7hWLBBbDsFmY5W7Xhvxi1vPmrJ3uJ2M+R9WIeCM4xygLQPcMkZbY2k1bonv3NhK+AlapmY36y3IBbziL1Xv4agjRAykls3y+qrxMjE4Lx4ZUAI0OdX7COqdz7Ix7baYpMHrLgROjtkp/EJqVIfhvRSvJqMWLsZxbqCjoswNSI4zlyWFR980y4ITHhBsbP95X0yJnoRsgcN+wARNolxVL7o=
|
@ -1,34 +0,0 @@
|
||||
# This is a template
|
||||
# Saved as .py for easier editing
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# pylint: disable=import-error, no-name-in-module, too-many-format-args, undefined-variable, invalid-sequence-index
|
||||
import subprocess
|
||||
from uds.tunnel import forward # type: ignore
|
||||
import os
|
||||
|
||||
from uds import tools # type: ignore
|
||||
|
||||
|
||||
cmd = '/Applications/OpenNX/OpenNX.app/Contents/MacOS/OpenNXapp'
|
||||
if os.path.isfile(cmd) is False:
|
||||
raise Exception('''<p>You need to have installed Open NX Client in order to connect to this UDS service.</p>
|
||||
<p>Please, install appropriate package for your system from <a href="http://www.opennx.net/">here</a>.</p>
|
||||
''')
|
||||
|
||||
# Open tunnel
|
||||
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
|
||||
|
||||
# Check that tunnel works..
|
||||
if fs.check() is False:
|
||||
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
|
||||
|
||||
theFile = sp['as_file_for_format'].format( # type: ignore
|
||||
address='127.0.0.1',
|
||||
port=fs.server_address[1]
|
||||
)
|
||||
|
||||
filename = tools.saveTempFile(theFile)
|
||||
|
||||
tools.addTaskToWait(subprocess.Popen([cmd, '--session={}'.format(filename), '--autologin', '--killerrors']))
|
||||
tools.addFileToUnlink(filename)
|
@ -1 +0,0 @@
|
||||
lsChjBOL2LNJeEjnFSXjK3y9F8uPfz/j6ZlHg511XyQxakyrxPKhEnrAJ9DT7X7Py99D1SQqrMmn+A9B/lH658LmXyCLaQMKFVNLZxc1WH/0Ytl4int6ZJA3uTrt/bHYMNh91OxMsS6WPWjN8g2aCkGhgZIKHehP4oKlQmxOnI4EXSoWtHwl/aN2JaWV6pltiVDKMiyVxMHCnRm0L1KSVaOsC5OxW76DvsUWcYELXiue+bMlBx96lQN0/g4xd9UJKJFqRmA+tPnUhKYdm/gt1804xsdGQ2v2IdPiJjhBvN4riFUffkls0T67HFOEedNdoV7ox/lz8RmamlAGbs36Qz84U/hYdeEwpOZfzHvVKuq8M1EZQciboqdlaRDPDbF+o7mZHQsOCSzRTp6qBqb46pzcELuXBH4/jod/tAX9iyvz7BBxrQsTmhivHIwu3VOdjClN3bw2GrNSyhKxSYsb7wq/YiABfHWHJkHzMZnwxGOpYuYSHNNew2liH3zE3gZPX6rGnyFn7rv80rIGvbLmQV9hJmAluyzU6hQivHYqZnpnfQN1cKT5SKbDiZVCnAC9c8uPGD7VsHJZpaGR3Hi4bB/J2qyVG+zbfVVsLyRh/wDfGfucCBxt9ecY/xcZ6aebzabrEnyluhEmrehu6Ovp1lsWJQPb3mUzSHC0muN4M3s=
|
@ -1,26 +0,0 @@
|
||||
# This is a template
|
||||
# Saved as .py for easier editing
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# pylint: disable=import-error, no-name-in-module
|
||||
try:
|
||||
import winreg as wreg
|
||||
except ImportError: # Python 2.7 fallback
|
||||
import _winreg as wreg # type: ignore
|
||||
import subprocess
|
||||
|
||||
from uds import tools # type: ignore
|
||||
|
||||
try:
|
||||
k = wreg.OpenKey(wreg.HKEY_CURRENT_USER, 'Software\\Classes\\NXClient.session\\shell\\open\\command') # @UndefinedVariable
|
||||
cmd = wreg.QueryValue(k, '') # type: ignore
|
||||
wreg.CloseKey(k)
|
||||
except Exception:
|
||||
raise Exception('''<p>You need to have installed NX Client version 3.5 in order to connect to this UDS service.</p>
|
||||
<p>Please, install appropriate package for your system.</p>
|
||||
''')
|
||||
|
||||
filename = tools.saveTempFile(sp['as_file']) # type: ignore
|
||||
cmd = cmd.replace('%1', filename)
|
||||
tools.addTaskToWait(subprocess.Popen(cmd))
|
||||
tools.addFileToUnlink(filename)
|
@ -1 +0,0 @@
|
||||
isXacHwak7jQEx9QFKLUaVUTG75t5ogtWFiV7m7eMDttzBTkkS1/0hVLX1avLdaMOBCY60JTfTrPcHcd8XESfSzR3w92i1BzfccHmpV3g67lbeESZqpjsJTWC3F9kCpZHsj6DHXQICQjPPeW++tchJj8bAoETc6MyH5IHSJ/KOmbgLOBM+2x9crnX1ZWHrwF2xQyMaLn5rgntklvSX2KmOS6z0WC0C5DLFpVzZvSsDwMyfhhxd4fGNWCxUW4v5f5S1GUCM1AfzXWZEPYAWbRFgOzG2MKB2dhHasxVt25VtjeKgrD+Q5A28ihQBUkh5vZRmOtAWjtneF6K6bOM59ZL0vzjGIL1/y/6oysjyeOAG4YvagekMRAZT0folf7d4prUb1tN+8jvabZszGCxjvb0kYjfiT6zN53lxDSExLuvjBEwHkWM3CPCTkPLJ7UWiRT6Fyd8c3vJw860WhnohPYg+4q2udjf/ZgdDiyVPEyOB5AKpDnHB3HfsQr7upw+WqWUH56ylF2myWyP0uSmOrLJnUyFX1FFVx2R+/Rc0AjPmM+VE9UwPUkSSpFaRdKPP2nJxDYrReZwk/kfFmRvIqLAUz+rwSIH2JJqEB6NT//tMdxRu4lAKrpX29nqDSWCiMvew3D21OQYafzGGJ9GTn2n+Mwki3cbKpxLXxLxlCh0S8=
|
@ -1,41 +0,0 @@
|
||||
# This is a template
|
||||
# Saved as .py for easier editing
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# pylint: disable=import-error, no-name-in-module, undefined-variable
|
||||
try:
|
||||
import winreg as wreg
|
||||
except ImportError: # Python 2.7 fallback
|
||||
import _winreg as wreg # type: ignore
|
||||
|
||||
import subprocess
|
||||
from uds.tunnel import forward # type: ignore
|
||||
|
||||
from uds import tools # type: ignore
|
||||
|
||||
try:
|
||||
k = wreg.OpenKey(wreg.HKEY_CURRENT_USER, 'Software\\Classes\\NXClient.session\\shell\\open\\command')
|
||||
cmd = wreg.QueryValue(k, '')
|
||||
wreg.CloseKey(k)
|
||||
except Exception:
|
||||
raise Exception('''<p>You need to have installed NX Client version 3.5 in order to connect to this UDS service.</p>
|
||||
<p>Please, install appropriate package for your system.</p>
|
||||
''')
|
||||
|
||||
# Open tunnel
|
||||
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
|
||||
|
||||
# Check that tunnel works..
|
||||
if fs.check() is False:
|
||||
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
|
||||
|
||||
theFile = sp['as_file_for_format'].format( # type: ignore
|
||||
address='127.0.0.1',
|
||||
port=fs.server_address[1]
|
||||
)
|
||||
|
||||
filename = tools.saveTempFile(theFile)
|
||||
|
||||
cmd = cmd.replace('%1', filename)
|
||||
tools.addTaskToWait(subprocess.Popen(cmd))
|
||||
tools.addFileToUnlink(filename)
|
@ -1 +0,0 @@
|
||||
o+152nwWH5xKg7nrK4ffYSeGjzitZS5LxvkC9Z0aa86J2D9gEIsUqDAQjh2ljuO+g4ik2s72T7Yb5HiZizhHfRfjwe22yjIj+NtK1Xoeh/VW3773bq5VCXAjfMbVU6GuGnNMndQOn4qrS/l12YLDhxXFKUkpwNU1TjRGo33ns1DFPNTf0dT7W/WpQkf/75Jlt6bMnGxFWDWYhc1wLySmwlVPj7GOKQTD9pS9MaB7eqpq/GO9gADNGWcTbz3GGs8iO8N5dxBHTnyHxO7P29aQL9bOvtrY0rxAopfy+TTcuE03qNDI6pCBjhYxCqL+GqiRrzmLJq9ZtvhNxvQ5+kvDDrw3ErFZbXoBOF4f7SeP6Tr9A6aOkLG579czsqNGSpHqkUPgvb38xXfSPv983pDvzhi3lo2GzNhAu4ZYM+/Z/Q32ssYBfst4joHAC9mcHmP37ZTKRiMfRz3hafkJlSmm2RQf5/OPYCz5ha8AAcs2CvqYMlOiJhP9Zx8AwtB9oxVlFPS+ZUJ9h/0waRVFBKQm1m70Z7odjJqT0ThTTJQEjuedfnNuxW1V5GtCi62NcwskulWOL2fXjmf9eh0u5PPn1tdqLIUmZXa9eqGU+LjZqA52w7V3sHHWoMYvfEC4SG9HXfZxd6YZdfPx12z6WYh4PnJLNUqd7bgfl4YswALJyaA=
|
Loading…
Reference in New Issue
Block a user