This commit is contained in:
Adolfo Gómez 2021-01-20 12:42:38 +01:00
commit f0b6726e19
151 changed files with 997 additions and 8800 deletions

View File

@ -57,6 +57,7 @@ class ForwardServer(socketserver.ThreadingTCPServer):
remote: typing.Tuple[str, int] remote: typing.Tuple[str, int]
ticket: str ticket: str
stop_flag: threading.Event stop_flag: threading.Event
can_stop: bool
timeout: int timeout: int
timer: typing.Optional[threading.Timer] timer: typing.Optional[threading.Timer]
check_certificate: bool check_certificate: bool
@ -79,20 +80,22 @@ class ForwardServer(socketserver.ThreadingTCPServer):
) )
self.remote = remote self.remote = remote
self.ticket = ticket self.ticket = ticket
self.timeout = int(time.time()) + timeout if timeout else 0 # Negative values for timeout, means "accept always connections"
# "but if no connection is stablished on timeout (positive)"
# "stop the listener"
self.timeout = int(time.time()) + timeout if timeout > 0 else 0
self.check_certificate = check_certificate self.check_certificate = check_certificate
self.stop_flag = threading.Event() # False initial self.stop_flag = threading.Event() # False initial
self.current_connections = 0 self.current_connections = 0
self.status = TUNNEL_LISTENING self.status = TUNNEL_LISTENING
self.can_stop = False
if timeout: timeout = abs(timeout) or 60
self.timer = threading.Timer( self.timer = threading.Timer(
timeout, ForwardServer.__checkStarted, args=(self,) abs(timeout), ForwardServer.__checkStarted, args=(self,)
) )
self.timer.start() self.timer.start()
else:
self.timer = None
def stop(self) -> None: def stop(self) -> None:
if not self.stop_flag.is_set(): if not self.stop_flag.is_set():
@ -120,6 +123,9 @@ class ForwardServer(socketserver.ThreadingTCPServer):
return context.wrap_socket(rsocket, server_hostname=self.remote[0]) return context.wrap_socket(rsocket, server_hostname=self.remote[0])
def check(self) -> bool: def check(self) -> bool:
if self.status == TUNNEL_ERROR:
return False
try: try:
with self.connect() as ssl_socket: with self.connect() as ssl_socket:
ssl_socket.sendall(HANDSHAKE_V1 + b'TEST') ssl_socket.sendall(HANDSHAKE_V1 + b'TEST')
@ -135,11 +141,14 @@ class ForwardServer(socketserver.ThreadingTCPServer):
@property @property
def stoppable(self) -> bool: def stoppable(self) -> bool:
return self.timeout != 0 and int(time.time()) > self.timeout logger.debug('Is stoppable: %s', self.can_stop)
return self.can_stop or (self.timeout != 0 and int(time.time()) > self.timeout)
@staticmethod @staticmethod
def __checkStarted(fs: 'ForwardServer') -> None: def __checkStarted(fs: 'ForwardServer') -> None:
logger.debug('New connection limit reached')
fs.timer = None fs.timer = None
fs.can_stop = True
if fs.current_connections <= 0: if fs.current_connections <= 0:
fs.stop() fs.stop()
@ -150,15 +159,17 @@ class Handler(socketserver.BaseRequestHandler):
# server: ForwardServer # server: ForwardServer
def handle(self) -> None: def handle(self) -> None:
self.server.current_connections += 1
self.server.status = TUNNEL_OPENING self.server.status = TUNNEL_OPENING
# If server processing is over time # If server processing is over time
if self.server.stoppable: if self.server.stoppable:
logger.info('Rejected timedout connection try') self.server.status = TUNNEL_ERROR
logger.info('Rejected timedout connection')
self.request.close() # End connection without processing it self.request.close() # End connection without processing it
return return
self.server.current_connections += 1
# Open remote connection # Open remote connection
try: try:
logger.debug('Ticket %s', self.server.ticket) logger.debug('Ticket %s', self.server.ticket)
@ -169,7 +180,9 @@ class Handler(socketserver.BaseRequestHandler):
data = ssl_socket.recv(2) data = ssl_socket.recv(2)
if data != b'OK': if data != b'OK':
data += ssl_socket.recv(128) data += ssl_socket.recv(128)
raise Exception(f'Error received: {data.decode(errors="ignore")}') # Notify error raise Exception(
f'Error received: {data.decode(errors="ignore")}'
) # Notify error
# All is fine, now we can tunnel data # All is fine, now we can tunnel data
self.process(remote=ssl_socket) self.process(remote=ssl_socket)

View File

@ -1,7 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (c) 2014-2019 Virtual Cable S.L. # Copyright (c) 2014-2021 Virtual Cable S.L.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without modification, # Redistribution and use in source and binary forms, with or without modification,
@ -423,6 +422,13 @@ class Login(LoginLogout):
""" """
name = 'login' name = 'login'
@staticmethod
def process_login(userService: UserService, username: str) -> typing.Optional[osmanagers.OSManager]:
osManager: typing.Optional[osmanagers.OSManager] = userService.getOsManagerInstance()
if not userService.in_use: # If already logged in, do not add a second login (windows does this i.e.)
osmanagers.OSManager.loggedIn(userService, username)
return osManager
def action(self) -> typing.MutableMapping[str, typing.Any]: def action(self) -> typing.MutableMapping[str, typing.Any]:
isManaged = self._params.get('type') != UNMANAGED isManaged = self._params.get('type') != UNMANAGED
ip = hostname = '' ip = hostname = ''
@ -432,9 +438,7 @@ class Login(LoginLogout):
try: try:
userService: UserService = self.getUserService() userService: UserService = self.getUserService()
osManager: typing.Optional[osmanagers.OSManager] = userService.getOsManagerInstance() osManager = Login.process_login(userService, self._params.get('username') or '')
if not userService.in_use: # If already logged in, do not add a second login (windows does this i.e.)
osmanagers.OSManager.loggedIn(userService, self._params.get('username') or '')
maxIdle = osManager.maxIdle() if osManager else None maxIdle = osManager.maxIdle() if osManager else None
@ -462,21 +466,29 @@ class Logout(LoginLogout):
""" """
name = 'logout' name = 'logout'
def action(self) -> typing.MutableMapping[str, typing.Any]: @staticmethod
isManaged = self._params.get('type') != UNMANAGED def process_logout(userService: UserService, username: str) -> None:
"""
logger.debug('Args: %s, Params: %s', self._args, self._params) This method is static so can be invoked from elsewhere
try: """
userService: UserService = self.getUserService()
osManager: typing.Optional[osmanagers.OSManager] = userService.getOsManagerInstance() osManager: typing.Optional[osmanagers.OSManager] = userService.getOsManagerInstance()
if userService.in_use: # If already logged out, do not add a second logout (windows does this i.e.) if userService.in_use: # If already logged out, do not add a second logout (windows does this i.e.)
osmanagers.OSManager.loggedOut(userService, self._params.get('username') or '') osmanagers.OSManager.loggedOut(userService, username)
if osManager: if osManager:
if osManager.isRemovableOnLogout(userService): if osManager.isRemovableOnLogout(userService):
logger.debug('Removable on logout: %s', osManager) logger.debug('Removable on logout: %s', osManager)
userService.remove() userService.remove()
else: else:
userService.remove() userService.remove()
def action(self) -> typing.MutableMapping[str, typing.Any]:
isManaged = self._params.get('type') != UNMANAGED
logger.debug('Args: %s, Params: %s', self._args, self._params)
try:
userService: UserService = self.getUserService()
Logout.process_logout(userService, self._params.get('username') or '')
except Exception: # If unamanaged host, lest do a bit more work looking for a service with the provided parameters... except Exception: # If unamanaged host, lest do a bit more work looking for a service with the provided parameters...
if isManaged: if isManaged:
raise raise

View File

@ -177,7 +177,7 @@ class OSManager(Module):
Helper method that informs if the os manager transforms the username and/or the password. Helper method that informs if the os manager transforms the username and/or the password.
This is used from ServicePool This is used from ServicePool
""" """
return cls.processUserPassword != OSManager.processUserPassword return hash(cls.processUserPassword) != hash(OSManager.processUserPassword)
def processUserPassword(self, userService: 'UserService', username: str, password: str) -> typing.Tuple[str, str]: def processUserPassword(self, userService: 'UserService', username: str, password: str) -> typing.Tuple[str, str]:
""" """
@ -299,5 +299,5 @@ class OSManager(Module):
""" """
return False return False
def __str__(self): def __str__(self) -> str:
return "Base OS Manager" return "Base OS Manager"

View File

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 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
'''

View File

@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 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
'''
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^uds/ognotify/(?P<msg>[a-z]+)/(?P<token>[a-zA-Z0-9-_]+)/(?P<uuid>[a-zA-Z0-9-_]+)$', views.opengnsys, name='dispatcher.opengnsys'),
]

View File

@ -0,0 +1,107 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 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
'''
import typing
import logging
from django.http import HttpResponse, HttpRequest
from uds.REST.methods import actor_v3
from uds.core.auths import auth
from uds.models import UserService
from uds.core.util.model import processUuid
from uds.core.util import states
logger = logging.getLogger(__name__)
OK = 'OK'
CONTENT_TYPE = 'text/plain'
@auth.trustedSourceRequired
def opengnsys(request: HttpRequest, msg: str, token: str, uuid: str) -> HttpResponse:
logger.debug('Received opengnsys message %s, token %s, uuid %s', msg, token, uuid)
def getUserService() -> typing.Optional[UserService]:
try:
userService = UserService.objects.get(uuid=processUuid(uuid), state=states.userService.USABLE)
if userService.getProperty('token') == token:
return userService
logger.warning(
'OpenGnsys: invalid token %s for userService %s. (Ignored)',
token,
uuid,
)
# Sleep a while in case of error?
except Exception as e:
# Any exception will stop process
logger.warning('OpenGnsys: invalid userService %s:%s. (Ignored)', token, uuid)
return None
def release() -> None:
userService = getUserService()
if userService:
logger.info('Released from OpenGnsys %s', userService.friendly_name)
userService.setProperty('from_release', '1')
userService.release()
def login() -> None:
userService = getUserService()
if userService:
# Ignore login to cached machines...
if userService.cache_level != 0:
logger.info('Ignored OpenGnsys login to %s to cached machine', userService.friendly_name)
return
logger.debug('Processing login from OpenGnsys %s', userService.friendly_name)
actor_v3.Login.process_login(userService, 'OpenGnsys')
def logout() -> None:
userService = getUserService()
if userService:
# Ignore logout to cached machines...
if userService.cache_level != 0:
logger.info('Ignored OpenGnsys logout to %s to cached machine', userService.friendly_name)
return
logger.debug('Processing logout from OpenGnsys %s', userService.friendly_name)
actor_v3.Logout.process_logout(userService, 'OpenGnsys')
fnc: typing.Optional[typing.Callable[[], None]] = {
'login': login,
'logout': logout,
'release': release,
}.get(msg)
if fnc:
fnc()
# Silently fail errors, do not notify anything (not needed anyway)
return HttpResponse(OK, content_type=CONTENT_TYPE)

View File

@ -197,12 +197,12 @@ class LinuxOsManager(osmanagers.OSManager):
elif message == "log": elif message == "log":
self.doLog(userService, data, log.ACTOR) self.doLog(userService, data, log.ACTOR)
elif message == "login": elif message == "login":
osmanagers.OSManager.loggedIn(userService, data) osmanagers.OSManager.loggedIn(userService, typing.cast(str, data))
ip, hostname = userService.getConnectionSource() ip, hostname = userService.getConnectionSource()
deadLine = userService.deployed_service.getDeadline() deadLine = userService.deployed_service.getDeadline()
ret = "{}\t{}\t{}".format(ip, hostname, 0 if deadLine is None else deadLine) ret = "{}\t{}\t{}".format(ip, hostname, 0 if deadLine is None else deadLine)
elif message == "logout": elif message == "logout":
osmanagers.OSManager.loggedOut(userService, data) osmanagers.OSManager.loggedOut(userService, typing.cast(str, data))
doRemove = self.isRemovableOnLogout(userService) doRemove = self.isRemovableOnLogout(userService)
elif message == "ip": elif message == "ip":
# This ocurss on main loop inside machine, so userService is usable # This ocurss on main loop inside machine, so userService is usable

View File

@ -1,7 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (c) 2017-2019 Virtual Cable S.L. # Copyright (c) 2017-2021 Virtual Cable S.L.U.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without modification, # Redistribution and use in source and binary forms, with or without modification,

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (c) 2012 Virtual Cable S.L. # Copyright (c) 2015-2021 Virtual Cable S.L.U.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without modification, # Redistribution and use in source and binary forms, with or without modification,
@ -34,6 +34,7 @@ import logging
import typing import typing
from uds.core.services import UserDeployment from uds.core.services import UserDeployment
from uds.core.managers import cryptoManager
from uds.core.util.state import State from uds.core.util.state import State
from uds.core.util import log from uds.core.util import log
from uds.models.util import getSqlDatetimeAsUnix from uds.models.util import getSqlDatetimeAsUnix
@ -47,7 +48,7 @@ if typing.TYPE_CHECKING:
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
opCreate, opError, opFinish, opRemove, opRetry = range(5) opCreate, opError, opFinish, opRemove, opRetry, opStart = range(6)
class OGDeployment(UserDeployment): class OGDeployment(UserDeployment):
@ -71,7 +72,9 @@ class OGDeployment(UserDeployment):
_stamp: int = 0 _stamp: int = 0
_reason: str = '' _reason: str = ''
_queue: typing.List[int] # Do not initialize mutable, just declare and it is initialized on "initialize" _queue: typing.List[
int
] # Do not initialize mutable, just declare and it is initialized on "initialize"
_uuid: str _uuid: str
def initialize(self) -> None: def initialize(self) -> None:
@ -93,7 +96,8 @@ class OGDeployment(UserDeployment):
""" """
Does nothing right here, we will use environment storage in this sample Does nothing right here, we will use environment storage in this sample
""" """
return b'\1'.join([ return b'\1'.join(
[
b'v1', b'v1',
self._name.encode('utf8'), self._name.encode('utf8'),
self._ip.encode('utf8'), self._ip.encode('utf8'),
@ -101,8 +105,9 @@ class OGDeployment(UserDeployment):
self._machineId.encode('utf8'), self._machineId.encode('utf8'),
self._reason.encode('utf8'), self._reason.encode('utf8'),
str(self._stamp).encode('utf8'), str(self._stamp).encode('utf8'),
pickle.dumps(self._queue, protocol=0) pickle.dumps(self._queue, protocol=0),
]) ]
)
def unmarshal(self, data: bytes) -> None: def unmarshal(self, data: bytes) -> None:
""" """
@ -135,11 +140,34 @@ class OGDeployment(UserDeployment):
OpenGnsys will try it best by sending an WOL OpenGnsys will try it best by sending an WOL
""" """
dbs = self.dbservice() dbs = self.dbservice()
deadline = dbs.deployed_service.getDeadline() if dbs else 0 if not dbs:
self.service().notifyDeadline(self._machineId, deadline)
return State.FINISHED return State.FINISHED
try:
# First, check Machine is alive..
status = self.__checkMachineReady()
if status == State.FINISHED:
self.service().notifyDeadline(
self._machineId, dbs.deployed_service.getDeadline()
)
return State.FINISHED
if status == State.ERROR:
return State.ERROR
# Machine powered off, check what to do...
if self.service().isRemovableIfUnavailable():
return self.__error(
'Machine is unavailable and service has "Remove if unavailable" flag active.'
)
# Try to start it, and let's see
self._queue = [opStart, opFinish]
return self.__executeQueue()
except Exception as e:
return self.__error('Error setting ready state: {}'.format(e))
def deployForUser(self, user: 'models.User') -> str: def deployForUser(self, user: 'models.User') -> str:
""" """
Deploys an service instance for an user. Deploys an service instance for an user.
@ -159,7 +187,11 @@ class OGDeployment(UserDeployment):
self._queue = [opCreate, opFinish] self._queue = [opCreate, opFinish]
def __checkMachineReady(self) -> str: def __checkMachineReady(self) -> str:
logger.debug('Checking that state of machine %s (%s) is ready', self._machineId, self._name) logger.debug(
'Checking that state of machine %s (%s) is ready',
self._machineId,
self._name,
)
try: try:
status = self.service().status(self._machineId) status = self.service().status(self._machineId)
@ -202,7 +234,11 @@ class OGDeployment(UserDeployment):
logger.debug('Setting error state, reason: %s', reason) logger.debug('Setting error state, reason: %s', reason)
self.doLog(log.ERROR, reason) self.doLog(log.ERROR, reason)
# TODO: Unreserve machine?? Maybe it just better to keep it assigned so UDS don't get it again in a while... if self._machineId:
try:
self.service().unreserve(self._machineId)
except Exception:
pass
self._queue = [opError] self._queue = [opError]
self._reason = str(reason) self._reason = str(reason)
@ -222,13 +258,16 @@ class OGDeployment(UserDeployment):
opCreate: self.__create, opCreate: self.__create,
opRetry: self.__retry, opRetry: self.__retry,
opRemove: self.__remove, opRemove: self.__remove,
opStart: self.__start,
} }
try: try:
execFnc: typing.Optional[typing.Callable[[], str]] = fncs.get(op, None) execFnc: typing.Optional[typing.Callable[[], str]] = fncs.get(op)
if execFnc is None: if execFnc is None:
return self.__error('Unknown operation found at execution queue ({0})'.format(op)) return self.__error(
'Unknown operation found at execution queue ({0})'.format(op)
)
execFnc() execFnc()
@ -252,10 +291,11 @@ class OGDeployment(UserDeployment):
""" """
Deploys a machine from template for user/cache Deploys a machine from template for user/cache
""" """
try:
r: typing.Any = None r: typing.Any = None
token = cryptoManager().randomString(32)
try:
r = self.service().reserve() r = self.service().reserve()
self.service().notifyEvents(r['id'], self._uuid) self.service().notifyEvents(r['id'], token, self._uuid)
except Exception as e: except Exception as e:
# logger.exception('Creating machine') # logger.exception('Creating machine')
if r: # Reservation was done, unreserve it!!! if r: # Reservation was done, unreserve it!!!
@ -274,18 +314,35 @@ class OGDeployment(UserDeployment):
self._ip = r['ip'] self._ip = r['ip']
self._stamp = getSqlDatetimeAsUnix() self._stamp = getSqlDatetimeAsUnix()
self.doLog(
log.INFO,
f'Reserved machine {self._name}: id: {self._machineId}, mac: {self._mac}, ip: {self._ip}',
)
# Store actor version & Known ip # Store actor version & Known ip
dbs = self.dbservice() dbs = self.dbservice()
if dbs: if dbs:
dbs.setProperty('actor_version', '1.0-OpenGnsys') dbs.setProperty('actor_version', '1.1-OpenGnsys')
dbs.setProperty('token', token)
dbs.logIP(self._ip) dbs.logIP(self._ip)
return State.RUNNING return State.RUNNING
def __start(self) -> str:
if self._machineId:
self.service().powerOn(self._machineId)
return State.RUNNING
def __remove(self) -> str: def __remove(self) -> str:
""" """
Removes a machine from system Removes a machine from system
Avoids "double unreserve" in case the reservation was made from release
""" """
dbs = self.dbservice()
if dbs:
# On release callback, we will set a property on DB called "from_release"
# so we can avoid double unreserve
if dbs.getProperty('from_release') is None:
self.service().unreserve(self._machineId) self.service().unreserve(self._machineId)
return State.RUNNING return State.RUNNING
@ -296,6 +353,9 @@ class OGDeployment(UserDeployment):
""" """
return self.__checkMachineReady() return self.__checkMachineReady()
# Alias for poweron check
__checkStart = __checkCreate
def __checkRemoved(self) -> str: def __checkRemoved(self) -> str:
""" """
Checks if a machine has been removed Checks if a machine has been removed
@ -319,13 +379,18 @@ class OGDeployment(UserDeployment):
opCreate: self.__checkCreate, opCreate: self.__checkCreate,
opRetry: self.__retry, opRetry: self.__retry,
opRemove: self.__checkRemoved, opRemove: self.__checkRemoved,
opStart: self.__checkStart,
} }
try: try:
chkFnc: typing.Optional[typing.Optional[typing.Callable[[], str]]] = fncs.get(op, None) chkFnc: typing.Optional[
typing.Optional[typing.Callable[[], str]]
] = fncs.get(op)
if chkFnc is None: if chkFnc is None:
return self.__error('Unknown operation found at check queue ({0})'.format(op)) return self.__error(
'Unknown operation found at check queue ({0})'.format(op)
)
state = chkFnc() state = chkFnc()
if state == State.FINISHED: if state == State.FINISHED:
@ -379,4 +444,12 @@ class OGDeployment(UserDeployment):
}.get(op, '????') }.get(op, '????')
def __debug(self, txt) -> None: def __debug(self, txt) -> None:
logger.debug('State at %s: name: %s, ip: %s, mac: %s, machine:%s, queue: %s', txt, self._name, self._ip, self._mac, self._machineId, [OGDeployment.__op2str(op) for op in self._queue]) logger.debug(
'State at %s: name: %s, ip: %s, mac: %s, machine:%s, queue: %s',
txt,
self._name,
self._ip,
self._mac,
self._machineId,
[OGDeployment.__op2str(op) for op in self._queue],
)

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (c) 2012 Virtual Cable S.L. # Copyright (c) 2015-2021 Virtual Cable S.L.U.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without modification, # Redistribution and use in source and binary forms, with or without modification,
@ -53,8 +53,12 @@ def getResources(parameters: typing.Any) -> typing.List[typing.Dict[str, typing.
api = provider.api api = provider.api
labs = [gui.choiceItem('0', _('All Labs'))] + [gui.choiceItem(l['id'], l['name']) for l in api.getLabs(ou=parameters['ou'])] labs = [gui.choiceItem('0', _('All Labs'))] + [
images = [gui.choiceItem(z['id'], z['name']) for z in api.getImages(ou=parameters['ou'])] gui.choiceItem(l['id'], l['name']) for l in api.getLabs(ou=parameters['ou'])
]
images = [
gui.choiceItem(z['id'], z['name']) for z in api.getImages(ou=parameters['ou'])
]
data = [ data = [
{'name': 'lab', 'values': labs}, {'name': 'lab', 'values': labs},

View File

@ -56,17 +56,22 @@ def ensureConnected(fnc: typing.Callable[..., RT]) -> typing.Callable[..., RT]:
def inner(*args, **kwargs) -> RT: def inner(*args, **kwargs) -> RT:
args[0].connect() args[0].connect()
return fnc(*args, **kwargs) return fnc(*args, **kwargs)
return inner return inner
# Result checker # Result checker
def ensureResponseIsValid(response: requests.Response, errMsg: typing.Optional[str] = None) -> typing.Any: def ensureResponseIsValid(
response: requests.Response, errMsg: typing.Optional[str] = None
) -> typing.Any:
if not response.ok: if not response.ok:
if not errMsg: if not errMsg:
errMsg = 'Invalid response' errMsg = 'Invalid response'
try: try:
err = response.json()['message'] # Extract any key, in case of error is expected to have only one top key so this will work err = response.json()[
'message'
] # Extract any key, in case of error is expected to have only one top key so this will work
except Exception: except Exception:
err = response.content err = response.content
errMsg = '{}: {}, ({})'.format(errMsg, err, response.status_code) errMsg = '{}: {}, ({})'.format(errMsg, err, response.status_code)
@ -76,7 +81,11 @@ def ensureResponseIsValid(response: requests.Response, errMsg: typing.Optional[s
try: try:
return json.loads(response.content) return json.loads(response.content)
except Exception: except Exception:
raise Exception('Error communicating with OpenGnsys: {}'.format(response.content[:128].decode())) raise Exception(
'Error communicating with OpenGnsys: {}'.format(
response.content[:128].decode()
)
)
class OpenGnsysClient: class OpenGnsysClient:
@ -88,7 +97,14 @@ class OpenGnsysClient:
verifyCert: bool verifyCert: bool
cachedVersion: typing.Optional[str] cachedVersion: typing.Optional[str]
def __init__(self, username: str, password: str, endpoint: str, cache: 'Cache', verifyCert: bool = False): def __init__(
self,
username: str,
password: str,
endpoint: str,
cache: 'Cache',
verifyCert: bool = False,
):
self.username = username self.username = username
self.password = password self.password = password
self.endpoint = endpoint self.endpoint = endpoint
@ -108,11 +124,18 @@ class OpenGnsysClient:
def _ogUrl(self, path: str) -> str: def _ogUrl(self, path: str) -> str:
return self.endpoint + '/' + path return self.endpoint + '/' + path
def _post(self, path: str, data: typing.Any, errMsg: typing.Optional[str] = None) -> typing.Any: def _post(
self, path: str, data: typing.Any, errMsg: typing.Optional[str] = None
) -> typing.Any:
if not FAKE: if not FAKE:
return ensureResponseIsValid( return ensureResponseIsValid(
requests.post(self._ogUrl(path), data=json.dumps(data), headers=self.headers, verify=self.verifyCert), requests.post(
errMsg=errMsg self._ogUrl(path),
data=json.dumps(data),
headers=self.headers,
verify=self.verifyCert,
),
errMsg=errMsg,
) )
# FAKE Connection :) # FAKE Connection :)
return fake.post(path, data, errMsg) return fake.post(path, data, errMsg)
@ -120,8 +143,10 @@ class OpenGnsysClient:
def _get(self, path: str, errMsg: typing.Optional[str] = None) -> typing.Any: def _get(self, path: str, errMsg: typing.Optional[str] = None) -> typing.Any:
if not FAKE: if not FAKE:
return ensureResponseIsValid( return ensureResponseIsValid(
requests.get(self._ogUrl(path), headers=self.headers, verify=self.verifyCert), requests.get(
errMsg=errMsg self._ogUrl(path), headers=self.headers, verify=self.verifyCert
),
errMsg=errMsg,
) )
# FAKE Connection :) # FAKE Connection :)
return fake.get(path, errMsg) return fake.get(path, errMsg)
@ -129,8 +154,10 @@ class OpenGnsysClient:
def _delete(self, path: str, errMsg: typing.Optional[str] = None) -> typing.Any: def _delete(self, path: str, errMsg: typing.Optional[str] = None) -> typing.Any:
if not FAKE: if not FAKE:
return ensureResponseIsValid( return ensureResponseIsValid(
requests.delete(self._ogUrl(path), headers=self.headers, verify=self.verifyCert), requests.delete(
errMsg=errMsg self._ogUrl(path), headers=self.headers, verify=self.verifyCert
),
errMsg=errMsg,
) )
return fake.delete(path, errMsg) return fake.delete(path, errMsg)
@ -145,11 +172,8 @@ class OpenGnsysClient:
auth = self._post( auth = self._post(
urls.LOGIN, urls.LOGIN,
data={ data={'username': self.username, 'password': self.password},
'username': self.username, errMsg='Loggin in',
'password': self.password
},
errMsg='Loggin in'
) )
self.auth = auth['apikey'] self.auth = auth['apikey']
@ -179,7 +203,11 @@ class OpenGnsysClient:
# /ous/{ouid}/labs # /ous/{ouid}/labs
# Take into accout that we must exclude the ones with "inremotepc" set to false. # Take into accout that we must exclude the ones with "inremotepc" set to false.
errMsg = 'Getting list of labs from ou {}'.format(ou) errMsg = 'Getting list of labs from ou {}'.format(ou)
return [{'id': l['id'], 'name': l['name']} for l in self._get(urls.LABS.format(ou=ou), errMsg=errMsg) if l.get('inremotepc', False) is True] return [
{'id': l['id'], 'name': l['name']}
for l in self._get(urls.LABS.format(ou=ou), errMsg=errMsg)
if l.get('inremotepc', False) is True
]
@ensureConnected @ensureConnected
def getImages(self, ou: str) -> typing.List[typing.MutableMapping[str, str]]: def getImages(self, ou: str) -> typing.List[typing.MutableMapping[str, str]]:
@ -187,20 +215,23 @@ class OpenGnsysClient:
# /ous/{ouid}/images # /ous/{ouid}/images
# Take into accout that we must exclude the ones with "inremotepc" set to false. # Take into accout that we must exclude the ones with "inremotepc" set to false.
errMsg = 'Getting list of images from ou {}'.format(ou) errMsg = 'Getting list of images from ou {}'.format(ou)
return [{'id': l['id'], 'name': l['name']} for l in self._get(urls.IMAGES.format(ou=ou), errMsg=errMsg) if l.get('inremotepc', False) is True] return [
{'id': l['id'], 'name': l['name']}
for l in self._get(urls.IMAGES.format(ou=ou), errMsg=errMsg)
if l.get('inremotepc', False) is True
]
@ensureConnected @ensureConnected
def reserve(self, ou: str, image: str, lab: int = 0, maxtime: int = 24) -> typing.MutableMapping[str, typing.Union[str, int]]: def reserve(
self, ou: str, image: str, lab: int = 0, maxtime: int = 24
) -> typing.MutableMapping[str, typing.Union[str, int]]:
# This method is inteded to "get" a machine from OpenGnsys # This method is inteded to "get" a machine from OpenGnsys
# The method used is POST # The method used is POST
# invokes /ous/{ouid}}/images/{imageid}/reserve # invokes /ous/{ouid}}/images/{imageid}/reserve
# also remember to store "labid" # also remember to store "labid"
# Labid can be "0" that means "all laboratories" # Labid can be "0" that means "all laboratories"
errMsg = 'Reserving image {} in ou {}'.format(image, ou) errMsg = 'Reserving image {} in ou {}'.format(image, ou)
data = { data = {'labid': lab, 'maxtime': maxtime}
'labid': lab,
'maxtime': maxtime
}
res = self._post(urls.RESERVE.format(ou=ou, image=image), data, errMsg=errMsg) res = self._post(urls.RESERVE.format(ou=ou, image=image), data, errMsg=errMsg)
return { return {
'ou': ou, 'ou': ou,
@ -210,7 +241,7 @@ class OpenGnsysClient:
'id': '.'.join((str(ou), str(res['lab']['id']), str(res['id']))), 'id': '.'.join((str(ou), str(res['lab']['id']), str(res['id']))),
'name': res['name'], 'name': res['name'],
'ip': res['ip'], 'ip': res['ip'],
'mac': ':'.join(re.findall('..', res['mac'])) 'mac': ':'.join(re.findall('..', res['mac'])),
} }
@ensureConnected @ensureConnected
@ -219,29 +250,48 @@ class OpenGnsysClient:
# Invoked every time we need to release a reservation (i mean, if a reservation is done, this will be called with the obtained id from that reservation) # Invoked every time we need to release a reservation (i mean, if a reservation is done, this will be called with the obtained id from that reservation)
ou, lab, client = machineId.split('.') ou, lab, client = machineId.split('.')
errMsg = 'Unreserving client {} in lab {} in ou {}'.format(client, lab, ou) errMsg = 'Unreserving client {} in lab {} in ou {}'.format(client, lab, ou)
return self._delete(urls.UNRESERVE.format(ou=ou, lab=lab, client=client), errMsg=errMsg) return self._delete(
urls.UNRESERVE.format(ou=ou, lab=lab, client=client), errMsg=errMsg
)
def powerOn(self, machineId, image):
# This method ask to poweron a machine to openGnsys
ou, lab, client = machineId.split('.')
errMsg = 'Powering on client {} in lab {} in ou {}'.format(client, lab, ou)
try:
data = {
'image': image,
}
return self._post(
urls.START.format(ou=ou, lab=lab, client=client), data, errMsg=errMsg
)
except Exception: # For now, if this fails, ignore it to keep backwards compat
return 'OK'
@ensureConnected @ensureConnected
def notifyURLs(self, machineId: str, loginURL: str, logoutURL: str) -> typing.Any: def notifyURLs(
self, machineId: str, loginURL: str, logoutURL: str, releaseURL: str
) -> typing.Any:
ou, lab, client = machineId.split('.') ou, lab, client = machineId.split('.')
errMsg = 'Notifying login/logout urls' errMsg = 'Notifying login/logout urls'
data = { data = {'urlLogin': loginURL, 'urlLogout': logoutURL, 'urlRelease': releaseURL}
'urlLogin': loginURL,
'urlLogout': logoutURL
}
return self._post(urls.EVENTS.format(ou=ou, lab=lab, client=client), data, errMsg=errMsg) return self._post(
urls.EVENTS.format(ou=ou, lab=lab, client=client), data, errMsg=errMsg
)
@ensureConnected @ensureConnected
def notifyDeadline(self, machineId: str, deadLine: typing.Optional[int]) -> typing.Any: def notifyDeadline(
self, machineId: str, deadLine: typing.Optional[int]
) -> typing.Any:
ou, lab, client = machineId.split('.') ou, lab, client = machineId.split('.')
deadLine = deadLine or 0 deadLine = deadLine or 0
errMsg = 'Notifying deadline' errMsg = 'Notifying deadline'
data = { data = {'deadLine': deadLine}
'deadLine': deadLine
}
return self._post(urls.SESSIONS.format(ou=ou, lab=lab, client=client), data, errMsg=errMsg) return self._post(
urls.SESSIONS.format(ou=ou, lab=lab, client=client), data, errMsg=errMsg
)
@ensureConnected @ensureConnected
def status(self, id_: str) -> typing.Any: def status(self, id_: str) -> typing.Any:

View File

@ -40,20 +40,13 @@ from . import urls
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
AUTH = { AUTH = {"userid": 1001, "apikey": "fakeAPIKeyJustForDeveloping"}
"userid": 1001,
"apikey": "fakeAPIKeyJustForDeveloping"
}
INFO = { INFO = {
"project": "OpenGnsys", "project": "OpenGnsys",
"version": "1.1.0pre", "version": "1.1.0pre",
"release": "r5299", "release": "r5299",
"services": [ "services": ["server", "repository", "tracker"],
"server",
"repository",
"tracker"
],
"oglive": [ "oglive": [
{ {
"distribution": "xenial", "distribution": "xenial",
@ -61,7 +54,7 @@ INFO = {
"architecture": "amd64", "architecture": "amd64",
"revision": "r5225", "revision": "r5225",
"directory": "ogLive-xenial-4.8.0-amd64-r5225", "directory": "ogLive-xenial-4.8.0-amd64-r5225",
"iso": "ogLive-xenial-4.8.0-39-generic-amd64-r5225.iso" "iso": "ogLive-xenial-4.8.0-39-generic-amd64-r5225.iso",
}, },
{ {
"iso": "ogLive-precise-3.2.0-23-generic-r4820.iso", "iso": "ogLive-precise-3.2.0-23-generic-r4820.iso",
@ -69,19 +62,14 @@ INFO = {
"revision": "r4820", "revision": "r4820",
"architecture": "i386", "architecture": "i386",
"kernel": "3.2.0-23-generic", "kernel": "3.2.0-23-generic",
"distribution": "precise" "distribution": "precise",
}] },
],
} }
OUS = [ OUS = [
{ {"id": "1", "name": "Unidad Organizativa (Default)"},
"id": "1", {"id": "2", "name": "Unidad Organizatva VACIA"},
"name": "Unidad Organizativa (Default)"
},
{
"id": "2",
"name": "Unidad Organizatva VACIA"
},
] ]
LABS = [ LABS = [
@ -89,58 +77,32 @@ LABS = [
"id": "1", "id": "1",
"name": "Sala de control", "name": "Sala de control",
"inremotepc": True, "inremotepc": True,
"group": { "group": {"id": "0"},
"id": "0" "ou": {"id": "1"},
},
"ou": {
"id": "1"
}
}, },
{ {
"id": "2", "id": "2",
"name": "Sala de computación cuántica", "name": "Sala de computación cuántica",
"inremotepc": True, "inremotepc": True,
"group": { "group": {"id": "0"},
"id": "0" "ou": {"id": "1"},
}, },
"ou": {
"id": "1"
}
}
] ]
IMAGES = [ IMAGES = [
{ {"id": "1", "name": "Basica1604", "inremotepc": True, "ou": {"id": "1"}},
"id": "1", {"id": "2", "name": "Ubuntu16", "inremotepc": True, "ou": {"id": "1"}},
"name": "Basica1604",
"inremotepc": True,
"ou": {
"id": "1"
}
},
{
"id": "2",
"name": "Ubuntu16",
"inremotepc": True,
"ou": {
"id": "1"
}
},
{ {
"id": "3", "id": "3",
"name": "Ubuntu64 Not in Remote", "name": "Ubuntu64 Not in Remote",
"inremotepc": False, "inremotepc": False,
"ou": { "ou": {"id": "1"},
"id": "1"
}
}, },
{ {
"id": "4", "id": "4",
"name": "Ubuntu96 Not In Remote", "name": "Ubuntu96 Not In Remote",
"inremotepc": False, "inremotepc": False,
"ou": { "ou": {"id": "1"},
"id": "1"
}
}, },
] ]
@ -149,58 +111,50 @@ RESERVE: typing.Dict[str, typing.Any] = {
"name": "pcpruebas", "name": "pcpruebas",
"mac": "4061860521FE", "mac": "4061860521FE",
"ip": "10.1.14.31", "ip": "10.1.14.31",
"lab": { "lab": {"id": 1},
"id": 1 "ou": {"id": 1},
},
"ou": {
"id": 1
}
} }
UNRESERVE = '' UNRESERVE = ''
STATUS_OFF = { STATUS_OFF = {"id": 4, "ip": "10.1.14.31", "status": "off", "loggedin": False}
"id": 4,
"ip": "10.1.14.31",
"status": "off",
"loggedin": False
}
# A couple of status for testing # A couple of status for testing
STATUS_READY_LINUX = { STATUS_READY_LINUX = {"id": 4, "ip": "10.1.14.31", "status": "linux", "loggedin": False}
"id": 4,
"ip": "10.1.14.31",
"status": "linux",
"loggedin": False
}
STATUS_READY_WINDOWS = { STATUS_READY_WINDOWS = {
"id": 4, "id": 4,
"ip": "10.1.14.31", "ip": "10.1.14.31",
"status": "windows", "status": "windows",
"loggedin": False "loggedin": False,
} }
# FAKE post # FAKE post
def post(path: str, data: typing.Any, errMsg: typing.Optional[str] = None) -> typing.Any: def post(
path: str, data: typing.Any, errMsg: typing.Optional[str] = None
) -> typing.Any:
logger.info('FAKE POST request to %s with %s data. (%s)', path, data, errMsg) logger.info('FAKE POST request to %s with %s data. (%s)', path, data, errMsg)
if path == urls.LOGIN: if path == urls.LOGIN:
return AUTH return AUTH
if path == urls.RESERVE.format(ou=1, image=1) or path == urls.RESERVE.format(ou=1, image=2): if path == urls.RESERVE.format(ou=1, image=1) or path == urls.RESERVE.format(
ou=1, image=2
):
res = copy.deepcopy(RESERVE) res = copy.deepcopy(RESERVE)
res['name'] += str(random.randint(5000, 100000)) res['name'] += str(random.randint(5000, 100000))
res['mac'] = ''.join(random.choice('0123456789ABCDEF') for _ in range(12)) res['mac'] = ''.join(random.choice('0123456789ABCDEF') for _ in range(12))
res['ip'] = '1.2.3.4' res['ip'] = '1.2.3.4'
return res return res
# raise Exception('Unknown FAKE URL on POST: {}'.format(path)) # Ignore rest of responses
return '' return {'status': 'ok'}
# FAKE get # FAKE get
def get(path, errMsg: typing.Optional[str]) -> typing.Any: # pylint: disable=too-many-return-statements def get(
path, errMsg: typing.Optional[str]
) -> typing.Any: # pylint: disable=too-many-return-statements
logger.info('FAKE GET request to %s. (%s)', path, errMsg) logger.info('FAKE GET request to %s. (%s)', path, errMsg)
if path == urls.INFO: if path == urls.INFO:
return INFO return INFO

View File

@ -1,7 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (c) 2017-2019 Virtual Cable S.L. # Copyright (c) 2017-2021 Virtual Cable S.L.U.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without modification, # Redistribution and use in source and binary forms, with or without modification,
@ -43,3 +42,5 @@ UNRESERVE = '/ous/{ou}/labs/{lab}/clients/{client}/unreserve'
STATUS = '/ous/{ou}/labs/{lab}/clients/{client}/status' STATUS = '/ous/{ou}/labs/{lab}/clients/{client}/status'
EVENTS = '/ous/{ou}/labs/{lab}/clients/{client}/events' EVENTS = '/ous/{ou}/labs/{lab}/clients/{client}/events'
SESSIONS = '/ous/{ou}/labs/{lab}/clients/{client}/session' SESSIONS = '/ous/{ou}/labs/{lab}/clients/{client}/session'
# TODO: fix this
START = '/ous/{ou}/labs/{lab}/clients/{client}/init'

View File

@ -1,7 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (c) 2012-2019 Virtual Cable S.L. # Copyright (c) 2012-2021 Virtual Cable S.L.U.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without modification, # Redistribution and use in source and binary forms, with or without modification,
@ -51,6 +50,7 @@ if typing.TYPE_CHECKING:
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class OGProvider(ServiceProvider): class OGProvider(ServiceProvider):
""" """
This class represents the sample services provider This class represents the sample services provider
@ -68,6 +68,7 @@ class OGProvider(ServiceProvider):
we MUST register it at package __init__. we MUST register it at package __init__.
""" """
# : What kind of services we offer, this are classes inherited from Service # : What kind of services we offer, this are classes inherited from Service
offers = [OGService] offers = [OGService]
# : Name to show the administrator. This string will be translated BEFORE # : Name to show the administrator. This string will be translated BEFORE
@ -92,17 +93,81 @@ class OGProvider(ServiceProvider):
# but used for sample purposes # but used for sample purposes
# If we don't indicate an order, the output order of fields will be # If we don't indicate an order, the output order of fields will be
# "random" # "random"
host = gui.TextField(length=64, label=_('Host'), order=1, tooltip=_('OpenGnsys Host'), required=True) host = gui.TextField(
port = gui.NumericField(length=5, label=_('Port'), defvalue='443', order=2, tooltip=_('OpenGnsys Port (default is 443, and only ssl connection is allowed)'), required=True) length=64, label=_('Host'), order=1, tooltip=_('OpenGnsys Host'), required=True
checkCert = gui.CheckBoxField(label=_('Check Cert.'), order=3, tooltip=_('If checked, ssl certificate of OpenGnsys server must be valid (not self signed)')) )
username = gui.TextField(length=32, label=_('Username'), order=4, tooltip=_('User with valid privileges on OpenGnsys'), required=True) port = gui.NumericField(
password = gui.PasswordField(lenth=32, label=_('Password'), order=5, tooltip=_('Password of the user of OpenGnsys'), required=True) length=5,
udsServerAccessUrl = gui.TextField(length=32, label=_('UDS Server URL'), order=6, tooltip=_('URL used by OpenGnsys to access UDS. If empty, UDS will guess it.'), required=False, tab=gui.PARAMETERS_TAB) label=_('Port'),
defvalue='443',
order=2,
tooltip=_(
'OpenGnsys Port (default is 443, and only ssl connection is allowed)'
),
required=True,
)
checkCert = gui.CheckBoxField(
label=_('Check Cert.'),
order=3,
tooltip=_(
'If checked, ssl certificate of OpenGnsys server must be valid (not self signed)'
),
)
username = gui.TextField(
length=32,
label=_('Username'),
order=4,
tooltip=_('User with valid privileges on OpenGnsys'),
required=True,
)
password = gui.PasswordField(
lenth=32,
label=_('Password'),
order=5,
tooltip=_('Password of the user of OpenGnsys'),
required=True,
)
udsServerAccessUrl = gui.TextField(
length=32,
label=_('UDS Server URL'),
order=6,
tooltip=_('URL used by OpenGnsys to access UDS. If empty, UDS will guess it.'),
required=False,
tab=gui.PARAMETERS_TAB,
)
maxPreparingServices = gui.NumericField(length=3, label=_('Creation concurrency'), defvalue='10', minValue=1, maxValue=65536, order=50, tooltip=_('Maximum number of concurrently creating VMs'), required=True, tab=gui.ADVANCED_TAB) maxPreparingServices = gui.NumericField(
maxRemovingServices = gui.NumericField(length=3, label=_('Removal concurrency'), defvalue='8', minValue=1, maxValue=65536, order=51, tooltip=_('Maximum number of concurrently removing VMs'), required=True, tab=gui.ADVANCED_TAB) length=3,
label=_('Creation concurrency'),
defvalue='10',
minValue=1,
maxValue=65536,
order=50,
tooltip=_('Maximum number of concurrently creating VMs'),
required=True,
tab=gui.ADVANCED_TAB,
)
maxRemovingServices = gui.NumericField(
length=3,
label=_('Removal concurrency'),
defvalue='8',
minValue=1,
maxValue=65536,
order=51,
tooltip=_('Maximum number of concurrently removing VMs'),
required=True,
tab=gui.ADVANCED_TAB,
)
timeout = gui.NumericField(length=3, label=_('Timeout'), defvalue='10', order=90, tooltip=_('Timeout in seconds of connection to OpenGnsys'), required=True, tab=gui.ADVANCED_TAB) timeout = gui.NumericField(
length=3,
label=_('Timeout'),
defvalue='10',
order=90,
tooltip=_('Timeout in seconds of connection to OpenGnsys'),
required=True,
tab=gui.ADVANCED_TAB,
)
# Own variables # Own variables
_api: typing.Optional[og.OpenGnsysClient] = None _api: typing.Optional[og.OpenGnsysClient] = None
@ -137,7 +202,13 @@ class OGProvider(ServiceProvider):
@property @property
def api(self) -> og.OpenGnsysClient: def api(self) -> og.OpenGnsysClient:
if not self._api: if not self._api:
self._api = og.OpenGnsysClient(self.username.value, self.password.value, self.endpoint, self.cache, self.checkCert.isTrue()) self._api = og.OpenGnsysClient(
self.username.value,
self.password.value,
self.endpoint,
self.cache,
self.checkCert.isTrue(),
)
logger.debug('Api: %s', self._api) logger.debug('Api: %s', self._api)
return self._api return self._api
@ -155,7 +226,12 @@ class OGProvider(ServiceProvider):
""" """
try: try:
if self.api.version[0:5] < '1.1.0': if self.api.version[0:5] < '1.1.0':
return [False, 'OpenGnsys version is not supported (required version 1.1.0 or newer and found {})'.format(self.api.version)] return [
False,
'OpenGnsys version is not supported (required version 1.1.0 or newer and found {})'.format(
self.api.version
),
]
except Exception as e: except Exception as e:
logger.exception('Error') logger.exception('Error')
return [False, '{}'.format(e)] return [False, '{}'.format(e)]
@ -184,16 +260,25 @@ class OGProvider(ServiceProvider):
def getUDSServerAccessUrl(self) -> str: def getUDSServerAccessUrl(self) -> str:
return self.udsServerAccessUrl.value return self.udsServerAccessUrl.value
def reserve(self, ou: str, image: str, lab: int = 0, maxtime: int = 0) -> typing.Any: def reserve(
self, ou: str, image: str, lab: int = 0, maxtime: int = 0
) -> typing.Any:
return self.api.reserve(ou, image, lab, maxtime) return self.api.reserve(ou, image, lab, maxtime)
def unreserve(self, machineId: str) -> typing.Any: def unreserve(self, machineId: str) -> typing.Any:
return self.api.unreserve(machineId) return self.api.unreserve(machineId)
def notifyEvents(self, machineId: str, loginURL: str, logoutURL: str) -> typing.Any: def powerOn(self, machineId: str, image: str) -> typing.Any:
return self.api.notifyURLs(machineId, loginURL, logoutURL) return self.api.powerOn(machineId, image)
def notifyDeadline(self, machineId: str, deadLine: typing.Optional[int]) -> typing.Any: def notifyEvents(
self, machineId: str, loginURL: str, logoutURL: str, releaseURL: str
) -> typing.Any:
return self.api.notifyURLs(machineId, loginURL, logoutURL, releaseURL)
def notifyDeadline(
self, machineId: str, deadLine: typing.Optional[int]
) -> typing.Any:
return self.api.notifyDeadline(machineId, deadLine) return self.api.notifyDeadline(machineId, deadLine)
def status(self, machineId: str) -> typing.Any: def status(self, machineId: str) -> typing.Any:

View File

@ -1,7 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (c) 2017-2019 Virtual Cable S.L. # Copyright (c) 2017-2021 Virtual Cable S.L.U.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without modification, # Redistribution and use in source and binary forms, with or without modification,
@ -48,9 +47,12 @@ class OGPublication(Publication):
""" """
This class provides the publication of a oVirtLinkedService This class provides the publication of a oVirtLinkedService
""" """
_name: str = '' _name: str = ''
suggestedTime = 5 # : Suggested recheck time if publication is unfinished in seconds suggestedTime = (
5 # : Suggested recheck time if publication is unfinished in seconds
)
def service(self) -> 'OGService': def service(self) -> 'OGService':
return typing.cast('OGService', super().service()) return typing.cast('OGService', super().service())

View File

@ -1,7 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (c) 2017-2019 Virtual Cable S.L. # Copyright (c) 2017-2021 Virtual Cable S.L.U.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without modification, # Redistribution and use in source and binary forms, with or without modification,
@ -55,6 +54,7 @@ class OGService(Service):
""" """
OpenGnsys Service OpenGnsys Service
""" """
# : Name to show the administrator. This string will be translated BEFORE # : Name to show the administrator. This string will be translated BEFORE
# : sending it to administration interface, so don't forget to # : sending it to administration interface, so don't forget to
# : mark it as _ (using ugettext_noop) # : mark it as _ (using ugettext_noop)
@ -102,20 +102,17 @@ class OGService(Service):
label=_("OU"), label=_("OU"),
order=100, order=100,
fills={ fills={
'callbackName' : 'osFillData', 'callbackName': 'osFillData',
'function' : helpers.getResources, 'function': helpers.getResources,
'parameters' : ['ov', 'ev', 'ou'] 'parameters': ['ov', 'ev', 'ou'],
}, },
tooltip=_('Organizational Unit'), tooltip=_('Organizational Unit'),
required=True required=True,
) )
# Lab is not required, but maybe used as filter # Lab is not required, but maybe used as filter
lab = gui.ChoiceField( lab = gui.ChoiceField(
label=_("lab"), label=_("lab"), order=101, tooltip=_('Laboratory'), required=False
order=101,
tooltip=_('Laboratory'),
required=False
) )
# Required, this is the base image # Required, this is the base image
@ -123,22 +120,33 @@ class OGService(Service):
label=_("OS Image"), label=_("OS Image"),
order=102, order=102,
tooltip=_('OpenGnsys Operating System Image'), tooltip=_('OpenGnsys Operating System Image'),
required=True required=True,
) )
maxReservationTime = gui.NumericField( maxReservationTime = gui.NumericField(
length=3, length=3,
label=_("Max. reservation time"), label=_("Max. reservation time"),
order=110, order=110,
tooltip=_('Security parameter for OpenGnsys to keep reservations at most this hours. Handle with care!'), tooltip=_(
'Security parameter for OpenGnsys to keep reservations at most this hours. Handle with care!'
),
defvalue='2400', # 1 hundred days defvalue='2400', # 1 hundred days
minValue='24', minValue='24',
tab=_('Advanced'), tab=_('Advanced'),
required=False required=False,
)
startIfUnavailable = gui.CheckBoxField(
label=_('Start if unavailable'),
defvalue=gui.TRUE,
order=111,
tooltip=_('If active, machines that are not available on user connect (on some OS) will try to power on through OpenGnsys.'),
) )
ov = gui.HiddenField(value=None) ov = gui.HiddenField(value=None)
ev = gui.HiddenField(value=None) # We need to keep the env so we can instantiate the Provider ev = gui.HiddenField(
value=None
) # We need to keep the env so we can instantiate the Provider
def initGui(self) -> None: def initGui(self) -> None:
""" """
@ -157,27 +165,49 @@ class OGService(Service):
return self.parent().status(machineId) return self.parent().status(machineId)
def reserve(self) -> typing.Any: def reserve(self) -> typing.Any:
return self.parent().reserve(self.ou.value, self.image.value, self.lab.value, self.maxReservationTime.num()) return self.parent().reserve(
self.ou.value,
self.image.value,
self.lab.value,
self.maxReservationTime.num(),
)
def unreserve(self, machineId: str) -> typing.Any: def unreserve(self, machineId: str) -> typing.Any:
return self.parent().unreserve(machineId) return self.parent().unreserve(machineId)
def notifyEvents(self, machineId: str, serviceUUID: str) -> typing.Any: def notifyEvents(self, machineId: str, token: str, uuid: str) -> typing.Any:
return self.parent().notifyEvents(machineId, self.getLoginNotifyURL(serviceUUID), self.getLogoutNotifyURL(serviceUUID)) return self.parent().notifyEvents(
machineId,
self.getLoginNotifyURL(uuid, token),
self.getLogoutNotifyURL(uuid, token),
self.getReleaseURL(uuid, token)
)
def notifyDeadline(self, machineId: str, deadLine: typing.Optional[int]) -> typing.Any: def notifyDeadline(
self, machineId: str, deadLine: typing.Optional[int]
) -> typing.Any:
return self.parent().notifyDeadline(machineId, deadLine) return self.parent().notifyDeadline(machineId, deadLine)
def _notifyURL(self, uuid: str, message: str) -> str: def powerOn(self, machineId: str) -> typing.Any:
return self.parent().powerOn(machineId, self.image.value)
def _notifyURL(self, uuid: str, token:str, message: str) -> str:
# The URL is "GET messages URL". # The URL is "GET messages URL".
return '{accessURL}rest/actor/PostThoughGet/{uuid}/{message}'.format( return '{accessURL}uds/ognotify/{message}/{token}/{uuid}'.format(
accessURL=self.parent().getUDSServerAccessUrl(), accessURL=self.parent().getUDSServerAccessUrl(),
uuid=uuid, uuid=uuid,
token=token,
message=message message=message
) )
def getLoginNotifyURL(self, serviceUUID: str) -> str: def getLoginNotifyURL(self, uuid: str, token: str) -> str:
return self._notifyURL(serviceUUID, 'login') return self._notifyURL(uuid, token, 'login')
def getLogoutNotifyURL(self, serviceUUID: str) -> str: def getLogoutNotifyURL(self, uuid: str, token: str) -> str:
return self._notifyURL(serviceUUID, 'logout') return self._notifyURL(uuid, token, 'logout')
def getReleaseURL(self, uuid: str, token: str) -> str:
return self._notifyURL(uuid, token, 'release')
def isRemovableIfUnavailable(self):
return self.startIfUnavailable.isTrue()

View File

@ -30,7 +30,7 @@ MIT
MIT MIT
The MIT License The MIT License
Copyright (c) 2020 Google LLC. Copyright (c) 2021 Google LLC.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -64,7 +64,7 @@ MIT
MIT MIT
The MIT License The MIT License
Copyright (c) 2020 Google LLC. Copyright (c) 2021 Google LLC.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -30,7 +30,7 @@ MIT
MIT MIT
The MIT License The MIT License
Copyright (c) 2020 Google LLC. Copyright (c) 2021 Google LLC.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -64,7 +64,7 @@ MIT
MIT MIT
The MIT License The MIT License
Copyright (c) 2020 Google LLC. Copyright (c) 2021 Google LLC.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -25,7 +25,7 @@ gettext("Error launching service");
gettext("Please wait until the service is launched."); gettext("Please wait until the service is launched.");
gettext("Your connection is being prepared. It will open on a new window when ready."); gettext("Your connection is being prepared. It will open on a new window when ready.");
gettext("The service is now being prepared. (It is at #).'.replace('#', '' + data.running + '%"); gettext("The service is now being prepared. (It is at #).'.replace('#', '' + data.running + '%");
gettext("Please, tray again in a few moments."); gettext("Please, try again in a few moments.");
gettext("Error launching service"); gettext("Error launching service");
// HTML // HTML
gettext("You can access UDS Open Source code at"); gettext("You can access UDS Open Source code at");

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (c) 2012-2019 Virtual Cable S.L. # Copyright (c) 2012-2021 Virtual Cable S.L.U.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without modification, # Redistribution and use in source and binary forms, with or without modification,

View File

@ -84,34 +84,23 @@ class TSNXTransport(BaseNXTransport):
label=_('Tunnel wait time'), label=_('Tunnel wait time'),
defvalue='30', defvalue='30',
minValue=5, minValue=5,
maxValue=65536, maxValue=3600 * 24,
order=2, order=2,
tooltip=_('Maximum time to wait before closing the tunnel listener'), tooltip=_('Maximum time to wait before closing the tunnel listener'),
required=True, required=True,
tab=gui.TUNNEL_TAB, tab=gui.TUNNEL_TAB,
) )
ticketValidity = gui.NumericField(
length=3,
label=_('Tunnel ticket validity time (seconds)'),
defvalue='7200',
minValue=60, # One minute as min
maxValue=7*60*60*24, # one week as max
order=3,
tooltip=_('Maximum validity time for user ticket to allow reconnection'),
required=True,
tab=gui.TUNNEL_TAB,
)
verifyCertificate = gui.CheckBoxField( verifyCertificate = gui.CheckBoxField(
label=_('Force SSL certificate verification'), label=_('Force SSL certificate verification'),
order=23, order=23,
tooltip=_('If enabled, the certificate of tunnel server will be verified (recommended).'), tooltip=_(
'If enabled, the certificate of tunnel server will be verified (recommended).'
),
defvalue=gui.TRUE, defvalue=gui.TRUE,
tab=gui.TUNNEL_TAB tab=gui.TUNNEL_TAB,
) )
useEmptyCreds = gui.CheckBoxField( useEmptyCreds = gui.CheckBoxField(
label=_('Empty creds'), label=_('Empty creds'),
order=3, order=3,
@ -217,7 +206,6 @@ class TSNXTransport(BaseNXTransport):
_cacheMem: str = '' _cacheMem: str = ''
_screenSize: str = '' _screenSize: str = ''
_tunnelWait: int = 30 _tunnelWait: int = 30
_ticketValidity: int = 60
_verifyCertificate: bool = False _verifyCertificate: bool = False
def initialize(self, values: 'Module.ValuesType'): def initialize(self, values: 'Module.ValuesType'):
@ -228,7 +216,6 @@ class TSNXTransport(BaseNXTransport):
) )
self._tunnelServer = values['tunnelServer'] self._tunnelServer = values['tunnelServer']
self._tunnelWait = int(values['tunnelWait']) self._tunnelWait = int(values['tunnelWait'])
self._ticketValidity = int(values['ticketValidity'])
self._verifyCertificate = gui.strToBool(values['verifyCertificate']) self._verifyCertificate = gui.strToBool(values['verifyCertificate'])
self._tunnelCheckServer = '' self._tunnelCheckServer = ''
self._useEmptyCreds = gui.strToBool(values['useEmptyCreds']) self._useEmptyCreds = gui.strToBool(values['useEmptyCreds'])
@ -241,7 +228,6 @@ class TSNXTransport(BaseNXTransport):
self._cacheMem = values['cacheMem'] self._cacheMem = values['cacheMem']
self._screenSize = values['screenSize'] self._screenSize = values['screenSize']
def marshal(self) -> bytes: def marshal(self) -> bytes:
""" """
Serializes the transport data so we can store it in database Serializes the transport data so we can store it in database
@ -262,7 +248,6 @@ class TSNXTransport(BaseNXTransport):
self._tunnelCheckServer, self._tunnelCheckServer,
self._screenSize, self._screenSize,
str(self._tunnelWait), str(self._tunnelWait),
str(self._ticketValidity),
gui.boolToStr(self._verifyCertificate), gui.boolToStr(self._verifyCertificate),
], ],
) )
@ -288,10 +273,9 @@ class TSNXTransport(BaseNXTransport):
values[11] if values[0] == 'v2' else CommonPrefs.SZ_FULLSCREEN values[11] if values[0] == 'v2' else CommonPrefs.SZ_FULLSCREEN
) )
if values[0] == 'v3': if values[0] == 'v3':
self._tunnelWait, self._ticketValidity, self._verifyCertificate = ( self._tunnelWait, self._verifyCertificate = (
int(values[12]), int(values[12]),
int(values[13]), gui.strToBool(values[13]),
gui.strToBool(values[14])
) )
def valuesDict(self) -> gui.ValuesDictType: def valuesDict(self) -> gui.ValuesDictType:
@ -306,7 +290,6 @@ class TSNXTransport(BaseNXTransport):
'cacheMem': self._cacheMem, 'cacheMem': self._cacheMem,
'tunnelServer': self._tunnelServer, 'tunnelServer': self._tunnelServer,
'tunnelWait': str(self._tunnelWait), 'tunnelWait': str(self._tunnelWait),
'ticketValidity': str(self._ticketValidity),
'verifyCertificate': gui.boolToStr(self._verifyCertificate), 'verifyCertificate': gui.boolToStr(self._verifyCertificate),
} }
@ -334,8 +317,8 @@ class TSNXTransport(BaseNXTransport):
ticket = TicketStore.create_for_tunnel( ticket = TicketStore.create_for_tunnel(
userService=userService, userService=userService,
port=3389, port=int(self._listenPort),
validity=self.ticketValidity.num() validity=self._tunnelWait + 60, # Ticket overtime
) )
tunHost, tunPort = self.tunnelServer.value.split(':') tunHost, tunPort = self.tunnelServer.value.split(':')
@ -367,10 +350,9 @@ class TSNXTransport(BaseNXTransport):
'ip': ip, 'ip': ip,
'tunHost': tunHost, 'tunHost': tunHost,
'tunPort': tunPort, 'tunPort': tunPort,
'tunWait': self.tunnelWait.num(), 'tunWait': self._tunnelWait,
'tunChk': self.verifyCertificate.isTrue(), 'tunChk': self._verifyCertificate,
'ticket': ticket, 'ticket': ticket,
'port': self._listenPort,
'as_file_for_format': r.as_file_for_format, 'as_file_for_format': r.as_file_for_format,
} }

View File

@ -18,13 +18,13 @@ except Exception:
''') ''')
# Open tunnel # Open tunnel
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
# Check that tunnel works.. # Check that tunnel works..
if fs.check() is False: if fs.check() is False:
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>') raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
theFile = sp['as_file_for_format'].format( theFile = sp['as_file_for_format'].format( # type: ignore
address='127.0.0.1', address='127.0.0.1',
port=fs.server_address[1] port=fs.server_address[1]
) )

View File

@ -1 +1 @@
Jb61ZM6xlsxMLnk4a2X2INN3IyGp+ztSgjXV+AsbH2hKDtKANM9nqHXgI/4LfxAogM3Y17k2tHOnbf049mWNaDRNCqOY9tG/xL3am2HkOTb3L9YOpK60gk/0hF9y1qLN9Y/CM+TP6B3DvVW+fsSnVfmDoK/NyqR5nb+6iRs37nmr+ILcum8IYgT4BeoKUqcMjHBQFF1MGfD5arKJW1t9pFQZw9+BZUzyw1c++2mnajIe294gjUEqgRxKPX6ejYX9J/AfAvM8K+NruT23VcxbBkp6diRUHFzM0buqHxUVzCqyfnU+umS7FKLOLw8M1B0goYfK8B0p8lu8ICRA24yOPpnnbBBWBUjZm3OZUGt7fqanaPbsVvehibxOsPB2z/vktp6mVBx8tkjU8Uyli1RxMSdT8xjsCT3mkK521AasqfE5Vn/Plwe9ciBo5AfqVxkl9OFVgUCCDTug9oNx50u+eSj/XUCxlTu39OBWUV6HAUhWDIgRWoYpLCC5Xtb+ILkgYPtTU8CiQSS2EFk8uUqxCSCbJKwfQRHhcYItSZk6fP0TH1nfirR8DB/AW5ltbO8QPe4PIllAyQl827fy6vQTytSw1wWBkEf7OCBEfv1w3AwFOC35fKQoRk+ygbD5fLhFbQsDpaMVtabNL/zjlw51CtrQfQ1ru69bvKeHLbp265M= 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=

View File

@ -6,7 +6,7 @@ from __future__ import unicode_literals
import subprocess import subprocess
import os import os
from uds import tools # @UnresolvedImport from uds import tools # type: ignore
cmd = '/Applications/OpenNX/OpenNX.app/Contents/MacOS/OpenNXapp' cmd = '/Applications/OpenNX/OpenNX.app/Contents/MacOS/OpenNXapp'
@ -16,6 +16,6 @@ if os.path.isfile(cmd) is False:
''') ''')
filename = tools.saveTempFile(sp['as_file']) # @UndefinedVariable filename = tools.saveTempFile(sp['as_file']) # type: ignore
tools.addTaskToWait(subprocess.Popen([cmd, '--session={{}}'.format(filename), '--autologin', '--killerrors'])) tools.addTaskToWait(subprocess.Popen([cmd, '--session={{}}'.format(filename), '--autologin', '--killerrors'])) # type: ignore
tools.addFileToUnlink(filename) tools.addFileToUnlink(filename)

View File

@ -1 +1 @@
A4XL73+4BMMTm+pLNL5Ae4xqoZVasAxPc10CveDJFoSLNyierVIQRlNfbEP4ZuUSnpR/q01Y1KoRuYao5wQaNdW/4LKlnN4OFM01K04782Ug05JiSO1BZ8KBM5w8XmWyVqbmGveQiGVGWwyXwg0YqBmlSbMeFLDYZsO5ILq5F+FsY223C26P9XUiwzTSh58qb1OX6L6Yj5fhFVP3yLldy236SxBZAA7HmvoMvIGk8bKw4r+HRWtgfpUU5rxmFszNUikfcSSR45ci7qZYU/S6WuQ0RZD/5XV+jwTIQdZpn8qcFtXf5GSqSjdVV1vqUaRg04/cRpaFVZ8s+31Os00sZ7AWmBLFZAmRD8BRqks4Nz7RbjM2teH1+S67pvOPDzzYIiLpWeq0qQRKmJ6/DLprqBPfZ4uthqus2f6i6w2t+/CzI25K4Vrjaz0z3wp9k9O5bP7GFpFmfmwt0WW6jLJO43b4XVJ6N+yj02rvAGS2t1i/1S4IfK58/B6XMSchqUgPx1UiW/WHT7dujqiDDTMhLAncW7mwHs2ABwBlPfRxWkyHY8KZUpD9PWDypUf5JvOsNJgyNP/mXIDvCd2htscyfVkpZj5mAdeg9m3sMWNJivCHX0qa5KVcxyI2bn+MfBU9/khRTnOyhgikB8pHVnWqPIiSHL6BLdHiBFlJ7e8OYHw= hgPD0KnclF5OpaW4tIs+6pWX5tLeactCv1MGI1bk942nHoS4c/Nm87qd5dkHek51UMm1s8o2eB7xdrkJ6CVi/eOf2jnEs63luF+etmdwccHQU9BcQZjev1aId4q0q7HiQCXjXaS2vorIevH9uvf1NWl6AyPABynYhC7zvWb9nz/GTNBXO7TAqfVarGJLRXwY2KHpBXqUKEPB0H46+h3S9AWD2pHxfZnVBKdjoGgrD5/pt905aI2lrl1yCE14LFENkpssH/dBxYnaEMMYiWTuAe3lAP8MQEFlWmHBT63G7xMhDR3wc2sqC2eh8RQieEj1EoqCPLJFwMoxA1SZfS+JLhppskdJi06o+pqiJ4bzO0Is47plGn+KBodBAT+5/dOgOK/lKv+7Q8j3MS59TQUFty4TkybS6Ujk40SjlOlCwofVb6awKMSUSny853K20yKClt0gGhUjykstex3/eaXmU7hWLBBbDsFmY5W7Xhvxi1vPmrJ3uJ2M+R9WIeCM4xygLQPcMkZbY2k1bonv3NhK+AlapmY36y3IBbziL1Xv4agjRAykls3y+qrxMjE4Lx4ZUAI0OdX7COqdz7Ix7baYpMHrLgROjtkp/EJqVIfhvRSvJqMWLsZxbqCjoswNSI4zlyWFR980y4ITHhBsbP95X0yJnoRsgcN+wARNolxVL7o=

View File

@ -17,13 +17,13 @@ if os.path.isfile(cmd) is False:
''') ''')
# Open tunnel # Open tunnel
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
# Check that tunnel works.. # Check that tunnel works..
if fs.check() is False: if fs.check() is False:
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>') raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
theFile = sp['as_file_for_format'].format( theFile = sp['as_file_for_format'].format( # type: ignore
address='127.0.0.1', address='127.0.0.1',
port=fs.server_address[1] port=fs.server_address[1]
) )

View File

@ -1 +1 @@
sNIIRiS5PiCdCSHQ0Uv5iS4gdYBcFEfI8KPfvD1V8ZTry/Hw8NqB0qzHW0D3YgKGPZMBBnHM+mYiZNXwPuSObRn12Iw/dSh1kmSgh/1S/UvummsdD1vq8T8WdupvI8z1AyQemNPzjA0vUPhDhGakMy5/dAuy7hlND+K9swSTBI3kz5Dcx+PfsnNLxcCtCtmBT/3RDEESJlEVQAbH0sjt9sAQpHap8lDDV2vO/8kahKM4Gpre+uloFbjiYR53qEiQkECJipq3WWQbMq/5IIyBqcruXrHen0jybpuHoWjI++deS6d1NI6A+u9+oUp0AacQOnRzMdKUiykyA14Zjb+Hws0s/fVjPpWDqQMD52Ii1O6goCtsRszJVIdU7UGCTHYctBd+iQ3Qxk5cLXs/vBZ22WIwF6/YN62Gt9aIxonTojUevL2cvCQ6YrMR+X6fAIuvD1Jso86X4Fr2jGPPbzSnfLSn4dLtf8T6XPOn4mPaivosn9eUtMptJiUl3++vYGcdnOhF8Amk7hGUI58ck+gg+vo/MfUFCHTW3XxJtsD4Hr8uelgQNPvFs6whZuUSGVCjyvo107ikqafkiCu4QgWqMfmWzs8DVYAZ3KgPKaqp62R5gIIDdjwH0XZ4DET2+h8gFs+K+T1xcbbHvo8q8i2PRCSbdX9JsupOLuqE78NXAfA= lsChjBOL2LNJeEjnFSXjK3y9F8uPfz/j6ZlHg511XyQxakyrxPKhEnrAJ9DT7X7Py99D1SQqrMmn+A9B/lH658LmXyCLaQMKFVNLZxc1WH/0Ytl4int6ZJA3uTrt/bHYMNh91OxMsS6WPWjN8g2aCkGhgZIKHehP4oKlQmxOnI4EXSoWtHwl/aN2JaWV6pltiVDKMiyVxMHCnRm0L1KSVaOsC5OxW76DvsUWcYELXiue+bMlBx96lQN0/g4xd9UJKJFqRmA+tPnUhKYdm/gt1804xsdGQ2v2IdPiJjhBvN4riFUffkls0T67HFOEedNdoV7ox/lz8RmamlAGbs36Qz84U/hYdeEwpOZfzHvVKuq8M1EZQciboqdlaRDPDbF+o7mZHQsOCSzRTp6qBqb46pzcELuXBH4/jod/tAX9iyvz7BBxrQsTmhivHIwu3VOdjClN3bw2GrNSyhKxSYsb7wq/YiABfHWHJkHzMZnwxGOpYuYSHNNew2liH3zE3gZPX6rGnyFn7rv80rIGvbLmQV9hJmAluyzU6hQivHYqZnpnfQN1cKT5SKbDiZVCnAC9c8uPGD7VsHJZpaGR3Hi4bB/J2qyVG+zbfVVsLyRh/wDfGfucCBxt9ecY/xcZ6aebzabrEnyluhEmrehu6Ovp1lsWJQPb3mUzSHC0muN4M3s=

View File

@ -3,21 +3,24 @@
from __future__ import unicode_literals from __future__ import unicode_literals
# pylint: disable=import-error, no-name-in-module # pylint: disable=import-error, no-name-in-module
import _winreg try:
import winreg as wreg
except ImportError: # Python 2.7 fallback
import _winreg as wreg # type: ignore
import subprocess import subprocess
from uds import tools # @UnresolvedImport from uds import tools # type: ignore
try: try:
k = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, 'Software\\Classes\\NXClient.session\\shell\\open\\command') # @UndefinedVariable k = wreg.OpenKey(wreg.HKEY_CURRENT_USER, 'Software\\Classes\\NXClient.session\\shell\\open\\command') # @UndefinedVariable
cmd = _winreg.QueryValue(k, '') # @UndefinedVariable cmd = wreg.QueryValue(k, '') # type: ignore
wreg.CloseKey(k)
except 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> 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> <p>Please, install appropriate package for your system.</p>
''') ''')
filename = tools.saveTempFile(sp['as_file']) # @UndefinedVariable filename = tools.saveTempFile(sp['as_file']) # type: ignore
cmd = cmd.replace('%1', filename) cmd = cmd.replace('%1', filename)
tools.addTaskToWait(subprocess.Popen(cmd)) tools.addTaskToWait(subprocess.Popen(cmd))
tools.addFileToUnlink(filename) tools.addFileToUnlink(filename)

View File

@ -1 +1 @@
jyAVq4zJ1QR0otsMsh2vIarVH2Jy2UPGHi3JfLZPlwR1NFlM67f6uDgZO4wJNeQzOkPOGgpoklkB5ROxHjdUQUdm23XANXDpIZA1ywhrjLQ6lh4HSkbZ0i3QZizDAH5x5XxwHSOIrFeiT75qxXY67lFEXE4DhfxBMJMLm3xQyyjBxTyB1K/3UG3Ryhf0ApFqpaERoLEPJGjLeVj6bIeRre7TlxJMgO+VosjKkbUKRDTZD85X/iwvyRzGHy3OpS8zTOWt/Wstcph9+DrlPkbx8Z6yMpuwNW/mMEWblMcYWdyApBpnLEt8nLKlSQb3rGu2j7QaxzWwtPwuxWcd1IQzxCt0R/pbMlyl75QfrumKKoZ+MnPL4kK5kI4RHoBqzNKpirXHm36URfW5+9oKTuIgbwK6YvOPXtLAsYTtaWEmO21Tb6g+4XCzC1eoOlXWaA6NQe3rr0JXQpwAWjzg+EkaW0G45amef7ta4wGQC8zCZ1cSsA8uFGe6Q11fS94Q+Rv6rl5KubCf6KxvmsYDqkQkdzdvN8tDVkVX9mPNMaquLWaDWmKVp3Hp6WxdUELtAt50KfmGbaD7eMyLgHtBrhCUr1aRG3DxxysDOPhZYiO7Z73BR7OAeVM/bH3rpZLRsZOwi6s6zifqmmV5K2I5aozwybAQgVoR7+ZjZn5irPPULBc= isXacHwak7jQEx9QFKLUaVUTG75t5ogtWFiV7m7eMDttzBTkkS1/0hVLX1avLdaMOBCY60JTfTrPcHcd8XESfSzR3w92i1BzfccHmpV3g67lbeESZqpjsJTWC3F9kCpZHsj6DHXQICQjPPeW++tchJj8bAoETc6MyH5IHSJ/KOmbgLOBM+2x9crnX1ZWHrwF2xQyMaLn5rgntklvSX2KmOS6z0WC0C5DLFpVzZvSsDwMyfhhxd4fGNWCxUW4v5f5S1GUCM1AfzXWZEPYAWbRFgOzG2MKB2dhHasxVt25VtjeKgrD+Q5A28ihQBUkh5vZRmOtAWjtneF6K6bOM59ZL0vzjGIL1/y/6oysjyeOAG4YvagekMRAZT0folf7d4prUb1tN+8jvabZszGCxjvb0kYjfiT6zN53lxDSExLuvjBEwHkWM3CPCTkPLJ7UWiRT6Fyd8c3vJw860WhnohPYg+4q2udjf/ZgdDiyVPEyOB5AKpDnHB3HfsQr7upw+WqWUH56ylF2myWyP0uSmOrLJnUyFX1FFVx2R+/Rc0AjPmM+VE9UwPUkSSpFaRdKPP2nJxDYrReZwk/kfFmRvIqLAUz+rwSIH2JJqEB6NT//tMdxRu4lAKrpX29nqDSWCiMvew3D21OQYafzGGJ9GTn2n+Mwki3cbKpxLXxLxlCh0S8=

View File

@ -13,23 +13,23 @@ from uds.tunnel import forward # type: ignore
from uds import tools # type: ignore from uds import tools # type: ignore
try: try:
k = wreg.OpenKey(wreg.HKEY_CURRENT_USER, 'Software\\Classes\\NXClient.session\\shell\\open\\command') # @UndefinedVariable k = wreg.OpenKey(wreg.HKEY_CURRENT_USER, 'Software\\Classes\\NXClient.session\\shell\\open\\command')
cmd = wreg.QueryValue(k, '') cmd = wreg.QueryValue(k, '')
wreg.CloseKey(k)
except 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> 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> <p>Please, install appropriate package for your system.</p>
''') ''')
# Open tunnel # Open tunnel
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
# Check that tunnel works.. # Check that tunnel works..
if fs.check() is False: if fs.check() is False:
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>') raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
theFile = sp['as_file_for_format'].format( theFile = sp['as_file_for_format'].format( # type: ignore
address='127.0.0.1', address='127.0.0.1',
port=fs.server_address[1] port=fs.server_address[1]
) )

View File

@ -1 +1 @@
jR6BkXPX1vmZqU6AMnLXJNwHhdw+v6pt4DdqpF0bWorB7tFbxAJ7U47A2NjDPSHMVpe2qtUIpL2eBAgpQCcfEbQNyzqpJmtS2w2y2lCHfT0sb/TMjsMJLfLpwJiH4dkRfF/bP7rAw55DHj4Q0Mc/lzwxGZuTOd+sjp89WxBximdD9y2/BQF9IRlsVGQOU2pjB1Ko1Wg719gXfqBM/ezg1gC2M8vAqxRZq6jyaPIRs+Hl1GALR2gi0MiwYckopJMWGQHmgGIUt8S9bAR8M5wkmNK3Fbc7qoa+tGuthfkoVYYqhSC2Wdd9tmhcVyGSwDv77OnN4QK9MAFSJxQV2GejaOn1Dp96prtmkNn1350d8y5kjTNFV0h4Y5sGW0XtDROrg/fdbuxHf7cZhn+hThotZjNfWp7PXbc5mlwwc+gYTGIwNd7qV20WzdBodvc6X79pJP4Oy2fZbMGYPdHYjiC8yPV+SliqrhUBCYLZI0z667rGupnyu4qh0ciRrz33AKHuQZZGJfux4WFOfhB9mMUyL621ospkORGKaWwr/v7dePotGUSkUbDHBrliN/qOlgHXls9C6NDGvXr1z2nlo2VCgjQMAxkqh8Lc/DDOOBSbcZ4S8RczxBwevYdKVA+ZZ1FP+PuhA/x50JtctbjiltaBFeK8buuv25PMsFVsNuNp05k= o+152nwWH5xKg7nrK4ffYSeGjzitZS5LxvkC9Z0aa86J2D9gEIsUqDAQjh2ljuO+g4ik2s72T7Yb5HiZizhHfRfjwe22yjIj+NtK1Xoeh/VW3773bq5VCXAjfMbVU6GuGnNMndQOn4qrS/l12YLDhxXFKUkpwNU1TjRGo33ns1DFPNTf0dT7W/WpQkf/75Jlt6bMnGxFWDWYhc1wLySmwlVPj7GOKQTD9pS9MaB7eqpq/GO9gADNGWcTbz3GGs8iO8N5dxBHTnyHxO7P29aQL9bOvtrY0rxAopfy+TTcuE03qNDI6pCBjhYxCqL+GqiRrzmLJq9ZtvhNxvQ5+kvDDrw3ErFZbXoBOF4f7SeP6Tr9A6aOkLG579czsqNGSpHqkUPgvb38xXfSPv983pDvzhi3lo2GzNhAu4ZYM+/Z/Q32ssYBfst4joHAC9mcHmP37ZTKRiMfRz3hafkJlSmm2RQf5/OPYCz5ha8AAcs2CvqYMlOiJhP9Zx8AwtB9oxVlFPS+ZUJ9h/0waRVFBKQm1m70Z7odjJqT0ThTTJQEjuedfnNuxW1V5GtCi62NcwskulWOL2fXjmf9eh0u5PPn1tdqLIUmZXa9eqGU+LjZqA52w7V3sHHWoMYvfEC4SG9HXfZxd6YZdfPx12z6WYh4PnJLNUqd7bgfl4YswALJyaA=

View File

@ -74,7 +74,6 @@ class TRDPTransport(BaseRDPTransport):
), ),
tab=gui.TUNNEL_TAB, tab=gui.TUNNEL_TAB,
) )
# tunnelCheckServer = gui.TextField(label=_('Tunnel host check'), order=2, tooltip=_('If not empty, this server will be used to check if service is running before assigning it to user. (use HOST:PORT format)'), tab=gui.TUNNEL_TAB)
tunnelWait = gui.NumericField( tunnelWait = gui.NumericField(
length=3, length=3,
@ -88,27 +87,16 @@ class TRDPTransport(BaseRDPTransport):
tab=gui.TUNNEL_TAB, tab=gui.TUNNEL_TAB,
) )
ticketValidity = gui.NumericField(
length=3,
label=_('Tunnel ticket validity time (seconds)'),
defvalue='7200',
minValue=60, # One minute as min
maxValue=7*60*60*24, # one week as max
order=3,
tooltip=_('Maximum validity time for user ticket to allow reconnection'),
required=True,
tab=gui.TUNNEL_TAB,
)
verifyCertificate = gui.CheckBoxField( verifyCertificate = gui.CheckBoxField(
label=_('Force SSL certificate verification'), label=_('Force SSL certificate verification'),
order=23, order=23,
tooltip=_('If enabled, the certificate of tunnel server will be verified (recommended).'), tooltip=_(
'If enabled, the certificate of tunnel server will be verified (recommended).'
),
defvalue=gui.TRUE, defvalue=gui.TRUE,
tab=gui.TUNNEL_TAB tab=gui.TUNNEL_TAB,
) )
useEmptyCreds = BaseRDPTransport.useEmptyCreds useEmptyCreds = BaseRDPTransport.useEmptyCreds
fixedName = BaseRDPTransport.fixedName fixedName = BaseRDPTransport.fixedName
fixedPassword = BaseRDPTransport.fixedPassword fixedPassword = BaseRDPTransport.fixedPassword
@ -175,12 +163,11 @@ class TRDPTransport(BaseRDPTransport):
ticket = TicketStore.create_for_tunnel( ticket = TicketStore.create_for_tunnel(
userService=userService, userService=userService,
port=3389, port=3389,
validity=self.ticketValidity.num() validity=self.tunnelWait.num() + 60, # Ticket overtime
) )
tunHost, tunPort = self.tunnelServer.value.split(':') tunHost, tunPort = self.tunnelServer.value.split(':')
r = RDPFile( r = RDPFile(
width == '-1' or height == '-1', width, height, depth, target=os['OS'] width == '-1' or height == '-1', width, height, depth, target=os['OS']
) )

View File

@ -2,24 +2,22 @@
# Saved as .py for easier editing # Saved as .py for easier editing
from __future__ import unicode_literals 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 subprocess
import re
from uds import tools from uds import tools # type: ignore
# Inject local passed sp into globals for inner functions # Inject local passed sp into globals for inner functions
globals()['sp'] = sp # type: ignore # pylint: disable=undefined-variable globals()['sp'] = sp # type: ignore # pylint: disable=undefined-variable
def execUdsRdp(udsrdp): def execUdsRdp(udsrdp):
import subprocess # @Reimport import subprocess # @Reimport
params = [udsrdp] + sp['as_new_xfreerdp_params'] + ['/v:{}'.format(sp['address'])] # @UndefinedVariable params = [udsrdp] + sp['as_new_xfreerdp_params'] + ['/v:{}'.format(sp['address'])] # type: ignore
tools.addTaskToWait(subprocess.Popen(params)) tools.addTaskToWait(subprocess.Popen(params))
def execNewXFreeRdp(xfreerdp): def execNewXFreeRdp(xfreerdp):
import subprocess # @Reimport import subprocess # @Reimport
params = [xfreerdp] + sp['as_new_xfreerdp_params'] + ['/v:{}'.format(sp['address'])] # @UndefinedVariable params = [xfreerdp] + sp['as_new_xfreerdp_params'] + ['/v:{}'.format(sp['address'])] # type: ignore
tools.addTaskToWait(subprocess.Popen(params)) tools.addTaskToWait(subprocess.Popen(params))
# Try to locate a "valid" version of xfreerdp as first option (<1.1 does not allows drive redirections, so it will not be used if found) # Try to locate a "valid" version of xfreerdp as first option (<1.1 does not allows drive redirections, so it will not be used if found)

View File

@ -1 +1 @@
m7XY+kUSxXSqD276bNG7ChwBU06IOR75uTw9eXdSdBYqbvG4FhrUmL1OXRjfNRUh5kzUqkIggcJ5mj3b5Ws76QMWUjqcKS+SM2V5CGOzzPW+lFDeMLEnLCtsrmxZcCPacLce/utMlNf/AqLnraWAUCj8s+5CR68FeHE9fH3CRUryjHhvUPf51GDpMMXq+jnLotWn34xgZ2DI62Kp39qTdFYhmnZ3cGI3cHSks5Jo+uqeD1n0J+pF7vPM22aRknxW8XcLj+tXeUSw1QZVD0tXOI8RaUeD1jAH3bn0tBwP2spUfBwLFsxbWDULkuN89klfe1C/rardNJgIog7pUyyUD4HmeYQqd31Z5kfno3KD9NeAkEe8EaW99PAj3maLPrl8wZB6myYJfiq5k0LV0tzt5JNy20p61JOXFl4F04Ndb0m+IlcvYcknfecsF5RA6ID9U/0vX84y0OHtrEut1G5OBck95X2l0ksKHYcCqxhSKAAds227aeHI3FcWNsIpGpvtnQDrCrxM/lHO5mXk9+t4OVCG8dxawNrSoRmx1gUN/QvRiZvRFJ3WFZgo4OLc6ls62YBxm8FhWn+19NyVzXKI5U+Q5wJFAUkZ7+XnnHrvz75zvt/Ym5SvgMHSBMe7L+4njcEFq5UMfiTCEATorJXk03YDUrQI7uKiE0UTVwIJlGc= eY7ynpCTiB3Y0zGryBe7SAuc426LEi4+UbyAbMmZXi4I8uFA4KnO7lsQfdmfDjIzZqktTWaAQBGy0cRUEypa8fjbPc+TrkQmAJerLE5+DtH1RH2eHm9eH5uQHN7e4tn8vf3NrD5FCYdenOlVXtzCZhauATjy7VyjMha5RfPbuRDfHvNPcAwlE4Ty6Im8oKBa3kLmCczdI1eSKZgrXHrzDOyJYpIAlBE6RknVusGEcPnUbtoPxgBB3/YNIcy3AswToyElrmWeY0egpYm3skcTKtrrvKD5zc74ueTb5WZER0EzCfEZNHPwo6QnCbyo06U5u6dEkBg1kVFIXxEx/OoIXwpWWUWJn08cqVA/g7RNNdkXZ4iB9v4gRducZEpWGJbH8aq0tOSBOgTg7dxN1SGoayXQT0We3pCZL8Utl/gU5FqvCCGBeHE3dq/ELoAlFuq66AHV+stY08cUuURPObvgwrwA18HpmnppXgYY3RXmX8udfxwCCvOzya4iTuzC4mlQTj/QbYvKCtOgnP/upv7bEhu0+bGfTYSyLBKNFPItgIThc0ockn0BxSHuM0Ln2mK5COruhyYh3sNaQALFGST6pcBm2SvfP1HqWKzvB2V6a+xls5yqYtAR9RyHvZ1bc5QouwKNgqjzV9xSclf7QBwPjXTlOXvln6s4dj6LhLyt9kg=

View File

@ -2,9 +2,7 @@
# Saved as .py for easier editing # Saved as .py for easier editing
from __future__ import unicode_literals 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 subprocess
import re
from uds.tunnel import forward # type: ignore from uds.tunnel import forward # type: ignore
from uds import tools # type: ignore from uds import tools # type: ignore
@ -14,13 +12,13 @@ globals()['sp'] = sp # type: ignore # pylint: disable=undefined-variable
def execUdsRdp(udsrdp, port): def execUdsRdp(udsrdp, port):
import subprocess # @Reimport import subprocess # @Reimport
params = [udsrdp] + sp['as_new_xfreerdp_params'] + ['/v:127.0.0.1:{}'.format(port)] # @UndefinedVariable params = [udsrdp] + sp['as_new_xfreerdp_params'] + ['/v:127.0.0.1:{}'.format(port)] # type: ignore
tools.addTaskToWait(subprocess.Popen(params)) tools.addTaskToWait(subprocess.Popen(params))
def execNewXFreeRdp(xfreerdp, port): def execNewXFreeRdp(xfreerdp, port):
import subprocess # @Reimport import subprocess # @Reimport
params = [xfreerdp] + sp['as_new_xfreerdp_params'] + ['/v:127.0.0.1:{}'.format(port)] # @UndefinedVariable params = [xfreerdp] + sp['as_new_xfreerdp_params'] + ['/v:127.0.0.1:{}'.format(port)] # type: ignore
tools.addTaskToWait(subprocess.Popen(params)) tools.addTaskToWait(subprocess.Popen(params))
# Try to locate a "valid" version of xfreerdp as first option (<1.1 does not allows drive redirections, so it will not be used if found) # Try to locate a "valid" version of xfreerdp as first option (<1.1 does not allows drive redirections, so it will not be used if found)
@ -41,7 +39,7 @@ if app is None or fnc is None:
''') ''')
else: else:
# Open tunnel # Open tunnel
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
# Check that tunnel works.. # Check that tunnel works..
if fs.check() is False: if fs.check() is False:

View File

@ -1 +1 @@
F12wItI+7Bo+mnANcC0IX3hdcr7d/V+XbnX7sH6zKpw7q/gEJBZW3xHaKpYDWBYYsR5pkCiJ+zawt7lHcc7+GmPJYIpFeXZeGlJWjrNN5FqqI02C+sRnuImX9DNggHGNW0hn3mGdE6U/wB1T6clXtoMK6um8cpLVQtfcVUKn1/gki4dMg+0NSJhQHfBpeQ1yffO/VLaTBWB2qnnQUjYNkqGo0x+nxJ4G67jqJU/sh0vM0OyT3JQwgIH+AidCqL694amngAprWzlOiABL3NoF/yJjn9bBfLHhHtsVp4v1YsYjTWXMegVRK8HWGvAaiGzRbOAdfjZl8GejaROSpLQTo5djBwuHN7ULtnNpk0ZCYJP00AKvQU6yW3omm5c2vZwVc1yUj5fzxnY4QY6VcpoSK15p8wR0FEWaY6kdE4bf2PWwaBGcNVGIe7itmwKv0n7AhZsJG68zmZOR45PNx1ljgFCco/Sg+rGnAxk09c0DtZNIs3BR7lhcUUHo16EFTHeUI8RwxyMKRBW75bTqrNMDUtwk7yxA58ec/mAkZmdlJ5MLYOAc1iL3U+qd8ZKxMOiwo9ZWZNsgLALXfKcg8/DGponnsrPXkmEY4CigW25t9fdooJ8WwrDTssYQJdmmOgXAkj5YyjcEryF73gXaGYL2j9tu6VKEfs9cY5WtGvfJUmA= qohDf0W4PxfiAn8RDcQrZcl3v/V6+B6Zj2Ba2FukDlm+XXEbrNE0dHONXJPd6zTZ+lWRvYrTHKWWyJVgRoN3gxhEghY+iw+4B4yX6uwxynb/DtHNVg8wG1tFzFfGnHCua9E7+iY+5Y6oDJo76tOmLGYZNGmOA0vwn5IDNqIKTqnAPzJnNbpHrePV5LO/xF59aZ2RthxhcBquSpkZA8Hm9z7Hw4oagOysqSknXTxdyeLBxQLc+KpGXhdo8jbD2In+21r/9V3pqFUM5AyL85tl5eunhDDyKt5KvN8vznMFCITxpJWQ8BSWtqOqNiJvhfqSXm3CVlATeLEDOeuVinF/P4AYzw9qybagKyxL0GQTSATXEmarevAKsZ5nvY5wPUx1BL6OloUWXHjlAvSDCBIRyde3ravDWtT+cajQGyinD8Mhb4emOutr/syirKZXDK8orP3L0gEMCqERKHrv0IpbIldyiyZ2Pt85lvtAQ0nYkPBUnA/kodBrESgJ0DVFqZLEx1YhzEEHEVGZuklt/hUpOzOhtTGhT2MHG2la8ANYJo8pQ+QZTaMtZHGH4uI3r6AxrI7DIBa1K5JZn66jC5pFik5Y7KcJR9d+D8QZU8QVFK4pz5oO6RI7xzka48MxhV3CFvRQ+wDeukfOWS1xThpabxPQbsrc0O/KLFkRrzsHHco=

View File

@ -7,7 +7,7 @@ import subprocess
import shutil import shutil
import os import os
from uds import tools # @UnresolvedImport from uds import tools # type: ignore
# Inject local passed sp into globals for functions # Inject local passed sp into globals for functions
globals()['sp'] = sp # type: ignore # pylint: disable=undefined-variable globals()['sp'] = sp # type: ignore # pylint: disable=undefined-variable
@ -20,18 +20,18 @@ def fixResolution():
import re import re
import subprocess import subprocess
results = str(subprocess.Popen(['system_profiler SPDisplaysDataType'],stdout=subprocess.PIPE, shell=True).communicate()[0]) results = str(subprocess.Popen(['system_profiler SPDisplaysDataType'],stdout=subprocess.PIPE, shell=True).communicate()[0])
res = re.search(': \d* x \d*', results).group(0).split(' ') res = re.search(r': \d* x \d*', results).group(0).split(' ')
width, height = str(int(res[1])-4), str(int(int(res[3])-128)) # Width and Height width, height = str(int(res[1])-4), str(int(int(res[3])-128)) # Width and Height
return list(map(lambda x: x.replace('#WIDTH#', width).replace('#HEIGHT#', height), sp['as_new_xfreerdp_params'])) return list(map(lambda x: x.replace('#WIDTH#', width).replace('#HEIGHT#', height), sp['as_new_xfreerdp_params'])) # type: ignore
# Check first xfreerdp, allow password redir # Check first xfreerdp, allow password redir
if os.path.isfile(xfreerdp): if os.path.isfile(xfreerdp):
executable = xfreerdp executable = xfreerdp
elif os.path.isfile(msrdc) and sp['as_file']: elif os.path.isfile(msrdc) and sp['as_file']: # type: ignore
executable = msrdc executable = msrdc
if executable is None: if executable is None:
if sp['as_file']: if sp['as_file']: # type: ignore
raise Exception('''<p><b>Microsoft Remote Desktop or xfreerdp not found</b></p> raise Exception('''<p><b>Microsoft Remote Desktop or xfreerdp not found</b></p>
<p>In order to connect to UDS RDP Sessions, you need to have a<p> <p>In order to connect to UDS RDP Sessions, you need to have a<p>
<ul> <ul>
@ -63,7 +63,7 @@ if executable is None:
</ul> </ul>
''') ''')
elif executable == msrdc: elif executable == msrdc:
theFile = sp['as_file'] theFile = sp['as_file'] # type: ignore
filename = tools.saveTempFile(theFile) filename = tools.saveTempFile(theFile)
# Rename as .rdp, so open recognizes it # Rename as .rdp, so open recognizes it
shutil.move(filename, filename + '.rdp') shutil.move(filename, filename + '.rdp')
@ -75,8 +75,8 @@ elif executable == xfreerdp:
try: try:
xfparms = fixResolution() xfparms = fixResolution()
except Exception as e: except Exception as e:
xfparms = list(map(lambda x: x.replace('#WIDTH#', '1400').replace('#HEIGHT#', '800'), sp['as_new_xfreerdp_params'])) xfparms = list(map(lambda x: x.replace('#WIDTH#', '1400').replace('#HEIGHT#', '800'), sp['as_new_xfreerdp_params'])) # type: ignore
params = [executable] + xfparms + ['/v:{}'.format(sp['address'])] # @UndefinedVariable params = [executable] + xfparms + ['/v:{}'.format(sp['address'])] # type: ignore
subprocess.Popen(params) subprocess.Popen(params)

View File

@ -1 +1 @@
noBupbQ4cXphbjY5YyaiPhqdv7z47GKvj++IvZHyyyit+9wWgZGxaPx+bLmqvr6Rz+ZJrxXYcW4qk5+CN+AKDe2aoGzbusAziBdd0Oluik09Vl5EHq1+OPUp/VkdNHu3M6EB8SiwwHM0KGWz5PEvegp5V3xyaJutnr7JcEMrMxGL97iCbYtKT3G7BaZOY/gCO7BPTexJlyjZ66xb8+hmUTix12Cnwhxpn2xEuZ3N6raGtbmgOHAp6SHz4Y78GBnFhHrhu/EnkHZVgSIoQbyW9koB2tBYdQi3915sUvTLIdHuN3kjz9UKSH/tPJVL+CGrBE/+TXJe90xOTBbzRAgZcUtUjCNyDULhRCT87N1sRH5RFJNsvQv3cqYTgnVUBF5Oew8guTj0UdAAB6tGtUdZqFXz4NspA+f+PkzLmUzmd8y6hqwX4Ojbh0SL0N3Tb5SJw+uOcKTN/FNSEavWK62alPyA36VDf0IIJLV604DhxvOeUTWYz0H7TnrME4e5d9F82iYPCre71yNofzHihZ5SelKJUQ0AniZxQIY+7vYcZNRpcEkGnt0oTWHDvXeTqDwtAkvzwt3QvTsl7/i3yDQ2XYJInICLWaM81op/sVOSM+DSgEd0n+O3r1SE/dD72u0VhSMZYYKZw0ZApcFXMHBk7c9DcjVYMXoMFMKqsqnoe9A= Ro5JrmfPQnCaJAd5mc1x+wKPoB3ipy3ueRnbD00lUtKhTpLxNm2HGovfEk8CbL3VOzpDyvvavWGo+wiU1qpU1baF5/gGzGYuFQiFB4da+kwjSmd8Jr6p9p9KS3eTkRD5GiWV5zBCHNnlO9200+gw9tvMGllZ65chkEbCHaN1MGiP6Af3wi9hK9yi2QR8sqpxqJ06UgolK+HM2OFuZTf28BVNZACcL8rZmCpjVN27nv9WE7nYnICr5OXL9VV7uclZuLH9VjZkkxpJWH3o8E8ftO6MqbOBeLwlyZgQU+PlGHu4rXtSjH39h9tSLjbAkF4YrT2n6yO9BxrEwqasW+mwnMqm0uI4Cpj60nKrm9eTEIPMhsgZRGyCcA0l/ozzBKwtOfP2OLu1bPdUNdU7XlW6ctgjcfczukCU3/aEbVACkv+6nsg7EFoFkPW4RN+xbB5URaTlA7ddfbjKkCQjY5h/ZeEEm0Nj8e+uIYzOmA9/ftsQOWyhTkwRqK4o+bylQFWSQJhGWPB7hF4jY01yPo7sLY9H/YMci2ds1emys0K4tyyBDQOjcqRz6H0owvjPmWAPflJ6w+g39yklzPdegj4zHzbCtj0NFkWY0xGxhEclG/meTh1txl1SflU1k2E7LtLlV8x3Lgm1FF/QNFH/u0bBlXHg8AMik6Qi9fcf5NEveKY=

View File

@ -18,9 +18,9 @@ def fixResolution():
import re import re
import subprocess import subprocess
results = str(subprocess.Popen(['system_profiler SPDisplaysDataType'],stdout=subprocess.PIPE, shell=True).communicate()[0]) results = str(subprocess.Popen(['system_profiler SPDisplaysDataType'],stdout=subprocess.PIPE, shell=True).communicate()[0])
res = re.search(': \d* x \d*', results).group(0).split(' ') res = re.search(r': \d* x \d*', results).group(0).split(' ')
width, height = str(int(res[1])-4), str(int(int(res[3])-128)) # Width and Height width, height = str(int(res[1])-4), str(int(int(res[3])-128)) # Width and Height
return list(map(lambda x: x.replace('#WIDTH#', width).replace('#HEIGHT#', height), sp['as_new_xfreerdp_params'])) return list(map(lambda x: x.replace('#WIDTH#', width).replace('#HEIGHT#', height), sp['as_new_xfreerdp_params'])) # type: ignore
msrdc = '/Applications/Microsoft Remote Desktop.app/Contents/MacOS/Microsoft Remote Desktop' msrdc = '/Applications/Microsoft Remote Desktop.app/Contents/MacOS/Microsoft Remote Desktop'
@ -30,11 +30,11 @@ executable = None
# Check first xfreerdp, allow password redir # Check first xfreerdp, allow password redir
if os.path.isfile(xfreerdp): if os.path.isfile(xfreerdp):
executable = xfreerdp executable = xfreerdp
elif os.path.isfile(msrdc) and sp['as_file']: elif os.path.isfile(msrdc) and sp['as_file']: # type: ignore
executable = msrdc executable = msrdc
if executable is None: if executable is None:
if sp['as_rdp_url']: if sp['as_rdp_url']: # type: ignore
raise Exception('''<p><b>Microsoft Remote Desktop or xfreerdp not found</b></p> raise Exception('''<p><b>Microsoft Remote Desktop or xfreerdp not found</b></p>
<p>In order to connect to UDS RDP Sessions, you need to have a<p> <p>In order to connect to UDS RDP Sessions, you need to have a<p>
<ul> <ul>
@ -67,15 +67,16 @@ if executable is None:
''') ''')
# Open tunnel # Open tunnel
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
address = '127.0.0.1:{}'.format(fs.server_address[1])
# Check that tunnel works.. # Check that tunnel works..
if fs.check() is False: if fs.check() is False:
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>') raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
if executable == msrdc: if executable == msrdc:
theFile = theFile = sp['as_file'].format( theFile = theFile = sp['as_file'].format( # type: ignore
address='127.0.0.1:{}'.format(fs.server_address[1]) address=address
) )
filename = tools.saveTempFile(theFile) filename = tools.saveTempFile(theFile)
@ -89,7 +90,7 @@ elif executable == xfreerdp:
try: try:
xfparms = fixResolution() xfparms = fixResolution()
except Exception as e: except Exception as e:
xfparms = list(map(lambda x: x.replace('#WIDTH#', '1400').replace('#HEIGHT#', '800'), sp['as_new_xfreerdp_params'])) xfparms = list(map(lambda x: x.replace('#WIDTH#', '1400').replace('#HEIGHT#', '800'), sp['as_new_xfreerdp_params'])) # type: ignore
params = [executable] + xfparms + ['/v:{}'.format(address)] params = [executable] + xfparms + ['/v:{}'.format(address)]
subprocess.Popen(params) subprocess.Popen(params)

View File

@ -1 +1 @@
akjWk2TMZx4h/STESjRKWvyxDs4IKdIdX2e2bX2Os6wDhFm40THwJENyXzOjjvDwIv77WgdQJLbBAbKusVA+GA70slmA6W+cdG5pMFFtjgna3OxNo8ClSHHRKer6cwz4FJ70k2nihpTfsQOIlUBr60Gt4/3Il5c7AAUED4/IpekS3MwJfWvsxEpUujP+nsQSEeIvhpFD9oqfA3WnCGD+OOZlXfMe05fNaWKA2/UmtxQlo0rvRsPV4puGjWWHZxmdYVYIvSIcNkqGc6nIxmMmO5NwHXRY7JgoCBEAeLExVcn4ZUW+qPWQji+6tvsiycIfydT2A5ZOUcpbvIY8l1zLR4HaBs6+RiAa+fVEwIlnMl4qvZl2eP7ljo2RKZeaD/t4H+9wLa1kYVEE7/suVEny/Pap6I1BkDHXh6qEUn90pE8QPCFbutzWmbVXpiE+5UhPAp7L4DMc65Oh/qW8QZVzjpB4Np6LRnxMe5Qwb4+uFYNJH2H04Bmbgor+StvEnO/4rOAb1rCOjKDD1V8tzYvUAfizXBLP1ImiHHxJ6tg5s7ztUb+vyH1rD1U5OktpkzfIaBB7/sHG87DnF+e+PDb/mKY3IKyRGL4ndf7yE2TEbOgXqH6dJUuFh1V9JALWFcaB3fPN5FC0R/EB+3iBp/RsEv5ABrqGnOImMWLgNU1OXEo= eD97r30FTBTbnkNU3qWsqJoiB8jyrpXhN3LcjYILryptrOLhxY5uTw9wfXGkFeB8UIEJl/QMjH85t6E8pKPQdzs35qqH5DMgQWCg/QCmhTa8T8gqSqXT3ZWSTkzvyVXu5aVM8TYdLbsQqZ6o7Y4DO6vt5h2rm+jVLHg7GlhALDaV1WbQKqjMLekt6QLb3M3hN2YYA0j7XbeunplgpzyS9BeMvRtt4dRaPs6yrWP4AmopP+2oYk4qTDzKxiZBje0548n+wA3oYVQdOeYtAVawApg2Ve7Jst3pkG5qAMvzt08Iiu4wIKWJrvUTsapWm3iD1N8dVgheh054L6Nv3MpKvifwhJfY1XeATIFJkvCFw8VAuJBMko1cEcsjmPAEhLCnwBPnOvPDsrvt7CEX8sBiYbZX8M2PR/UHHmKvJ7RE8LEsmhK+5LqhbwnmUypFwuEYciQo0Yg26xIKTRpldQG491a8dGiqjcLI5Qw5F/xG7xzgIsq6puyNXW3Lmi3Iu/cYXmOdleQHWtjfUs4Je+X7f1MHkGduuy7S+b/TKRooa5diVPpmZzAk1jBZAFAaFu+AqaieotbM2Pu3QtPxtiG/2rQSQtgsWGGV+MGKDpBAcTUeKwt9ZYPpHkumyDsSrKy5pt4y2aU/9AcdYiu5Ry7HOev0PygMusSGA6EGzBkTWHA=

View File

@ -17,23 +17,24 @@ from uds import tools # type: ignore
import six import six
thePass = six.binary_type(sp['password'].encode('UTF-16LE')) # type: ignore
try: try:
thePass = six.binary_type(sp['password'].encode('UTF-16LE')) # type: ignore
password = codecs.encode(win32crypt.CryptProtectData(thePass, None, None, None, None, 0x01), 'hex').decode() password = codecs.encode(win32crypt.CryptProtectData(thePass, None, None, None, None, 0x01), 'hex').decode()
except Exception: except Exception:
# logger.info('Cannot encrypt for user, trying for machine') # logger.info('Cannot encrypt for user, trying for machine')
password = codecs.encode(win32crypt.CryptProtectData(thePass, None, None, None, None, 0x05), 'hex').decode() password = codecs.encode(win32crypt.CryptProtectData(thePass, None, None, None, None, 0x05), 'hex').decode()
try: try:
key = wreg.OpenKey(wreg.HKEY_CURRENT_USER, 'Software\\Microsoft\\Terminal Server Client\\LocalDevices', 0, wreg.KEY_SET_VALUE) # @UndefinedVariable key = wreg.OpenKey(wreg.HKEY_CURRENT_USER, 'Software\\Microsoft\\Terminal Server Client\\LocalDevices', 0, wreg.KEY_SET_VALUE)
wreg.SetValueEx(key, sp['ip'], 0, wreg.REG_DWORD, 255) # @UndefinedVariable wreg.SetValueEx(key, sp['ip'], 0, wreg.REG_DWORD, 255) # type: ignore
wreg.CloseKey(key) # @UndefinedVariable wreg.CloseKey(key)
except Exception as e: except Exception as e:
# logger.warn('Exception fixing redirection dialog: %s', e) # logger.warn('Exception fixing redirection dialog: %s', e)
pass # Key does not exists, ok... pass # Key does not exists, ok...
# The password must be encoded, to be included in a .rdp file, as 'UTF-16LE' before protecting (CtrpyProtectData) it in order to work with mstsc # The password must be encoded, to be included in a .rdp file, as 'UTF-16LE' before protecting (CtrpyProtectData) it in order to work with mstsc
theFile = sp['as_file'].format(# @UndefinedVariable theFile = sp['as_file'].format( # type: ignore
password=password password=password
) )
filename = tools.saveTempFile(theFile) filename = tools.saveTempFile(theFile)

View File

@ -1 +1 @@
V8FP9WC6BBzo9NnAZNKznkQE5Xdrz1D4KDif+rw7x+0X8MMNbzhB2g/Ukjyvdc1KPBH1T0M89LLFw7XNHwHWLrNmnAppyBCnBgJuIReWPBKvtSqyYRapDydykx0Xv9s+vbaI+LO9vPnO4KSZbxgbfocGhNzV7kYE0pwlXV5N8Qe4dpr2GvnnXwMHv/UGBBRf+KnGIa+/h77+qrejW8dvlvo4od0enH12oh1zQJMZrd7LUx+1vds4/IDPs5seu1KVVNDHawcDg8Fg8RKh+K5kAK8O/kHalulbBcGu3woFxFqERTf65bCG5Cj/476b6JoCk1enyE1HN+0DzrNqvJakim/mAWYIkfkqmsLZ0bu3oFJHfFDixbdj+flMwZ7mv9qNjXFBEp2G6OTGn8I5vEgs0ZFKAQi4sNYyso92k5um3fady1jr+Xf9CMTJsmbEuAIafs44k/9BRpBKHfTaJudVGB3Y2l+/wW2ynh7/J9sO8AkHPrmxNmKpQGHLUpdoHATRKq1AJvZf/fb+cTu/VFF2qigbFk+oApOh6KTeWhU/2qOIWPCczQ/9hbExaTSCVlQ6coQbHBU+S0sHVlqq+zxf0sWhfXfduwM3dqRHKW/pm57gItbH7HgS+yG9o9SeLVaxB52p4019j6Da+DAfmrovYVqPxrykA6kKnka3sY7cCHE= EbLkCRb09VB7luaOpj43/F1tiPfnw8TPO3bCRqasEwWEi1S9BvK/hgpfTuCKFsKJ4q8+X1lGwPbIGquryzBaa+g+Q9o74ZMaP7hLZH2ko9G32Zd56B6XisHg7qfJC46pjwrHEI7jBec8Du6cBEfi3FCg3i1lHxUXPgZeLWrmuSv4x/HZKYGtXTSMI77ZL6zi8ZFkUk1pceyo9aNj9Zr3uok4Ddg/z/OSU+tD49tkJvIj8GTbpl0Wf4gu02ikrN+nF5+Yu5zac2nz26yPnAXJh1PecoKw/uuwDW5hpvSAwMfBIACezD1r5wfzjpMLqfbIq8VKca57USsi+1R4kwbV1dewTotwh6pHOj8bcVk78LTPqshdVud56390D3jV4C7fQtdA3+CWe6M6SScAwu7a0zDo2CNagmQJuBmlbmxjYgKFsUfjQTZehESCHBLpGiXPuIipU7A+F0iWYLUMKtrT1twfWDaxkCDSO5PGt+hNbt1Jie4qCQ97SvDx4cReaQomkVm4hAaAphS+/HOhZSTQ/+jfGmOYX8MgrM43c3o7r3Avg7heDn2r7CCMMeC5Kh8Clh3nzvM/F0QjvY9TibvlzO1qzyylt5U2OXrJ8agZ8Rpu4IJJQFL6DubVZAlPjlHAJ2d+8Vv8QNi42HEc967RDToaStoeofS6d4eft2SOUP4=

View File

@ -20,21 +20,22 @@ from uds import tools # type: ignore
import six import six
# Open tunnel # Open tunnel
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
# Check that tunnel works.. # Check that tunnel works..
if fs.check() is False: if fs.check() is False:
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>') raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
thePass = six.binary_type(sp['password'].encode('UTF-16LE')) # type: ignore
try: try:
thePass = six.binary_type(sp['password'].encode('UTF-16LE')) # @UndefinedVariable
password = codecs.encode(win32crypt.CryptProtectData(thePass, None, None, None, None, 0x01), 'hex').decode() password = codecs.encode(win32crypt.CryptProtectData(thePass, None, None, None, None, 0x01), 'hex').decode()
except Exception: except Exception:
# Cannot encrypt for user, trying for machine # Cannot encrypt for user, trying for machine
password = codecs.encode(win32crypt.CryptProtectData(thePass, None, None, None, None, 0x05), 'hex').decode() password = codecs.encode(win32crypt.CryptProtectData(thePass, None, None, None, None, 0x05), 'hex').decode()
# The password must be encoded, to be included in a .rdp file, as 'UTF-16LE' before protecting (CtrpyProtectData) it in order to work with mstsc # The password must be encoded, to be included in a .rdp file, as 'UTF-16LE' before protecting (CtrpyProtectData) it in order to work with mstsc
theFile = sp['as_file'].format(# @UndefinedVariable theFile = sp['as_file'].format( # type: ignore
password=password, password=password,
address='127.0.0.1:{}'.format(fs.server_address[1]) address='127.0.0.1:{}'.format(fs.server_address[1])
) )
@ -45,9 +46,9 @@ if executable is None:
raise Exception('Unable to find mstsc.exe. Check that path points to your SYSTEM32 folder') raise Exception('Unable to find mstsc.exe. Check that path points to your SYSTEM32 folder')
try: try:
key = wreg.OpenKey(wreg.HKEY_CURRENT_USER, 'Software\Microsoft\Terminal Server Client\LocalDevices', 0, wreg.KEY_SET_VALUE) # @UndefinedVariable key = wreg.OpenKey(wreg.HKEY_CURRENT_USER, 'Software\\Microsoft\\Terminal Server Client\\LocalDevices', 0, wreg.KEY_SET_VALUE)
wreg.SetValueEx(key, '127.0.0.1', 0, wreg.REG_DWORD, 255) # @UndefinedVariable wreg.SetValueEx(key, '127.0.0.1', 0, wreg.REG_DWORD, 255) # type: ignore
wreg.CloseKey(key) # @UndefinedVariable wreg.CloseKey(key)
except Exception as e: except Exception as e:
# logger.warn('Exception fixing redirection dialog: %s', e) # logger.warn('Exception fixing redirection dialog: %s', e)
pass # Key does not exists, but it's ok pass # Key does not exists, but it's ok

View File

@ -1 +1 @@
Jnc7MGVnKf5HG89jPUC/bdAebjCX9g6Afl9MX9d9vgpFvopcRmAw5pQrvGi+J9W8jLjg//kNoatGtZ7OCV6Umt7/UQjJyVUQ2bqGm3qBMagtr00v82vz5uUgald/kxvhHPdNYLP8ZKzSs5jESF+WeyKfF2mIhm4CpZLjmwwfQviG7V/Yr7NgENRz+gCaaGlTuz2JIxF7shZjw/zZqRzJQ6CtYozRXjJRTgO+BNNsN+k/dFKRZnRHsVIPQHooPCQ/5duDzWnqG3wEwOx4aibrOb1OSmhOtA0PQjt0pKUUveddRnKMbhqRGFA2+KbYE2pcDAaYCWTI27JEP+gPSoqjFX+8b4LnnM9qrnam5LMQ4EdURdb5/LZdAUyAm8MLglzNBhUbSzBC45PGG9Hs5lf6Hx8RCvZ5yzw17sJfAjJL8CbQoWE2/jy06hidvNDmUJbl/5NSuwAvXzB162qdGRSEpz0q1K6uYl+kmvrSgQEyu6V4P4ITbeHJmVmaaPXK5tPvf2SQhScUhz80Qclh0dE9ZZFJ46KjLohqBgRac0//MIVpuNVjvDuom/p84K3HiY0MUV8V/3KoBcDofR3T/jAwd/0ZgEkwoRNFBsBpseRXkacDq7j9zkpe0S8a5W4gQnay8tJmLmKjKd16OWhqpKLkJKVs1e87Gy1osswwU+f87AA= PxgUpszz7f/yliXrWhEzYUPd8D4bTMhI2Wq94xh8ZszcHVWwkwudtv7M9on3QJ9vDQ/E7YF9bFsuM+Vql4Fjcnk8sJMHiToXXJADIvNPUOWB24inPUxSkJGiZVITpfMhyNFzcykxcQ7U8U/UepK7ZRdIVQWJpR23XGTARmBDzxgYITS3LrIhpgtJ3jiQZov1K3Ub0oY3GUUK6UxidtRov70e/S1btHi7U6OvjT0Q/PhJBpxMBm0+xf7IF1t//dcGg591SOn1s97wjWhvSTVVFm/P1+7Xso6ZJuWVd5P+yTSH5v9xVTLcARkKRou+0I2syrSb6+zn2FyJgthp3PWYoepFJ+t946qDj//ew6fEBP4p4PcFeQ4Uuc/1F7/bKbNdHj6UzE06qmzbMpYl8QD2DXlL0zrUTlKFEUIKGSdmVmeWFgMrp/yJyUJaFceX0WMSC88Wj3MUW8qO0eTG/KtwgFRYldNt+l9xXl46pp/CsyIRnZQmWf2Lv3+YBU4okn6EPdS9V23Oy+jC4WkgOdHGwaP9weL8BLEIbvpPwgtAGJm9v6MuLT/VXf9sx5PidA+e1XUuvkR7yq7LtfbjdjTKvWtKtaPUiBnCQMc0uYGB0YnpaEj6WU/7yiahbEBZzbShbWMFXbV4RuV+lQsfHYwBNbAxbckhgEK2+ASpNb/7au8=

View File

@ -5,7 +5,7 @@ from __future__ import unicode_literals
# pylint: disable=import-error, no-name-in-module # pylint: disable=import-error, no-name-in-module
import subprocess import subprocess
from uds import tools # @UnresolvedImport from uds import tools # type: ignore
executable = tools.findApp('remote-viewer') executable = tools.findApp('remote-viewer')
@ -16,7 +16,7 @@ if executable is None:
</p> </p>
''') ''')
theFile = sp['as_file'] theFile = sp['as_file'] # type: ignore
filename = tools.saveTempFile(theFile) filename = tools.saveTempFile(theFile)

View File

@ -1 +1 @@
KVdckBRbRq0iPwi9PwkkNDA7lLaopVALN+nNHanqrbNT6BT382WIx2aZQl542OOR6lr1y9A8nRDqpuqrWzwQvHESoetb/apvWKtM0H8qH3kygtN3jUwyr9854LQ3woaiykPOwBQC0w0JnSra1aeNM+rCbL035r40d7yYqHyul9fCkCuSMrnMamSBTqykKSGUOZ+dY4Wr9jYD2CEsyD3jgULlLTyTH0rVgE/1I2jiebzjgUMPHxdW1T43TXt4UQdPXb2AlUFRCgCxwxZ/0bE3bAOuxvaYG1oejT0lJPBswqlrQcYLDoAbd9hqotWqfTEB5qFEd2Xsr3TzO7ijfMlAE/UpU3Foybc8+FB90d0uGGjunsYyy+y4C5B6a/XkYfV25X2llSk21mOMGlzXDvY9FaH2CHIfiN7nUOuO1hl8p5aLr16sNMPibcRvx3bLvamexAAPMLB6r8hyQViZIHhMIT+DLXOWN3LyW4U+dR3QdG7KCF06r90OZ39Wf4p6ZXTJ0xK4NJHMRn3UznOhjmHSWGGrDdM5e3N8wrvCPOAHlP5JzWb4aVAFjTUGxxjVGTZk5qWm00o1JGTwVwViTsYfqyCvxXJ1oUq4xiOwjuiheTjD00rc1OUwkGYWwTs1qVVE/q5/V6MZSgiOlteh9bx5VADzGoIyhfR8GjIpi6wFNzk= Ke13liZe+UPqfKgJBONj0zbw3IaTUVMr5YA3fDbf7tnOf47E7CwFE5l8cBZhpHwg29o/KFZyCDaQ5fwIyT2fQHa4q1HN1I5ra+MG+EFM2wPxOD8y2ZE5QzlVNOt2NvZ4mPJI2RKHaTSd0+wtEUISuY84DAgu8mKG06N1+M2E3yjN6KA2tgZBWiURkaJMuzwDYFRE0kdWi23KdXp2m1EYRf8EBa5klkYAT/cwHgX5iM66Mc92/JirFs/9qZ4bww57fee59gnq1RErmfWbK+V0YX1ROZ4WWs+dYE1cK1zmY/oTtJlmeu6HOkPYEXZldeu+od5/bFdeQzPsVwTTraZsDjeIoyX23YLPUz2hf8vRUhI/JDw+QVsG1xUyKQBmkWYc2W6Gqd25kl2pIOacVy+fzMSrufcd3ekkFrxJbBe1Yc1I9WDwxuG7MaA3atycKZcjLS5hSYXoIwjw7nWlAOYdaxW6DjsmH96LP80IgwumOhrB11+LrYzN+tzBpU+jCpm+3T2Dhpm/FciidCrr0OE1kBC+y1H6eq6H7EFm0nvDG7gOoRw4RZVqdQrTjSs9D+clz8c2K3T16/8cekJhIA6unHHdh89ESmf5liK5cYUNPBZ0Jk07BGAUEHSs/sXXQLM2daUQxyKcuPlrkEawqUhK5aQSV96XCZ/J+PkPahShju8=

View File

@ -5,8 +5,8 @@ from __future__ import unicode_literals
# pylint: disable=import-error, no-name-in-module, undefined-variable # pylint: disable=import-error, no-name-in-module, undefined-variable
import subprocess import subprocess
from uds import tools # @UnresolvedImport from uds import tools # type: ignore
from uds.forward import forward # @UnresolvedImport from uds.tunnel import forward # type: ignore
executable = tools.findApp('remote-viewer') executable = tools.findApp('remote-viewer')
@ -21,31 +21,28 @@ if executable is None:
''') ''')
theFile = sp['as_file_ns'] theFile = sp['as_file_ns'] # type: ignore
if sp['port'] != '-1': fs = None
forwardThread1, port = forward(sp['tunHost'], sp['tunPort'], sp['tunUser'], sp['tunPass'], sp['ip'], sp['port']) if sp['ticket']: # type: ignore
# 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>')
if forwardThread1.status == 2: fss = None
raise Exception('Unable to open tunnel') if sp['ticket_secure']: # type: ignore
else: # Open tunnel
port = -1 fss = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket_secure'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
if sp['secure_port'] != '-1': # Check that tunnel works..
theFile = sp['as_file'] if fss.check() is False:
if port != -1: raise Exception('<p>Could not connect to tunnel server 2.</p><p>Please, check your network settings.</p>')
forwardThread2, secure_port = forwardThread1.clone(sp['ip'], sp['secure_port'])
else:
forwardThread2, secure_port = forward(sp['tunHost'], sp['tunPort'], sp['tunUser'], sp['tunPass'], sp['ip'], sp['secure_port'])
if forwardThread2.status == 2:
raise Exception('Unable to open tunnel')
else:
secure_port = -1
theFile = theFile.format( theFile = theFile.format(
secure_port=secure_port, secure_port='-1' if not fss else fss.server_address[1],
port=port port='-1' if not fs else fs.server_address[1]
) )
filename = tools.saveTempFile(theFile) filename = tools.saveTempFile(theFile)

View File

@ -1 +1 @@
MwVxZsoxUK+gcMchgM9c3iYky6K7KZ+3z34uZCgpJzvad8dH7lwihqrJ+7tlk55mZU/ea+J4dqk4EgMX1LGzzm9SyE6/9Yz86lfNlj/bH4AtnwkWUHEtKUizTOCpZlhFjRs5Cif6LICeVzGLnPx27vpKzHhbre95kpsmCzJ33vmMnB0IsCrFBSmJw4BdxUcf/+n1CyA5WiUqzIXC1cIkJ212plpl6n+WP0tc40A7WVVcnMV7Kpel7xyihI+hSvpSwOubgXTbdS01IzCD6ecG35VPbuBoOK/rl7yfTVexo+grfiDtTN9kRkXzBkJIkYaPlIhEJNODcGv/23ni1Dx0+45TmFFdfthspZobEsA0b9YKpMZ5FhH1cx5sDQtZTEW9/YrA+cP8KC4UJ+uRuebbF96rKJL6l1OYX88aWoFtRNFf92QvSREwJFmA9MGnpHphdqo4bmwS06CEDn6KE3AxR76ICcJvoioBvO+F+X7CRll7KNJumIB60k74XNxKdBdlR8fV+PDY1kP0RvwQYii2z/40zRFB8l7BnvSs8OgSwACHoKDcsESAUvAwVSi6q9mmTZkKvrpDu0fZIstn4iLFgOS+PnwJYZv5dmW3SrE7DCnwn6ktZMqGCQoRZ2R+Ydi1mnH8+CTf1F03Vxn4UUwZ+G5gPMYk4iW0FhX543TdqBA= LGPWahJB3T+s8VzwosVugREQVNuBWpzHibiVGK/rHsiOfZFDWkWvErLCZsLQMdDF5VptZ8EeQL2iIUXN3170xaxzT9Nvi6dYah47vTfKPscZEj9MafzER5rchXEPZunBXnuAYBEamN6h2Y6RguEd6E12Mr3YQ0etxi82ZqaOM8iMGSLQJnFZM6rxmIbSNArXYszCnQgIfYfJV1yTKLKeTWCCw6b7hOgQSXalRaRVpx22aCawxInHMfGkH1O0B2ZBEClLeLP9XoD/K0LeKROe72ouyeeAjzeX3x+LHdsSemc/ql8DDQMJUNhTsrNJWfDPlhImD2CcvSyMOJhimPfUeztFjDNhSA7mpoSudMMjpROtz5E5l+VVTUHeFIoRL2F8pAqtN+9Sk544AXcsc+uXbGm6/Hwwc4Df9+jXUNoDgRwhZ1EAUDLeAcoV+lu5u2Kyb60p9K6GhbK8i1IIDcxxg3akR3/FIF/Dqv04TOrKaCO3lZKMI4UmT0btjmCrlxDTn9RsAO+n/lJ2AdcbsKuo6sCwyEvLge2i8F2yxlibA1pQh+v3ZD/agapWf7MUlQgM8RCtq1BD/Bm7FmnNFhbkKVzu8vAHdbKGooSqg64ZzIc5Ak6u9nRaupnn5DHGnKNcR4DRxmCYjLdHhzjzfE61ErQ8PnVI7Yc4j23hYEMd+TM=

View File

@ -6,7 +6,7 @@ from __future__ import unicode_literals
import os import os
import subprocess import subprocess
from uds import tools # @UnresolvedImport from uds import tools # type: ignore
remoteViewer = '/Applications/RemoteViewer.app/Contents/MacOS/RemoteViewer' remoteViewer = '/Applications/RemoteViewer.app/Contents/MacOS/RemoteViewer'
@ -25,7 +25,7 @@ if not os.path.isfile(remoteViewer):
''') ''')
theFile = sp['as_file'] theFile = sp['as_file'] # type: ignore
filename = tools.saveTempFile(theFile) filename = tools.saveTempFile(theFile)

View File

@ -1 +1 @@
omMUcXLu3wGpKRISFlcEG9j0GWbhkud++umoXOoAREnLPlqwxxlIiWEaB5fkTR2ZjPFIXB/lQzGN28PEDbCkxagXb8KA+zXWmYvwkj3uB0QpCkfk0I+5/0cy5p1njxaAyENGZQFVZorqWvtWzuaFsDZrDZvV0qygWK/a7TTwQOxr2xFElnG+u/HzSNx09VzAIeVNkIu/3xP3LA6fo5/uzswDDFmRSch02aFp7AL6PBroq2mdN4aopu/xsdSAEdRzSumPWRLNLVd/yttfW+OOvMX6liUQr0CkFP0BQrHeAJnZVHXVnUNYDqRvnb3m9DjVfjUbFRs5vljxgr9zlcmFRdUXOJMYgDZelMqY0MidOPStoxnx/VHNijurMyBF4rlra0jIAkojqwNMxe788A9WJwKmPxkgeBiqVrVNYgSUpGWixSp3UpNGOtyD6jbY0ghnABoED/3NQl2NZj93SUHliUV14shf6pkrcxk7I4AB0BSIvvLRX6B3sN5hk6wm5rgzLpPl1DlgRGLvCLuLyp8cqiXQalntWPThck9OZLL9MATRK5BkPqNx5M2eEl3gqNNYKwnm+cEFvwbUhSQKsnyqpKCdzQJzp6LkgO4XuSdP4GrNCjUObL4X6Ogq2kb/tc3//ouvES81M11aeS84jBV7+PRcibLXc0t7gcyAUuRxlnc= dqg89d/khZKFk2SUIrROrthcq22mzSffp2JwLDEMqt6RVwvpT9hHY3eajSauVFJXdAl/DfLnUB1W0mQHWp1FyFQsFzprQhvOxROmnsa+vju2TnwjJHpGFMGIT7AWs3pGlxs1399gGcTXoU09m2/qtHxGgzxTyLprdlqMD1WivN2T+8o1QjLvfPIkXX/A252zJ2GEgZPRW9eni4TjAPY7jUVyoFs3wXkAO5uqBZcB2tGnCkxQ9UuGIa2ladff6o00m9TgAuSvCikVDnknVWFIOguJ+WZ8TDfYVCmHLAH43JI+EWwPcn4OvIgdDc6E9GAn71Mnv33yI48/VTtzV/KFu9aQiAuPoUV1JPCP++jcfsZ7vs1Qe8PdI6gBeHM/3j48oREoQRGpn//q0xpwfbKvBm8qHQ+GI9tv9gDi4sva7tJPNELK4xzMBhCZcG3bHt0tq984oid6o3e8q6sgkVdUE7Jvh3gjlk6H8x596rX2f8hPvqzPEEB8JERl3iJTEGBYWl0l+d9LJiMQcSaMyKSoySoYT9btcdK6p3Dr1uurZxOjgjF/jHi/5yP3H8i5XspiEY/u4Dcehf8Y2rd7K3sFRh1GVSROCdUhBFXbvE4nDRxwUKehwmE769jLOWsq21L0TYtq3ErFahr5QxVjGP3yAmFWGjY2ToTKTqBveCb8DmU=

View File

@ -6,8 +6,8 @@ from __future__ import unicode_literals
import os import os
import subprocess import subprocess
from uds import tools # @UnresolvedImport from uds import tools # type: ignore
from uds.forward import forward # @UnresolvedImport from uds.tunnel import forward # type: ignore
remoteViewer = '/Applications/RemoteViewer.app/Contents/MacOS/RemoteViewer' remoteViewer = '/Applications/RemoteViewer.app/Contents/MacOS/RemoteViewer'
@ -25,31 +25,28 @@ if not os.path.isfile(remoteViewer):
</p> </p>
''') ''')
theFile = sp['as_file_ns'] theFile = sp['as_file_ns'] # type: ignore
if sp['port'] != '-1': fs = None
forwardThread1, port = forward(sp['tunHost'], sp['tunPort'], sp['tunUser'], sp['tunPass'], sp['ip'], sp['port']) if sp['ticket']: # type: ignore
# 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>')
if forwardThread1.status == 2: fss = None
raise Exception('Unable to open tunnel') if sp['ticket_secure']: # type: ignore
else: # Open tunnel
port = -1 fss = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket_secure'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
if sp['secure_port'] != '-1': # Check that tunnel works..
theFile = sp['as_file'] if fss.check() is False:
if port != -1: raise Exception('<p>Could not connect to tunnel server 2.</p><p>Please, check your network settings.</p>')
forwardThread2, secure_port = forwardThread1.clone(sp['ip'], sp['secure_port'])
else:
forwardThread2, secure_port = forward(sp['tunHost'], sp['tunPort'], sp['tunUser'], sp['tunPass'], sp['ip'], sp['secure_port'])
if forwardThread2.status == 2:
raise Exception('Unable to open tunnel')
else:
secure_port = -1
theFile = theFile.format( theFile = theFile.format(
secure_port=secure_port, secure_port='-1' if not fss else fss.server_address[1],
port=port port='-1' if not fs else fs.server_address[1]
) )
filename = tools.saveTempFile(theFile) filename = tools.saveTempFile(theFile)

View File

@ -1 +1 @@
dR+uIC5WKTM3Iicua7Jv7YEksMy8gIf3U5MfYzh6pCNYkkdEywpuszoIxHqgn/ltIjuvY4s2kATXqQtuZ7BYCNhB7vGw/nA/PDGqpOPNDCAamRL+N15Ctjb1+olmhQgqR+D/lv7GaScO+5n579OSmrHPaZkDbRo3U9wRiMzg+FLaL6Rknz8Hirpeas4kAculg+s3BeCRmf0fghz6UI9/xf+At0sd6M76p1E/3oFiIBjBNw9yKkLiPgDzq5DrrxA0SLWBwl15IPYqNpBCGo/VMV2pBQsSWmFGS62C3R6KdjMHN9jmO+seWcfhcNF2eCk3ODcoFeZUTfvXT+GoN7u7z3Dt4CyWx9k01RqSMxXcnf+vv2MqgBZde5Lu75ZqIpYP4qBkO4h6CH5isg1KVZJW/tGWGgU3fyVAkY9oxt6B8R2xo3mQeTkY+AGH+7KQHsB9l/OU0R1jHllbEIo9wopb4/SzZLMrECDMgOscA69BFodoFt6suT+QimzPHcgCQLE8xGY9KUZ7rrEn82rr3O7bAKXlJIti+UaT+zbgOizekA5+9CJRNVsWTmFsZ+6ghqY6L/QdyWJhere3Rrzh/0mg36Jk4XEaI8GI/VI/TmtmTwgut6B5gH/6fg+yaVAqYexIcINVMSSdIZyBVeX1QXbzcgYc5QJo9+EOJrzP5U0K+pI= NCdcJPSAu3yby5d/PiANn+iTTGsOt/GF8Kp9XxhdE1hZKFsR2USQob6tGTdM0HIIuL6i0KDOOvSa5JiD4Tq4OPE4sYSmaK4eDNo+RO7Fa4qP91ksOc3EcUCBGCru9+BNBVrWmAmlaJIfywvowodv8cP70yQxWqz93VomWvVUfJXhF6ylomzYN+gtLqjueKATWznf2d8pQ63g6p9j7p5yVJUGGZQCbuepS1Y3WUhSkf1EHrA233O+ZRK3YP6XDS75WnGkBEr/d/LrkzyYxlHX1UNFYaOay1I5cRXPJ9n2AVkmmZX8wyKxoCvAjwVZWaHoQWSZxNaDQ4YaEh14JK1JBnkpDQUDmgwVq1M0iY+aNlLg4VIMlFz6pVk3jcLk/CZfxMpH7ZkzYkL41vFlzG4lpFnQYoCCb3dPTZdAzg0EdtMy/Sk0X3Bn3dJzz+S2S4RjcLRHgy9hI5YeSVhFksruirWsbryb1WXIWjkjUIlMc/WVN17457onNpNQI2u7bebtoRopIox3gx06Afb3u5f0r7fUus+/1jWwoI8H73ES/RqpL2zXwXh9Ks1+5gFD1TDNkQn98Ia717DKwWoqZtjiJ+thY5Q3rgfLhgzJxRXm+XWDDSIVFdviyFB6m8U7/51xKME7ll5Tx4lVrwhMjFkfJj1TbOlnuvEiVrn4/9XDqo8=

View File

@ -7,14 +7,14 @@ import os
import glob import glob
import subprocess import subprocess
from uds import tools # @UnresolvedImport from uds import tools # type: ignore
# Lets find remote viewer # Lets find remote viewer
# There is a bug that when installed, the remote viewer (at least 64 bits version) does not store correctly its path, so lets find it "a las bravas" # There is a bug that when installed, the remote viewer (at least 64 bits version) does not store correctly its path, so lets find it "a las bravas"
extraPaths = () extraPaths = ()
for env in ('PROGRAMFILES', 'PROGRAMW6432'): for env in ('PROGRAMFILES', 'PROGRAMW6432'):
if env in os.environ: if env in os.environ:
extraPaths += tuple(p + '\\bin' for p in glob.glob(os.environ[env] + '\\VirtViewer*')) extraPaths += tuple(p + '\\bin' for p in glob.glob(os.environ[env] + '\\VirtViewer*')) # type: ignore
executable = tools.findApp('remote-viewer.exe', extraPaths) executable = tools.findApp('remote-viewer.exe', extraPaths)
@ -28,7 +28,7 @@ if executable is None:
</p> </p>
''') ''')
theFile = sp['as_file'] theFile = sp['as_file'] # type: ignore
filename = tools.saveTempFile(theFile) filename = tools.saveTempFile(theFile)

View File

@ -1 +1 @@
CVmFltgXbShVc/gO64FfdFJU7BzxnSs+I6MjMpDk/dm3U+mdPNC/4uVe0ZX/+uc13dUSYzqTMKfuU3dnee8eh03WLIvOHlzs0k1ApQiIj6zaWYpQcjmyTzMbiADykN+JTzy37aQDu0kANuYWePqqNWGruWFwNul4kHCVjvRzvXnSxmLYAleIg4yMUABTRou3AIMAeAaW6oUBqKEvLdQz9z+Iu83DzX8l6MW/okR9DgaMiiqbamJKs4lyE/qXcIC5hegcV2/KcWWKt4FEoHbpnat23u6gg6Bmfri4kC66CiIrD5U2HmWK/6EkdmbrJxVglBF8RmHX7f6wpW20xD3rlw9SL+k01p1QN77Xu7kiHj+uoFi6jl7MYnA02/PVw6Ke/lBx0fFLAdd1KCj5VqEIhccU+k37VEcGPKW3GbTAinZ2yvkzo4rL8uFRnNTQ/ClWfaPV32BRfAoXCPO1yiZxy498uVa1QuKcCQnCrC7X2ZgwEacsePUY+0zHuaBCNqdlHRFsXCwNiwGjETuuCNJmVtzGfOrhaSlHWUdxWOCNpY10XwmIw2s3BL/5T5N0Adh08N5ozI9lbzHUHngj78B9kfTrZDIXR2lJBBQ7CQGN++3iLAd6IlVD8eNwRk39FUQyp/OxMyzrBS1R8O/nIgTK0j68fpU2y3vLxh9pELo2gCw= eziVaJ6nCWndvYbDpD483QpNFA375Y9FB4lSasUZxJocIW9zjbF4082o+XMPbz/SSO9/6KlSJnZfABVJNFoPWETkf55ryHvzPj6AwNUtWkR/UZQLT4k/RZ8DPz1/r1Boha4A3nxRpuwMbsSy7z4rmg7HKQpwsyD/0qu8Rc0+YmhT14N0Jqkhh4aIISIKiwdUD6+6y6yq9iRPDoL0UJXeEBLJNOJGJk0jBV5YNwcYVoabiTthh4vPnaSzWE45GqJrFe9fX92pnM/3wVDL0Wld67Br5SAwxlKEeucveZedbLwYbAnL/cv0WHkqWC6+o4ahPlXobVXIGtd3mHeiwrNn9SVBnk/fQpeMHN/wwqIs/9VArvOKRcuaMrGR2U3slRwIpWODGTN2DHIHwZ1s3ghIfgm/REC7Q33pz7/pAQ0LthjJ77H41rePMig6aaO8yWhTuEk4K0XHJVq5fHaDAWCTvUdUiuRQuEjjJOhC8wSE0uMjCJ9hARVk+66xbrgllgbQwnDlmLVeA61+DQo6ygOCpqrHDlRFyPjVUvBThSehYM/eyUXY+Rsf9YLNx8FfCZQxmyUvb4r97EtCKadyDecumS/KHgeyA8gbosJLu2nNeHDYgOAFX5fewOt0leUHsqNTMpVznSMOFjO8wIv/XAJsfjkCkct0HVYVW3erQ2FVWyE=

View File

@ -7,15 +7,15 @@ import os
import glob import glob
import subprocess import subprocess
from uds import tools # @UnresolvedImport from uds import tools # type: ignore
from uds.forward import forward # @UnresolvedImport from uds.tunnel import forward # type: ignore
# Lets find remote viewer # Lets find remote viewer
# There is a bug that when installed, the remote viewer (at least 64 bits version) does not store correctly its path, so lets find it "a las bravas" # There is a bug that when installed, the remote viewer (at least 64 bits version) does not store correctly its path, so lets find it "a las bravas"
extraPaths = () extraPaths = ()
for env in ('PROGRAMFILES', 'PROGRAMW6432'): for env in ('PROGRAMFILES', 'PROGRAMW6432'):
if env in os.environ: if env in os.environ:
extraPaths += tuple(p + '\\bin' for p in glob.glob(os.environ[env] + '\\VirtViewer*')) extraPaths += tuple(p + '\\bin' for p in glob.glob(os.environ[env] + '\\VirtViewer*')) # type: ignore
executable = tools.findApp('remote-viewer.exe', extraPaths) executable = tools.findApp('remote-viewer.exe', extraPaths)
@ -28,31 +28,28 @@ if executable is None:
<a href="http://virt-manager.org/download/">Open download page</a> <a href="http://virt-manager.org/download/">Open download page</a>
</p> </p>
''') ''')
theFile = sp['as_file_ns'] theFile = sp['as_file_ns'] # type: ignore
if sp['port'] != '-1': fs = None
forwardThread1, port = forward(sp['tunHost'], sp['tunPort'], sp['tunUser'], sp['tunPass'], sp['ip'], sp['port']) if sp['ticket']: # type: ignore
# 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>')
if forwardThread1.status == 2: fss = None
raise Exception('Unable to open tunnel') if sp['ticket_secure']: # type: ignore
else: # Open tunnel
port = -1 fss = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket_secure'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
if sp['secure_port'] != '-1': # Check that tunnel works..
theFile = sp['as_file'] if fss.check() is False:
if port != -1: raise Exception('<p>Could not connect to tunnel server 2.</p><p>Please, check your network settings.</p>')
forwardThread2, secure_port = forwardThread1.clone(sp['ip'], sp['secure_port'])
else:
forwardThread2, secure_port = forward(sp['tunHost'], sp['tunPort'], sp['tunUser'], sp['tunPass'], sp['ip'], sp['secure_port'])
if forwardThread2.status == 2:
raise Exception('Unable to open tunnel')
else:
secure_port = -1
theFile = theFile.format( theFile = theFile.format(
secure_port=secure_port, secure_port='-1' if not fss else fss.server_address[1],
port=port port='-1' if not fs else fs.server_address[1]
) )
filename = tools.saveTempFile(theFile) filename = tools.saveTempFile(theFile)

View File

@ -1 +1 @@
WxhSxSYZISZNlj+Slprz8cdzstKFghx3zuQXdMmakzg5mLDyetwR9cSdWRkYd9vcP8j6aeufbK1io4rwvsdxu+7jRLSL9GVwB+MbIQYrBZ7RbiA2hqWhzQ/LCncSL73Jq9jZtt3i2pgWyA691z8UUbpts6wimsn6cDXQtEHda7MOFIi4Nzlzjf8AMpPTCkPldIDiXhyH+nuCXdzpOY32Gvrq8w6eTQrUWF8dswa1er0SQJENc2StEh9Tt1378QwTBtPQNgyop++sv/FhLdDB8hBQliX5LX7t9NxzZcvyFBYHqFnfXEsYc2bWWkt264CWfULREPLRQK11UWZ51ldvY1+xFOEg1eGAna8nWhapZ9R5DagSfehokpAov30Y0PwjTx5MGxiubd0gMeP4Vr2YZ77qBb5JnPKplEH2VsHS7TRgJyKNf2xI9Yw80iGSrO8LUC6L+9+cLDACyrmFINUA/2sFbRLjqdogY7CREIMzP07DUOluEcNgMnPLBKrTZ5U9nxnwgdgptLZgDNJHagitAiW5zMS10lEnJKRLZ0zVgWdiFna29SB7o75jO5M0LA+adIOzRH4G0C5vFYiiMVwsfLhqT3nUvaacTMLslFxWbr5T4QxWJkuLNjIMypw0cOzSaPsXW1tuZXwL0CjgnXDat7iNFQZCzEDQuoDaGDWvYpE= LNhHPgRKio48GqUpYgPIokcVEV6XHf/I17eSLSNabQ34QWiZybvlq2O7Gfztdag+1Zvig5urzFVbjuOfR3kIWAlt6hDRBo32cOveMngzUNnZfrpfehmMiFoCD91+/R/lXNm6x/fSpisbnThDejzk5vnG/xUZEls9qazSJLvpgRYR95IJxoArkhUMrAhkK7n0/0RDGQmhNJV50TYYYlnRcXCzeRaOJcReK1JkuovVHGFwTDDiLYa/irr5gWZqIhCgIzW7yGHeQGMAUoJkgPXexV9mWjMPIRbx3rBnPhtOJnywyILN+HQZ6SU2lsvGZMQQ2d/4WAZ+uP0k7CNS/81Cm6PZAL3LpnZ0zfszcWaAAF4rLbkimm1aKUXHoUwWkXfxjxodlQRXD3oE/jnTuMucl8WLUNnP7AwH5VQNxVTn33EoE8C3jRR5LcjL1ut7qSPno7Lf/UW2Yx1GGOCR0GLtuB5OPq0cIRjdqckibkL4jXRMX7QsXnh5uEYG+wih7gohzdcprFnhzQjFy4esQsKXqWTSaMgBVtUMOSGHylsQAps1j7Co6EGCMu/g7jrevk0f9T8moETA2fRPEmdV2Md/DFezsP2a042g8Git8llLGtibq329K/XAwC2mAwN768BHVu+WlZQmYcyz7iEU/tR9Dxq7y05ljiOCgAS4oK8ucQE=

View File

@ -1,7 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (c) 2012-2019 Virtual Cable S.L. # Copyright (c) 2012-2021 Virtual Cable S.L.U.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without modification, # Redistribution and use in source and binary forms, with or without modification,
@ -57,15 +56,44 @@ logger = logging.getLogger(__name__)
class TSPICETransport(BaseSpiceTransport): class TSPICETransport(BaseSpiceTransport):
""" """
Provides access via SPICE to service. Provides access via SPICE 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 = _('SPICE') typeName = _('SPICE')
typeType = 'TSSPICETransport' typeType = 'TSSPICETransport'
typeDescription = _('SPICE Protocol. Tunneled connection.') typeDescription = _('SPICE Protocol. Tunneled connection.')
protocol = transports.protocols.SPICE protocol = transports.protocols.SPICE
group: typing.ClassVar[str] = transports.TUNNELED_GROUP group: typing.ClassVar[str] = 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) 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=65536,
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.TRUE,
tab=gui.TUNNEL_TAB,
)
serverCertificate = BaseSpiceTransport.serverCertificate serverCertificate = BaseSpiceTransport.serverCertificate
fullScreen = BaseSpiceTransport.fullScreen fullScreen = BaseSpiceTransport.fullScreen
@ -76,7 +104,9 @@ class TSPICETransport(BaseSpiceTransport):
def initialize(self, values: 'Module.ValuesType'): def initialize(self, values: 'Module.ValuesType'):
if values: if values:
if values['tunnelServer'].count(':') != 1: if values['tunnelServer'].count(':') != 1:
raise transports.Transport.ValidationException(_('Must use HOST:PORT in Tunnel Server Field')) raise transports.Transport.ValidationException(
_('Must use HOST:PORT in Tunnel Server Field')
)
def getUDSTransportScript( # pylint: disable=too-many-locals def getUDSTransportScript( # pylint: disable=too-many-locals
self, self,
@ -86,24 +116,40 @@ class TSPICETransport(BaseSpiceTransport):
os: typing.Dict[str, str], os: typing.Dict[str, str],
user: 'models.User', user: 'models.User',
password: str, password: str,
request: 'HttpRequest' request: 'HttpRequest',
) -> typing.Tuple[str, str, typing.Dict[str, typing.Any]]: ) -> typing.Tuple[str, str, typing.Dict[str, typing.Any]]:
userServiceInstance: typing.Any = userService.getInstance() userServiceInstance: typing.Any = userService.getInstance()
# Spice connection # Spice connection
con = userServiceInstance.getConsoleConnection() con = userServiceInstance.getConsoleConnection()
port: str = con['port'] or '-1'
secure_port: str = con['secure_port'] or '-1'
# Ticket # We MAY need two tickets, one for 'insecure' port an one for secure
tunpass = ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits) for _i in range(12)) ticket = ''
tunuser = TicketStore.create(tunpass) if con['port']:
ticket = TicketStore.create_for_tunnel(
userService=userService,
port=int(con['port']),
validity=self.tunnelWait.num() + 60, # Ticket overtime
)
sshHost, sshPort = self.tunnelServer.value.split(':') ticket_secure = ''
if con['secure_port']:
ticket_secure = TicketStore.create_for_tunnel(
userService=userService,
port=int(con['secure_port']),
validity=self.tunnelWait.num() + 60, # Ticket overtime
)
tunHost, tunPort = self.tunnelServer.value.split(':')
r = RemoteViewerFile( r = RemoteViewerFile(
'127.0.0.1', '{port}', '{secure_port}', con['ticket']['value'], '127.0.0.1',
self.serverCertificate.value.strip(), con['cert_subject'], fullscreen=self.fullScreen.isTrue() '{port}',
'{secure_port}',
con['ticket']['value'], # This is secure ticket from kvm, not UDS ticket
self.serverCertificate.value.strip(),
con['cert_subject'],
fullscreen=self.fullScreen.isTrue(),
) )
r.usb_auto_share = self.usbShare.isTrue() r.usb_auto_share = self.usbShare.isTrue()
r.new_usb_auto_share = self.autoNewUsbShare.isTrue() r.new_usb_auto_share = self.autoNewUsbShare.isTrue()
@ -112,11 +158,13 @@ class TSPICETransport(BaseSpiceTransport):
osName = { osName = {
OsDetector.Windows: 'windows', OsDetector.Windows: 'windows',
OsDetector.Linux: 'linux', OsDetector.Linux: 'linux',
OsDetector.Macintosh: 'macosx' OsDetector.Macintosh: 'macosx',
}.get(os['OS']) }.get(os['OS'])
if osName is None: if osName is None:
return super().getUDSTransportScript(userService, transport, ip, os, user, password, request) return super().getUDSTransportScript(
userService, transport, ip, os, user, password, request
)
# if sso: # If SSO requested, and when supported by platform # if sso: # If SSO requested, and when supported by platform
# userServiceInstance.desktopLogin(user, password, '') # userServiceInstance.desktopLogin(user, password, '')
@ -124,13 +172,12 @@ class TSPICETransport(BaseSpiceTransport):
sp = { sp = {
'as_file': r.as_file, 'as_file': r.as_file,
'as_file_ns': r.as_file_ns, 'as_file_ns': r.as_file_ns,
'tunUser': tunuser, 'tunHost': tunHost,
'tunPass': tunpass, 'tunPort': tunPort,
'tunHost': sshHost, 'tunWait': self.tunnelWait.num(),
'tunPort': sshPort, 'tunChk': self.verifyCertificate.isTrue(),
'ip': con['address'], 'ticket': ticket,
'port': port, 'ticket_secure': ticket_secure,
'secure_port': secure_port
} }
return self.getScript('scripts/{}/tunnel.py', osName, sp) return self.getScript('scripts/{}/tunnel.py', osName, sp)

View File

@ -6,11 +6,11 @@ from __future__ import unicode_literals
import subprocess import subprocess
from os.path import expanduser from os.path import expanduser
from uds import tools # @UnresolvedImport from uds import tools # type: ignore
home = expanduser('~') + ':1;/media:1;' home = expanduser('~') + ':1;/media:1;'
keyFile = tools.saveTempFile(sp['key']) keyFile = tools.saveTempFile(sp['key']) # type: ignore
theFile = sp['xf'].format(export=home, keyFile=keyFile.replace('\\', '/'), ip=sp['ip'], port=sp['port']) theFile = sp['xf'].format(export=home, keyFile=keyFile.replace('\\', '/'), ip=sp['ip'], port=sp['port']) # type: ignore
filename = tools.saveTempFile(theFile) filename = tools.saveTempFile(theFile)
# HOME=[temporal folder, where we create a .x2goclient folder and a sessions inside] pyhoca-cli -P UDS/test-session # HOME=[temporal folder, where we create a .x2goclient folder and a sessions inside] pyhoca-cli -P UDS/test-session

View File

@ -1 +1 @@
Td27A1n4tterDd2/pY/jMBlvZyucmhte0u8aj9KQ2zSGNFXWdKnqmyfes2QY38weBVHEiI71jMopKsrZ3NGefFkvHODTFmiyA6gtzNZkO3ux1QEioPfP8BrvY0IjMrrmvlAOb3OSF3hCqGcWbbM2F3U6wdGmWirRmThN2FUSgTaOW0ITffKcPE2Fc8CHXDMGgvjloyP01KXy3M72DMR5Ir/Yj5RmumfvHLhi8/nsXz/jHjCLYxoSi3rOHTterH41/axT3cFIE4nVZIFSegx85mJ0JZRFcTL6dUx1b9FC/7iw8H5fuutkcCi/3gEL1j1tsD0juWT+36QPpH7SrT/TM2H2T+dlaZ9DxlRn+EaWwcW8olfygtNjpqOOspGLMSnI3c1cZeS4QGegCaeYK6xeOpmsF0qh+1J4ctu/GA/0hMJ3Cv+mSQA5w4B9uGWj7p8K4Z2rMpIB+uZouijDNe8J+wj4AMttFUypkZBX+oa+33uQDasM2AZSG2247AqRqLcAfNj3m3I9LGqW85V45ytbcmqfQGTfE8mO3FAl0o2aivHi1KUgZQrze06pYJi/C1K9quqV9Pq2XntJPJsM8LzUuIWZrfesCge6h7w1i+CCos3L3MxHu8S9jU/uFeeXWHS1wwYkTghw3DFcZu0bGQilZa2XM6ITwxiVtyFaucHFPwU= FDUIODILNyuC5PSK/2BNLgcenZ3xdaMw1UPAvwWc1hG93v7MtKNptbSOkSsMEh9/0dlME0+icUvj46aUbuflemQ+36gUVELdd+7e8aP+J0jLhHpBKHl4QGYcRGJv8u9VnmfSIQGJfFRatyVMEFNCCl+81lmRwKYq+2qP0nS5ufbcjQLd4cfQEgXpiTJsW69jENIc5/TgifLhCsaoL3y2vln4pq5VXTWlBTNYAyNOV/BiBgdPvLlPmIdD+wLrZ1gJ+Bzk+QjENdeBfhZE8N6DthjCTn1FzLcG00q7rlL0qo37J1TKojXe+CkuWoOPXXuBfGfzWTnrF7CdVl9kPb4jb56FHUa69nFp5+3ISH3tKlVQjsXekv/XezQWRihRze9wXJAb1lP2qxRJrkMPmI1iRa3ie1YSuxzbnpuysFkuTg8rl23cYLFyWRy/zdokJAdX9FC5b1KsFZ3slGI4iy1Q9WEIrNuFTvgZCE44V4HgP7IwadfMceF/RKOUs3L8Y1JAktqhe6bWjt/7e+ZLz0hIgoRj+OqCEkfp7xqp9eYNGTscUfQRcrqjN73786l34NNqYeWBkTnJNBcgZrp5NnKF3avzNDnMHTRnCZSSuGzKcXDP+UXdI2EUlk2oWQ0cZpuXe4JKH6fvWqtZ9E+TpywVMp3JEtlFZOmao+KKIst8Wdw=

View File

@ -5,20 +5,21 @@ from __future__ import unicode_literals
# pylint: disable=import-error, no-name-in-module, too-many-format-args, undefined-variable # pylint: disable=import-error, no-name-in-module, too-many-format-args, undefined-variable
import subprocess import subprocess
from uds.forward import forward # @UnresolvedImport from uds.tunnel import forward # type: ignore
from os.path import expanduser from os.path import expanduser
from uds import tools # @UnresolvedImport from uds import tools # type: ignore
forwardThread, port = forward(sp['tunHost'], sp['tunPort'], sp['tunUser'], sp['tunPass'], sp['ip'], sp['port']) # Open tunnel
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
if forwardThread.status == 2: # Check that tunnel works..
raise Exception('Unable to open tunnel') if fs.check() is False:
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
tools.addTaskToWait(forwardThread)
home = expanduser('~') + ':1;/media:1;' home = expanduser('~') + ':1;/media:1;'
keyFile = tools.saveTempFile(sp['key']) keyFile = tools.saveTempFile(sp['key']) # type: ignore
theFile = sp['xf'].format(export=home, keyFile=keyFile.replace('\\', '/'), ip='127.0.0.1', port=port) theFile = sp['xf'].format(export=home, keyFile=keyFile.replace('\\', '/'), ip='127.0.0.1', port=fs.server_address[1]) # type: ignore
filename = tools.saveTempFile(theFile) filename = tools.saveTempFile(theFile)
# HOME=[temporal folder, where we create a .x2goclient folder and a sessions inside] pyhoca-cli -P UDS/test-session # HOME=[temporal folder, where we create a .x2goclient folder and a sessions inside] pyhoca-cli -P UDS/test-session

View File

@ -1 +1 @@
CnCqJRFLyii+jk4neecfXQ1tK3pKsdJ0b4z6XmLKPSLtzP+mMyrr5EK7RStN02KwvRhLwuXoH3lSp6ydGSwGtnRn44E6V2wIHkb/2dm09guR/KlTw21uBVabyYvH62yRjs54il0gL6YmTku3qWA7LeEEg7YuSxtXuNUgyEx28B1sTNBnW9E/FjIUSYF7vPgxiUaSbntmPvQehuqgaYKREtfVyB8cbTctqaJhz7sUtcetu461N9me4Lz7dxqAA3aAI2N1JV5QR/ATJAx29VuH0pG7iqhaXGe+K9oNbQyaS4sNIGHX+u/WR5a/ngr/m0llIcewHu/WxrAnSJLv6e+4+xpB5NQko0HR42cG6hy+IsaGMpid9Ubwilje1w+R0jWVZr3Xt14NnJKktysNhqLTEWw/hoCaJThJhzvEtM8B4H9Um65lPXGwTgvi2S71Hlql+IVJqxoj4DGdC7emU+MtwdHc3H4/YyCJC7X27PA1Hnmvr+BIjciQZC6BjuCyyppP3DozplmptAs0+FVZZs8BvJSsqm0pnFI5NM5Tf1WF/56JxBaAz0u4ugEwx4w/JnxorrydezOmP/xADIjFY3Xh7fkAGg1a48+WFGB+gpmXohbHnR8u4tnY30gnkCUqoJe/ZVJuK2Wyzs+8508+1A7ztTUGamZjhQPoXIrn0EDA5bs= OQ3g4Z39LoR6k8LseDP2Kktk3QCj14WeJ7RlqLcyXN5QXJTdu86lKQhLHapS4GUX9apcgcF1I+o5NyPeXoE8iXBQr0456Cz6k+O35jzlwrO1BXPby9bWEuUwlXvyQuHPY9wThQA++jWiKDV9UD5UC+BHP3BWWZVj1aVEunHJa2uqnMLQMVb63vIndclQXJcLXNuQk1v2jD6f2INxG0iojzfxJ95XrCN5OjgfhStimuFC3dCjm1shq1vSgpPVgampzMYO8ViJCzIk9dg6UKO+aWUmd617wRf0ZHJvez2Oerc8PDu/uYKSjPOChUapvkWRX84S8Ydn/4wUhUK9TKQt9iIBW4HOCVxB8gzX1fZwu5LqEii5f/LJWybFgrh33eJIBBJDyUU0Y+fp9IS8ayvOnEj1xONNTKpo0ZO407H1yTjcwoWAhT9Uob2BaMxCk90qy/OTN6mjtYbUvgKayUkV3OhbbSS8B/+t/wpyk2N6w74Qx2SqB5EqNIZT82raz4QM/Rggjq2im2F3gWwKUMkldt4u0Zf0qt6x8ov8qr/xeVuP+lUfnHJyYXvIOyUI6QZmdTem+lIATs/0a/Dp02yb+khW0TyDc3kc6F3Igf32PzleCiwXVkKfC/QZzKTLPPjaRZL+vEWu0tfh9qOZAutSRzs5nCuhIbvmnH19sbvBr4w=

View File

@ -7,12 +7,12 @@ import os
import subprocess import subprocess
from os.path import expanduser from os.path import expanduser
from uds import tools # @UnresolvedImport from uds import tools # type: ignore
home = expanduser('~').replace('\\', '\\\\') + '#1;' home = expanduser('~').replace('\\', '\\\\') + '#1;'
keyFile = tools.saveTempFile(sp['key']) keyFile = tools.saveTempFile(sp['key']) # type: ignore
# On windows, the separator beween active and not is "#" # On windows, the separator beween active and not is "#"
theFile = sp['xf'].format(export='c:\\\\#1;', keyFile=keyFile.replace('\\', '/'), ip=sp['ip'], port=sp['port']) theFile = sp['xf'].format(export='c:\\\\#1;', keyFile=keyFile.replace('\\', '/'), ip=sp['ip'], port=sp['port']) # type: ignore
filename = tools.saveTempFile(theFile) filename = tools.saveTempFile(theFile)
x2goPath = os.environ['PROGRAMFILES(X86)'] + '\\x2goclient' x2goPath = os.environ['PROGRAMFILES(X86)'] + '\\x2goclient'

View File

@ -1 +1 @@
LuB4norDe9e4uHcdO158ENqlTNC9Wyp3xE7p/usaTGkJiQ8xgEbojPpXlJcbL9ovhRdcbkM499iJ8+tpd2XNNPkq3kEa3yy8ZbfKQWvcoDArJsi3MaWsTBfL48BpsPAwpgFgXwTNYLldWJ2uOp1RJijfNce1zD3NdC6JEWsewwoR0H+BjfHGHHvFtXSx5No35onSGS3g3Y1igmkg9/6GEqmANHCNyfegyFHIfaDJZwynm19Fk4A7ZQIY3PTq/kxWq5PXaVcHB6nC0UJBXHsEXePBFek9zaKViWiA5ZFlGYiaqKp1dj87QDEuwJ7GWrktDBRrbt8ZARAV/odhozx14V0Uxh6IiSvNUECb1pJ76H/Nqm1oQW3eRnWXZHjgN2rfsL9+988AZymJluC9acNcPHZw6TjaWksGrCu2qSIYAc62dxHSOJlov6/4/AqDPdmj2VSO8yRrmLkjhmlAZ1mcH29s8E1tw0HpBjPPiFRN+Hw4PCXdI3Qm5TkTbpWWYX14rm5u+KoNviUi1G0r9S0ZVM0e/xtUa9WKuOwUs81D3vHrAzgjHRGL7MaUWgXNHb1dB7SpogGsPmV05r4FMrZ9ip4qdVgM6391oETGzc+kWrWn6U8/Hm/N7aiUF19ipDN3U5ICiOMfeQqwb3oHJyvyoZUR2+x0q95FFND7O/gx0mg= HW48ZI/UF5SKfE5vTqyfKKOm2CZDoRVPyrJrmL2z6B9kuBQMB+o4T6RYsOPYMNQaII7ynG2YTSwfrFC3vQ5qNcWQtYbED0oRxGVW8Vl+sxFW3AvIcxhC3LMcO6+sRr5MUA5E8gGAq01AWbIE/lXBF8n/jovqT6sv1mApBQ3qlBwPq+YgqsvKdOXsNKWcZCc7Ig9xPGvVAQwSyiQCUUfyw2zk4l1LlAEklKpOcjy4c19dmO6wiU4ZWB3UZdMbu1vFRVMHTcKe5r/I0yUgB/2OcylniCvqM4+10OJAZKIEsK+mHz7+hF1rbBdey4qlXgUGtnCd5YLfctp6+lpsqr/awgl0h3BPRz+uPUMEQWqPxnqKMsP6sLrz4WJYnqP4yFnlUJKNqt1XZShMrzCz7VkT91RWHrIi7Mzz+QVlpC+PZS+0c2APiU1yfTPeXaaLKOQYjcKwHtFc4wZOJquwRbYFQbf/g/33zkRcmRQEueli6AHqKwxhpOPyuunNgY6itoS+PNIvyHK/xURrsao3kO7RhDavBOIiWiaIpvsaDCYPdpGTtgD/yVjlAMQnvQMqPUhg8Gxjxc5h3KaNNMJrLjFjXicY9Xh5P3sx0SgJKUxvg3UdYgyJHlNNLa5dJBQSEUfiP6zzX88w2h73rMP+BE6u1Yv0YsSY3967ctLMRO2/fWA=

View File

@ -6,22 +6,22 @@
import os import os
import subprocess import subprocess
from uds.forward import forward # @UnresolvedImport from uds.tunnel import forward # type: ignore
from os.path import expanduser from os.path import expanduser
from uds import tools # @UnresolvedImport from uds import tools # type: ignore
# Open tunnel
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
forwardThread, port = forward(sp['tunHost'], sp['tunPort'], sp['tunUser'], sp['tunPass'], sp['ip'], sp['port']) # 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>')
if forwardThread.status == 2: # Care, expanduser is encoding using "mcbs", so treat it as bytes on python 2.7
raise Exception('Unable to open tunnel')
tools.addTaskToWait(forwardThread)
# Care, expanduser is encoding using "mcbs", so treat it as bytes always
home = expanduser('~').replace('\\', '\\\\') + '#1;' home = expanduser('~').replace('\\', '\\\\') + '#1;'
keyFile = tools.saveTempFile(sp['key']) keyFile = tools.saveTempFile(sp['key']) # type: ignore
theFile = sp['xf'].format(export=home, keyFile=keyFile.replace('\\', '/'), ip='127.0.0.1', port=port) theFile = sp['xf'].format(export=home, keyFile=keyFile.replace('\\', '/'), ip='127.0.0.1', port=fs.server_address[1]) # type: ignore
filename = tools.saveTempFile(theFile) filename = tools.saveTempFile(theFile)
x2goPath = os.environ['PROGRAMFILES(X86)'] + '\\x2goclient' x2goPath = os.environ['PROGRAMFILES(X86)'] + '\\x2goclient'

View File

@ -1 +1 @@
pKLTspUmlmfjY7Ei6aiNFtCh+8mQ8TkZztS7D/kjGRj25FxmfG5Y0HMOdlu8kouiLTAwkzpyj+J+GjebWwcPCJv7hFJ8kWFJ7XaX8b3uX8BREq+G1p4UYSiZDM7qSaPviM9VFoTLNwRa+yBknbyosLBRCpesKSbaUlis9tsAHByU98peQ0QSOrrUvfFBIl5EUzx+frgKTS67tCNGJ+L4POOnOakKNoqDYiJ0z4/S4vMC2w/JQ1OxZPgXsyPRAwM7KqCOA5zhzB1Pjucoj9lfZvJz8T7DDpX05eN8dUU0dsgUZHKbm92Tn6MnMDpNbUH/CIIeQMfbBThTNlr2vvYYzdAjbpNlg4R4s10RCfIWb0Tqfvu9jRs/8dUOMkfOZSbv3DVukXIadQt1ednzbagBXoMPE3jiLe5OKQqAg4LFcU9vm1HJB/EIenpeCo/Oxmytb6VLatl5RF4COwC0WfFAZoku9qXW6BFzTWhGMGkzuXYS0C8rnDb1m53DBXNp3aPkVJ8ktoDCQ4fWbb9YDFZ2GNDVt5QppyizkblvbQoy4gVxPXlo+aPc9b92/hKmMha9RA1FByhDB7Lzx4a0iYZicv3LjX3N/VPvrTGpmfeiSDovqMWfBR9au3qneNmndxM4LnXL6wbyVyfeJey6XRIshRAE+gWlz9Ew1vzD0llnfN8= mYksg6meXqkKrrIES6xDkYeWsb78ejjJqA7EV7H3OgExs3gpxYr35fJR5IpVKrxUu1uT3mZK8PqmQ2ZA4beZkB+1IqdOZk5OWBpm4a1IGzU+KsPsCw+F1auvizJioZtM2JaG5FSSuskzu/Gflm1/akq3F4Ttkv0+Jt6daiEOnXioO0I+Jiv/fgaaI2DVDl2kc6bcPP+A/oS/cLO7RVrjLf+rcIeK1sUrhLhwhtD/8NyN/5nP5Xfq4jjNxEl2SFQZC3SUyXDfWY2LhbSt24O6rkYG9WkX/eNUwGK0ojdX4jdPlRq3gsu2rlkhIW91IBOztGoWZRWOi0vkqWODQdd7uTHA0Wrbi+5YZb07gv4K4r1TFPTEVWjEiY/xox3fZIJYhSIbGxFZXd9LlVOhpZ8Q2tEME/18rjDxuEsr5AdBihv9JEvsYIwfjHoOY9a5LK7FExnTWwEHlzscQ7f3sq9CihT3QnAwKBhqp2hQbZxT/28SAQF+0JAehWCSAi6hCk3ZYs3US5SmPcm32jwsHxh93Ae64Vfm1R/HA/QH9J1EEVA0pVS0H9H3mCAaPz2qq/oLLnXh5qbsbrXKFl/2pi3haYhGR0FSxbG625d7ZoAVTFrF8BMFErWerQjx9X9UDftbf5moBJZiTyk2cwnCnG4Q3DDddukudKiLwPzEnHaN1Zo=

View File

@ -1,7 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (c) 2016-2019 Virtual Cable S.L. # Copyright (c) 2016-2021 Virtual Cable S.L.U.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without modification, # Redistribution and use in source and binary forms, with or without modification,
@ -60,12 +59,43 @@ class TX2GOTransport(BaseX2GOTransport):
Provides access via X2GO to service. Provides access via X2GO 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 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 = _('X2Go') typeName = _('X2Go')
typeType = 'TX2GOTransport' typeType = 'TX2GOTransport'
typeDescription = _('X2Go access (Experimental). Tunneled connection.') typeDescription = _('X2Go access (Experimental). Tunneled connection.')
group = transports.TUNNELED_GROUP 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) 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=65536,
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.TRUE,
tab=gui.TUNNEL_TAB,
)
fixedName = BaseX2GOTransport.fixedName fixedName = BaseX2GOTransport.fixedName
screenSize = BaseX2GOTransport.screenSize screenSize = BaseX2GOTransport.screenSize
@ -83,7 +113,9 @@ class TX2GOTransport(BaseX2GOTransport):
def initialize(self, values: 'Module.ValuesType'): def initialize(self, values: 'Module.ValuesType'):
if values: if values:
if values['tunnelServer'].count(':') != 1: if values['tunnelServer'].count(':') != 1:
raise BaseX2GOTransport.ValidationException(_('Must use HOST:PORT in Tunnel Server Field')) raise BaseX2GOTransport.ValidationException(
_('Must use HOST:PORT in Tunnel Server Field')
)
def getUDSTransportScript( # pylint: disable=too-many-locals def getUDSTransportScript( # pylint: disable=too-many-locals
self, self,
@ -93,7 +125,7 @@ class TX2GOTransport(BaseX2GOTransport):
os: typing.Dict[str, str], os: typing.Dict[str, str],
user: 'models.User', user: 'models.User',
password: str, password: str,
request: 'HttpRequest' request: 'HttpRequest',
) -> typing.Tuple[str, str, typing.Dict[str, typing.Any]]: ) -> typing.Tuple[str, str, typing.Dict[str, typing.Any]]:
ci = self.getConnectionInfo(userService, user, password) ci = self.getConnectionInfo(userService, user, password)
@ -120,13 +152,16 @@ class TX2GOTransport(BaseX2GOTransport):
rootless=rootless, rootless=rootless,
width=width, width=width,
height=height, height=height,
user=username user=username,
) )
tunpass = ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits) for _i in range(12)) ticket = TicketStore.create_for_tunnel(
tunuser = TicketStore.create(tunpass) userService=userService,
port=22,
validity=self.tunnelWait.num() + 60, # Ticket overtime
)
sshHost, sshPort = self.tunnelServer.value.split(':') tunHost, tunPort = self.tunnelServer.value.split(':')
# data # data
data = { data = {
@ -140,7 +175,7 @@ class TX2GOTransport(BaseX2GOTransport):
'drives': self.exports.isTrue(), 'drives': self.exports.isTrue(),
'fullScreen': width == -1 or height == -1, 'fullScreen': width == -1 or height == -1,
'this_server': request.build_absolute_uri('/'), 'this_server': request.build_absolute_uri('/'),
'xf': xf 'xf': xf,
} }
m = tools.DictAsObj(data) m = tools.DictAsObj(data)
@ -152,17 +187,18 @@ class TX2GOTransport(BaseX2GOTransport):
}.get(os['OS']) }.get(os['OS'])
if osName is None: if osName is None:
return super().getUDSTransportScript(userService, transport, ip, os, user, password, request) return super().getUDSTransportScript(
userService, transport, ip, os, user, password, request
)
sp = { sp = {
'tunUser': tunuser, 'tunHost': tunHost,
'tunPass': tunpass, 'tunPort': tunPort,
'tunHost': sshHost, 'tunWait': self.tunnelWait.num(),
'tunPort': sshPort, 'tunChk': self.verifyCertificate.isTrue(),
'ip': ip, 'ticket': ticket,
'port': '22',
'key': priv, 'key': priv,
'xf': xf 'xf': xf,
} }
return self.getScript('scripts/{}/tunnel.py', osName, sp) return self.getScript('scripts/{}/tunnel.py', osName, sp)

View File

@ -1,3 +0,0 @@
{
"directory": "bower_components"
}

View File

@ -1,21 +0,0 @@
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org
root = true
[*]
# Change these settings to your own preference
indent_style = space
indent_size = 2
# We recommend you to keep these unchanged
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false

View File

@ -1 +0,0 @@
* text=auto

View File

@ -1,4 +0,0 @@
node_modules
.tmp
bower_components
dist

View File

@ -1,3 +0,0 @@
{
"generator-mocha": {}
}

View File

@ -1,428 +0,0 @@
// Generated on 2015-09-21 using
// generator-webapp 1.1.0
'use strict';
// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// If you want to recursively match all subfolders, use:
// 'test/spec/**/*.js'
module.exports = function (grunt) {
// Time how long tasks take. Can help when optimizing build times
require('time-grunt')(grunt);
// Automatically load required grunt tasks
require('jit-grunt')(grunt, {
useminPrepare: 'grunt-usemin'
});
// Configurable paths
var config = {
app: 'app',
dist: 'dist'
};
// Define the configuration for all the tasks
grunt.initConfig({
// Project settings
config: config,
// Watches files for changes and runs tasks based on the changed files
watch: {
bower: {
files: ['bower.json'],
tasks: ['wiredep']
},
babel: {
// files: ['<%= config.app %>/js/{,*/}*.js'],
files: [],
tasks: ['babel:dist']
},
babelTest: {
// files: ['test/spec/{,*/}*.js'],
files: [],
tasks: ['babel:test', 'test:watch']
},
gruntfile: {
files: ['Gruntfile.js']
},
sass: {
files: ['<%= config.app %>/css/{,*/}*.{scss,sass}'],
tasks: ['sass', 'postcss']
},
css: {
files: ['<%= config.app %>/css/{,*/}*.css'],
tasks: ['newer:copy:css', 'postcss']
}
},
browserSync: {
options: {
notify: false,
background: true,
watchOptions: {
ignored: ''
}
},
livereload: {
options: {
files: [
'<%= config.app %>/{,*/}*.html',
'.tmp/css/{,*/}*.css',
'<%= config.app %>/img/{,*/}*',
'.tmp/js/{,*/}*.js'
],
port: 9000,
server: {
baseDir: ['.tmp', config.app],
routes: {
'/bower_components': './bower_components'
}
}
}
},
test: {
options: {
port: 9001,
open: false,
logLevel: 'silent',
host: 'localhost',
server: {
baseDir: ['.tmp', './test', config.app],
routes: {
'/bower_components': './bower_components'
}
}
}
},
dist: {
options: {
background: false,
server: '<%= config.dist %>'
}
}
},
// Empties folders to start fresh
clean: {
dist: {
files: [{
dot: true,
src: [
'.tmp',
'<%= config.dist %>/*',
'!<%= config.dist %>/.git*'
]
}]
},
server: '.tmp'
},
// Make sure code css are up to par and there are no obvious mistakes
eslint: {
target: [
'Gruntfile.js',
// '<%= config.app %>/js/{,*/}*.js',
'!<%= config.app %>/js/vendor/*',
'test/spec/{,*/}*.js'
]
},
// Mocha testing framework configuration options
mocha: {
all: {
options: {
run: true,
urls: ['http://<%= browserSync.test.options.host %>:<%= browserSync.test.options.port %>/index.html']
}
}
},
// Compiles ES6 with Babel
babel: {
options: {
sourceMap: true
},
dist: {
files: [{
expand: true,
cwd: '<%= config.app %>/js',
src: '{,*/}*.jss',
dest: '.tmp/js',
ext: '.jss'
}]
},
test: {
files: [{
expand: true,
cwd: 'test/spec',
src: '{,*/}*.jss',
dest: '.tmp/spec',
ext: '.jss'
}]
}
},
// Compiles Sass to CSS and generates necessary files if requested
sass: {
options: {
sourceMap: true,
sourceMapEmbed: true,
sourceMapContents: true,
includePaths: ['.']
},
dist: {
files: [{
expand: true,
cwd: '<%= config.app %>/css',
src: ['*.{scss,sass}'],
dest: '.tmp/css',
ext: '.css'
}]
}
},
postcss: {
options: {
map: true,
processors: [
// Add vendor prefixed css
require('autoprefixer')({
browsers: ['> 1%', 'last 2 versions', 'Firefox ESR']
})
]
},
dist: {
files: [{
expand: true,
cwd: '.tmp/css/',
src: '{,*/}*.css',
dest: '.tmp/css/'
}]
}
},
// Automatically inject Bower components into the HTML file
wiredep: {
app: {
src: ['<%= config.app %>/index.html'],
exclude: ['bootstrap.js'],
ignorePath: /^(\.\.\/)*\.\./
},
sass: {
src: ['<%= config.app %>/css/{,*/}*.{scss,sass}'],
ignorePath: /^(\.\.\/)+/
}
},
// Renames files for browser caching purposes
filerev: {
dist: {
src: [
'<%= config.dist %>/js/{,*/}*.js',
'<%= config.dist %>/css/{,*/}*.css',
'<%= config.dist %>/img/{,*/}*.*',
'<%= config.dist %>/css/fonts/{,*/}*.*',
'<%= config.dist %>/*.{ico,png}'
]
}
},
// Reads HTML for usemin blocks to enable smart builds that automatically
// concat, minify and revision files. Creates configurations in memory so
// additional tasks can operate on them
useminPrepare: {
options: {
dest: '<%= config.dist %>'
},
html: '<%= config.app %>/index.html'
},
// Performs rewrites based on rev and the useminPrepare configuration
usemin: {
options: {
assetsDirs: [
'<%= config.dist %>',
'<%= config.dist %>/img',
'<%= config.dist %>/css'
]
},
html: ['<%= config.dist %>/{,*/}*.html'],
css: ['<%= config.dist %>/css/{,*/}*.css']
},
// The following *-min tasks produce minified files in the dist folder
imagemin: {
dist: {
files: [{
expand: true,
cwd: '<%= config.app %>/img',
src: '{,*/}*.{gif,jpeg,jpg,png}',
dest: '<%= config.dist %>/img'
}]
}
},
svgmin: {
dist: {
files: [{
expand: true,
cwd: '<%= config.app %>/img',
src: '{,*/}*.svg',
dest: '<%= config.dist %>/img'
}]
}
},
htmlmin: {
dist: {
options: {
collapseBooleanAttributes: true,
collapseWhitespace: true,
conservativeCollapse: true,
removeAttributeQuotes: true,
removeCommentsFromCDATA: true,
removeEmptyAttributes: true,
removeOptionalTags: true,
// true would impact css with attribute selectors
removeRedundantAttributes: false,
useShortDoctype: true
},
files: [{
expand: true,
cwd: '<%= config.dist %>',
src: '{,*/}*.html',
dest: '<%= config.dist %>'
}]
}
},
// By default, your `index.html`'s <!-- Usemin block --> will take care
// of minification. These next options are pre-configured if you do not
// wish to use the Usemin blocks.
// cssmin: {
// dist: {
// files: {
// '<%= config.dist %>/css/main.css': [
// '.tmp/css/{,*/}*.css',
// '<%= config.app %>/css/{,*/}*.css'
// ]
// }
// }
// },
// uglify: {
// dist: {
// files: {
// '<%= config.dist %>/js/js.js': [
// '<%= config.dist %>/js/js.js'
// ]
// }
// }
// },
// concat: {
// dist: {}
// },
// Copies remaining files to places other tasks can use
copy: {
dist: {
files: [{
expand: true,
dot: true,
cwd: '<%= config.app %>',
dest: '<%= config.dist %>',
src: [
'*.{ico,png,txt}',
'img/{,*/}*.webp',
'{,*/}*.html',
'css/fonts/{,*/}*.*'
]
}, {
expand: true,
dot: true,
cwd: '.',
src: 'bower_components/bootstrap-sass/assets/fonts/bootstrap/*',
dest: '<%= config.dist %>'
}]
}
},
// Run some tasks in parallel to speed up build process
concurrent: {
server: [
// 'babel:dist',
'sass'
],
test: [
//'babel'
],
dist: [
//'babel',
'sass',
//'imagemin',
//'svgmin'
]
}
});
grunt.registerTask('serve', 'start the server and preview your app', function (target) {
if (target === 'dist') {
return grunt.task.run(['build', 'browserSync:dist']);
}
grunt.task.run([
'clean:server',
'wiredep',
'concurrent:server',
'postcss',
'browserSync:livereload',
'watch'
]);
});
grunt.registerTask('server', function (target) {
grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
grunt.task.run([target ? ('serve:' + target) : 'serve']);
});
grunt.registerTask('test', function (target) {
if (target !== 'watch') {
grunt.task.run([
'clean:server',
'concurrent:test',
'postcss'
]);
}
grunt.task.run([
'browserSync:test',
'mocha'
]);
});
grunt.registerTask('build', [
'clean:dist',
'wiredep',
'useminPrepare',
'concurrent:dist',
'postcss',
'concat',
'cssmin',
// 'uglify',
'copy:dist'
// 'filerev',
// 'usemin'
// 'htmlmin'
]);
grunt.registerTask('default', [
'newer:eslint',
'test',
'build'
]);
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

View File

@ -1,76 +0,0 @@
$btn-margin: $font-size-base/2;
.btn-alert {
//@include button-variant(complement($brand-danger), darken($brand-danger, 10%), darken($brand-danger, 20%));
@include pretty-buttons(complement($brand-danger), darken($brand-danger, 10%));
margin-right: $btn-margin;
}
.btn-action {
//@include button-variant($btn-default-color, invert($btn-default-color), $btn-default-border);
@include pretty-buttons($btn-default-color, $btn-default-bg);
margin-right: $font-size-base/2;
}
.btn-export {
//@include button-variant($btn-default-color, $btn-default-bg, $btn-default-border);
@include pretty-buttons($btn-default-color, $btn-default-bg);
margin-right: $font-size-base/2;
}
// Default buttons a bit more beautiful
.btn {
&.btn-default {
@include pretty-buttons($btn-default-color, $btn-default-bg);
}
&.btn-primary {
@include pretty-buttons($btn-primary-color, $btn-primary-bg);
}
&.btn-success {
@include pretty-buttons($btn-success-color, $btn-success-bg);
}
&.btn-info {
@include pretty-buttons($btn-info-color, $btn-info-bg);
}
&.btn-warning {
@include pretty-buttons($btn-warning-color, $btn-warning-bg);
}
&.btn-danger {
@include pretty-buttons($btn-danger-color, $btn-danger-bg);
}
&.btn-inverse {
@include pretty-buttons(white, #474949);
}
}
/*.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-primary, .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-primary {
background: #337ab7 none repeat scroll 0 0;
color: #fff;
}*/
.bootstrap-switch {
.bootstrap-switch-label {
@include pretty-buttons($btn-default-color, $btn-default-bg);
}
.bootstrap-switch-handle-on {
&.bootstrap-switch-default {
@include pretty-buttons($btn-default-color, $btn-default-bg);
}
&.bootstrap-switch-primary {
@include pretty-buttons($btn-primary-color, $btn-primary-bg);
}
}
.bootstrap-switch-handle-off {
&.bootstrap-switch-default {
@include pretty-buttons($btn-warning-color, $btn-warning-bg);
}
&.bootstrap-switch-primary {
@include pretty-buttons($btn-warning-color, $btn-warning-bg);
}
}
}

View File

@ -1,42 +0,0 @@
.dataTables_wrapper {
overflow-x: hidden;
}
table.dataTable thead .sorting {
background-image: url("../img/sort_both.png");
}
table.dataTable thead .sorting_asc {
background-image: url("../img/sort_asc.png");
}
table.dataTable thead .sorting_desc {
background-image: url("../img/sort_desc.png");
}
table.dataTable thead .sorting_asc_disabled {
background-image: url("../img/sort_asc_disabled.png");
}
table.dataTable thead .sorting_desc_disabled {
background-image: url("../img/sort_desc_disabled.png");
}
table.dataTable {
border-collapse: inherit;
}
table.dataTable tbody > tr.selected, table.dataTable tbody > tr > .selected {
background-color: lighten($table-bg-active, 30%);
&:hover {
background-color: $table-bg-hover;
}
}
tr.even:not(.selected):not(:hover) {
.sorting_1 {
background-color: darken(#FFFFFF, 5%);
}
}
tr.odd:not(.selected):not(:hover) {
.sorting_1 {
background-color: darken($table-bg-accent, 5%);
}
}

View File

@ -1,89 +0,0 @@
/*
This states displays as default
*/
.row-maintenance-true {
color: lighten($brand-danger, 20%);
}
.log-WARN {
color: $brand-warning;
}
.log-DEBUG {
color: $brand-success;
}
.log-INFO, .log-OTHER {
color: $brand-info;
}
.log-ERROR, &.log-FATAL {
color: $brand-danger;
}
// To position correctly things
.btns-tables {
float: left;
margin-bottom: 16px;
}
.dataTables_info {
float: left;
}
.dataTables_paginate {
float: right;
}
.table {
color: #00496b;
border: 1px solid $brand-primary;
// $font-family-monospace
// $font-family-serif
// $font-family-sans-serif
// font-family: $font-family-monospace;
// font-size: $font-size-large;
> tbody > tr {
cursor: pointer;
}
}
/*.table tbody tr.selected {
background-color: $uds-color-blue;
color: $brand-warning;
&:hover {
background-color: $uds-color-blue-dark;
}
}*/
/*.table-striped > tbody > tr {
td.sorting_1 {
color: $uds-color-blue;
}
}*/
.uds-table {
min-height: $uds-panel-min-height - 48px;
padding-right: 2px;
}
.row-state-S {
color: gray;
}
.row-running-Yes {
color: green;
}
@media (max-width: 768px) {
.label-tbl-button {
display: none;
}
.uds-table {
min-height: 0px;
}
}

View File

@ -1,20 +0,0 @@
// fixes breadcrumb for using
.breadcrumb {
> li {
+ li:before {
content: "/ "; // Unicode space added since inline-block means non-collapsing white-space
}
}
}
.bootstrap-timepicker-widget a.btn, .bootstrap-timepicker-widget input {
background: $input-bg;
border-color: $brand-primary;
border-radius: 0;
border-style: solid;
border-width: 1px;
}
.bootstrap-timepicker-widget table td a {
color: $brand-primary;
}

View File

@ -1,58 +0,0 @@
@mixin pretty-buttons($color, $background, $text-shadow: none) {
color: $color;
@include gradient-vertical(lighten($background, 5%), darken($background, 5%), 0%, 100%);
border-color: darken($background, 10%);
border-bottom-color: darken($background, 20%);
text-shadow: $text-shadow;
//@include box-shadow(inset 0 1px 0 rgba(255, 255, 255, .1));
&:hover,
&:focus,
&:active,
&.active {
@include gradient-vertical(darken($background, 0), darken($background, 10%), 0%, 100%);
border-color: darken($background, 20%);
color: $color;
}
&.disabled,
&[disabled],
fieldset[disabled] & {
&,
&:hover,
&:focus,
&:active,
&.active {
background-color: $background;
border-color: darken($background, 5%);
}
}
}
/*
.btn {
&.btn-default {
@include pretty-buttons($btn-default-color, $btn-default-bg);
}
&.btn-primary {
@include pretty-buttons($btn-primary-color, $btn-primary-bg);
}
&.btn-success {
@include pretty-buttons($btn-success-color, $btn-success-bg);
}
&.btn-info {
@include pretty-buttons($btn-info-color, $btn-info-bg);
}
&.btn-warning {
@include pretty-buttons($btn-warning-color, $btn-warning-bg);
}
&.btn-danger {
@include pretty-buttons($btn-danger-color, $btn-danger-bg);
}
&.btn-inverse {
@include pretty-buttons(white, #474949);
}
}
*/

View File

@ -1,859 +0,0 @@
//
// Variables
// --------------------------------------------------
//== Colors
//
//## Gray and brand colors for use across Bootstrap.
$bg-color1: #252830;
$bg-color2: lighten($bg-color1, 14%);
$gray-base: #FFFFFF;
$gray-darker: darken($gray-base, 13.5%); // #222
$gray-dark: darken($gray-base, 20%); // #333
$gray: darken($gray-base, 33.5%); // #555
$gray-light: darken($gray-base, 46.7%); // #777
$gray-lighter: darken($gray-base, 93.5%); // #eee
$brand-primary: darken(#1CA8DD, 0%); // #337ab7
$brand-success: #1BC98E;
$brand-info: #9F86FF;
$brand-warning: #E4D836;
$brand-danger: #E64759;
//== Scaffolding
//
//## Settings for some of the most global styles.
//** Background color for `<body>`.
$body-bg: $bg-color1;
//** Global text color on `<body>`.
$text-color: $gray-darker;
//** Global textual link color.
$link-color: $brand-primary;
//** Link hover color set via `darken()` function.
$link-hover-color: lighten($link-color, 15%);
//** Link hover decoration.
$link-hover-decoration: underline;
//== Typography
//
//## Font, line-height, and color for body text, headings, and more.
$font-family-sans-serif: "Helvetica Neue", Helvetica, Arial, sans-serif;
$font-family-serif: Georgia, "Times New Roman", Times, serif;
//** Default monospace fonts for `<code>`, `<kbd>`, and `<pre>`.
$font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace;
$font-family-base: $font-family-sans-serif;
$font-size-base: 14px;
$font-size-large: ceil(($font-size-base * 1.25)); // ~18px
$font-size-small: ceil(($font-size-base * 0.85)); // ~12px
$font-size-h1: floor(($font-size-base * 2.6)); // ~36px
$font-size-h2: floor(($font-size-base * 2.15)); // ~30px
$font-size-h3: ceil(($font-size-base * 1.7)); // ~24px
$font-size-h4: ceil(($font-size-base * 1.25)); // ~18px
$font-size-h5: $font-size-base;
$font-size-h6: ceil(($font-size-base * 0.85)); // ~12px
//** Unit-less `line-height` for use in components like buttons.
$line-height-base: 1.428571429; // 20/14
//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
$line-height-computed: floor(($font-size-base * $line-height-base)); // ~20px
//** By default, this inherits from the `<body>`.
$headings-font-family: inherit;
$headings-font-weight: 500;
$headings-line-height: 1.1;
$headings-color: $brand-info;
//== Iconography
//
//## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.
//** Load fonts from this directory.
$icon-font-path: "../fonts/";
//** File name for all font files.
$icon-font-name: "glyphicons-halflings-regular";
//** Element ID within SVG icon file.
$icon-font-svg-id: "glyphicons_halflingsregular";
//== Components
//
//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
$padding-base-vertical: 6px;
$padding-base-horizontal: 12px;
$padding-large-vertical: 10px;
$padding-large-horizontal: 16px;
$padding-small-vertical: 5px;
$padding-small-horizontal: 10px;
$padding-xs-vertical: 1px;
$padding-xs-horizontal: 5px;
$line-height-large: 1.33;
$line-height-small: 1.5;
$border-radius-base: 0px;
$border-radius-large: 0px;
$border-radius-small: 0px;
//** Global color for active items (e.g., navs or dropdowns).
$component-active-color: #fff;
//** Global background color for active items (e.g., navs or dropdowns).
$component-active-bg: $brand-primary;
//** Width of the `border` for generating carets that indicator dropdowns.
$caret-width-base: 4px;
//** Carets increase slightly in size for larger components.
$caret-width-large: 5px;
//== Tables
//
//## Customizes the `.table` component with basic values, each used across all table variations.
//** Padding for `<th>`s and `<td>`s.
$table-cell-padding: 8px;
//** Padding for cells in `.table-condensed`.
$table-condensed-cell-padding: 5px;
//** Default background color used for all tables.
$table-bg: transparent;
//** Background color used for `.table-striped`.
$table-bg-accent: lighten($body-bg, 10%);
//** Background color used for `.table-hover`.
$table-bg-hover: $brand-primary;
$table-bg-active: darken($brand-primary, 20%);
//** Border color for table and cell borders.
$table-border-color: darken($body-bg, 10%);
//== Buttons
//
//## For each of Bootstrap's buttons, define text, background and border color.
$btn-font-weight: normal;
$btn-default-color: $gray-base;
$btn-default-bg: lighten($body-bg, 20%);
$btn-default-border: lighten($body-bg, 10%);
$btn-primary-color: $gray-base;
$btn-primary-bg: $brand-primary;
$btn-primary-border: darken($btn-primary-bg, 5%);
$btn-success-color: $gray-base;
$btn-success-bg: $brand-success;
$btn-success-border: darken($btn-success-bg, 5%);
$btn-info-color: $gray-base;
$btn-info-bg: $brand-info;
$btn-info-border: darken($btn-info-bg, 5%);
$btn-warning-color: $gray-base;
$btn-warning-bg: $brand-warning;
$btn-warning-border: darken($btn-warning-bg, 5%);
$btn-danger-color: $gray-base;
$btn-danger-bg: $brand-danger;
$btn-danger-border: darken($btn-danger-bg, 5%);
$btn-link-disabled-color: $gray-light;
//== Forms
//
//##
//** `<input>` background color
$input-bg: $body-bg;
//** `<input disabled>` background color
$input-bg-disabled: lighten($body-bg, 15%);
//** Text color for `<input>`s
$input-color: $gray-base;
//** `<input>` border color
$input-border: $brand-primary;
// TODO: Rename `$input-border-radius` to `$input-border-radius-base` in v4
//** Default `.form-control` border radius
$input-border-radius: $border-radius-base;
//** Large `.form-control` border radius
$input-border-radius-large: $border-radius-large;
//** Small `.form-control` border radius
$input-border-radius-small: $border-radius-small;
//** Border color for inputs on focus
$input-border-focus: $brand-info;
//** Placeholder text color
$input-color-placeholder: darken($brand-primary, 15%);
//** Default `.form-control` height
$input-height-base: ($line-height-computed + ($padding-base-vertical * 2) + 2);
//** Large `.form-control` height
$input-height-large: (ceil($font-size-large * $line-height-large) + ($padding-large-vertical * 2) + 2);
//** Small `.form-control` height
$input-height-small: (floor($font-size-small * $line-height-small) + ($padding-small-vertical * 2) + 2);
$legend-color: $gray-dark;
$legend-border-color: lighten($body-bg, 15%);
//** Background color for textual input addons
$input-group-addon-bg: $input-bg;
//** Border color for textual input addons
$input-group-addon-border-color: $input-border;
//** Disabled cursor for form controls and buttons.
$cursor-disabled: not-allowed;
//== Dropdowns
//
//## Dropdown menu container and contents.
//** Background for the dropdown menu.
$dropdown-bg: lighten($body-bg, 15%);
//** Dropdown menu `border-color`.
$dropdown-border: lighten($body-bg, 40%);
//** Dropdown menu `border-color` **for IE8**.
$dropdown-fallback-border: lighten($body-bg, 40%);
//** Divider color for between dropdown items.
$dropdown-divider-bg: lighten($body-bg, 40%);
//** Dropdown link text color.
$dropdown-link-color: $gray-dark;
//** Hover color for dropdown links.
$dropdown-link-hover-color: darken($gray-dark, 5%);
//** Hover background for dropdown links.
$dropdown-link-hover-bg: $gray-lighter;
//** Active dropdown menu item text color.
$dropdown-link-active-color: $component-active-color;
//** Active dropdown menu item background color.
$dropdown-link-active-bg: $component-active-bg;
//** Disabled dropdown menu item background color.
$dropdown-link-disabled-color: $gray-light;
//** Text color for headers within dropdown menus.
$dropdown-header-color: $gray-light;
//** Deprecated `$dropdown-caret-color` as of v3.1.0
$dropdown-caret-color: $gray-light;
//-- Z-index master list
//
// Warning: Avoid customizing these values. They're used for a bird's eye view
// of components dependent on the z-axis and are designed to all work together.
//
// Note: These variables are not generated into the Customizer.
$zindex-navbar: 1000;
$zindex-dropdown: 1000;
$zindex-popover: 1060;
$zindex-tooltip: 1070;
$zindex-navbar-fixed: 1030;
$zindex-modal: 1050;
$zindex-modal-background: 1040;
//== Media queries breakpoints
//
//## Define the breakpoints at which your layout will change, adapting to different screen sizes.
// Extra small screen / phone
//** Deprecated `$screen-xs` as of v3.0.1
$screen-xs: 480px;
//** Deprecated `$screen-xs-min` as of v3.2.0
$screen-xs-min: $screen-xs;
//** Deprecated `$screen-phone` as of v3.0.1
$screen-phone: $screen-xs-min;
// Small screen / tablet
//** Deprecated `$screen-sm` as of v3.0.1
$screen-sm: 768px;
$screen-sm-min: $screen-sm;
//** Deprecated `$screen-tablet` as of v3.0.1
$screen-tablet: $screen-sm-min;
// Medium screen / desktop
//** Deprecated `$screen-md` as of v3.0.1
$screen-md: 992px;
$screen-md-min: $screen-md;
//** Deprecated `$screen-desktop` as of v3.0.1
$screen-desktop: $screen-md-min;
// Large screen / wide desktop
//** Deprecated `$screen-lg` as of v3.0.1
$screen-lg: 1200px;
$screen-lg-min: $screen-lg;
//** Deprecated `$screen-lg-desktop` as of v3.0.1
$screen-lg-desktop: $screen-lg-min;
// So media queries don't overlap when required, provide a maximum
$screen-xs-max: ($screen-sm-min - 1);
$screen-sm-max: ($screen-md-min - 1);
$screen-md-max: ($screen-lg-min - 1);
//== Grid system
//
//## Define your custom responsive grid.
//** Number of columns in the grid.
$grid-columns: 12;
//** Padding between columns. Gets divided in half for the left and right.
$grid-gutter-width: 30px;
// Navbar collapse
//** Point at which the navbar becomes uncollapsed.
$grid-float-breakpoint: $screen-sm-min;
//** Point at which the navbar begins collapsing.
$grid-float-breakpoint-max: ($grid-float-breakpoint - 1);
//== Container sizes
//
//## Define the maximum width of `.container` for different screen sizes.
// Small screen / tablet
$container-tablet: (720px + $grid-gutter-width);
//** For `$screen-sm-min` and up.
$container-sm: $container-tablet;
// Medium screen / desktop
$container-desktop: (940px + $grid-gutter-width);
//** For `$screen-md-min` and up.
$container-md: $container-desktop;
// Large screen / wide desktop
$container-large-desktop: (1140px + $grid-gutter-width);
//** For `$screen-lg-min` and up.
$container-lg: $container-large-desktop;
//== Navbar
//
//##
// Basics of a navbar
$navbar-height: 50px;
$navbar-margin-bottom: $line-height-computed;
$navbar-border-radius: $border-radius-base;
$navbar-padding-horizontal: floor(($grid-gutter-width / 2));
$navbar-padding-vertical: (($navbar-height - $line-height-computed) / 2);
$navbar-collapse-max-height: 340px;
$navbar-default-color: #777;
$navbar-default-bg: #f8f8f8;
$navbar-default-border: darken($navbar-default-bg, 6.5%);
// Navbar links
$navbar-default-link-color: #777;
$navbar-default-link-hover-color: #333;
$navbar-default-link-hover-bg: transparent;
$navbar-default-link-active-color: #555;
$navbar-default-link-active-bg: darken($navbar-default-bg, 6.5%);
$navbar-default-link-disabled-color: #ccc;
$navbar-default-link-disabled-bg: transparent;
// Navbar brand label
$navbar-default-brand-color: $navbar-default-link-color;
$navbar-default-brand-hover-color: darken($navbar-default-brand-color, 10%);
$navbar-default-brand-hover-bg: transparent;
// Navbar toggle
$navbar-default-toggle-hover-bg: #ddd;
$navbar-default-toggle-icon-bar-bg: #888;
$navbar-default-toggle-border-color: #ddd;
// Inverted navbar
// Reset inverted navbar basics
$navbar-inverse-color: lighten($gray-light, 15%);
$navbar-inverse-bg: darken($body-bg, 5%);
$navbar-inverse-border: darken($navbar-inverse-bg, 10%);
// Inverted navbar links
$navbar-inverse-link-color: lighten($gray-light, 15%);
$navbar-inverse-link-hover-color: $gray-light;
$navbar-inverse-link-hover-bg: darken($brand-primary, 30%);
$navbar-inverse-link-active-color: $gray-lighter;
$navbar-inverse-link-active-bg: $brand-primary;
$navbar-inverse-link-disabled-color: #444;
$navbar-inverse-link-disabled-bg: transparent;
// Inverted navbar brand label
$navbar-inverse-brand-color: $navbar-inverse-link-color;
$navbar-inverse-brand-hover-color: $brand-primary;
$navbar-inverse-brand-hover-bg: transparent;
// Inverted navbar toggle
$navbar-inverse-toggle-hover-bg: #333;
$navbar-inverse-toggle-icon-bar-bg: #fff;
$navbar-inverse-toggle-border-color: #333;
//== Navs
//
//##
//=== Shared nav styles
$nav-link-padding: 10px 15px;
$nav-link-hover-bg: $gray-lighter;
$nav-disabled-link-color: $gray-light;
$nav-disabled-link-hover-color: $gray-light;
//== Tabs
$nav-tabs-border-color: #ddd;
$nav-tabs-link-hover-border-color: $gray-lighter;
$nav-tabs-active-link-hover-bg: $body-bg;
$nav-tabs-active-link-hover-color: $gray;
$nav-tabs-active-link-hover-border-color: #ddd;
$nav-tabs-justified-link-border-color: #ddd;
$nav-tabs-justified-active-link-border-color: $body-bg;
//== Pills
$nav-pills-border-radius: $border-radius-base;
$nav-pills-active-link-hover-bg: $component-active-bg;
$nav-pills-active-link-hover-color: $component-active-color;
//== Pagination
//
//##
$pagination-color: $link-color;
$pagination-bg: $body-bg;
$pagination-border: $brand-primary;
$pagination-hover-color: $gray-base;
$pagination-hover-bg: $brand-primary;
$pagination-hover-border: $pagination-border;
$pagination-active-color: $gray-lighter;
$pagination-active-bg: $brand-primary;
$pagination-active-border: $brand-primary;
$pagination-disabled-color: darken($pagination-color, 30%);
$pagination-disabled-bg: darken($pagination-bg, 30%);
$pagination-disabled-border: darken($pagination-border, 0%);
//== Pager
//
//##
$pager-bg: $pagination-bg;
$pager-border: $pagination-border;
$pager-border-radius: 0px;
$pager-hover-bg: $pagination-hover-bg;
$pager-active-bg: $pagination-active-bg;
$pager-active-color: $pagination-active-color;
$pager-disabled-color: $pagination-disabled-color;
//== Jumbotron
//
//##
$jumbotron-padding: 30px;
$jumbotron-color: inherit;
$jumbotron-bg: lighten($body-bg,30%);
$jumbotron-heading-color: inherit;
$jumbotron-font-size: ceil(($font-size-base * 1.5));
//== Form states and alerts
//
//## Define colors for form feedback states and, by default, alerts.
$state-success-text: $brand-success;
$state-success-bg: darken($state-success-text, 50%);;
$state-success-border: darken(adjust-hue($state-success-bg, -10), 5%);
$state-info-text: $brand-info;
$state-info-bg: darken($state-info-text, 50%);;
$state-info-border: darken(adjust-hue($state-info-bg, -10), 7%);
$state-warning-text: $brand-warning;
$state-warning-bg: darken($state-warning-text, 50%);
$state-warning-border: darken(adjust-hue($state-warning-bg, -10), 5%);
$state-danger-text: $brand-danger;
$state-danger-bg: darken($state-danger-text, 50%);
$state-danger-border: darken(adjust-hue($state-danger-bg, -10), 5%);
//== Tooltips
//
//##
//** Tooltip max width
$tooltip-max-width: 200px;
//** Tooltip text color
$tooltip-color: $gray-base;
//** Tooltip background color
$tooltip-bg: lighten($body-bg, 25%);
$tooltip-opacity: .9;
//** Tooltip arrow width
$tooltip-arrow-width: 5px;
//** Tooltip arrow color
$tooltip-arrow-color: $tooltip-bg;
//== Popovers
//
//##
//** Popover body background color
$popover-bg: #fff;
//** Popover maximum width
$popover-max-width: 276px;
//** Popover border color
$popover-border-color: rgba(0,0,0,.2);
//** Popover fallback border color
$popover-fallback-border-color: #ccc;
//** Popover title background color
$popover-title-bg: darken($popover-bg, 3%);
//** Popover arrow width
$popover-arrow-width: 10px;
//** Popover arrow color
$popover-arrow-color: $popover-bg;
//** Popover outer arrow width
$popover-arrow-outer-width: ($popover-arrow-width + 1);
//** Popover outer arrow color
$popover-arrow-outer-color: fadein($popover-border-color, 5%);
//** Popover outer arrow fallback color
$popover-arrow-outer-fallback-color: darken($popover-fallback-border-color, 20%);
//== Labels
//
//##
//** Default label background color
$label-default-bg: lighten($body-bg, 15%);
//** Primary label background color
$label-primary-bg: $brand-primary;
//** Success label background color
$label-success-bg: $brand-success;
//** Info label background color
$label-info-bg: $brand-info;
//** Warning label background color
$label-warning-bg: $brand-warning;
//** Danger label background color
$label-danger-bg: $brand-danger;
//** Default label text color
$label-color: $gray-lighter;
//** Default text color of a linked label
$label-link-hover-color: #fff;
//== Modals
//
//##
//** Padding applied to the modal body
$modal-inner-padding: 15px;
//** Padding applied to the modal title
$modal-title-padding: 15px;
//** Modal title line-height
$modal-title-line-height: $line-height-base;
//** Background color of modal content area
$modal-content-bg: lighten($body-bg, 15%);
//** Modal content border color
$modal-content-border-color: $brand-primary;
//** Modal content border color **for IE8**
$modal-content-fallback-border-color: $brand-info;
//** Modal backdrop background color
$modal-backdrop-bg: #000;
//** Modal backdrop opacity
$modal-backdrop-opacity: .4;
//** Modal header border color
$modal-header-border-color: $brand-primary;
//** Modal footer border color
$modal-footer-border-color: $modal-header-border-color;
$modal-lg: 900px;
$modal-md: 600px;
$modal-sm: 300px;
//== Alerts
//
//## Define alert colors, border radius, and padding.
$alert-padding: 15px;
$alert-border-radius: $border-radius-base;
$alert-link-font-weight: bold;
$alert-success-bg: $state-success-bg;
$alert-success-text: $state-success-text;
$alert-success-border: $state-success-border;
$alert-info-bg: $state-info-bg;
$alert-info-text: $state-info-text;
$alert-info-border: $state-info-border;
$alert-warning-bg: $state-warning-bg;
$alert-warning-text: $state-warning-text;
$alert-warning-border: $state-warning-border;
$alert-danger-bg: $state-danger-bg;
$alert-danger-text: $state-danger-text;
$alert-danger-border: $state-danger-border;
//== Progress bars
//
//##
//** Background color of the whole progress component
$progress-bg: lighten($body-bg, 15%);
//** Progress bar text color
$progress-bar-color: #fff;
//** Variable for setting rounded corners on progress bar.
$progress-border-radius: $border-radius-base;
//** Default progress bar color
$progress-bar-bg: $brand-primary;
//** Success progress bar color
$progress-bar-success-bg: $brand-success;
//** Warning progress bar color
$progress-bar-warning-bg: $brand-warning;
//** Danger progress bar color
$progress-bar-danger-bg: $brand-danger;
//** Info progress bar color
$progress-bar-info-bg: $brand-info;
//== List group
//
//##
//** Background color on `.list-group-item`
$list-group-bg: lighten($body-bg, 15%);
//** `.list-group-item` border color
$list-group-border: lighten($body-bg, 30%);
//** List group border radius
$list-group-border-radius: $border-radius-base;
//** Background color of single list items on hover
$list-group-hover-bg: $gray-dark;
//** Text color of active list items
$list-group-active-color: $gray-base;
//** Background color of active list items
$list-group-active-bg: $gray-darker;
//** Border color of active list elements
$list-group-active-border: $list-group-active-bg;
//** Text color for content within active list items
$list-group-active-text-color: lighten($list-group-active-bg, 40%);
//** Text color of disabled list items
$list-group-disabled-color: $gray-darker;
//** Background color of disabled list items
$list-group-disabled-bg: $gray-lighter;
//** Text color for content within disabled list items
$list-group-disabled-text-color: $list-group-disabled-color;
$list-group-link-color: $brand-primary;
$list-group-link-hover-color: $list-group-link-color;
$list-group-link-heading-color: $gray-base;
//== Panels
//
//##
$panel-bg: lighten($body-bg, 15%);
$panel-body-padding: 15px;
$panel-heading-padding: 10px 15px;
$panel-footer-padding: $panel-heading-padding;
$panel-border-radius: $border-radius-base;
//** Border color for elements within panels
$panel-inner-border: $brand-primary;
$panel-footer-bg: lighten($body-bg,5%);
$panel-default-text: $gray-lighter;
$panel-default-border: $brand-primary;
$panel-default-heading-bg: lighten($body-bg, 45%);
$panel-primary-text: $gray-lighter;
$panel-primary-border: $brand-primary;
$panel-primary-heading-bg: $brand-primary;
$panel-success-text: $state-success-text;
$panel-success-border: $state-success-border;
$panel-success-heading-bg: $state-success-bg;
$panel-info-text: $state-info-text;
$panel-info-border: $state-info-border;
$panel-info-heading-bg: $state-info-bg;
$panel-warning-text: $state-warning-text;
$panel-warning-border: $state-warning-border;
$panel-warning-heading-bg: $state-warning-bg;
$panel-danger-text: $state-danger-text;
$panel-danger-border: $state-danger-border;
$panel-danger-heading-bg: $state-danger-bg;
//== Thumbnails
//
//##
//** Padding around the thumbnail image
$thumbnail-padding: 4px;
//** Thumbnail background color
$thumbnail-bg: $body-bg;
//** Thumbnail border color
$thumbnail-border: #ddd;
//** Thumbnail border radius
$thumbnail-border-radius: $border-radius-base;
//** Custom text color for thumbnail captions
$thumbnail-caption-color: $text-color;
//** Padding around the thumbnail caption
$thumbnail-caption-padding: 9px;
//== Wells
//
//##
$well-bg: lighten($body-bg, 15%);
$well-border: darken($well-bg, 7%);
//== Badges
//
//##
$badge-color: #fff;
//** Linked badge text color on hover
$badge-link-hover-color: #fff;
$badge-bg: $gray-light;
//** Badge text color in active nav link
$badge-active-color: $link-color;
//** Badge background color in active nav link
$badge-active-bg: #fff;
$badge-font-weight: bold;
$badge-line-height: 1;
$badge-border-radius: 10px;
//== Breadcrumbs
//
//##
$breadcrumb-padding-vertical: 8px;
$breadcrumb-padding-horizontal: 15px;
//** Breadcrumb background color
$breadcrumb-bg: $body-bg;
//** Breadcrumb text color
$breadcrumb-color: #ccc;
//** Text color of current page in the breadcrumb
$breadcrumb-active-color: $gray-light;
//** Textual separator for between breadcrumb elements
$breadcrumb-separator: "/ ";
//== Carousel
//
//##
$carousel-text-shadow: 0 1px 2px rgba(0,0,0,.6);
$carousel-control-color: #fff;
$carousel-control-width: 15%;
$carousel-control-opacity: .5;
$carousel-control-font-size: 20px;
$carousel-indicator-active-bg: #fff;
$carousel-indicator-border-color: #fff;
$carousel-caption-color: #fff;
//== Close
//
//##
$close-font-weight: bold;
$close-color: #000;
$close-text-shadow: 0 1px 0 #fff;
//== Code
//
//##
$code-color: #c7254e;
$code-bg: #f9f2f4;
$kbd-color: #fff;
$kbd-bg: #333;
$pre-bg: #f5f5f5;
$pre-color: $gray-dark;
$pre-border-color: #ccc;
$pre-scrollable-max-height: 340px;
//== Type
//
//##
//** Horizontal offset for forms and lists.
$component-offset-horizontal: 180px;
//** Text muted color
$text-muted: $gray-light;
//** Abbreviations and acronyms border color
$abbr-border-color: $gray-light;
//** Headings small color
$headings-small-color: $gray-light;
//** Blockquote small color
$blockquote-small-color: $gray-light;
//** Blockquote font size
$blockquote-font-size: ($font-size-base * 1.25);
//** Blockquote border color
$blockquote-border-color: $gray-lighter;
//** Page header border color
$page-header-border-color: $gray-lighter;
//** Width of horizontal description list titles
$dl-horizontal-offset: $component-offset-horizontal;
//** Horizontal line color.
$hr-border: $gray-lighter;

View File

@ -1,857 +0,0 @@
//
// Variables
// --------------------------------------------------
//== Colors
//
//## Gray and brand colors for use across Bootstrap.
$gray-base: #000;
$gray-darker: lighten($gray-base, 13.5%); // #222
$gray-dark: lighten($gray-base, 20%); // #333
$gray: lighten($gray-base, 33.5%); // #555
$gray-light: lighten($gray-base, 46.7%); // #777
$gray-lighter: lighten($gray-base, 93.5%); // #eee
$brand-primary: darken(#428bca, 6.5%); // #337ab7
$brand-success: #5cb85c;
$brand-info: #5bc0de;
$brand-warning: #f0ad4e;
$brand-danger: #d9534f;
//== Scaffolding
//
//## Settings for some of the most global styles.
//** Background color for `<body>`.
$body-bg: #fff;
//** Global text color on `<body>`.
$text-color: $gray-dark;
//** Global textual link color.
$link-color: $brand-primary;
//** Link hover color set via `darken()` function.
$link-hover-color: darken($link-color, 15%);
//** Link hover decoration.
$link-hover-decoration: underline;
//== Typography
//
//## Font, line-height, and color for body text, headings, and more.
$font-family-sans-serif: "Helvetica Neue", Helvetica, Arial, sans-serif;
$font-family-serif: Georgia, "Times New Roman", Times, serif;
//** Default monospace fonts for `<code>`, `<kbd>`, and `<pre>`.
$font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace;
$font-family-base: $font-family-sans-serif;
$font-size-base: 14px;
$font-size-large: ceil(($font-size-base * 1.25)); // ~18px
$font-size-small: ceil(($font-size-base * 0.85)); // ~12px
$font-size-h1: floor(($font-size-base * 2.6)); // ~36px
$font-size-h2: floor(($font-size-base * 2.15)); // ~30px
$font-size-h3: ceil(($font-size-base * 1.7)); // ~24px
$font-size-h4: ceil(($font-size-base * 1.25)); // ~18px
$font-size-h5: $font-size-base;
$font-size-h6: ceil(($font-size-base * 0.85)); // ~12px
//** Unit-less `line-height` for use in components like buttons.
$line-height-base: 1.428571429; // 20/14
//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
$line-height-computed: floor(($font-size-base * $line-height-base)); // ~20px
//** By default, this inherits from the `<body>`.
$headings-font-family: inherit;
$headings-font-weight: 500;
$headings-line-height: 1.1;
$headings-color: inherit;
//== Iconography
//
//## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.
//** Load fonts from this directory.
$icon-font-path: "../fonts/";
//** File name for all font files.
$icon-font-name: "glyphicons-halflings-regular";
//** Element ID within SVG icon file.
$icon-font-svg-id: "glyphicons_halflingsregular";
//== Components
//
//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
$padding-base-vertical: 6px;
$padding-base-horizontal: 12px;
$padding-large-vertical: 10px;
$padding-large-horizontal: 16px;
$padding-small-vertical: 5px;
$padding-small-horizontal: 10px;
$padding-xs-vertical: 1px;
$padding-xs-horizontal: 5px;
$line-height-large: 1.33;
$line-height-small: 1.5;
$border-radius-base: 0px;
$border-radius-large: 0px;
$border-radius-small: 0px;
//** Global color for active items (e.g., navs or dropdowns).
$component-active-color: #fff;
//** Global background color for active items (e.g., navs or dropdowns).
$component-active-bg: $brand-primary;
//** Width of the `border` for generating carets that indicator dropdowns.
$caret-width-base: 4px;
//** Carets increase slightly in size for larger components.
$caret-width-large: 5px;
//== Tables
//
//## Customizes the `.table` component with basic values, each used across all table variations.
//** Padding for `<th>`s and `<td>`s.
$table-cell-padding: 8px;
//** Padding for cells in `.table-condensed`.
$table-condensed-cell-padding: 5px;
//** Default background color used for all tables.
$table-bg: transparent;
//** Background color used for `.table-striped`.
$table-bg-accent: #e1eef4;
//** Background color used for `.table-hover`.
$table-bg-hover: lighten($brand-primary, 10%);
$table-bg-active: $table-bg-hover;
//** Border color for table and cell borders.
$table-border-color: #ddd;
//== Buttons
//
//## For each of Bootstrap's buttons, define text, background and border color.
$btn-font-weight: normal;
$btn-default-color: #333;
$btn-default-bg: #fff;
$btn-default-border: #ccc;
$btn-primary-color: #fff;
$btn-primary-bg: $brand-primary;
$btn-primary-border: darken($btn-primary-bg, 5%);
$btn-success-color: #fff;
$btn-success-bg: $brand-success;
$btn-success-border: darken($btn-success-bg, 5%);
$btn-info-color: #fff;
$btn-info-bg: $brand-info;
$btn-info-border: darken($btn-info-bg, 5%);
$btn-warning-color: #fff;
$btn-warning-bg: $brand-warning;
$btn-warning-border: darken($btn-warning-bg, 5%);
$btn-danger-color: #fff;
$btn-danger-bg: $brand-danger;
$btn-danger-border: darken($btn-danger-bg, 5%);
$btn-link-disabled-color: $gray-light;
//== Forms
//
//##
//** `<input>` background color
$input-bg: #fff;
//** `<input disabled>` background color
$input-bg-disabled: $gray-lighter;
//** Text color for `<input>`s
$input-color: $gray;
//** `<input>` border color
$input-border: #ccc;
// TODO: Rename `$input-border-radius` to `$input-border-radius-base` in v4
//** Default `.form-control` border radius
$input-border-radius: $border-radius-base;
//** Large `.form-control` border radius
$input-border-radius-large: $border-radius-large;
//** Small `.form-control` border radius
$input-border-radius-small: $border-radius-small;
//** Border color for inputs on focus
$input-border-focus: #66afe9;
//** Placeholder text color
$input-color-placeholder: #999;
//** Default `.form-control` height
$input-height-base: ($line-height-computed + ($padding-base-vertical * 2) + 2);
//** Large `.form-control` height
$input-height-large: (ceil($font-size-large * $line-height-large) + ($padding-large-vertical * 2) + 2);
//** Small `.form-control` height
$input-height-small: (floor($font-size-small * $line-height-small) + ($padding-small-vertical * 2) + 2);
$legend-color: $gray-dark;
$legend-border-color: #e5e5e5;
//** Background color for textual input addons
$input-group-addon-bg: $gray-lighter;
//** Border color for textual input addons
$input-group-addon-border-color: $input-border;
//** Disabled cursor for form controls and buttons.
$cursor-disabled: not-allowed;
//== Dropdowns
//
//## Dropdown menu container and contents.
//** Background for the dropdown menu.
$dropdown-bg: #fff;
//** Dropdown menu `border-color`.
$dropdown-border: rgba(0,0,0,.15);
//** Dropdown menu `border-color` **for IE8**.
$dropdown-fallback-border: #ccc;
//** Divider color for between dropdown items.
$dropdown-divider-bg: #e5e5e5;
//** Dropdown link text color.
$dropdown-link-color: $gray-dark;
//** Hover color for dropdown links.
$dropdown-link-hover-color: darken($gray-dark, 5%);
//** Hover background for dropdown links.
$dropdown-link-hover-bg: #f5f5f5;
//** Active dropdown menu item text color.
$dropdown-link-active-color: $component-active-color;
//** Active dropdown menu item background color.
$dropdown-link-active-bg: $component-active-bg;
//** Disabled dropdown menu item background color.
$dropdown-link-disabled-color: $gray-light;
//** Text color for headers within dropdown menus.
$dropdown-header-color: $gray-light;
//** Deprecated `$dropdown-caret-color` as of v3.1.0
$dropdown-caret-color: #000;
//-- Z-index master list
//
// Warning: Avoid customizing these values. They're used for a bird's eye view
// of components dependent on the z-axis and are designed to all work together.
//
// Note: These variables are not generated into the Customizer.
$zindex-navbar: 1000;
$zindex-dropdown: 1000;
$zindex-popover: 1060;
$zindex-tooltip: 1070;
$zindex-navbar-fixed: 1030;
$zindex-modal: 1050;
$zindex-modal-background: 1040;
//== Media queries breakpoints
//
//## Define the breakpoints at which your layout will change, adapting to different screen sizes.
// Extra small screen / phone
//** Deprecated `$screen-xs` as of v3.0.1
$screen-xs: 480px;
//** Deprecated `$screen-xs-min` as of v3.2.0
$screen-xs-min: $screen-xs;
//** Deprecated `$screen-phone` as of v3.0.1
$screen-phone: $screen-xs-min;
// Small screen / tablet
//** Deprecated `$screen-sm` as of v3.0.1
$screen-sm: 768px;
$screen-sm-min: $screen-sm;
//** Deprecated `$screen-tablet` as of v3.0.1
$screen-tablet: $screen-sm-min;
// Medium screen / desktop
//** Deprecated `$screen-md` as of v3.0.1
$screen-md: 992px;
$screen-md-min: $screen-md;
//** Deprecated `$screen-desktop` as of v3.0.1
$screen-desktop: $screen-md-min;
// Large screen / wide desktop
//** Deprecated `$screen-lg` as of v3.0.1
$screen-lg: 1200px;
$screen-lg-min: $screen-lg;
//** Deprecated `$screen-lg-desktop` as of v3.0.1
$screen-lg-desktop: $screen-lg-min;
// So media queries don't overlap when required, provide a maximum
$screen-xs-max: ($screen-sm-min - 1);
$screen-sm-max: ($screen-md-min - 1);
$screen-md-max: ($screen-lg-min - 1);
//== Grid system
//
//## Define your custom responsive grid.
//** Number of columns in the grid.
$grid-columns: 12;
//** Padding between columns. Gets divided in half for the left and right.
$grid-gutter-width: 30px;
// Navbar collapse
//** Point at which the navbar becomes uncollapsed.
$grid-float-breakpoint: $screen-sm-min;
//** Point at which the navbar begins collapsing.
$grid-float-breakpoint-max: ($grid-float-breakpoint - 1);
//== Container sizes
//
//## Define the maximum width of `.container` for different screen sizes.
// Small screen / tablet
$container-tablet: (720px + $grid-gutter-width);
//** For `$screen-sm-min` and up.
$container-sm: $container-tablet;
// Medium screen / desktop
$container-desktop: (940px + $grid-gutter-width);
//** For `$screen-md-min` and up.
$container-md: $container-desktop;
// Large screen / wide desktop
$container-large-desktop: (1140px + $grid-gutter-width);
//** For `$screen-lg-min` and up.
$container-lg: $container-large-desktop;
//== Navbar
//
//##
// Basics of a navbar
$navbar-height: 50px;
$navbar-margin-bottom: $line-height-computed;
$navbar-border-radius: $border-radius-base;
$navbar-padding-horizontal: floor(($grid-gutter-width / 2));
$navbar-padding-vertical: (($navbar-height - $line-height-computed) / 2);
$navbar-collapse-max-height: 340px;
$navbar-default-color: #777;
$navbar-default-bg: #f8f8f8;
$navbar-default-border: darken($navbar-default-bg, 6.5%);
// Navbar links
$navbar-default-link-color: #777;
$navbar-default-link-hover-color: #333;
$navbar-default-link-hover-bg: transparent;
$navbar-default-link-active-color: #555;
$navbar-default-link-active-bg: darken($navbar-default-bg, 6.5%);
$navbar-default-link-disabled-color: #ccc;
$navbar-default-link-disabled-bg: transparent;
// Navbar brand label
$navbar-default-brand-color: $navbar-default-link-color;
$navbar-default-brand-hover-color: darken($navbar-default-brand-color, 10%);
$navbar-default-brand-hover-bg: transparent;
// Navbar toggle
$navbar-default-toggle-hover-bg: #ddd;
$navbar-default-toggle-icon-bar-bg: #888;
$navbar-default-toggle-border-color: #ddd;
// Inverted navbar
// Reset inverted navbar basics
$navbar-inverse-color: lighten($gray-light, 15%);
$navbar-inverse-bg: #222;
$navbar-inverse-border: darken($navbar-inverse-bg, 10%);
// Inverted navbar links
$navbar-inverse-link-color: lighten($gray-light, 15%);
$navbar-inverse-link-hover-color: #fff;
$navbar-inverse-link-hover-bg: transparent;
$navbar-inverse-link-active-color: $navbar-inverse-link-hover-color;
$navbar-inverse-link-active-bg: darken($navbar-inverse-bg, 10%);
$navbar-inverse-link-disabled-color: #444;
$navbar-inverse-link-disabled-bg: transparent;
// Inverted navbar brand label
$navbar-inverse-brand-color: $navbar-inverse-link-color;
$navbar-inverse-brand-hover-color: #fff;
$navbar-inverse-brand-hover-bg: transparent;
// Inverted navbar toggle
$navbar-inverse-toggle-hover-bg: #333;
$navbar-inverse-toggle-icon-bar-bg: #fff;
$navbar-inverse-toggle-border-color: #333;
//== Navs
//
//##
//=== Shared nav styles
$nav-link-padding: 10px 15px;
$nav-link-hover-bg: $gray-lighter;
$nav-disabled-link-color: $gray-light;
$nav-disabled-link-hover-color: $gray-light;
//== Tabs
$nav-tabs-border-color: #ddd;
$nav-tabs-link-hover-border-color: $gray-lighter;
$nav-tabs-active-link-hover-bg: $body-bg;
$nav-tabs-active-link-hover-color: $gray;
$nav-tabs-active-link-hover-border-color: #ddd;
$nav-tabs-justified-link-border-color: #ddd;
$nav-tabs-justified-active-link-border-color: $body-bg;
//== Pills
$nav-pills-border-radius: $border-radius-base;
$nav-pills-active-link-hover-bg: $component-active-bg;
$nav-pills-active-link-hover-color: $component-active-color;
//== Pagination
//
//##
$pagination-color: $link-color;
$pagination-bg: #fff;
$pagination-border: #ddd;
$pagination-hover-color: $link-hover-color;
$pagination-hover-bg: $gray-lighter;
$pagination-hover-border: #ddd;
$pagination-active-color: #fff;
$pagination-active-bg: $brand-primary;
$pagination-active-border: $brand-primary;
$pagination-disabled-color: $gray-light;
$pagination-disabled-bg: #fff;
$pagination-disabled-border: #ddd;
//== Pager
//
//##
$pager-bg: $pagination-bg;
$pager-border: $pagination-border;
$pager-border-radius: 15px;
$pager-hover-bg: $pagination-hover-bg;
$pager-active-bg: $pagination-active-bg;
$pager-active-color: $pagination-active-color;
$pager-disabled-color: $pagination-disabled-color;
//== Jumbotron
//
//##
$jumbotron-padding: 30px;
$jumbotron-color: inherit;
$jumbotron-bg: $gray-lighter;
$jumbotron-heading-color: inherit;
$jumbotron-font-size: ceil(($font-size-base * 1.5));
//== Form states and alerts
//
//## Define colors for form feedback states and, by default, alerts.
$state-success-text: #3c763d;
$state-success-bg: #dff0d8;
$state-success-border: darken(adjust-hue($state-success-bg, -10), 5%);
$state-info-text: #31708f;
$state-info-bg: #d9edf7;
$state-info-border: darken(adjust-hue($state-info-bg, -10), 7%);
$state-warning-text: #8a6d3b;
$state-warning-bg: #fcf8e3;
$state-warning-border: darken(adjust-hue($state-warning-bg, -10), 5%);
$state-danger-text: #a94442;
$state-danger-bg: #f2dede;
$state-danger-border: darken(adjust-hue($state-danger-bg, -10), 5%);
//== Tooltips
//
//##
//** Tooltip max width
$tooltip-max-width: 200px;
//** Tooltip text color
$tooltip-color: #fff;
//** Tooltip background color
$tooltip-bg: #000;
$tooltip-opacity: .9;
//** Tooltip arrow width
$tooltip-arrow-width: 5px;
//** Tooltip arrow color
$tooltip-arrow-color: $tooltip-bg;
//== Popovers
//
//##
//** Popover body background color
$popover-bg: #fff;
//** Popover maximum width
$popover-max-width: 276px;
//** Popover border color
$popover-border-color: rgba(0,0,0,.2);
//** Popover fallback border color
$popover-fallback-border-color: #ccc;
//** Popover title background color
$popover-title-bg: darken($popover-bg, 3%);
//** Popover arrow width
$popover-arrow-width: 10px;
//** Popover arrow color
$popover-arrow-color: $popover-bg;
//** Popover outer arrow width
$popover-arrow-outer-width: ($popover-arrow-width + 1);
//** Popover outer arrow color
$popover-arrow-outer-color: fadein($popover-border-color, 5%);
//** Popover outer arrow fallback color
$popover-arrow-outer-fallback-color: darken($popover-fallback-border-color, 20%);
//== Labels
//
//##
//** Default label background color
$label-default-bg: $gray-light;
//** Primary label background color
$label-primary-bg: $brand-primary;
//** Success label background color
$label-success-bg: $brand-success;
//** Info label background color
$label-info-bg: $brand-info;
//** Warning label background color
$label-warning-bg: $brand-warning;
//** Danger label background color
$label-danger-bg: $brand-danger;
//** Default label text color
$label-color: #fff;
//** Default text color of a linked label
$label-link-hover-color: #fff;
//== Modals
//
//##
//** Padding applied to the modal body
$modal-inner-padding: 15px;
//** Padding applied to the modal title
$modal-title-padding: 15px;
//** Modal title line-height
$modal-title-line-height: $line-height-base;
//** Background color of modal content area
$modal-content-bg: #fff;
//** Modal content border color
$modal-content-border-color: rgba(0,0,0,.2);
//** Modal content border color **for IE8**
$modal-content-fallback-border-color: #999;
//** Modal backdrop background color
$modal-backdrop-bg: #000;
//** Modal backdrop opacity
$modal-backdrop-opacity: .5;
//** Modal header border color
$modal-header-border-color: #e5e5e5;
//** Modal footer border color
$modal-footer-border-color: $modal-header-border-color;
$modal-lg: 900px;
$modal-md: 600px;
$modal-sm: 300px;
//== Alerts
//
//## Define alert colors, border radius, and padding.
$alert-padding: 15px;
$alert-border-radius: $border-radius-base;
$alert-link-font-weight: bold;
$alert-success-bg: $state-success-bg;
$alert-success-text: $state-success-text;
$alert-success-border: $state-success-border;
$alert-info-bg: $state-info-bg;
$alert-info-text: $state-info-text;
$alert-info-border: $state-info-border;
$alert-warning-bg: $state-warning-bg;
$alert-warning-text: $state-warning-text;
$alert-warning-border: $state-warning-border;
$alert-danger-bg: $state-danger-bg;
$alert-danger-text: $state-danger-text;
$alert-danger-border: $state-danger-border;
//== Progress bars
//
//##
//** Background color of the whole progress component
$progress-bg: #f5f5f5;
//** Progress bar text color
$progress-bar-color: #fff;
//** Variable for setting rounded corners on progress bar.
$progress-border-radius: $border-radius-base;
//** Default progress bar color
$progress-bar-bg: $brand-primary;
//** Success progress bar color
$progress-bar-success-bg: $brand-success;
//** Warning progress bar color
$progress-bar-warning-bg: $brand-warning;
//** Danger progress bar color
$progress-bar-danger-bg: $brand-danger;
//** Info progress bar color
$progress-bar-info-bg: $brand-info;
//== List group
//
//##
//** Background color on `.list-group-item`
$list-group-bg: #fff;
//** `.list-group-item` border color
$list-group-border: #ddd;
//** List group border radius
$list-group-border-radius: $border-radius-base;
//** Background color of single list items on hover
$list-group-hover-bg: #f5f5f5;
//** Text color of active list items
$list-group-active-color: $component-active-color;
//** Background color of active list items
$list-group-active-bg: $component-active-bg;
//** Border color of active list elements
$list-group-active-border: $list-group-active-bg;
//** Text color for content within active list items
$list-group-active-text-color: lighten($list-group-active-bg, 40%);
//** Text color of disabled list items
$list-group-disabled-color: $gray-light;
//** Background color of disabled list items
$list-group-disabled-bg: $gray-lighter;
//** Text color for content within disabled list items
$list-group-disabled-text-color: $list-group-disabled-color;
$list-group-link-color: #555;
$list-group-link-hover-color: $list-group-link-color;
$list-group-link-heading-color: #333;
//== Panels
//
//##
$panel-bg: #fff;
$panel-body-padding: 15px;
$panel-heading-padding: 10px 15px;
$panel-footer-padding: $panel-heading-padding;
$panel-border-radius: $border-radius-base;
//** Border color for elements within panels
$panel-inner-border: #ddd;
$panel-footer-bg: #f5f5f5;
$panel-default-text: $gray-dark;
$panel-default-border: #ddd;
$panel-default-heading-bg: #f5f5f5;
$panel-primary-text: #fff;
$panel-primary-border: $brand-primary;
$panel-primary-heading-bg: $brand-primary;
$panel-success-text: $state-success-text;
$panel-success-border: $state-success-border;
$panel-success-heading-bg: $state-success-bg;
$panel-info-text: $state-info-text;
$panel-info-border: $state-info-border;
$panel-info-heading-bg: $state-info-bg;
$panel-warning-text: $state-warning-text;
$panel-warning-border: $state-warning-border;
$panel-warning-heading-bg: $state-warning-bg;
$panel-danger-text: $state-danger-text;
$panel-danger-border: $state-danger-border;
$panel-danger-heading-bg: $state-danger-bg;
//== Thumbnails
//
//##
//** Padding around the thumbnail image
$thumbnail-padding: 4px;
//** Thumbnail background color
$thumbnail-bg: $body-bg;
//** Thumbnail border color
$thumbnail-border: #ddd;
//** Thumbnail border radius
$thumbnail-border-radius: $border-radius-base;
//** Custom text color for thumbnail captions
$thumbnail-caption-color: $text-color;
//** Padding around the thumbnail caption
$thumbnail-caption-padding: 9px;
//== Wells
//
//##
$well-bg: #f5f5f5;
$well-border: darken($well-bg, 7%);
//== Badges
//
//##
$badge-color: #fff;
//** Linked badge text color on hover
$badge-link-hover-color: #fff;
$badge-bg: $gray-light;
//** Badge text color in active nav link
$badge-active-color: $link-color;
//** Badge background color in active nav link
$badge-active-bg: #fff;
$badge-font-weight: bold;
$badge-line-height: 1;
$badge-border-radius: 10px;
//== Breadcrumbs
//
//##
$breadcrumb-padding-vertical: 8px;
$breadcrumb-padding-horizontal: 15px;
//** Breadcrumb background color
$breadcrumb-bg: #f5f5f5;
//** Breadcrumb text color
$breadcrumb-color: #ccc;
//** Text color of current page in the breadcrumb
$breadcrumb-active-color: $gray-light;
//** Textual separator for between breadcrumb elements
$breadcrumb-separator: "/";
//== Carousel
//
//##
$carousel-text-shadow: 0 1px 2px rgba(0,0,0,.6);
$carousel-control-color: #fff;
$carousel-control-width: 15%;
$carousel-control-opacity: .5;
$carousel-control-font-size: 20px;
$carousel-indicator-active-bg: #fff;
$carousel-indicator-border-color: #fff;
$carousel-caption-color: #fff;
//== Close
//
//##
$close-font-weight: bold;
$close-color: #000;
$close-text-shadow: 0 1px 0 #fff;
//== Code
//
//##
$code-color: #c7254e;
$code-bg: #f9f2f4;
$kbd-color: #fff;
$kbd-bg: #333;
$pre-bg: #f5f5f5;
$pre-color: $gray-dark;
$pre-border-color: #ccc;
$pre-scrollable-max-height: 340px;
//== Type
//
//##
//** Horizontal offset for forms and lists.
$component-offset-horizontal: 180px;
//** Text muted color
$text-muted: $gray-light;
//** Abbreviations and acronyms border color
$abbr-border-color: $gray-light;
//** Headings small color
$headings-small-color: $gray-light;
//** Blockquote small color
$blockquote-small-color: $gray-light;
//** Blockquote font size
$blockquote-font-size: ($font-size-base * 1.25);
//** Blockquote border color
$blockquote-border-color: $gray-lighter;
//** Page header border color
$page-header-border-color: $gray-lighter;
//** Width of horizontal description list titles
$dl-horizontal-offset: $component-offset-horizontal;
//** Horizontal line color.
$hr-border: $gray-lighter;

View File

@ -1,361 +0,0 @@
// Widgets
$widget-head-bg-start: darken($body-bg, 10%);
$widget-head-bg-end: darken($body-bg, 15%);
$widget-body-bg: transparent;
$widget-border-color: darken($body-bg, 25%);
.widget {
background: $widget-body-bg;
border: 1px solid $widget-border-color;
margin: 0 auto 20px;
position: static;
.tab-content {
padding: 0;
}
.widget-head {
background-color: $widget-head-bg-start;
background-image: linear-gradient(to bottom, $widget-head-bg-start, $widget-head-bg-end);
background-image: -moz-linear-gradient(top, $widget-head-bg-start, $widget-head-bg-end);
background-image: -o-linear-gradient(top, $widget-head-bg-start, $widget-head-bg-end);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from($widget-head-bg-start), to($widget-head-bg-end));
background-image: -webkit-linear-gradient(top, $widget-head-bg-start, $widget-head-bg-end);
background-repeat: repeat-x;
border-bottom: 1px solid $widget-border-color;
color: $text-color;
height: 40px;
line-height: 40px;
padding: 0 15px 0 0;
position: relative;
// text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
&.progress {
border-radius: 0 0 0 0;
margin: 0;
moz-border-radius: 0 0 0 0;
padding: 0;
webkit-border-radius: 0 0 0 0;
}
.glyphicons {
height: 40px;
padding: 0;
width: 30px;
}
.fai:before {
color: rgba(255, 255, 255, 0.5);
font-size: 16px;
height: 40px;
line-height: 31px;
text-align: center;
width: 30px;
}
.heading {
color: $text-color;
float: left;
font-size: 14px;
height: 40px;
line-height: 40px;
margin: 0;
padding: 0 15px;
&.glyphicons {
display: block;
padding: 0 0 0 35px;
width: auto;
}
&.fai:before {
color: #45484d;
font-size: 16px;
font-weight: normal;
height: 40px;
left: 0;
line-height: 40px;
margin: 0;
padding: 0;
text-align: center;
text-shadow: none;
top: 0;
width: 35px;
}
}
a {
text-shadow: none;
}
.dropdown-menu li > a {
&:hover, &:focus {
background-color: $body-bg;
background-image: linear-gradient(to bottom, $body-bg, #d24343);
background-image: -moz-linear-gradient(top, $body-bg, #d24343);
background-image: -o-linear-gradient(top, $body-bg, #d24343);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from($body-bg), to(#d24343));
background-image: -webkit-linear-gradient(top, $body-bg, #d24343);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffda4c4c', endColorstr='#ffd24343', GradientType=0);
}
}
.dropdown-submenu:hover > a {
background-color: $body-bg;
background-image: linear-gradient(to bottom, $body-bg, #d24343);
background-image: -moz-linear-gradient(top, $body-bg, #d24343);
background-image: -o-linear-gradient(top, $body-bg, #d24343);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from($body-bg), to(#d24343));
background-image: -webkit-linear-gradient(top, $body-bg, #d24343);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffda4c4c', endColorstr='#ffd24343', GradientType=0);
}
}
.details {
color: $text-color;
font-size: 8pt;
}
.widget-body {
padding: 20px 15px;
background-color: $widget-body-bg;
form {
margin: 0;
}
.count {
font-size: 15pt;
font-weight: 400;
}
> p:last-child {
margin: 0;
}
&.list {
color: #575655;
padding: 0;
ul {
list-style: none;
margin: 0;
li {
border-bottom: 1px solid rgba(0, 0, 0, 0.02);
clear: both;
height: 39px;
line-height: 39px;
padding: 0 10px;
text-align: left;
&:first-child {
border-top: none;
}
&:last-child {
border-bottom: none;
}
.count {
color: $body-bg;
float: right;
}
.sparkline {
margin-left: 5px;
position: relative;
top: 5px;
}
}
}
&.products {
li {
height: 60px;
line-height: 60px;
}
.img {
background: #272729;
border-radius: 3px 3px 3px 3px;
color: #818181;
cursor: pointer;
display: inline-block;
float: left;
font-size: 10pt;
font-weight: 600;
height: 44px;
line-height: 44px;
margin: 8px 8px 0 0;
moz-border-radius: 3px 3px 3px 3px;
text-align: center;
webkit-border-radius: 3px 3px 3px 3px;
width: 48px;
}
.title {
display: inline-block;
font-family: "Raleway",sans-serif;
line-height: normal;
padding: 13px 0 0;
text-transform: uppercase;
strong {
font-family: "Open Sans",sans-serif;
text-transform: none;
}
}
}
&.fluid ul li {
height: auto;
line-height: normal;
padding: 10px;
}
&.list-2 ul li {
background: #f8f8f8;
border-bottom: 1px solid #d8d9da;
border-top: none;
&.active {
background: #fff;
border-color: #dddddd;
i:before {
background: $body-bg;
color: #fff;
font-weight: normal;
text-shadow: none;
}
a {
color: $body-bg;
}
}
&:last-child {
border-bottom: none;
}
a {
color: #222;
display: block;
padding: 0 0 0 30px;
i:before {
background: #dddddd;
border: 1px solid #ccc;
color: #555;
font-size: 14px;
height: 17px;
left: 0;
padding-top: 3px;
text-align: center;
text-shadow: 0 1px 0 #fff;
top: 9px;
vertical-align: middle;
width: 20px;
}
}
&.hasSubmenu {
height: auto;
ul {
padding: 0 0 10px;
li {
background: none;
border: none;
height: auto;
line-height: 20px;
line-height: normal;
a {
color: #333;
padding: 0 0 0 20px;
}
&.active a {
font-weight: bold;
}
}
}
}
}
}
}
.widget-footer {
background: $body-bg;
// border-bottom: 1px solid $widget-border-color;
border-top: 1px solid $widget-border-color;
height: 25px;
line-height: 25px;
.fa {
float: right;
height: 25px;
line-height: 25px;
padding: 0;
width: 25px;
i:before {
color: #c3c3c3;
font-size: 16px;
height: 25px;
line-height: 25px;
text-align: center;
text-shadow: 0 1px 0 #fff;
width: 20px;
}
&:hover i:before {
color: rgba(0, 0, 0, 0.5);
}
}
}
&.margin-bottom-none {
margin-bottom: 0;
}
&.widget-gray {
background: #f5f5f5;
.widget-head {
background: #e9e9e9;
border-color: #d1d2d3;
box-shadow: inset 1px 1px 1px rgba(255, 255, 255, 0.6), inset -1px -1px 1px rgba(0, 0, 0, 0);
moz-box-shadow: inset 1px 1px 1px rgba(255, 255, 255, 0.6), inset -1px -1px 1px rgba(0, 0, 0, 0);
webkit-box-shadow: inset 1px 1px 1px rgba(255, 255, 255, 0.6), inset -1px -1px 1px rgba(0, 0, 0, 0);
.heading {
color: #555555;
text-shadow: 0 1px 0 #fff;
&.fai:before {
background: none;
border-color: rgba(0, 0, 0, 0.1);
color: #555;
}
}
}
}
&.widget-body-white .widget-body {
background: $body-bg;
}
}
.widget-icon {
margin-left: 0.6em !important;
cursor: pointer;
}

View File

@ -1,195 +0,0 @@
/* ========================================================================
* bootstrap-switch - v3.3.2
* http://www.bootstrap-switch.org
* ========================================================================
* Copyright 2012-2013 Mattia Larentis
*
* ========================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ========================================================================
*/
.bootstrap-switch {
display: inline-block;
direction: ltr;
cursor: pointer;
border-radius: 4px;
border: 1px solid;
border-color: #cccccc;
position: relative;
text-align: left;
overflow: hidden;
line-height: 8px;
z-index: 0;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
vertical-align: middle;
-webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
-o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
}
.bootstrap-switch .bootstrap-switch-container {
display: inline-block;
top: 0;
border-radius: 4px;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
.bootstrap-switch .bootstrap-switch-handle-on,
.bootstrap-switch .bootstrap-switch-handle-off,
.bootstrap-switch .bootstrap-switch-label {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
cursor: pointer;
display: inline-block !important;
height: 100%;
padding: 6px 12px;
font-size: 14px;
line-height: 20px;
}
.bootstrap-switch .bootstrap-switch-handle-on,
.bootstrap-switch .bootstrap-switch-handle-off {
text-align: center;
z-index: 1;
}
.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-primary,
.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-primary {
color: #fff;
background: #337ab7;
}
.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-info,
.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-info {
color: #fff;
background: #5bc0de;
}
.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-success,
.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-success {
color: #fff;
background: #5cb85c;
}
.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-warning,
.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-warning {
background: #f0ad4e;
color: #fff;
}
.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-danger,
.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-danger {
color: #fff;
background: #d9534f;
}
.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-default,
.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-default {
color: #000;
background: #eeeeee;
}
.bootstrap-switch .bootstrap-switch-label {
text-align: center;
margin-top: -1px;
margin-bottom: -1px;
z-index: 100;
color: #333333;
background: #ffffff;
}
.bootstrap-switch .bootstrap-switch-handle-on {
border-bottom-left-radius: 3px;
border-top-left-radius: 3px;
}
.bootstrap-switch .bootstrap-switch-handle-off {
border-bottom-right-radius: 3px;
border-top-right-radius: 3px;
}
.bootstrap-switch input[type='radio'],
.bootstrap-switch input[type='checkbox'] {
position: absolute !important;
top: 0;
left: 0;
margin: 0;
z-index: -1;
opacity: 0;
filter: alpha(opacity=0);
}
.bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-handle-on,
.bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-handle-off,
.bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-label {
padding: 1px 5px;
font-size: 12px;
line-height: 1.5;
}
.bootstrap-switch.bootstrap-switch-small .bootstrap-switch-handle-on,
.bootstrap-switch.bootstrap-switch-small .bootstrap-switch-handle-off,
.bootstrap-switch.bootstrap-switch-small .bootstrap-switch-label {
padding: 5px 10px;
font-size: 12px;
line-height: 1.5;
}
.bootstrap-switch.bootstrap-switch-large .bootstrap-switch-handle-on,
.bootstrap-switch.bootstrap-switch-large .bootstrap-switch-handle-off,
.bootstrap-switch.bootstrap-switch-large .bootstrap-switch-label {
padding: 6px 16px;
font-size: 18px;
line-height: 1.3333333;
}
.bootstrap-switch.bootstrap-switch-disabled,
.bootstrap-switch.bootstrap-switch-readonly,
.bootstrap-switch.bootstrap-switch-indeterminate {
cursor: default !important;
}
.bootstrap-switch.bootstrap-switch-disabled .bootstrap-switch-handle-on,
.bootstrap-switch.bootstrap-switch-readonly .bootstrap-switch-handle-on,
.bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-handle-on,
.bootstrap-switch.bootstrap-switch-disabled .bootstrap-switch-handle-off,
.bootstrap-switch.bootstrap-switch-readonly .bootstrap-switch-handle-off,
.bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-handle-off,
.bootstrap-switch.bootstrap-switch-disabled .bootstrap-switch-label,
.bootstrap-switch.bootstrap-switch-readonly .bootstrap-switch-label,
.bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-label {
opacity: 0.5;
filter: alpha(opacity=50);
cursor: default !important;
}
.bootstrap-switch.bootstrap-switch-animate .bootstrap-switch-container {
-webkit-transition: margin-left 0.5s;
-o-transition: margin-left 0.5s;
transition: margin-left 0.5s;
}
.bootstrap-switch.bootstrap-switch-inverse .bootstrap-switch-handle-on {
border-bottom-left-radius: 0;
border-top-left-radius: 0;
border-bottom-right-radius: 3px;
border-top-right-radius: 3px;
}
.bootstrap-switch.bootstrap-switch-inverse .bootstrap-switch-handle-off {
border-bottom-right-radius: 0;
border-top-right-radius: 0;
border-bottom-left-radius: 3px;
border-top-left-radius: 3px;
}
.bootstrap-switch.bootstrap-switch-focused {
border-color: #66afe9;
outline: 0;
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
}
.bootstrap-switch.bootstrap-switch-on .bootstrap-switch-label,
.bootstrap-switch.bootstrap-switch-inverse.bootstrap-switch-off .bootstrap-switch-label {
border-bottom-right-radius: 3px;
border-top-right-radius: 3px;
}
.bootstrap-switch.bootstrap-switch-off .bootstrap-switch-label,
.bootstrap-switch.bootstrap-switch-inverse.bootstrap-switch-on .bootstrap-switch-label {
border-bottom-left-radius: 3px;
border-top-left-radius: 3px;
}

View File

@ -1,809 +0,0 @@
/*
* This combined file was created by the DataTables downloader builder:
* https://datatables.net/download
*
* To rebuild or modify this file with the latest versions of the included
* software please visit:
* https://datatables.net/download/#dt/dt-1.10.11,cr-1.3.1,fh-3.1.1,r-2.0.2,rr-1.1.1,se-1.1.2
*
* Included libraries:
* DataTables 1.10.11, ColReorder 1.3.1, FixedHeader 3.1.1, Responsive 2.0.2, RowReorder 1.1.1, Select 1.1.2
*/
/*
* Table styles
*/
table.dataTable {
width: 100%;
margin: 0 auto;
clear: both;
border-collapse: separate;
border-spacing: 0;
/*
* Header and footer styles
*/
/*
* Body styles
*/
}
table.dataTable thead th,
table.dataTable tfoot th {
font-weight: bold;
}
table.dataTable thead th,
table.dataTable thead td {
padding: 10px 18px;
border-bottom: 1px solid #111;
}
table.dataTable thead th:active,
table.dataTable thead td:active {
outline: none;
}
table.dataTable tfoot th,
table.dataTable tfoot td {
padding: 10px 18px 6px 18px;
border-top: 1px solid #111;
}
table.dataTable thead .sorting,
table.dataTable thead .sorting_asc,
table.dataTable thead .sorting_desc {
cursor: pointer;
*cursor: hand;
}
table.dataTable thead .sorting,
table.dataTable thead .sorting_asc,
table.dataTable thead .sorting_desc,
table.dataTable thead .sorting_asc_disabled,
table.dataTable thead .sorting_desc_disabled {
background-repeat: no-repeat;
background-position: center right;
}
table.dataTable thead .sorting {
background-image: url("DataTables-1.10.11/images/sort_both.png");
}
table.dataTable thead .sorting_asc {
background-image: url("DataTables-1.10.11/images/sort_asc.png");
}
table.dataTable thead .sorting_desc {
background-image: url("DataTables-1.10.11/images/sort_desc.png");
}
table.dataTable thead .sorting_asc_disabled {
background-image: url("DataTables-1.10.11/images/sort_asc_disabled.png");
}
table.dataTable thead .sorting_desc_disabled {
background-image: url("DataTables-1.10.11/images/sort_desc_disabled.png");
}
table.dataTable tbody tr {
background-color: #ffffff;
}
table.dataTable tbody tr.selected {
background-color: #B0BED9;
}
table.dataTable tbody th,
table.dataTable tbody td {
padding: 8px 10px;
}
table.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {
border-top: 1px solid #ddd;
}
table.dataTable.row-border tbody tr:first-child th,
table.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,
table.dataTable.display tbody tr:first-child td {
border-top: none;
}
table.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {
border-top: 1px solid #ddd;
border-right: 1px solid #ddd;
}
table.dataTable.cell-border tbody tr th:first-child,
table.dataTable.cell-border tbody tr td:first-child {
border-left: 1px solid #ddd;
}
table.dataTable.cell-border tbody tr:first-child th,
table.dataTable.cell-border tbody tr:first-child td {
border-top: none;
}
table.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {
background-color: #f9f9f9;
}
table.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {
background-color: #acbad4;
}
table.dataTable.hover tbody tr:hover, table.dataTable.display tbody tr:hover {
background-color: #f6f6f6;
}
table.dataTable.hover tbody tr:hover.selected, table.dataTable.display tbody tr:hover.selected {
background-color: #aab7d1;
}
table.dataTable.order-column tbody tr > .sorting_1,
table.dataTable.order-column tbody tr > .sorting_2,
table.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,
table.dataTable.display tbody tr > .sorting_2,
table.dataTable.display tbody tr > .sorting_3 {
background-color: #fafafa;
}
table.dataTable.order-column tbody tr.selected > .sorting_1,
table.dataTable.order-column tbody tr.selected > .sorting_2,
table.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,
table.dataTable.display tbody tr.selected > .sorting_2,
table.dataTable.display tbody tr.selected > .sorting_3 {
background-color: #acbad5;
}
table.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {
background-color: #f1f1f1;
}
table.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {
background-color: #f3f3f3;
}
table.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {
background-color: whitesmoke;
}
table.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {
background-color: #a6b4cd;
}
table.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {
background-color: #a8b5cf;
}
table.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {
background-color: #a9b7d1;
}
table.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {
background-color: #fafafa;
}
table.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {
background-color: #fcfcfc;
}
table.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {
background-color: #fefefe;
}
table.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {
background-color: #acbad5;
}
table.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {
background-color: #aebcd6;
}
table.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {
background-color: #afbdd8;
}
table.dataTable.display tbody tr:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1 {
background-color: #eaeaea;
}
table.dataTable.display tbody tr:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2 {
background-color: #ececec;
}
table.dataTable.display tbody tr:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3 {
background-color: #efefef;
}
table.dataTable.display tbody tr:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1 {
background-color: #a2aec7;
}
table.dataTable.display tbody tr:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2 {
background-color: #a3b0c9;
}
table.dataTable.display tbody tr:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3 {
background-color: #a5b2cb;
}
table.dataTable.no-footer {
border-bottom: 1px solid #111;
}
table.dataTable.nowrap th, table.dataTable.nowrap td {
white-space: nowrap;
}
table.dataTable.compact thead th,
table.dataTable.compact thead td {
padding: 4px 17px 4px 4px;
}
table.dataTable.compact tfoot th,
table.dataTable.compact tfoot td {
padding: 4px;
}
table.dataTable.compact tbody th,
table.dataTable.compact tbody td {
padding: 4px;
}
table.dataTable th.dt-left,
table.dataTable td.dt-left {
text-align: left;
}
table.dataTable th.dt-center,
table.dataTable td.dt-center,
table.dataTable td.dataTables_empty {
text-align: center;
}
table.dataTable th.dt-right,
table.dataTable td.dt-right {
text-align: right;
}
table.dataTable th.dt-justify,
table.dataTable td.dt-justify {
text-align: justify;
}
table.dataTable th.dt-nowrap,
table.dataTable td.dt-nowrap {
white-space: nowrap;
}
table.dataTable thead th.dt-head-left,
table.dataTable thead td.dt-head-left,
table.dataTable tfoot th.dt-head-left,
table.dataTable tfoot td.dt-head-left {
text-align: left;
}
table.dataTable thead th.dt-head-center,
table.dataTable thead td.dt-head-center,
table.dataTable tfoot th.dt-head-center,
table.dataTable tfoot td.dt-head-center {
text-align: center;
}
table.dataTable thead th.dt-head-right,
table.dataTable thead td.dt-head-right,
table.dataTable tfoot th.dt-head-right,
table.dataTable tfoot td.dt-head-right {
text-align: right;
}
table.dataTable thead th.dt-head-justify,
table.dataTable thead td.dt-head-justify,
table.dataTable tfoot th.dt-head-justify,
table.dataTable tfoot td.dt-head-justify {
text-align: justify;
}
table.dataTable thead th.dt-head-nowrap,
table.dataTable thead td.dt-head-nowrap,
table.dataTable tfoot th.dt-head-nowrap,
table.dataTable tfoot td.dt-head-nowrap {
white-space: nowrap;
}
table.dataTable tbody th.dt-body-left,
table.dataTable tbody td.dt-body-left {
text-align: left;
}
table.dataTable tbody th.dt-body-center,
table.dataTable tbody td.dt-body-center {
text-align: center;
}
table.dataTable tbody th.dt-body-right,
table.dataTable tbody td.dt-body-right {
text-align: right;
}
table.dataTable tbody th.dt-body-justify,
table.dataTable tbody td.dt-body-justify {
text-align: justify;
}
table.dataTable tbody th.dt-body-nowrap,
table.dataTable tbody td.dt-body-nowrap {
white-space: nowrap;
}
table.dataTable,
table.dataTable th,
table.dataTable td {
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
}
/*
* Control feature layout
*/
.dataTables_wrapper {
position: relative;
clear: both;
*zoom: 1;
zoom: 1;
}
.dataTables_wrapper .dataTables_length {
float: left;
}
.dataTables_wrapper .dataTables_filter {
float: right;
text-align: right;
}
.dataTables_wrapper .dataTables_filter input {
margin-left: 0.5em;
}
.dataTables_wrapper .dataTables_info {
clear: both;
float: left;
padding-top: 0.755em;
}
.dataTables_wrapper .dataTables_paginate {
float: right;
text-align: right;
padding-top: 0.25em;
}
.dataTables_wrapper .dataTables_paginate .paginate_button {
box-sizing: border-box;
display: inline-block;
min-width: 1.5em;
padding: 0.5em 1em;
margin-left: 2px;
text-align: center;
text-decoration: none !important;
cursor: pointer;
*cursor: hand;
color: #333 !important;
border: 1px solid transparent;
border-radius: 2px;
}
.dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {
color: #333 !important;
border: 1px solid #979797;
background-color: white;
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #dcdcdc));
/* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, white 0%, #dcdcdc 100%);
/* Chrome10+,Safari5.1+ */
background: -moz-linear-gradient(top, white 0%, #dcdcdc 100%);
/* FF3.6+ */
background: -ms-linear-gradient(top, white 0%, #dcdcdc 100%);
/* IE10+ */
background: -o-linear-gradient(top, white 0%, #dcdcdc 100%);
/* Opera 11.10+ */
background: linear-gradient(to bottom, white 0%, #dcdcdc 100%);
/* W3C */
}
.dataTables_wrapper .dataTables_paginate .paginate_button.disabled, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active {
cursor: default;
color: #666 !important;
border: 1px solid transparent;
background: transparent;
box-shadow: none;
}
.dataTables_wrapper .dataTables_paginate .paginate_button:hover {
color: white !important;
border: 1px solid #111;
background-color: #585858;
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));
/* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, #585858 0%, #111 100%);
/* Chrome10+,Safari5.1+ */
background: -moz-linear-gradient(top, #585858 0%, #111 100%);
/* FF3.6+ */
background: -ms-linear-gradient(top, #585858 0%, #111 100%);
/* IE10+ */
background: -o-linear-gradient(top, #585858 0%, #111 100%);
/* Opera 11.10+ */
background: linear-gradient(to bottom, #585858 0%, #111 100%);
/* W3C */
}
.dataTables_wrapper .dataTables_paginate .paginate_button:active {
outline: none;
background-color: #2b2b2b;
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));
/* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
/* Chrome10+,Safari5.1+ */
background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
/* FF3.6+ */
background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
/* IE10+ */
background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
/* Opera 11.10+ */
background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);
/* W3C */
box-shadow: inset 0 0 3px #111;
}
.dataTables_wrapper .dataTables_paginate .ellipsis {
padding: 0 1em;
}
.dataTables_wrapper .dataTables_processing {
position: absolute;
top: 50%;
left: 50%;
width: 100%;
height: 40px;
margin-left: -50%;
margin-top: -25px;
padding-top: 20px;
text-align: center;
font-size: 1.2em;
background-color: white;
background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));
background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
}
.dataTables_wrapper .dataTables_length,
.dataTables_wrapper .dataTables_filter,
.dataTables_wrapper .dataTables_info,
.dataTables_wrapper .dataTables_processing,
.dataTables_wrapper .dataTables_paginate {
color: #333;
}
.dataTables_wrapper .dataTables_scroll {
clear: both;
}
.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody {
*margin-top: -1px;
-webkit-overflow-scrolling: touch;
}
.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td {
vertical-align: middle;
}
.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th > div.dataTables_sizing,
.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td > div.dataTables_sizing {
height: 0;
overflow: hidden;
margin: 0 !important;
padding: 0 !important;
}
.dataTables_wrapper.no-footer .dataTables_scrollBody {
border-bottom: 1px solid #111;
}
.dataTables_wrapper.no-footer div.dataTables_scrollHead table,
.dataTables_wrapper.no-footer div.dataTables_scrollBody table {
border-bottom: none;
}
.dataTables_wrapper:after {
visibility: hidden;
display: block;
content: "";
clear: both;
height: 0;
}
@media screen and (max-width: 767px) {
.dataTables_wrapper .dataTables_info,
.dataTables_wrapper .dataTables_paginate {
float: none;
text-align: center;
}
.dataTables_wrapper .dataTables_paginate {
margin-top: 0.5em;
}
}
@media screen and (max-width: 640px) {
.dataTables_wrapper .dataTables_length,
.dataTables_wrapper .dataTables_filter {
float: none;
text-align: center;
}
.dataTables_wrapper .dataTables_filter {
margin-top: 0.5em;
}
}
table.DTCR_clonedTable.dataTable {
position: absolute !important;
background-color: rgba(255, 255, 255, 0.7);
z-index: 202;
}
div.DTCR_pointer {
width: 1px;
background-color: #0259C4;
z-index: 201;
}
table.fixedHeader-floating {
position: fixed !important;
background-color: white;
}
table.fixedHeader-floating.no-footer {
border-bottom-width: 0;
}
table.fixedHeader-locked {
position: absolute !important;
background-color: white;
}
@media print {
table.fixedHeader-floating {
display: none;
}
}
table.dataTable.dtr-inline.collapsed > tbody > tr > td.child,
table.dataTable.dtr-inline.collapsed > tbody > tr > th.child,
table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty {
cursor: default !important;
}
table.dataTable.dtr-inline.collapsed > tbody > tr > td.child:before,
table.dataTable.dtr-inline.collapsed > tbody > tr > th.child:before,
table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty:before {
display: none !important;
}
table.dataTable.dtr-inline.collapsed > tbody > tr > td:first-child,
table.dataTable.dtr-inline.collapsed > tbody > tr > th:first-child {
position: relative;
padding-left: 30px;
cursor: pointer;
}
table.dataTable.dtr-inline.collapsed > tbody > tr > td:first-child:before,
table.dataTable.dtr-inline.collapsed > tbody > tr > th:first-child:before {
top: 8px;
left: 4px;
height: 16px;
width: 16px;
display: block;
position: absolute;
color: white;
border: 2px solid white;
border-radius: 16px;
box-shadow: 0 0 3px #444;
box-sizing: content-box;
text-align: left;
font-family: 'Courier New', Courier, monospace;
text-indent: 4px;
line-height: 16px;
content: '+';
background-color: #31b131;
}
table.dataTable.dtr-inline.collapsed > tbody > tr.parent > td:first-child:before,
table.dataTable.dtr-inline.collapsed > tbody > tr.parent > th:first-child:before {
content: '-';
background-color: #d33333;
}
table.dataTable.dtr-inline.collapsed > tbody > tr.child td:before {
display: none;
}
table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child,
table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child {
padding-left: 27px;
}
table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child:before,
table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child:before {
top: 5px;
left: 4px;
height: 14px;
width: 14px;
border-radius: 14px;
line-height: 14px;
text-indent: 3px;
}
table.dataTable.dtr-column > tbody > tr > td.control,
table.dataTable.dtr-column > tbody > tr > th.control {
position: relative;
cursor: pointer;
}
table.dataTable.dtr-column > tbody > tr > td.control:before,
table.dataTable.dtr-column > tbody > tr > th.control:before {
top: 50%;
left: 50%;
height: 16px;
width: 16px;
margin-top: -10px;
margin-left: -10px;
display: block;
position: absolute;
color: white;
border: 2px solid white;
border-radius: 16px;
box-shadow: 0 0 3px #444;
box-sizing: content-box;
text-align: left;
font-family: 'Courier New', Courier, monospace;
text-indent: 4px;
line-height: 16px;
content: '+';
background-color: #31b131;
}
table.dataTable.dtr-column > tbody > tr.parent td.control:before,
table.dataTable.dtr-column > tbody > tr.parent th.control:before {
content: '-';
background-color: #d33333;
}
table.dataTable > tbody > tr.child {
padding: 0.5em 1em;
}
table.dataTable > tbody > tr.child:hover {
background: transparent !important;
}
table.dataTable > tbody > tr.child ul {
display: inline-block;
list-style-type: none;
margin: 0;
padding: 0;
}
table.dataTable > tbody > tr.child ul li {
border-bottom: 1px solid #efefef;
padding: 0.5em 0;
}
table.dataTable > tbody > tr.child ul li:first-child {
padding-top: 0;
}
table.dataTable > tbody > tr.child ul li:last-child {
border-bottom: none;
}
table.dataTable > tbody > tr.child span.dtr-title {
display: inline-block;
min-width: 75px;
font-weight: bold;
}
div.dtr-modal {
position: fixed;
box-sizing: border-box;
top: 0;
left: 0;
height: 100%;
width: 100%;
z-index: 100;
padding: 10em 1em;
}
div.dtr-modal div.dtr-modal-display {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
width: 50%;
height: 50%;
overflow: auto;
margin: auto;
z-index: 102;
overflow: auto;
background-color: #f5f5f7;
border: 1px solid black;
border-radius: 0.5em;
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.6);
}
div.dtr-modal div.dtr-modal-content {
position: relative;
padding: 1em;
}
div.dtr-modal div.dtr-modal-close {
position: absolute;
top: 6px;
right: 6px;
width: 22px;
height: 22px;
border: 1px solid #eaeaea;
background-color: #f9f9f9;
text-align: center;
border-radius: 3px;
cursor: pointer;
z-index: 12;
}
div.dtr-modal div.dtr-modal-close:hover {
background-color: #eaeaea;
}
div.dtr-modal div.dtr-modal-background {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 101;
background: rgba(0, 0, 0, 0.6);
}
@media screen and (max-width: 767px) {
div.dtr-modal div.dtr-modal-display {
width: 95%;
}
}
table.dt-rowReorder-float {
position: absolute !important;
opacity: 0.8;
table-layout: static;
outline: 2px solid #888;
outline-offset: -2px;
z-index: 2001;
}
tr.dt-rowReorder-moving {
outline: 2px solid #555;
outline-offset: -2px;
}
body.dt-rowReorder-noOverflow {
overflow-x: hidden;
}
table.dataTable td.reorder {
text-align: center;
cursor: move;
}
table.dataTable tbody > tr.selected,
table.dataTable tbody > tr > .selected {
background-color: #B0BED9;
}
table.dataTable.stripe tbody > tr.odd.selected,
table.dataTable.stripe tbody > tr.odd > .selected, table.dataTable.display tbody > tr.odd.selected,
table.dataTable.display tbody > tr.odd > .selected {
background-color: #acbad4;
}
table.dataTable.hover tbody > tr.selected:hover,
table.dataTable.hover tbody > tr > .selected:hover, table.dataTable.display tbody > tr.selected:hover,
table.dataTable.display tbody > tr > .selected:hover {
background-color: #aab7d1;
}
table.dataTable.order-column tbody > tr.selected > .sorting_1,
table.dataTable.order-column tbody > tr.selected > .sorting_2,
table.dataTable.order-column tbody > tr.selected > .sorting_3,
table.dataTable.order-column tbody > tr > .selected, table.dataTable.display tbody > tr.selected > .sorting_1,
table.dataTable.display tbody > tr.selected > .sorting_2,
table.dataTable.display tbody > tr.selected > .sorting_3,
table.dataTable.display tbody > tr > .selected {
background-color: #acbad5;
}
table.dataTable.display tbody > tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_1 {
background-color: #a6b4cd;
}
table.dataTable.display tbody > tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_2 {
background-color: #a8b5cf;
}
table.dataTable.display tbody > tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody > tr.odd.selected > .sorting_3 {
background-color: #a9b7d1;
}
table.dataTable.display tbody > tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_1 {
background-color: #acbad5;
}
table.dataTable.display tbody > tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_2 {
background-color: #aebcd6;
}
table.dataTable.display tbody > tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody > tr.even.selected > .sorting_3 {
background-color: #afbdd8;
}
table.dataTable.display tbody > tr.odd > .selected, table.dataTable.order-column.stripe tbody > tr.odd > .selected {
background-color: #a6b4cd;
}
table.dataTable.display tbody > tr.even > .selected, table.dataTable.order-column.stripe tbody > tr.even > .selected {
background-color: #acbad5;
}
table.dataTable.display tbody > tr.selected:hover > .sorting_1, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_1 {
background-color: #a2aec7;
}
table.dataTable.display tbody > tr.selected:hover > .sorting_2, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_2 {
background-color: #a3b0c9;
}
table.dataTable.display tbody > tr.selected:hover > .sorting_3, table.dataTable.order-column.hover tbody > tr.selected:hover > .sorting_3 {
background-color: #a5b2cb;
}
table.dataTable.display tbody > tr:hover > .selected,
table.dataTable.display tbody > tr > .selected:hover, table.dataTable.order-column.hover tbody > tr:hover > .selected,
table.dataTable.order-column.hover tbody > tr > .selected:hover {
background-color: #a2aec7;
}
table.dataTable td.select-checkbox {
position: relative;
}
table.dataTable td.select-checkbox:before, table.dataTable td.select-checkbox:after {
display: block;
position: absolute;
top: 1.2em;
left: 50%;
width: 12px;
height: 12px;
box-sizing: border-box;
}
table.dataTable td.select-checkbox:before {
content: ' ';
margin-top: -6px;
margin-left: -6px;
border: 1px solid black;
border-radius: 3px;
}
table.dataTable tr.selected td.select-checkbox:after {
content: '\2714';
margin-top: -11px;
margin-left: -4px;
text-align: center;
text-shadow: 1px 1px #B0BED9, -1px -1px #B0BED9, 1px -1px #B0BED9, -1px 1px #B0BED9;
}
div.dataTables_wrapper span.select-info,
div.dataTables_wrapper span.select-item {
margin-left: 0.5em;
}
@media screen and (max-width: 640px) {
div.dataTables_wrapper span.select-info,
div.dataTables_wrapper span.select-item {
margin-left: 0;
display: block;
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,45 +0,0 @@
/*
* Bootstrap TouchSpin - v3.0.1
* A mobile and touch friendly input spinner component for Bootstrap 3.
* http://www.virtuosoft.eu/code/bootstrap-touchspin/
*
* Made by István Ujj-Mészáros
* Under Apache License v2.0 License
*/
.bootstrap-touchspin .input-group-btn-vertical {
position: relative;
white-space: nowrap;
width: 1%;
vertical-align: middle;
display: table-cell;
}
.bootstrap-touchspin .input-group-btn-vertical > .btn {
display: block;
float: none;
width: 100%;
max-width: 100%;
padding: 8px 10px;
margin-left: -1px;
position: relative;
}
.bootstrap-touchspin .input-group-btn-vertical .bootstrap-touchspin-up {
border-radius: 0;
border-top-right-radius: 0px;
}
.bootstrap-touchspin .input-group-btn-vertical .bootstrap-touchspin-down {
margin-top: -2px;
border-radius: 0;
border-bottom-right-radius: 0px;
}
.bootstrap-touchspin .input-group-btn-vertical i {
position: absolute;
top: 3px;
left: 5px;
font-size: 9px;
font-weight: normal;
}

View File

@ -1,428 +0,0 @@
// Bootstrap
$icon-font-path: "../fonts/";
@import "_tools";
@import "_udsvars";
// Own variables
$sidebar-icon-width: 24px;
$sidebar-icon-width-collapsed: 24px;
$sidebar-size: 225px; // 225 px
$sidebar-size-collapsed: $sidebar-icon-width-collapsed + 2*$font-size-base; // 40px;
$sidebar-top: 50px;
$sidebar-switcher-size: 14px;
$sizebar-switcher-font-size: $sidebar-switcher-size - 2px;
$sidebar-switcher-pos: $sidebar-size - $sidebar-switcher-size;
$sidebar-switcher-pos-collapsed: $sidebar-size-collapsed - $sidebar-switcher-size;
$uds-panel-min-height: 500px;
// bower:scss
@import "bower_components/bootstrap-sass/assets/stylesheets/_bootstrap.scss";
// endbower
@font-face {
font-family: 'Droid Sans Mono';
font-style: normal;
font-weight: 400;
src: local('Droid Sans Mono'), local('DroidSansMono'), url(#{$icon-font-path}/DroidSansMono.woff2) format('woff2');
}
// Fix for firefox for fieldsets
@-moz-document url-prefix() {
fieldset {
display: table-cell;
}
}
body {
font-family: 'Droid Sans Mono', sans-serif;
background-color: $body-bg;
margin-top: 50px;
}
#wrapper {
padding-left: 0;
}
#page-wrapper {
width: 100%;
padding: 5px 15px;
}
/* collapsable && closeable pannels */
.chevron {
&:before {
content: "\f139";
}
&.collapsed:before {
content: "\f13a";
}
}
.widget-icon.fa-refresh {
&:hover {
animation: 2s linear 0s normal none infinite running fa-spin;
}
}
.panel-icon {
margin-left: 0.6em !important;
cursor: pointer;
}
.table-icon {
width: 1.2em;
padding-bottom: 3px;
}
.info-img {
width: 5em;
}
.navbar-img {
width: 2em;
margin-top: -8px;
}
.side-nav > .navbar-nav > li > a {
padding-bottom: $font-size-base/2;
padding-top: $font-size-base/2;
}
.cursor-pointer {
cursor: pointer !important;
}
#minimized {
margin-top: 0.6em;
margin-bottom: 0.3em;
}
/* modal dialogs & related*/
.modal-dialog {
/* new custom width */
width: 90%;
}
/*.modal-backdrop {
background-color: gray;
}*/
.modal {
overflow-y: auto;
}
.tab-pane {
margin-top: 24px;
}
.tooltip {
z-index: 2014;
}
/* Tables */
/* Logs */
.chart-big {
display: block;
height: 400px;
}
.chart-medium {
display: block;
height: 250px;
}
.chart-small {
display: block;
height: 100px;
}
/* End tables styling */
/* Charts */
.chart-content {
width: 100%;
height: 100%;
}
// Hides switcher on small devices, so menu displays correctly
.side-nav {
padding-top: 0px;
.switcher {
visibility: hidden;
width: 0px;
height: 0px;
}
.icon {
width: 24px;
vertical-align: center;
padding-bottom: 3px;
}
}
/* Edit Below to Customize Widths > 768px */
@media (min-width: 768px) {
/* Wrappers */
#wrapper {
padding-left: $sidebar-size;
-webkit-transition: padding 0.3s; /* For Safari 3.1 to 6.0 */
transition: padding 0.3s;
&.full {
padding-left: $sidebar-size-collapsed;
}
}
#page-wrapper {
padding: 15px 25px;
}
/* Side Nav */
.side-nav {
position: fixed;
top: 0px;
margin-top: $sidebar-top;
height: 100%;
overflow-y: auto;
border-radius: 0;
border-color: $navbar-default-border;
border-style: solid;
border-width: 0 1px 0 0;
background-color: $navbar-default-bg;
-webkit-transition: width 0.3s; /* For Safari 3.1 to 6.0 */
transition: width 0.3s;
margin-left: -$sidebar-size-collapsed;
padding-top: $sidebar-switcher-size;
left: $sidebar-size-collapsed;
width: $sidebar-size-collapsed;
.icon {
width: $sidebar-icon-width-collapsed;
-webkit-transition: all 0.3s; /* For Safari 3.1 to 6.0 */
transition: all 0.3s;
}
.menu-lnk {
display: none;
overflow-x: hidden;
}
> ul {
// border-top: 1px solid $navbar-default-border;
> li {
width: $sidebar-size;
overflow-x: hidden;
// border-bottom: 1px solid $navbar-default-border;
&:hover, &.active, &:focus {
color: $brand-primary;
background-color: darken($navbar-default-bg, 15%);
}
&.dropdown > ul.dropdown-menu {
width: $sidebar-size;
position: relative;
margin: 0;
padding: 0;
border: none;
border-radius: 0;
background-color: transparent;
box-shadow: none;
-webkit-box-shadow: none;
> li > a {
color: inherit;
padding: $font-size-base/2 $font-size-base/2 $font-size-base/2 32px;
&:hover, &.active, &:focus {
color: #fff;
background-color: #080808;
}
}
}
}
}
&.full {
margin-left: -$sidebar-size;
left: $sidebar-size;
width: $sidebar-size;
.icon {
width: $sidebar-icon-width;
}
.menu-lnk {
display: inline;
opacity: 1.0;
width: 100%;
}
> ul > li {
// border-bottom: none;
//border-bottom: none;
}
}
/*&:hover {
width: $sidebar-size;
}
> li {
&.dropdown > ul.dropdown-menu {
position: relative;
min-width: $sidebar-size;
margin: 0;
padding: 0;
border: none;
border-radius: 0;
background-color: transparent;
box-shadow: none;
-webkit-box-shadow: none;
> li > a {
color: #999999;
padding: 15px 15px 15px 15px;
&:hover, &.active, &:focus {
color: #fff;
background-color: #080808;
}
}
}
> a {
border-bottom: 1px solid darken($body-bg, 50%);
color: $text-color;
display: block;
font-size: 10px;
min-height: 60px;
padding-top: 12px;
text-align: center;
width: $sidebar-size-collapsed;
> img {
min-width: 32px;
}
}
//> a {
// width: $sidebar-size;
//}
}*/
}
/* Bootstrap Default Overrides - Customized Dropdowns for the Side Nav */
/*.navbar-inverse .navbar-nav > li > a {
&:hover, &:focus {
background-color: #080808;
}
}*/
.modal-dialog {
/* new custom width */
width: 60%;
}
}
// closeable
.closeable {
&:hover {
cursor: pointer;
color: red;
}
}
// Tag add
.tagadder {
&:hover {
cursor: pointer;
}
}
span.tag {
float: left;
margin-bottom: 4px;
margin-right: 4px;
padding-bottom: 4px;
}
/* submenus */
.dropdown-submenu {
position: relative;
>.dropdown-menu {
top: 0;
left: 100%;
margin-top: -6px;
margin-left: -1px;
-webkit-border-radius: 0 6px 6px 6px;
-moz-border-radius: 0 6px 6px 6px;
border-radius: 0 6px 6px 6px;
}
&:hover {
>.dropdown-menu {
display: block;
}
>a {
&:after {
border-left-color: #ffffff;
}
}
}
>a {
&:after {
display: block;
content: " ";
float: right;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
border-width: 5px 0 5px 5px;
border-left-color: #cccccc;
margin-top: 5px;
margin-right: -10px;
}
}
}
.dropdown-submenu.pull-left {
float: none;
>.dropdown-menu {
left: -100%;
margin-left: 10px;
-webkit-border-radius: 6px 0 6px 6px;
-moz-border-radius: 6px 0 6px 6px;
border-radius: 6px 0 6px 6px;
}
}
li.selected {
background-color: #5094CE;
}
/* theme */
@import "_theme";
@import "_widgets";
@import "_buttons";
@import "_data-tables";
@import "_tables";

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Some files were not shown because too many files have changed in this diff Show More