From 18d4147d594942491f1f34cf70a562bc9e69558f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20G=C3=B3mez=20Garc=C3=ADa?= Date: Tue, 15 Feb 2022 14:45:11 +0100 Subject: [PATCH] Changed OS Detection system --- server/src/uds/REST/methods/transports.py | 2 +- server/src/uds/core/auths/auth.py | 10 +-- server/src/uds/core/transports/transport.py | 4 +- server/src/uds/core/util/os_detector.py | 67 ++++++++++--------- server/src/uds/core/util/tools.py | 9 ++- server/src/uds/transports/RDP/rdp.py | 8 +-- server/src/uds/transports/RDP/rdp_file.py | 12 ++-- server/src/uds/transports/RDP/rdptunnel.py | 8 +-- server/src/uds/transports/SPICE/spice.py | 10 +-- .../src/uds/transports/SPICE/spice_tunnel.py | 8 +-- server/src/uds/transports/X2GO/x2go.py | 6 +- server/src/uds/transports/X2GO/x2go_base.py | 2 +- server/src/uds/transports/X2GO/x2go_tunnel.py | 6 +- server/src/uds/web/util/configjs.py | 2 +- server/src/uds/web/util/services.py | 16 ++--- server/src/uds/web/views/auth.py | 2 +- 16 files changed, 89 insertions(+), 83 deletions(-) diff --git a/server/src/uds/REST/methods/transports.py b/server/src/uds/REST/methods/transports.py index 0d0afe48..6fdd8c30 100644 --- a/server/src/uds/REST/methods/transports.py +++ b/server/src/uds/REST/methods/transports.py @@ -126,7 +126,7 @@ class Transports(ModelHandler): 'value': [], 'values': sorted( [ - {'id': x, 'text': x.replace('CrOS', 'Chrome OS')} + {'id': x.value[0], 'text': x.value[0].replace('CrOS', 'Chrome OS')} for x in OsDetector.knownOss ], key=lambda x: x['text'].lower(), diff --git a/server/src/uds/core/auths/auth.py b/server/src/uds/core/auths/auth.py index bf7db292..55546e8f 100644 --- a/server/src/uds/core/auths/auth.py +++ b/server/src/uds/core/auths/auth.py @@ -229,7 +229,7 @@ def __registerUser( events.addEvent( authenticator, events.ET_PLATFORM, - platform=request.os['OS'], + platform=request.os['OS'].value[0], browser=request.os['Browser'], version=request.os['Version'], ) @@ -383,7 +383,7 @@ def webLogin( user.name, password, get_language() or '', - request.os['OS'], + request.os['OS'].value[0], user.is_admin, user.staff_member, cookie, @@ -460,7 +460,7 @@ def authLogLogin( authenticator.name, userName, request.ip, - request.os['OS'], + request.os['OS'].value[0], logStr, request.META.get('HTTP_USER_AGENT', 'Undefined'), ] @@ -471,7 +471,7 @@ def authLogLogin( authenticator, level, 'user {} has {} from {} where os is {}'.format( - userName, logStr, request.ip, request.os['OS'] + userName, logStr, request.ip, request.os['OS'].value[0] ), log.WEB, ) @@ -481,7 +481,7 @@ def authLogLogin( log.doLog( user, level, - '{} from {} where OS is {}'.format(logStr, request.ip, request.os['OS']), + '{} from {} where OS is {}'.format(logStr, request.ip, request.os['OS'].value[0]), log.WEB, ) except Exception: diff --git a/server/src/uds/core/transports/transport.py b/server/src/uds/core/transports/transport.py index 4ece26b2..69fca1db 100644 --- a/server/src/uds/core/transports/transport.py +++ b/server/src/uds/core/transports/transport.py @@ -152,12 +152,12 @@ class Transport(Module): return False @classmethod - def supportsOs(cls, osName: str) -> bool: + def supportsOs(cls, osType: OsDetector.KnownOS) -> bool: """ Helper method to check if transport supports requested operating system. Class method """ - return cls.supportedOss.count(osName) > 0 + return cls.supportedOss.count(osType) > 0 @classmethod def providesConnetionInfo(cls) -> bool: diff --git a/server/src/uds/core/util/os_detector.py b/server/src/uds/core/util/os_detector.py index 24e4ac5d..c2039854 100644 --- a/server/src/uds/core/util/os_detector.py +++ b/server/src/uds/core/util/os_detector.py @@ -30,44 +30,47 @@ """ @author: Adolfo Gómez, dkmaster at dkmon dot com """ +import enum import re import logging import typing +from sympy import Li + from .tools import DictAsObj logger = logging.getLogger(__name__) -# Knowns OSs -Linux = 'Linux' -ChromeOS = 'CrOS' -WindowsPhone = 'Windows Phone' -Windows = 'Windows' -Macintosh = 'Mac' -Android = 'Android' -iPad = 'iPad' # -iPhone = 'iPhone' # In fact, these are IOS both, but we can diferentiate it... -WYSE = 'WYSE' -Unknown = 'Unknown' +class KnownOS(enum.Enum): + Linux = ('Linux', 'armv7l') + ChromeOS = ('CrOS',) + WindowsPhone = ('Windows Phone',) + Windows = ('Windows',) + Macintosh = ('Mac',) + Android = ('Android',) + iPad = ('iPad',) # + iPhone = ('iPhone',) # In fact, these are IOS both, but we can diferentiate it... + WYSE = ('WYSE',) + Unknown = ('Unknown',) knownOss = ( - WindowsPhone, - Android, - Linux, - Windows, - iPad, - iPhone, - Macintosh, - ChromeOS, - WYSE, + KnownOS.WindowsPhone, + KnownOS.Android, + KnownOS.Linux, + KnownOS.Windows, + KnownOS.iPad, + KnownOS.iPhone, + KnownOS.Macintosh, + KnownOS.ChromeOS, + KnownOS.WYSE, ) # Android is linux also, so it is cheched on first place -allOss = knownOss + (Unknown,) -desktopOss = (Linux, Windows, Macintosh) +allOss = knownOss + (KnownOS.Unknown,) +desktopOss = (KnownOS.Linux, KnownOS.Windows, KnownOS.Macintosh) mobilesODD = list(set(allOss) - set(desktopOss)) -DEFAULT_OS = 'Windows' +DEFAULT_OS = KnownOS.Windows # Known browsers Firefox = 'Firefox' @@ -115,18 +118,18 @@ def getOsFromUA( Basic OS Client detector (very basic indeed :-)) """ if ua is None: - ua = Unknown + ua = KnownOS.Unknown.value[0] - os = Unknown - - res = DictAsObj({'OS': os, 'Version': '0.0', 'Browser': 'unknown'}) + res = DictAsObj({'OS': KnownOS.Unknown, 'Version': '0.0', 'Browser': 'unknown'}) + found: bool = False for os in knownOss: - try: - ua.index(os) - res.OS = os # type: ignore + if found: break - except Exception: - pass + for osName in os.value: + if osName in ua: + res.OS = os # type: ignore + found = True + break match = None diff --git a/server/src/uds/core/util/tools.py b/server/src/uds/core/util/tools.py index 88934ce1..c2cabb3a 100644 --- a/server/src/uds/core/util/tools.py +++ b/server/src/uds/core/util/tools.py @@ -129,9 +129,12 @@ def packageRelativeFile(moduleName: str, fileName: str) -> str: Helper to get image path from relative to a module. This allows to keep images alongside report """ - pkgpath = os.path.dirname(sys.modules[moduleName].__file__) - return os.path.join(pkgpath, fileName) - + mod = sys.modules[moduleName] + if mod and mod.__file__: + pkgpath = os.path.dirname(mod.__file__) + return os.path.join(pkgpath, fileName) + # Not found, return fileName + return fileName def timestampAsStr(stamp, format_='SHORT_DATETIME_FORMAT'): """ diff --git a/server/src/uds/transports/RDP/rdp.py b/server/src/uds/transports/RDP/rdp.py index 33630df5..79dfa0c5 100644 --- a/server/src/uds/transports/RDP/rdp.py +++ b/server/src/uds/transports/RDP/rdp.py @@ -96,7 +96,7 @@ class RDPTransport(BaseRDPTransport): userService: 'models.UserService', transport: 'models.Transport', ip: str, - os: typing.Dict[str, str], + os: typing.Dict[str, typing.Any], user: 'models.User', password: str, request: 'HttpRequest', @@ -144,9 +144,9 @@ class RDPTransport(BaseRDPTransport): r.enforcedShares = self.enforceDrives.value osName = { - OsDetector.Windows: 'windows', - OsDetector.Linux: 'linux', - OsDetector.Macintosh: 'macosx', + OsDetector.KnownOS.Windows: 'windows', + OsDetector.KnownOS.Linux: 'linux', + OsDetector.KnownOS.Macintosh: 'macosx', }.get(os['OS']) if osName is None: diff --git a/server/src/uds/transports/RDP/rdp_file.py b/server/src/uds/transports/RDP/rdp_file.py index 088823cf..86f7b733 100644 --- a/server/src/uds/transports/RDP/rdp_file.py +++ b/server/src/uds/transports/RDP/rdp_file.py @@ -77,7 +77,7 @@ class RDPFile: width: typing.Union[str, int], height: typing.Union[str, int], bpp: str, - target: str = OsDetector.Windows, + target: OsDetector.KnownOS = OsDetector.KnownOS.Windows, ): self.width = str(width) self.height = str(height) @@ -86,7 +86,7 @@ class RDPFile: self.target = target def get(self): - if self.target in (OsDetector.Windows, OsDetector.Linux, OsDetector.Macintosh): + if self.target in (OsDetector.KnownOS.Windows, OsDetector.KnownOS.Linux, OsDetector.KnownOS.Macintosh): return self.getGeneric() # Unknown target return '' @@ -115,7 +115,7 @@ class RDPFile: params.append('/smartcard') if self.redirectAudio: - if self.alsa and self.target != OsDetector.Macintosh: + if self.alsa and self.target != OsDetector.KnownOS.Macintosh: params.append('/sound:sys:alsa,format:1,quality:high') params.append('/microphone:sys:alsa') else: @@ -126,7 +126,7 @@ class RDPFile: params.append('/video') if self.redirectDrives != 'false': - if self.target in (OsDetector.Linux, OsDetector.Macintosh): + if self.target in (OsDetector.KnownOS.Linux, OsDetector.KnownOS.Macintosh): params.append('/drive:home,$HOME') else: params.append('/drive:Users,/Users') @@ -152,7 +152,7 @@ class RDPFile: params.append('/multimon') if self.fullScreen: - if self.target != OsDetector.Macintosh: + if self.target != OsDetector.KnownOS.Macintosh: params.append('/f') else: # On mac, will fix this later... params.append('/w:#WIDTH#') @@ -221,7 +221,7 @@ class RDPFile: if self.username: res += 'username:s:' + self.username + '\n' res += 'domain:s:' + self.domain + '\n' - if self.target == OsDetector.Windows: + if self.target == OsDetector.KnownOS.Windows: res += 'password 51:b:' + password + '\n' res += 'alternate shell:s:' + '\n' diff --git a/server/src/uds/transports/RDP/rdptunnel.py b/server/src/uds/transports/RDP/rdptunnel.py index 16d4bff3..192149ce 100644 --- a/server/src/uds/transports/RDP/rdptunnel.py +++ b/server/src/uds/transports/RDP/rdptunnel.py @@ -140,7 +140,7 @@ class TRDPTransport(BaseRDPTransport): userService: 'models.UserService', transport: 'models.Transport', ip: str, - os: typing.Dict[str, str], + os: typing.Dict[str, typing.Any], user: 'models.User', password: str, request: 'HttpRequest', @@ -197,9 +197,9 @@ class TRDPTransport(BaseRDPTransport): r.enforcedShares = self.enforceDrives.value osName = { - OsDetector.Windows: 'windows', - OsDetector.Linux: 'linux', - OsDetector.Macintosh: 'macosx', + OsDetector.KnownOS.Windows: 'windows', + OsDetector.KnownOS.Linux: 'linux', + OsDetector.KnownOS.Macintosh: 'macosx', }.get(os['OS']) if osName is None: diff --git a/server/src/uds/transports/SPICE/spice.py b/server/src/uds/transports/SPICE/spice.py index 0b15dc73..dcf2f86f 100644 --- a/server/src/uds/transports/SPICE/spice.py +++ b/server/src/uds/transports/SPICE/spice.py @@ -65,12 +65,12 @@ class SPICETransport(BaseSpiceTransport): autoNewUsbShare = BaseSpiceTransport.autoNewUsbShare smartCardRedirect = BaseSpiceTransport.smartCardRedirect - def getUDSTransportScript( # pylint: disable=too-many-locals + def getUDSTransportScript( self, userService: 'models.UserService', transport: 'models.Transport', ip: str, - os: typing.Dict[str, str], + os: typing.Dict[str, typing.Any], user: 'models.User', password: str, request: 'HttpRequest', @@ -100,9 +100,9 @@ class SPICETransport(BaseSpiceTransport): r.smartcard = self.smartCardRedirect.isTrue() osName = { - OsDetector.Windows: 'windows', - OsDetector.Linux: 'linux', - OsDetector.Macintosh: 'macosx', + OsDetector.KnownOS.Windows: 'windows', + OsDetector.KnownOS.Linux: 'linux', + OsDetector.KnownOS.Macintosh: 'macosx', }.get(os['OS']) if osName is None: diff --git a/server/src/uds/transports/SPICE/spice_tunnel.py b/server/src/uds/transports/SPICE/spice_tunnel.py index 6b8e4891..fe2e895a 100644 --- a/server/src/uds/transports/SPICE/spice_tunnel.py +++ b/server/src/uds/transports/SPICE/spice_tunnel.py @@ -112,7 +112,7 @@ class TSPICETransport(BaseSpiceTransport): userService: 'models.UserService', transport: 'models.Transport', ip: str, - os: typing.Dict[str, str], + os: typing.Dict[str, typing.Any], user: 'models.User', password: str, request: 'HttpRequest', @@ -155,9 +155,9 @@ class TSPICETransport(BaseSpiceTransport): r.smartcard = self.smartCardRedirect.isTrue() osName = { - OsDetector.Windows: 'windows', - OsDetector.Linux: 'linux', - OsDetector.Macintosh: 'macosx', + OsDetector.KnownOS.Windows: 'windows', + OsDetector.KnownOS.Linux: 'linux', + OsDetector.KnownOS.Macintosh: 'macosx', }.get(os['OS']) if osName is None: diff --git a/server/src/uds/transports/X2GO/x2go.py b/server/src/uds/transports/X2GO/x2go.py index c9aedf1b..b73867af 100644 --- a/server/src/uds/transports/X2GO/x2go.py +++ b/server/src/uds/transports/X2GO/x2go.py @@ -74,7 +74,7 @@ class X2GOTransport(BaseX2GOTransport): userService: 'models.UserService', transport: 'models.Transport', ip: str, - os: typing.Dict[str, str], + os: typing.Dict[str, typing.Any], user: 'models.User', password: str, request: 'HttpRequest', @@ -106,8 +106,8 @@ class X2GOTransport(BaseX2GOTransport): ) osName = { - OsDetector.Windows: 'windows', - OsDetector.Linux: 'linux', + OsDetector.KnownOS.Windows: 'windows', + OsDetector.KnownOS.Linux: 'linux', # OsDetector.Macintosh: 'macosx' }.get(os['OS']) diff --git a/server/src/uds/transports/X2GO/x2go_base.py b/server/src/uds/transports/X2GO/x2go_base.py index 0f474d27..70d73c58 100644 --- a/server/src/uds/transports/X2GO/x2go_base.py +++ b/server/src/uds/transports/X2GO/x2go_base.py @@ -63,7 +63,7 @@ class BaseX2GOTransport(transports.Transport): iconFile = 'x2go.png' protocol = transports.protocols.X2GO - supportedOss = (OsDetector.Linux, OsDetector.Windows) + supportedOss = (OsDetector.KnownOS.Linux, OsDetector.KnownOS.Windows) fixedName = gui.TextField( order=2, diff --git a/server/src/uds/transports/X2GO/x2go_tunnel.py b/server/src/uds/transports/X2GO/x2go_tunnel.py index 20080666..6f1d9262 100644 --- a/server/src/uds/transports/X2GO/x2go_tunnel.py +++ b/server/src/uds/transports/X2GO/x2go_tunnel.py @@ -121,7 +121,7 @@ class TX2GOTransport(BaseX2GOTransport): userService: 'models.UserService', transport: 'models.Transport', ip: str, - os: typing.Dict[str, str], + os: typing.Dict[str, typing.Any], user: 'models.User', password: str, request: 'HttpRequest', @@ -180,8 +180,8 @@ class TX2GOTransport(BaseX2GOTransport): m = tools.DictAsObj(data) osName = { - OsDetector.Windows: 'windows', - OsDetector.Linux: 'linux', + OsDetector.KnownOS.Windows: 'windows', + OsDetector.KnownOS.Linux: 'linux', # OsDetector.Macintosh: 'macosx' }.get(os['OS']) diff --git a/server/src/uds/web/util/configjs.py b/server/src/uds/web/util/configjs.py index 0e98b2dc..3bb9b76a 100644 --- a/server/src/uds/web/util/configjs.py +++ b/server/src/uds/web/util/configjs.py @@ -151,7 +151,7 @@ def udsJs(request: 'ExtendedHttpRequest') -> str: getAuthInfo(auth) for auth in authenticators if auth.getType() ], 'tag': tag, - 'os': request.os['OS'], + 'os': request.os['OS'].value[0], 'csrf_field': CSRF_FIELD, 'csrf': csrf_token, 'image_size': Image.MAX_IMAGE_SIZE, diff --git a/server/src/uds/web/util/services.py b/server/src/uds/web/util/services.py index 935b441f..a1e94081 100644 --- a/server/src/uds/web/util/services.py +++ b/server/src/uds/web/util/services.py @@ -97,8 +97,8 @@ def getServicesData( nets = '' validTrans = '' - osName = request.os['OS'] - logger.debug('OS: %s', osName) + osType = request.os['OS'] + logger.debug('OS: %s', osType) if request.user.isStaff(): nets = ','.join([n.name for n in Network.networksFor(request.ip)]) @@ -120,8 +120,8 @@ def getServicesData( if ( typeTrans and t.validForIp(request.ip) - and typeTrans.supportsOs(osName) - and t.validForOs(osName) + and typeTrans.supportsOs(osType) + and t.validForOs(osType) ): yield t except Exception as e: @@ -200,8 +200,8 @@ def getServicesData( if ( typeTrans and t.validForIp(request.ip) - and typeTrans.supportsOs(osName) - and t.validForOs(osName) + and typeTrans.supportsOs(osType) + and t.validForOs(osType) ): metaTransports = [ { @@ -272,8 +272,8 @@ def getServicesData( if ( typeTrans and t.validForIp(request.ip) - and typeTrans.supportsOs(osName) - and t.validForOs(osName) + and typeTrans.supportsOs(osType) + and t.validForOs(osType) ): if typeTrans.ownLink: link = reverse('TransportOwnLink', args=('F' + sPool.uuid, t.uuid)) diff --git a/server/src/uds/web/views/auth.py b/server/src/uds/web/views/auth.py index 739ad683..f76e151e 100644 --- a/server/src/uds/web/views/auth.py +++ b/server/src/uds/web/views/auth.py @@ -283,7 +283,7 @@ def ticketAuth( except Authenticator.DoesNotExist: logger.error('Ticket has an non existing authenticator') return errors.errorView(request, errors.ACCESS_DENIED) - except ServicePool.DoesNotExist: + except ServicePool.DoesNotExist: # type: ignore # DoesNotExist is different for each model logger.error('Ticket has an invalid Service Pool') return errors.errorView(request, errors.SERVICE_NOT_FOUND) except Exception as e: