forked from shaba/openuds
Merge branch 'master' of https://github.com/dkmstr/openuds
This commit is contained in:
commit
f0b6726e19
@ -57,6 +57,7 @@ class ForwardServer(socketserver.ThreadingTCPServer):
|
||||
remote: typing.Tuple[str, int]
|
||||
ticket: str
|
||||
stop_flag: threading.Event
|
||||
can_stop: bool
|
||||
timeout: int
|
||||
timer: typing.Optional[threading.Timer]
|
||||
check_certificate: bool
|
||||
@ -79,20 +80,22 @@ class ForwardServer(socketserver.ThreadingTCPServer):
|
||||
)
|
||||
self.remote = remote
|
||||
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.stop_flag = threading.Event() # False initial
|
||||
self.current_connections = 0
|
||||
|
||||
self.status = TUNNEL_LISTENING
|
||||
self.can_stop = False
|
||||
|
||||
if timeout:
|
||||
self.timer = threading.Timer(
|
||||
timeout, ForwardServer.__checkStarted, args=(self,)
|
||||
)
|
||||
self.timer.start()
|
||||
else:
|
||||
self.timer = None
|
||||
timeout = abs(timeout) or 60
|
||||
self.timer = threading.Timer(
|
||||
abs(timeout), ForwardServer.__checkStarted, args=(self,)
|
||||
)
|
||||
self.timer.start()
|
||||
|
||||
def stop(self) -> None:
|
||||
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])
|
||||
|
||||
def check(self) -> bool:
|
||||
if self.status == TUNNEL_ERROR:
|
||||
return False
|
||||
|
||||
try:
|
||||
with self.connect() as ssl_socket:
|
||||
ssl_socket.sendall(HANDSHAKE_V1 + b'TEST')
|
||||
@ -135,11 +141,14 @@ class ForwardServer(socketserver.ThreadingTCPServer):
|
||||
|
||||
@property
|
||||
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
|
||||
def __checkStarted(fs: 'ForwardServer') -> None:
|
||||
logger.debug('New connection limit reached')
|
||||
fs.timer = None
|
||||
fs.can_stop = True
|
||||
if fs.current_connections <= 0:
|
||||
fs.stop()
|
||||
|
||||
@ -150,15 +159,17 @@ class Handler(socketserver.BaseRequestHandler):
|
||||
|
||||
# server: ForwardServer
|
||||
def handle(self) -> None:
|
||||
self.server.current_connections += 1
|
||||
self.server.status = TUNNEL_OPENING
|
||||
|
||||
# If server processing is over time
|
||||
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
|
||||
return
|
||||
|
||||
self.server.current_connections += 1
|
||||
|
||||
# Open remote connection
|
||||
try:
|
||||
logger.debug('Ticket %s', self.server.ticket)
|
||||
@ -169,7 +180,9 @@ class Handler(socketserver.BaseRequestHandler):
|
||||
data = ssl_socket.recv(2)
|
||||
if data != b'OK':
|
||||
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
|
||||
self.process(remote=ssl_socket)
|
||||
|
@ -1,7 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2014-2019 Virtual Cable S.L.
|
||||
# Copyright (c) 2014-2021 Virtual Cable S.L.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
@ -423,6 +422,13 @@ class Login(LoginLogout):
|
||||
"""
|
||||
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]:
|
||||
isManaged = self._params.get('type') != UNMANAGED
|
||||
ip = hostname = ''
|
||||
@ -432,9 +438,7 @@ class Login(LoginLogout):
|
||||
|
||||
try:
|
||||
userService: UserService = self.getUserService()
|
||||
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, self._params.get('username') or '')
|
||||
osManager = Login.process_login(userService, self._params.get('username') or '')
|
||||
|
||||
maxIdle = osManager.maxIdle() if osManager else None
|
||||
|
||||
@ -462,21 +466,29 @@ class Logout(LoginLogout):
|
||||
"""
|
||||
name = 'logout'
|
||||
|
||||
@staticmethod
|
||||
def process_logout(userService: UserService, username: str) -> None:
|
||||
"""
|
||||
This method is static so can be invoked from elsewhere
|
||||
"""
|
||||
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.)
|
||||
osmanagers.OSManager.loggedOut(userService, username)
|
||||
if osManager:
|
||||
if osManager.isRemovableOnLogout(userService):
|
||||
logger.debug('Removable on logout: %s', osManager)
|
||||
userService.remove()
|
||||
else:
|
||||
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()
|
||||
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.)
|
||||
osmanagers.OSManager.loggedOut(userService, self._params.get('username') or '')
|
||||
if osManager:
|
||||
if osManager.isRemovableOnLogout(userService):
|
||||
logger.debug('Removable on logout: %s', osManager)
|
||||
userService.remove()
|
||||
else:
|
||||
userService.remove()
|
||||
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...
|
||||
if isManaged:
|
||||
raise
|
||||
|
@ -177,7 +177,7 @@ class OSManager(Module):
|
||||
Helper method that informs if the os manager transforms the username and/or the password.
|
||||
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]:
|
||||
"""
|
||||
@ -299,5 +299,5 @@ class OSManager(Module):
|
||||
"""
|
||||
return False
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self) -> str:
|
||||
return "Base OS Manager"
|
||||
|
31
server/src/uds/dispatchers/opengnsys/__init__.py
Normal file
31
server/src/uds/dispatchers/opengnsys/__init__.py
Normal 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
|
||||
'''
|
38
server/src/uds/dispatchers/opengnsys/urls.py
Normal file
38
server/src/uds/dispatchers/opengnsys/urls.py
Normal 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'),
|
||||
]
|
107
server/src/uds/dispatchers/opengnsys/views.py
Normal file
107
server/src/uds/dispatchers/opengnsys/views.py
Normal 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)
|
@ -197,12 +197,12 @@ class LinuxOsManager(osmanagers.OSManager):
|
||||
elif message == "log":
|
||||
self.doLog(userService, data, log.ACTOR)
|
||||
elif message == "login":
|
||||
osmanagers.OSManager.loggedIn(userService, data)
|
||||
osmanagers.OSManager.loggedIn(userService, typing.cast(str, data))
|
||||
ip, hostname = userService.getConnectionSource()
|
||||
deadLine = userService.deployed_service.getDeadline()
|
||||
ret = "{}\t{}\t{}".format(ip, hostname, 0 if deadLine is None else deadLine)
|
||||
elif message == "logout":
|
||||
osmanagers.OSManager.loggedOut(userService, data)
|
||||
osmanagers.OSManager.loggedOut(userService, typing.cast(str, data))
|
||||
doRemove = self.isRemovableOnLogout(userService)
|
||||
elif message == "ip":
|
||||
# This ocurss on main loop inside machine, so userService is usable
|
||||
|
@ -1,7 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2017-2019 Virtual Cable S.L.
|
||||
# Copyright (c) 2017-2021 Virtual Cable S.L.U.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2012 Virtual Cable S.L.
|
||||
# Copyright (c) 2015-2021 Virtual Cable S.L.U.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
@ -34,6 +34,7 @@ import logging
|
||||
import typing
|
||||
|
||||
from uds.core.services import UserDeployment
|
||||
from uds.core.managers import cryptoManager
|
||||
from uds.core.util.state import State
|
||||
from uds.core.util import log
|
||||
from uds.models.util import getSqlDatetimeAsUnix
|
||||
@ -47,7 +48,7 @@ if typing.TYPE_CHECKING:
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
opCreate, opError, opFinish, opRemove, opRetry = range(5)
|
||||
opCreate, opError, opFinish, opRemove, opRetry, opStart = range(6)
|
||||
|
||||
|
||||
class OGDeployment(UserDeployment):
|
||||
@ -71,7 +72,9 @@ class OGDeployment(UserDeployment):
|
||||
_stamp: int = 0
|
||||
_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
|
||||
|
||||
def initialize(self) -> None:
|
||||
@ -93,16 +96,18 @@ class OGDeployment(UserDeployment):
|
||||
"""
|
||||
Does nothing right here, we will use environment storage in this sample
|
||||
"""
|
||||
return b'\1'.join([
|
||||
b'v1',
|
||||
self._name.encode('utf8'),
|
||||
self._ip.encode('utf8'),
|
||||
self._mac.encode('utf8'),
|
||||
self._machineId.encode('utf8'),
|
||||
self._reason.encode('utf8'),
|
||||
str(self._stamp).encode('utf8'),
|
||||
pickle.dumps(self._queue, protocol=0)
|
||||
])
|
||||
return b'\1'.join(
|
||||
[
|
||||
b'v1',
|
||||
self._name.encode('utf8'),
|
||||
self._ip.encode('utf8'),
|
||||
self._mac.encode('utf8'),
|
||||
self._machineId.encode('utf8'),
|
||||
self._reason.encode('utf8'),
|
||||
str(self._stamp).encode('utf8'),
|
||||
pickle.dumps(self._queue, protocol=0),
|
||||
]
|
||||
)
|
||||
|
||||
def unmarshal(self, data: bytes) -> None:
|
||||
"""
|
||||
@ -135,10 +140,33 @@ class OGDeployment(UserDeployment):
|
||||
OpenGnsys will try it best by sending an WOL
|
||||
"""
|
||||
dbs = self.dbservice()
|
||||
deadline = dbs.deployed_service.getDeadline() if dbs else 0
|
||||
self.service().notifyDeadline(self._machineId, deadline)
|
||||
if not dbs:
|
||||
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:
|
||||
"""
|
||||
@ -159,7 +187,11 @@ class OGDeployment(UserDeployment):
|
||||
self._queue = [opCreate, opFinish]
|
||||
|
||||
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:
|
||||
status = self.service().status(self._machineId)
|
||||
@ -202,7 +234,11 @@ class OGDeployment(UserDeployment):
|
||||
logger.debug('Setting error state, reason: %s', 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._reason = str(reason)
|
||||
@ -222,13 +258,16 @@ class OGDeployment(UserDeployment):
|
||||
opCreate: self.__create,
|
||||
opRetry: self.__retry,
|
||||
opRemove: self.__remove,
|
||||
opStart: self.__start,
|
||||
}
|
||||
|
||||
try:
|
||||
execFnc: typing.Optional[typing.Callable[[], str]] = fncs.get(op, None)
|
||||
execFnc: typing.Optional[typing.Callable[[], str]] = fncs.get(op)
|
||||
|
||||
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()
|
||||
|
||||
@ -252,10 +291,11 @@ class OGDeployment(UserDeployment):
|
||||
"""
|
||||
Deploys a machine from template for user/cache
|
||||
"""
|
||||
r: typing.Any = None
|
||||
token = cryptoManager().randomString(32)
|
||||
try:
|
||||
r: typing.Any = None
|
||||
r = self.service().reserve()
|
||||
self.service().notifyEvents(r['id'], self._uuid)
|
||||
self.service().notifyEvents(r['id'], token, self._uuid)
|
||||
except Exception as e:
|
||||
# logger.exception('Creating machine')
|
||||
if r: # Reservation was done, unreserve it!!!
|
||||
@ -265,7 +305,7 @@ class OGDeployment(UserDeployment):
|
||||
except Exception as ei:
|
||||
# Error unreserving reserved machine on creation
|
||||
logger.error('Error unreserving errored machine: %s', ei)
|
||||
|
||||
|
||||
raise Exception('Error creating reservation: {}'.format(e))
|
||||
|
||||
self._machineId = r['id']
|
||||
@ -274,19 +314,36 @@ class OGDeployment(UserDeployment):
|
||||
self._ip = r['ip']
|
||||
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
|
||||
dbs = self.dbservice()
|
||||
if dbs:
|
||||
dbs.setProperty('actor_version', '1.0-OpenGnsys')
|
||||
dbs.setProperty('actor_version', '1.1-OpenGnsys')
|
||||
dbs.setProperty('token', token)
|
||||
dbs.logIP(self._ip)
|
||||
|
||||
return State.RUNNING
|
||||
|
||||
def __start(self) -> str:
|
||||
if self._machineId:
|
||||
self.service().powerOn(self._machineId)
|
||||
return State.RUNNING
|
||||
|
||||
def __remove(self) -> str:
|
||||
"""
|
||||
Removes a machine from system
|
||||
Avoids "double unreserve" in case the reservation was made from release
|
||||
"""
|
||||
self.service().unreserve(self._machineId)
|
||||
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)
|
||||
return State.RUNNING
|
||||
|
||||
# Check methods
|
||||
@ -296,6 +353,9 @@ class OGDeployment(UserDeployment):
|
||||
"""
|
||||
return self.__checkMachineReady()
|
||||
|
||||
# Alias for poweron check
|
||||
__checkStart = __checkCreate
|
||||
|
||||
def __checkRemoved(self) -> str:
|
||||
"""
|
||||
Checks if a machine has been removed
|
||||
@ -319,13 +379,18 @@ class OGDeployment(UserDeployment):
|
||||
opCreate: self.__checkCreate,
|
||||
opRetry: self.__retry,
|
||||
opRemove: self.__checkRemoved,
|
||||
opStart: self.__checkStart,
|
||||
}
|
||||
|
||||
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:
|
||||
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()
|
||||
if state == State.FINISHED:
|
||||
@ -379,4 +444,12 @@ class OGDeployment(UserDeployment):
|
||||
}.get(op, '????')
|
||||
|
||||
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],
|
||||
)
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2012 Virtual Cable S.L.
|
||||
# Copyright (c) 2015-2021 Virtual Cable S.L.U.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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
|
||||
|
||||
labs = [gui.choiceItem('0', _('All Labs'))] + [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'])]
|
||||
labs = [gui.choiceItem('0', _('All Labs'))] + [
|
||||
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 = [
|
||||
{'name': 'lab', 'values': labs},
|
||||
|
@ -56,17 +56,22 @@ def ensureConnected(fnc: typing.Callable[..., RT]) -> typing.Callable[..., RT]:
|
||||
def inner(*args, **kwargs) -> RT:
|
||||
args[0].connect()
|
||||
return fnc(*args, **kwargs)
|
||||
|
||||
return inner
|
||||
|
||||
|
||||
# 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 errMsg:
|
||||
errMsg = 'Invalid response'
|
||||
|
||||
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:
|
||||
err = response.content
|
||||
errMsg = '{}: {}, ({})'.format(errMsg, err, response.status_code)
|
||||
@ -76,7 +81,11 @@ def ensureResponseIsValid(response: requests.Response, errMsg: typing.Optional[s
|
||||
try:
|
||||
return json.loads(response.content)
|
||||
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:
|
||||
@ -88,7 +97,14 @@ class OpenGnsysClient:
|
||||
verifyCert: bool
|
||||
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.password = password
|
||||
self.endpoint = endpoint
|
||||
@ -108,11 +124,18 @@ class OpenGnsysClient:
|
||||
def _ogUrl(self, path: str) -> str:
|
||||
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:
|
||||
return ensureResponseIsValid(
|
||||
requests.post(self._ogUrl(path), data=json.dumps(data), headers=self.headers, verify=self.verifyCert),
|
||||
errMsg=errMsg
|
||||
requests.post(
|
||||
self._ogUrl(path),
|
||||
data=json.dumps(data),
|
||||
headers=self.headers,
|
||||
verify=self.verifyCert,
|
||||
),
|
||||
errMsg=errMsg,
|
||||
)
|
||||
# FAKE Connection :)
|
||||
return fake.post(path, data, errMsg)
|
||||
@ -120,8 +143,10 @@ class OpenGnsysClient:
|
||||
def _get(self, path: str, errMsg: typing.Optional[str] = None) -> typing.Any:
|
||||
if not FAKE:
|
||||
return ensureResponseIsValid(
|
||||
requests.get(self._ogUrl(path), headers=self.headers, verify=self.verifyCert),
|
||||
errMsg=errMsg
|
||||
requests.get(
|
||||
self._ogUrl(path), headers=self.headers, verify=self.verifyCert
|
||||
),
|
||||
errMsg=errMsg,
|
||||
)
|
||||
# FAKE Connection :)
|
||||
return fake.get(path, errMsg)
|
||||
@ -129,8 +154,10 @@ class OpenGnsysClient:
|
||||
def _delete(self, path: str, errMsg: typing.Optional[str] = None) -> typing.Any:
|
||||
if not FAKE:
|
||||
return ensureResponseIsValid(
|
||||
requests.delete(self._ogUrl(path), headers=self.headers, verify=self.verifyCert),
|
||||
errMsg=errMsg
|
||||
requests.delete(
|
||||
self._ogUrl(path), headers=self.headers, verify=self.verifyCert
|
||||
),
|
||||
errMsg=errMsg,
|
||||
)
|
||||
return fake.delete(path, errMsg)
|
||||
|
||||
@ -145,11 +172,8 @@ class OpenGnsysClient:
|
||||
|
||||
auth = self._post(
|
||||
urls.LOGIN,
|
||||
data={
|
||||
'username': self.username,
|
||||
'password': self.password
|
||||
},
|
||||
errMsg='Loggin in'
|
||||
data={'username': self.username, 'password': self.password},
|
||||
errMsg='Loggin in',
|
||||
)
|
||||
|
||||
self.auth = auth['apikey']
|
||||
@ -179,7 +203,11 @@ class OpenGnsysClient:
|
||||
# /ous/{ouid}/labs
|
||||
# Take into accout that we must exclude the ones with "inremotepc" set to false.
|
||||
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
|
||||
def getImages(self, ou: str) -> typing.List[typing.MutableMapping[str, str]]:
|
||||
@ -187,20 +215,23 @@ class OpenGnsysClient:
|
||||
# /ous/{ouid}/images
|
||||
# Take into accout that we must exclude the ones with "inremotepc" set to false.
|
||||
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
|
||||
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
|
||||
# The method used is POST
|
||||
# invokes /ous/{ouid}}/images/{imageid}/reserve
|
||||
# also remember to store "labid"
|
||||
# Labid can be "0" that means "all laboratories"
|
||||
errMsg = 'Reserving image {} in ou {}'.format(image, ou)
|
||||
data = {
|
||||
'labid': lab,
|
||||
'maxtime': maxtime
|
||||
}
|
||||
data = {'labid': lab, 'maxtime': maxtime}
|
||||
res = self._post(urls.RESERVE.format(ou=ou, image=image), data, errMsg=errMsg)
|
||||
return {
|
||||
'ou': ou,
|
||||
@ -210,7 +241,7 @@ class OpenGnsysClient:
|
||||
'id': '.'.join((str(ou), str(res['lab']['id']), str(res['id']))),
|
||||
'name': res['name'],
|
||||
'ip': res['ip'],
|
||||
'mac': ':'.join(re.findall('..', res['mac']))
|
||||
'mac': ':'.join(re.findall('..', res['mac'])),
|
||||
}
|
||||
|
||||
@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)
|
||||
ou, lab, client = machineId.split('.')
|
||||
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
|
||||
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('.')
|
||||
errMsg = 'Notifying login/logout urls'
|
||||
data = {
|
||||
'urlLogin': loginURL,
|
||||
'urlLogout': logoutURL
|
||||
}
|
||||
data = {'urlLogin': loginURL, 'urlLogout': logoutURL, 'urlRelease': releaseURL}
|
||||
|
||||
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
|
||||
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('.')
|
||||
deadLine = deadLine or 0
|
||||
errMsg = 'Notifying deadline'
|
||||
data = {
|
||||
'deadLine': deadLine
|
||||
}
|
||||
data = {'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
|
||||
def status(self, id_: str) -> typing.Any:
|
||||
|
@ -40,20 +40,13 @@ from . import urls
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
AUTH = {
|
||||
"userid": 1001,
|
||||
"apikey": "fakeAPIKeyJustForDeveloping"
|
||||
}
|
||||
AUTH = {"userid": 1001, "apikey": "fakeAPIKeyJustForDeveloping"}
|
||||
|
||||
INFO = {
|
||||
"project": "OpenGnsys",
|
||||
"version": "1.1.0pre",
|
||||
"release": "r5299",
|
||||
"services": [
|
||||
"server",
|
||||
"repository",
|
||||
"tracker"
|
||||
],
|
||||
"services": ["server", "repository", "tracker"],
|
||||
"oglive": [
|
||||
{
|
||||
"distribution": "xenial",
|
||||
@ -61,7 +54,7 @@ INFO = {
|
||||
"architecture": "amd64",
|
||||
"revision": "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",
|
||||
@ -69,19 +62,14 @@ INFO = {
|
||||
"revision": "r4820",
|
||||
"architecture": "i386",
|
||||
"kernel": "3.2.0-23-generic",
|
||||
"distribution": "precise"
|
||||
}]
|
||||
"distribution": "precise",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
OUS = [
|
||||
{
|
||||
"id": "1",
|
||||
"name": "Unidad Organizativa (Default)"
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"name": "Unidad Organizatva VACIA"
|
||||
},
|
||||
{"id": "1", "name": "Unidad Organizativa (Default)"},
|
||||
{"id": "2", "name": "Unidad Organizatva VACIA"},
|
||||
]
|
||||
|
||||
LABS = [
|
||||
@ -89,58 +77,32 @@ LABS = [
|
||||
"id": "1",
|
||||
"name": "Sala de control",
|
||||
"inremotepc": True,
|
||||
"group": {
|
||||
"id": "0"
|
||||
},
|
||||
"ou": {
|
||||
"id": "1"
|
||||
}
|
||||
"group": {"id": "0"},
|
||||
"ou": {"id": "1"},
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"name": "Sala de computación cuántica",
|
||||
"inremotepc": True,
|
||||
"group": {
|
||||
"id": "0"
|
||||
},
|
||||
"ou": {
|
||||
"id": "1"
|
||||
}
|
||||
}
|
||||
"group": {"id": "0"},
|
||||
"ou": {"id": "1"},
|
||||
},
|
||||
]
|
||||
|
||||
IMAGES = [
|
||||
{
|
||||
"id": "1",
|
||||
"name": "Basica1604",
|
||||
"inremotepc": True,
|
||||
"ou": {
|
||||
"id": "1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"name": "Ubuntu16",
|
||||
"inremotepc": True,
|
||||
"ou": {
|
||||
"id": "1"
|
||||
}
|
||||
},
|
||||
{"id": "1", "name": "Basica1604", "inremotepc": True, "ou": {"id": "1"}},
|
||||
{"id": "2", "name": "Ubuntu16", "inremotepc": True, "ou": {"id": "1"}},
|
||||
{
|
||||
"id": "3",
|
||||
"name": "Ubuntu64 Not in Remote",
|
||||
"inremotepc": False,
|
||||
"ou": {
|
||||
"id": "1"
|
||||
}
|
||||
"ou": {"id": "1"},
|
||||
},
|
||||
{
|
||||
"id": "4",
|
||||
"name": "Ubuntu96 Not In Remote",
|
||||
"inremotepc": False,
|
||||
"ou": {
|
||||
"id": "1"
|
||||
}
|
||||
"ou": {"id": "1"},
|
||||
},
|
||||
]
|
||||
|
||||
@ -149,58 +111,50 @@ RESERVE: typing.Dict[str, typing.Any] = {
|
||||
"name": "pcpruebas",
|
||||
"mac": "4061860521FE",
|
||||
"ip": "10.1.14.31",
|
||||
"lab": {
|
||||
"id": 1
|
||||
},
|
||||
"ou": {
|
||||
"id": 1
|
||||
}
|
||||
"lab": {"id": 1},
|
||||
"ou": {"id": 1},
|
||||
}
|
||||
|
||||
UNRESERVE = ''
|
||||
|
||||
STATUS_OFF = {
|
||||
"id": 4,
|
||||
"ip": "10.1.14.31",
|
||||
"status": "off",
|
||||
"loggedin": False
|
||||
}
|
||||
STATUS_OFF = {"id": 4, "ip": "10.1.14.31", "status": "off", "loggedin": False}
|
||||
|
||||
# A couple of status for testing
|
||||
STATUS_READY_LINUX = {
|
||||
"id": 4,
|
||||
"ip": "10.1.14.31",
|
||||
"status": "linux",
|
||||
"loggedin": False
|
||||
}
|
||||
STATUS_READY_LINUX = {"id": 4, "ip": "10.1.14.31", "status": "linux", "loggedin": False}
|
||||
|
||||
STATUS_READY_WINDOWS = {
|
||||
"id": 4,
|
||||
"ip": "10.1.14.31",
|
||||
"status": "windows",
|
||||
"loggedin": False
|
||||
"loggedin": False,
|
||||
}
|
||||
|
||||
|
||||
# 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)
|
||||
if path == urls.LOGIN:
|
||||
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['name'] += str(random.randint(5000, 100000))
|
||||
res['mac'] = ''.join(random.choice('0123456789ABCDEF') for _ in range(12))
|
||||
res['ip'] = '1.2.3.4'
|
||||
return res
|
||||
|
||||
# raise Exception('Unknown FAKE URL on POST: {}'.format(path))
|
||||
return ''
|
||||
# Ignore rest of responses
|
||||
return {'status': 'ok'}
|
||||
|
||||
|
||||
# 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)
|
||||
if path == urls.INFO:
|
||||
return INFO
|
||||
|
@ -1,7 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2017-2019 Virtual Cable S.L.
|
||||
# Copyright (c) 2017-2021 Virtual Cable S.L.U.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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'
|
||||
EVENTS = '/ous/{ou}/labs/{lab}/clients/{client}/events'
|
||||
SESSIONS = '/ous/{ou}/labs/{lab}/clients/{client}/session'
|
||||
# TODO: fix this
|
||||
START = '/ous/{ou}/labs/{lab}/clients/{client}/init'
|
||||
|
@ -1,7 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012-2019 Virtual Cable S.L.
|
||||
# Copyright (c) 2012-2021 Virtual Cable S.L.U.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
@ -51,6 +50,7 @@ if typing.TYPE_CHECKING:
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OGProvider(ServiceProvider):
|
||||
"""
|
||||
This class represents the sample services provider
|
||||
@ -68,6 +68,7 @@ class OGProvider(ServiceProvider):
|
||||
we MUST register it at package __init__.
|
||||
|
||||
"""
|
||||
|
||||
# : What kind of services we offer, this are classes inherited from Service
|
||||
offers = [OGService]
|
||||
# : Name to show the administrator. This string will be translated BEFORE
|
||||
@ -92,17 +93,81 @@ class OGProvider(ServiceProvider):
|
||||
# but used for sample purposes
|
||||
# If we don't indicate an order, the output order of fields will be
|
||||
# "random"
|
||||
host = gui.TextField(length=64, label=_('Host'), order=1, tooltip=_('OpenGnsys Host'), required=True)
|
||||
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)
|
||||
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)
|
||||
host = gui.TextField(
|
||||
length=64, label=_('Host'), order=1, tooltip=_('OpenGnsys Host'), required=True
|
||||
)
|
||||
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,
|
||||
)
|
||||
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)
|
||||
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)
|
||||
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,
|
||||
)
|
||||
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
|
||||
_api: typing.Optional[og.OpenGnsysClient] = None
|
||||
@ -137,7 +202,13 @@ class OGProvider(ServiceProvider):
|
||||
@property
|
||||
def api(self) -> og.OpenGnsysClient:
|
||||
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)
|
||||
return self._api
|
||||
@ -155,7 +226,12 @@ class OGProvider(ServiceProvider):
|
||||
"""
|
||||
try:
|
||||
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:
|
||||
logger.exception('Error')
|
||||
return [False, '{}'.format(e)]
|
||||
@ -184,16 +260,25 @@ class OGProvider(ServiceProvider):
|
||||
def getUDSServerAccessUrl(self) -> str:
|
||||
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)
|
||||
|
||||
def unreserve(self, machineId: str) -> typing.Any:
|
||||
return self.api.unreserve(machineId)
|
||||
|
||||
def notifyEvents(self, machineId: str, loginURL: str, logoutURL: str) -> typing.Any:
|
||||
return self.api.notifyURLs(machineId, loginURL, logoutURL)
|
||||
def powerOn(self, machineId: str, image: str) -> typing.Any:
|
||||
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)
|
||||
|
||||
def status(self, machineId: str) -> typing.Any:
|
||||
|
@ -1,7 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2017-2019 Virtual Cable S.L.
|
||||
# Copyright (c) 2017-2021 Virtual Cable S.L.U.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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
|
||||
"""
|
||||
|
||||
_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':
|
||||
return typing.cast('OGService', super().service())
|
||||
|
@ -1,7 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2017-2019 Virtual Cable S.L.
|
||||
# Copyright (c) 2017-2021 Virtual Cable S.L.U.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
@ -55,6 +54,7 @@ class OGService(Service):
|
||||
"""
|
||||
OpenGnsys Service
|
||||
"""
|
||||
|
||||
# : Name to show the administrator. This string will be translated BEFORE
|
||||
# : sending it to administration interface, so don't forget to
|
||||
# : mark it as _ (using ugettext_noop)
|
||||
@ -102,20 +102,17 @@ class OGService(Service):
|
||||
label=_("OU"),
|
||||
order=100,
|
||||
fills={
|
||||
'callbackName' : 'osFillData',
|
||||
'function' : helpers.getResources,
|
||||
'parameters' : ['ov', 'ev', 'ou']
|
||||
},
|
||||
'callbackName': 'osFillData',
|
||||
'function': helpers.getResources,
|
||||
'parameters': ['ov', 'ev', 'ou'],
|
||||
},
|
||||
tooltip=_('Organizational Unit'),
|
||||
required=True
|
||||
required=True,
|
||||
)
|
||||
|
||||
# Lab is not required, but maybe used as filter
|
||||
lab = gui.ChoiceField(
|
||||
label=_("lab"),
|
||||
order=101,
|
||||
tooltip=_('Laboratory'),
|
||||
required=False
|
||||
label=_("lab"), order=101, tooltip=_('Laboratory'), required=False
|
||||
)
|
||||
|
||||
# Required, this is the base image
|
||||
@ -123,22 +120,33 @@ class OGService(Service):
|
||||
label=_("OS Image"),
|
||||
order=102,
|
||||
tooltip=_('OpenGnsys Operating System Image'),
|
||||
required=True
|
||||
required=True,
|
||||
)
|
||||
|
||||
maxReservationTime = gui.NumericField(
|
||||
length=3,
|
||||
label=_("Max. reservation time"),
|
||||
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
|
||||
minValue='24',
|
||||
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)
|
||||
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:
|
||||
"""
|
||||
@ -157,27 +165,49 @@ class OGService(Service):
|
||||
return self.parent().status(machineId)
|
||||
|
||||
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:
|
||||
return self.parent().unreserve(machineId)
|
||||
|
||||
def notifyEvents(self, machineId: str, serviceUUID: str) -> typing.Any:
|
||||
return self.parent().notifyEvents(machineId, self.getLoginNotifyURL(serviceUUID), self.getLogoutNotifyURL(serviceUUID))
|
||||
def notifyEvents(self, machineId: str, token: str, uuid: str) -> typing.Any:
|
||||
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)
|
||||
|
||||
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".
|
||||
return '{accessURL}rest/actor/PostThoughGet/{uuid}/{message}'.format(
|
||||
return '{accessURL}uds/ognotify/{message}/{token}/{uuid}'.format(
|
||||
accessURL=self.parent().getUDSServerAccessUrl(),
|
||||
uuid=uuid,
|
||||
token=token,
|
||||
message=message
|
||||
)
|
||||
|
||||
def getLoginNotifyURL(self, serviceUUID: str) -> str:
|
||||
return self._notifyURL(serviceUUID, 'login')
|
||||
def getLoginNotifyURL(self, uuid: str, token: str) -> str:
|
||||
return self._notifyURL(uuid, token, 'login')
|
||||
|
||||
def getLogoutNotifyURL(self, serviceUUID: str) -> str:
|
||||
return self._notifyURL(serviceUUID, 'logout')
|
||||
def getLogoutNotifyURL(self, uuid: str, token: str) -> str:
|
||||
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()
|
||||
|
@ -30,7 +30,7 @@ MIT
|
||||
MIT
|
||||
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
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@ -64,7 +64,7 @@ MIT
|
||||
MIT
|
||||
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
|
||||
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
@ -30,7 +30,7 @@ MIT
|
||||
MIT
|
||||
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
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@ -64,7 +64,7 @@ MIT
|
||||
MIT
|
||||
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
|
||||
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
@ -25,7 +25,7 @@ gettext("Error launching service");
|
||||
gettext("Please wait until the service is launched.");
|
||||
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("Please, tray again in a few moments.");
|
||||
gettext("Please, try again in a few moments.");
|
||||
gettext("Error launching service");
|
||||
// HTML
|
||||
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
@ -1,7 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012-2019 Virtual Cable S.L.
|
||||
# Copyright (c) 2012-2021 Virtual Cable S.L.U.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
|
@ -84,34 +84,23 @@ class TSNXTransport(BaseNXTransport):
|
||||
label=_('Tunnel wait time'),
|
||||
defvalue='30',
|
||||
minValue=5,
|
||||
maxValue=65536,
|
||||
maxValue=3600 * 24,
|
||||
order=2,
|
||||
tooltip=_('Maximum time to wait before closing the tunnel listener'),
|
||||
required=True,
|
||||
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(
|
||||
label=_('Force SSL certificate verification'),
|
||||
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,
|
||||
tab=gui.TUNNEL_TAB
|
||||
tab=gui.TUNNEL_TAB,
|
||||
)
|
||||
|
||||
|
||||
useEmptyCreds = gui.CheckBoxField(
|
||||
label=_('Empty creds'),
|
||||
order=3,
|
||||
@ -217,7 +206,6 @@ class TSNXTransport(BaseNXTransport):
|
||||
_cacheMem: str = ''
|
||||
_screenSize: str = ''
|
||||
_tunnelWait: int = 30
|
||||
_ticketValidity: int = 60
|
||||
_verifyCertificate: bool = False
|
||||
|
||||
def initialize(self, values: 'Module.ValuesType'):
|
||||
@ -228,7 +216,6 @@ class TSNXTransport(BaseNXTransport):
|
||||
)
|
||||
self._tunnelServer = values['tunnelServer']
|
||||
self._tunnelWait = int(values['tunnelWait'])
|
||||
self._ticketValidity = int(values['ticketValidity'])
|
||||
self._verifyCertificate = gui.strToBool(values['verifyCertificate'])
|
||||
self._tunnelCheckServer = ''
|
||||
self._useEmptyCreds = gui.strToBool(values['useEmptyCreds'])
|
||||
@ -240,7 +227,6 @@ class TSNXTransport(BaseNXTransport):
|
||||
self._cacheDisk = values['cacheDisk']
|
||||
self._cacheMem = values['cacheMem']
|
||||
self._screenSize = values['screenSize']
|
||||
|
||||
|
||||
def marshal(self) -> bytes:
|
||||
"""
|
||||
@ -262,7 +248,6 @@ class TSNXTransport(BaseNXTransport):
|
||||
self._tunnelCheckServer,
|
||||
self._screenSize,
|
||||
str(self._tunnelWait),
|
||||
str(self._ticketValidity),
|
||||
gui.boolToStr(self._verifyCertificate),
|
||||
],
|
||||
)
|
||||
@ -288,10 +273,9 @@ class TSNXTransport(BaseNXTransport):
|
||||
values[11] if values[0] == 'v2' else CommonPrefs.SZ_FULLSCREEN
|
||||
)
|
||||
if values[0] == 'v3':
|
||||
self._tunnelWait, self._ticketValidity, self._verifyCertificate = (
|
||||
self._tunnelWait, self._verifyCertificate = (
|
||||
int(values[12]),
|
||||
int(values[13]),
|
||||
gui.strToBool(values[14])
|
||||
gui.strToBool(values[13]),
|
||||
)
|
||||
|
||||
def valuesDict(self) -> gui.ValuesDictType:
|
||||
@ -306,7 +290,6 @@ class TSNXTransport(BaseNXTransport):
|
||||
'cacheMem': self._cacheMem,
|
||||
'tunnelServer': self._tunnelServer,
|
||||
'tunnelWait': str(self._tunnelWait),
|
||||
'ticketValidity': str(self._ticketValidity),
|
||||
'verifyCertificate': gui.boolToStr(self._verifyCertificate),
|
||||
}
|
||||
|
||||
@ -334,8 +317,8 @@ class TSNXTransport(BaseNXTransport):
|
||||
|
||||
ticket = TicketStore.create_for_tunnel(
|
||||
userService=userService,
|
||||
port=3389,
|
||||
validity=self.ticketValidity.num()
|
||||
port=int(self._listenPort),
|
||||
validity=self._tunnelWait + 60, # Ticket overtime
|
||||
)
|
||||
|
||||
tunHost, tunPort = self.tunnelServer.value.split(':')
|
||||
@ -367,10 +350,9 @@ class TSNXTransport(BaseNXTransport):
|
||||
'ip': ip,
|
||||
'tunHost': tunHost,
|
||||
'tunPort': tunPort,
|
||||
'tunWait': self.tunnelWait.num(),
|
||||
'tunChk': self.verifyCertificate.isTrue(),
|
||||
'tunWait': self._tunnelWait,
|
||||
'tunChk': self._verifyCertificate,
|
||||
'ticket': ticket,
|
||||
'port': self._listenPort,
|
||||
'as_file_for_format': r.as_file_for_format,
|
||||
}
|
||||
|
||||
|
@ -18,13 +18,13 @@ except Exception:
|
||||
''')
|
||||
|
||||
# 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..
|
||||
if fs.check() is False:
|
||||
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
|
||||
|
||||
theFile = sp['as_file_for_format'].format(
|
||||
theFile = sp['as_file_for_format'].format( # type: ignore
|
||||
address='127.0.0.1',
|
||||
port=fs.server_address[1]
|
||||
)
|
||||
|
@ -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=
|
@ -6,7 +6,7 @@ from __future__ import unicode_literals
|
||||
import subprocess
|
||||
import os
|
||||
|
||||
from uds import tools # @UnresolvedImport
|
||||
from uds import tools # type: ignore
|
||||
|
||||
|
||||
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
|
||||
tools.addTaskToWait(subprocess.Popen([cmd, '--session={{}}'.format(filename), '--autologin', '--killerrors']))
|
||||
filename = tools.saveTempFile(sp['as_file']) # type: ignore
|
||||
tools.addTaskToWait(subprocess.Popen([cmd, '--session={{}}'.format(filename), '--autologin', '--killerrors'])) # type: ignore
|
||||
tools.addFileToUnlink(filename)
|
||||
|
@ -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=
|
@ -17,13 +17,13 @@ if os.path.isfile(cmd) is False:
|
||||
''')
|
||||
|
||||
# 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..
|
||||
if fs.check() is False:
|
||||
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
|
||||
|
||||
theFile = sp['as_file_for_format'].format(
|
||||
theFile = sp['as_file_for_format'].format( # type: ignore
|
||||
address='127.0.0.1',
|
||||
port=fs.server_address[1]
|
||||
)
|
||||
|
@ -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=
|
@ -3,21 +3,24 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# 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
|
||||
|
||||
from uds import tools # @UnresolvedImport
|
||||
|
||||
from uds import tools # type: ignore
|
||||
|
||||
try:
|
||||
k = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, 'Software\\Classes\\NXClient.session\\shell\\open\\command') # @UndefinedVariable
|
||||
cmd = _winreg.QueryValue(k, '') # @UndefinedVariable
|
||||
k = wreg.OpenKey(wreg.HKEY_CURRENT_USER, 'Software\\Classes\\NXClient.session\\shell\\open\\command') # @UndefinedVariable
|
||||
cmd = wreg.QueryValue(k, '') # type: ignore
|
||||
wreg.CloseKey(k)
|
||||
except Exception:
|
||||
raise Exception('''<p>You need to have installed NX Client version 3.5 in order to connect to this UDS service.</p>
|
||||
<p>Please, install appropriate package for your system.</p>
|
||||
''')
|
||||
|
||||
filename = tools.saveTempFile(sp['as_file']) # @UndefinedVariable
|
||||
filename = tools.saveTempFile(sp['as_file']) # type: ignore
|
||||
cmd = cmd.replace('%1', filename)
|
||||
tools.addTaskToWait(subprocess.Popen(cmd))
|
||||
tools.addFileToUnlink(filename)
|
||||
|
@ -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=
|
@ -13,23 +13,23 @@ from uds.tunnel import forward # type: ignore
|
||||
|
||||
from uds import tools # type: ignore
|
||||
|
||||
|
||||
try:
|
||||
k = wreg.OpenKey(wreg.HKEY_CURRENT_USER, 'Software\\Classes\\NXClient.session\\shell\\open\\command') # @UndefinedVariable
|
||||
k = wreg.OpenKey(wreg.HKEY_CURRENT_USER, 'Software\\Classes\\NXClient.session\\shell\\open\\command')
|
||||
cmd = wreg.QueryValue(k, '')
|
||||
wreg.CloseKey(k)
|
||||
except Exception:
|
||||
raise Exception('''<p>You need to have installed NX Client version 3.5 in order to connect to this UDS service.</p>
|
||||
<p>Please, install appropriate package for your system.</p>
|
||||
''')
|
||||
|
||||
# Open tunnel
|
||||
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk'])
|
||||
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
|
||||
|
||||
# Check that tunnel works..
|
||||
if fs.check() is False:
|
||||
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
|
||||
|
||||
theFile = sp['as_file_for_format'].format(
|
||||
theFile = sp['as_file_for_format'].format( # type: ignore
|
||||
address='127.0.0.1',
|
||||
port=fs.server_address[1]
|
||||
)
|
||||
|
@ -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=
|
@ -74,7 +74,6 @@ class TRDPTransport(BaseRDPTransport):
|
||||
),
|
||||
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(
|
||||
length=3,
|
||||
@ -88,27 +87,16 @@ class TRDPTransport(BaseRDPTransport):
|
||||
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(
|
||||
label=_('Force SSL certificate verification'),
|
||||
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,
|
||||
tab=gui.TUNNEL_TAB
|
||||
tab=gui.TUNNEL_TAB,
|
||||
)
|
||||
|
||||
|
||||
useEmptyCreds = BaseRDPTransport.useEmptyCreds
|
||||
fixedName = BaseRDPTransport.fixedName
|
||||
fixedPassword = BaseRDPTransport.fixedPassword
|
||||
@ -175,11 +163,10 @@ class TRDPTransport(BaseRDPTransport):
|
||||
ticket = TicketStore.create_for_tunnel(
|
||||
userService=userService,
|
||||
port=3389,
|
||||
validity=self.ticketValidity.num()
|
||||
validity=self.tunnelWait.num() + 60, # Ticket overtime
|
||||
)
|
||||
|
||||
tunHost, tunPort = self.tunnelServer.value.split(':')
|
||||
|
||||
|
||||
r = RDPFile(
|
||||
width == '-1' or height == '-1', width, height, depth, target=os['OS']
|
||||
|
@ -2,24 +2,22 @@
|
||||
# Saved as .py for easier editing
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# pylint: disable=import-error, no-name-in-module, too-many-format-args, undefined-variable, invalid-sequence-index
|
||||
import subprocess
|
||||
import re
|
||||
|
||||
from uds import tools
|
||||
from uds import tools # type: ignore
|
||||
|
||||
# Inject local passed sp into globals for inner functions
|
||||
globals()['sp'] = sp # type: ignore # pylint: disable=undefined-variable
|
||||
|
||||
def execUdsRdp(udsrdp):
|
||||
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))
|
||||
|
||||
|
||||
def execNewXFreeRdp(xfreerdp):
|
||||
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))
|
||||
|
||||
# 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)
|
||||
|
@ -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=
|
@ -2,9 +2,7 @@
|
||||
# Saved as .py for easier editing
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# pylint: disable=import-error, no-name-in-module, too-many-format-args, undefined-variable, invalid-sequence-index
|
||||
import subprocess
|
||||
import re
|
||||
from uds.tunnel import forward # 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):
|
||||
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))
|
||||
|
||||
|
||||
def execNewXFreeRdp(xfreerdp, port):
|
||||
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))
|
||||
|
||||
# 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:
|
||||
# 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..
|
||||
if fs.check() is False:
|
||||
|
@ -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=
|
@ -7,7 +7,7 @@ import subprocess
|
||||
import shutil
|
||||
import os
|
||||
|
||||
from uds import tools # @UnresolvedImport
|
||||
from uds import tools # type: ignore
|
||||
|
||||
# Inject local passed sp into globals for functions
|
||||
globals()['sp'] = sp # type: ignore # pylint: disable=undefined-variable
|
||||
@ -20,18 +20,18 @@ def fixResolution():
|
||||
import re
|
||||
import subprocess
|
||||
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
|
||||
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
|
||||
if os.path.isfile(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
|
||||
|
||||
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>
|
||||
<p>In order to connect to UDS RDP Sessions, you need to have a<p>
|
||||
<ul>
|
||||
@ -63,7 +63,7 @@ if executable is None:
|
||||
</ul>
|
||||
''')
|
||||
elif executable == msrdc:
|
||||
theFile = sp['as_file']
|
||||
theFile = sp['as_file'] # type: ignore
|
||||
filename = tools.saveTempFile(theFile)
|
||||
# Rename as .rdp, so open recognizes it
|
||||
shutil.move(filename, filename + '.rdp')
|
||||
@ -75,8 +75,8 @@ elif executable == xfreerdp:
|
||||
try:
|
||||
xfparms = fixResolution()
|
||||
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)
|
||||
|
||||
|
@ -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=
|
@ -18,9 +18,9 @@ def fixResolution():
|
||||
import re
|
||||
import subprocess
|
||||
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
|
||||
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'
|
||||
@ -30,11 +30,11 @@ executable = None
|
||||
# Check first xfreerdp, allow password redir
|
||||
if os.path.isfile(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
|
||||
|
||||
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>
|
||||
<p>In order to connect to UDS RDP Sessions, you need to have a<p>
|
||||
<ul>
|
||||
@ -67,15 +67,16 @@ if executable is None:
|
||||
''')
|
||||
|
||||
# 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..
|
||||
if fs.check() is False:
|
||||
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
|
||||
|
||||
if executable == msrdc:
|
||||
theFile = theFile = sp['as_file'].format(
|
||||
address='127.0.0.1:{}'.format(fs.server_address[1])
|
||||
theFile = theFile = sp['as_file'].format( # type: ignore
|
||||
address=address
|
||||
)
|
||||
|
||||
filename = tools.saveTempFile(theFile)
|
||||
@ -89,7 +90,7 @@ elif executable == xfreerdp:
|
||||
try:
|
||||
xfparms = fixResolution()
|
||||
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)]
|
||||
subprocess.Popen(params)
|
||||
|
@ -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=
|
@ -17,23 +17,24 @@ from uds import tools # type: ignore
|
||||
|
||||
import six
|
||||
|
||||
thePass = six.binary_type(sp['password'].encode('UTF-16LE')) # type: ignore
|
||||
|
||||
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()
|
||||
except Exception:
|
||||
# logger.info('Cannot encrypt for user, trying for machine')
|
||||
password = codecs.encode(win32crypt.CryptProtectData(thePass, None, None, None, None, 0x05), 'hex').decode()
|
||||
|
||||
try:
|
||||
key = wreg.OpenKey(wreg.HKEY_CURRENT_USER, 'Software\\Microsoft\\Terminal Server Client\\LocalDevices', 0, wreg.KEY_SET_VALUE) # @UndefinedVariable
|
||||
wreg.SetValueEx(key, sp['ip'], 0, wreg.REG_DWORD, 255) # @UndefinedVariable
|
||||
wreg.CloseKey(key) # @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) # type: ignore
|
||||
wreg.CloseKey(key)
|
||||
except Exception as e:
|
||||
# logger.warn('Exception fixing redirection dialog: %s', e)
|
||||
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
|
||||
theFile = sp['as_file'].format(# @UndefinedVariable
|
||||
theFile = sp['as_file'].format( # type: ignore
|
||||
password=password
|
||||
)
|
||||
filename = tools.saveTempFile(theFile)
|
||||
|
@ -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=
|
@ -20,21 +20,22 @@ from uds import tools # type: ignore
|
||||
import six
|
||||
|
||||
# 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..
|
||||
if fs.check() is False:
|
||||
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:
|
||||
thePass = six.binary_type(sp['password'].encode('UTF-16LE')) # @UndefinedVariable
|
||||
password = codecs.encode(win32crypt.CryptProtectData(thePass, None, None, None, None, 0x01), 'hex').decode()
|
||||
except Exception:
|
||||
# Cannot encrypt for user, trying for machine
|
||||
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
|
||||
theFile = sp['as_file'].format(# @UndefinedVariable
|
||||
theFile = sp['as_file'].format( # type: ignore
|
||||
password=password,
|
||||
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')
|
||||
|
||||
try:
|
||||
key = wreg.OpenKey(wreg.HKEY_CURRENT_USER, 'Software\Microsoft\Terminal Server Client\LocalDevices', 0, wreg.KEY_SET_VALUE) # @UndefinedVariable
|
||||
wreg.SetValueEx(key, '127.0.0.1', 0, wreg.REG_DWORD, 255) # @UndefinedVariable
|
||||
wreg.CloseKey(key) # @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) # type: ignore
|
||||
wreg.CloseKey(key)
|
||||
except Exception as e:
|
||||
# logger.warn('Exception fixing redirection dialog: %s', e)
|
||||
pass # Key does not exists, but it's ok
|
||||
|
@ -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=
|
@ -5,7 +5,7 @@ from __future__ import unicode_literals
|
||||
# pylint: disable=import-error, no-name-in-module
|
||||
import subprocess
|
||||
|
||||
from uds import tools # @UnresolvedImport
|
||||
from uds import tools # type: ignore
|
||||
|
||||
executable = tools.findApp('remote-viewer')
|
||||
|
||||
@ -16,7 +16,7 @@ if executable is None:
|
||||
</p>
|
||||
''')
|
||||
|
||||
theFile = sp['as_file']
|
||||
theFile = sp['as_file'] # type: ignore
|
||||
|
||||
filename = tools.saveTempFile(theFile)
|
||||
|
||||
|
@ -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=
|
@ -5,8 +5,8 @@ from __future__ import unicode_literals
|
||||
# pylint: disable=import-error, no-name-in-module, undefined-variable
|
||||
import subprocess
|
||||
|
||||
from uds import tools # @UnresolvedImport
|
||||
from uds.forward import forward # @UnresolvedImport
|
||||
from uds import tools # type: ignore
|
||||
from uds.tunnel import forward # type: ignore
|
||||
|
||||
executable = tools.findApp('remote-viewer')
|
||||
|
||||
@ -21,31 +21,28 @@ if executable is None:
|
||||
''')
|
||||
|
||||
|
||||
theFile = sp['as_file_ns']
|
||||
if sp['port'] != '-1':
|
||||
forwardThread1, port = forward(sp['tunHost'], sp['tunPort'], sp['tunUser'], sp['tunPass'], sp['ip'], sp['port'])
|
||||
theFile = sp['as_file_ns'] # type: ignore
|
||||
fs = None
|
||||
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:
|
||||
raise Exception('Unable to open tunnel')
|
||||
else:
|
||||
port = -1
|
||||
fss = None
|
||||
if sp['ticket_secure']: # type: ignore
|
||||
# Open tunnel
|
||||
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':
|
||||
theFile = sp['as_file']
|
||||
if port != -1:
|
||||
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
|
||||
# Check that tunnel works..
|
||||
if fss.check() is False:
|
||||
raise Exception('<p>Could not connect to tunnel server 2.</p><p>Please, check your network settings.</p>')
|
||||
|
||||
theFile = theFile.format(
|
||||
secure_port=secure_port,
|
||||
port=port
|
||||
secure_port='-1' if not fss else fss.server_address[1],
|
||||
port='-1' if not fs else fs.server_address[1]
|
||||
)
|
||||
|
||||
filename = tools.saveTempFile(theFile)
|
||||
|
@ -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=
|
@ -6,7 +6,7 @@ from __future__ import unicode_literals
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from uds import tools # @UnresolvedImport
|
||||
from uds import tools # type: ignore
|
||||
|
||||
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)
|
||||
|
||||
|
@ -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=
|
@ -6,8 +6,8 @@ from __future__ import unicode_literals
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from uds import tools # @UnresolvedImport
|
||||
from uds.forward import forward # @UnresolvedImport
|
||||
from uds import tools # type: ignore
|
||||
from uds.tunnel import forward # type: ignore
|
||||
|
||||
remoteViewer = '/Applications/RemoteViewer.app/Contents/MacOS/RemoteViewer'
|
||||
|
||||
@ -25,31 +25,28 @@ if not os.path.isfile(remoteViewer):
|
||||
</p>
|
||||
''')
|
||||
|
||||
theFile = sp['as_file_ns']
|
||||
if sp['port'] != '-1':
|
||||
forwardThread1, port = forward(sp['tunHost'], sp['tunPort'], sp['tunUser'], sp['tunPass'], sp['ip'], sp['port'])
|
||||
theFile = sp['as_file_ns'] # type: ignore
|
||||
fs = None
|
||||
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:
|
||||
raise Exception('Unable to open tunnel')
|
||||
else:
|
||||
port = -1
|
||||
fss = None
|
||||
if sp['ticket_secure']: # type: ignore
|
||||
# Open tunnel
|
||||
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':
|
||||
theFile = sp['as_file']
|
||||
if port != -1:
|
||||
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
|
||||
# Check that tunnel works..
|
||||
if fss.check() is False:
|
||||
raise Exception('<p>Could not connect to tunnel server 2.</p><p>Please, check your network settings.</p>')
|
||||
|
||||
theFile = theFile.format(
|
||||
secure_port=secure_port,
|
||||
port=port
|
||||
secure_port='-1' if not fss else fss.server_address[1],
|
||||
port='-1' if not fs else fs.server_address[1]
|
||||
)
|
||||
|
||||
filename = tools.saveTempFile(theFile)
|
||||
|
@ -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=
|
@ -7,14 +7,14 @@ import os
|
||||
import glob
|
||||
import subprocess
|
||||
|
||||
from uds import tools # @UnresolvedImport
|
||||
from uds import tools # type: ignore
|
||||
|
||||
# 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"
|
||||
extraPaths = ()
|
||||
for env in ('PROGRAMFILES', 'PROGRAMW6432'):
|
||||
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)
|
||||
|
||||
@ -28,7 +28,7 @@ if executable is None:
|
||||
</p>
|
||||
''')
|
||||
|
||||
theFile = sp['as_file']
|
||||
theFile = sp['as_file'] # type: ignore
|
||||
|
||||
filename = tools.saveTempFile(theFile)
|
||||
|
||||
|
@ -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=
|
@ -7,15 +7,15 @@ import os
|
||||
import glob
|
||||
import subprocess
|
||||
|
||||
from uds import tools # @UnresolvedImport
|
||||
from uds.forward import forward # @UnresolvedImport
|
||||
from uds import tools # type: ignore
|
||||
from uds.tunnel import forward # type: ignore
|
||||
|
||||
# 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"
|
||||
extraPaths = ()
|
||||
for env in ('PROGRAMFILES', 'PROGRAMW6432'):
|
||||
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)
|
||||
|
||||
@ -28,31 +28,28 @@ if executable is None:
|
||||
<a href="http://virt-manager.org/download/">Open download page</a>
|
||||
</p>
|
||||
''')
|
||||
theFile = sp['as_file_ns']
|
||||
if sp['port'] != '-1':
|
||||
forwardThread1, port = forward(sp['tunHost'], sp['tunPort'], sp['tunUser'], sp['tunPass'], sp['ip'], sp['port'])
|
||||
theFile = sp['as_file_ns'] # type: ignore
|
||||
fs = None
|
||||
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:
|
||||
raise Exception('Unable to open tunnel')
|
||||
else:
|
||||
port = -1
|
||||
fss = None
|
||||
if sp['ticket_secure']: # type: ignore
|
||||
# Open tunnel
|
||||
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':
|
||||
theFile = sp['as_file']
|
||||
if port != -1:
|
||||
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
|
||||
# Check that tunnel works..
|
||||
if fss.check() is False:
|
||||
raise Exception('<p>Could not connect to tunnel server 2.</p><p>Please, check your network settings.</p>')
|
||||
|
||||
theFile = theFile.format(
|
||||
secure_port=secure_port,
|
||||
port=port
|
||||
secure_port='-1' if not fss else fss.server_address[1],
|
||||
port='-1' if not fs else fs.server_address[1]
|
||||
)
|
||||
|
||||
filename = tools.saveTempFile(theFile)
|
||||
|
@ -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=
|
@ -1,7 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012-2019 Virtual Cable S.L.
|
||||
# Copyright (c) 2012-2021 Virtual Cable S.L.U.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
@ -57,15 +56,44 @@ logger = logging.getLogger(__name__)
|
||||
class TSPICETransport(BaseSpiceTransport):
|
||||
"""
|
||||
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')
|
||||
typeType = 'TSSPICETransport'
|
||||
typeDescription = _('SPICE Protocol. Tunneled connection.')
|
||||
protocol = transports.protocols.SPICE
|
||||
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
|
||||
fullScreen = BaseSpiceTransport.fullScreen
|
||||
@ -76,34 +104,52 @@ class TSPICETransport(BaseSpiceTransport):
|
||||
def initialize(self, values: 'Module.ValuesType'):
|
||||
if values:
|
||||
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
|
||||
self,
|
||||
userService: 'models.UserService',
|
||||
transport: 'models.Transport',
|
||||
ip: str,
|
||||
os: typing.Dict[str, str],
|
||||
user: 'models.User',
|
||||
password: str,
|
||||
request: 'HttpRequest'
|
||||
) -> typing.Tuple[str, str, typing.Dict[str, typing.Any]]:
|
||||
self,
|
||||
userService: 'models.UserService',
|
||||
transport: 'models.Transport',
|
||||
ip: str,
|
||||
os: typing.Dict[str, str],
|
||||
user: 'models.User',
|
||||
password: str,
|
||||
request: 'HttpRequest',
|
||||
) -> typing.Tuple[str, str, typing.Dict[str, typing.Any]]:
|
||||
userServiceInstance: typing.Any = userService.getInstance()
|
||||
|
||||
# Spice connection
|
||||
con = userServiceInstance.getConsoleConnection()
|
||||
port: str = con['port'] or '-1'
|
||||
secure_port: str = con['secure_port'] or '-1'
|
||||
|
||||
# Ticket
|
||||
tunpass = ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits) for _i in range(12))
|
||||
tunuser = TicketStore.create(tunpass)
|
||||
# We MAY need two tickets, one for 'insecure' port an one for secure
|
||||
ticket = ''
|
||||
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(
|
||||
'127.0.0.1', '{port}', '{secure_port}', con['ticket']['value'],
|
||||
self.serverCertificate.value.strip(), con['cert_subject'], fullscreen=self.fullScreen.isTrue()
|
||||
'127.0.0.1',
|
||||
'{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.new_usb_auto_share = self.autoNewUsbShare.isTrue()
|
||||
@ -112,11 +158,13 @@ class TSPICETransport(BaseSpiceTransport):
|
||||
osName = {
|
||||
OsDetector.Windows: 'windows',
|
||||
OsDetector.Linux: 'linux',
|
||||
OsDetector.Macintosh: 'macosx'
|
||||
OsDetector.Macintosh: 'macosx',
|
||||
}.get(os['OS'])
|
||||
|
||||
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
|
||||
# userServiceInstance.desktopLogin(user, password, '')
|
||||
@ -124,13 +172,12 @@ class TSPICETransport(BaseSpiceTransport):
|
||||
sp = {
|
||||
'as_file': r.as_file,
|
||||
'as_file_ns': r.as_file_ns,
|
||||
'tunUser': tunuser,
|
||||
'tunPass': tunpass,
|
||||
'tunHost': sshHost,
|
||||
'tunPort': sshPort,
|
||||
'ip': con['address'],
|
||||
'port': port,
|
||||
'secure_port': secure_port
|
||||
'tunHost': tunHost,
|
||||
'tunPort': tunPort,
|
||||
'tunWait': self.tunnelWait.num(),
|
||||
'tunChk': self.verifyCertificate.isTrue(),
|
||||
'ticket': ticket,
|
||||
'ticket_secure': ticket_secure,
|
||||
}
|
||||
|
||||
return self.getScript('scripts/{}/tunnel.py', osName, sp)
|
||||
|
@ -6,11 +6,11 @@ from __future__ import unicode_literals
|
||||
import subprocess
|
||||
from os.path import expanduser
|
||||
|
||||
from uds import tools # @UnresolvedImport
|
||||
from uds import tools # type: ignore
|
||||
|
||||
home = expanduser('~') + ':1;/media:1;'
|
||||
keyFile = tools.saveTempFile(sp['key'])
|
||||
theFile = sp['xf'].format(export=home, keyFile=keyFile.replace('\\', '/'), ip=sp['ip'], port=sp['port'])
|
||||
keyFile = tools.saveTempFile(sp['key']) # type: ignore
|
||||
theFile = sp['xf'].format(export=home, keyFile=keyFile.replace('\\', '/'), ip=sp['ip'], port=sp['port']) # type: ignore
|
||||
filename = tools.saveTempFile(theFile)
|
||||
|
||||
# HOME=[temporal folder, where we create a .x2goclient folder and a sessions inside] pyhoca-cli -P UDS/test-session
|
||||
|
@ -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=
|
@ -5,20 +5,21 @@ from __future__ import unicode_literals
|
||||
# pylint: disable=import-error, no-name-in-module, too-many-format-args, undefined-variable
|
||||
|
||||
import subprocess
|
||||
from uds.forward import forward # @UnresolvedImport
|
||||
from uds.tunnel import forward # type: ignore
|
||||
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:
|
||||
raise Exception('Unable to open tunnel')
|
||||
# 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>')
|
||||
|
||||
tools.addTaskToWait(forwardThread)
|
||||
home = expanduser('~') + ':1;/media:1;'
|
||||
keyFile = tools.saveTempFile(sp['key'])
|
||||
theFile = sp['xf'].format(export=home, keyFile=keyFile.replace('\\', '/'), ip='127.0.0.1', port=port)
|
||||
keyFile = tools.saveTempFile(sp['key']) # type: ignore
|
||||
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)
|
||||
|
||||
# HOME=[temporal folder, where we create a .x2goclient folder and a sessions inside] pyhoca-cli -P UDS/test-session
|
||||
|
@ -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=
|
@ -7,12 +7,12 @@ import os
|
||||
import subprocess
|
||||
from os.path import expanduser
|
||||
|
||||
from uds import tools # @UnresolvedImport
|
||||
from uds import tools # type: ignore
|
||||
|
||||
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 "#"
|
||||
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)
|
||||
|
||||
x2goPath = os.environ['PROGRAMFILES(X86)'] + '\\x2goclient'
|
||||
|
@ -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=
|
@ -6,22 +6,22 @@
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
from uds.forward import forward # @UnresolvedImport
|
||||
from uds.tunnel import forward # type: ignore
|
||||
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:
|
||||
raise Exception('Unable to open tunnel')
|
||||
|
||||
tools.addTaskToWait(forwardThread)
|
||||
# Care, expanduser is encoding using "mcbs", so treat it as bytes always
|
||||
# Care, expanduser is encoding using "mcbs", so treat it as bytes on python 2.7
|
||||
home = expanduser('~').replace('\\', '\\\\') + '#1;'
|
||||
keyFile = tools.saveTempFile(sp['key'])
|
||||
theFile = sp['xf'].format(export=home, keyFile=keyFile.replace('\\', '/'), ip='127.0.0.1', port=port)
|
||||
keyFile = tools.saveTempFile(sp['key']) # type: ignore
|
||||
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)
|
||||
|
||||
x2goPath = os.environ['PROGRAMFILES(X86)'] + '\\x2goclient'
|
||||
|
@ -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=
|
@ -1,7 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2016-2019 Virtual Cable S.L.
|
||||
# Copyright (c) 2016-2021 Virtual Cable S.L.U.
|
||||
# All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
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')
|
||||
typeType = 'TX2GOTransport'
|
||||
typeDescription = _('X2Go access (Experimental). Tunneled connection.')
|
||||
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
|
||||
screenSize = BaseX2GOTransport.screenSize
|
||||
@ -83,18 +113,20 @@ class TX2GOTransport(BaseX2GOTransport):
|
||||
def initialize(self, values: 'Module.ValuesType'):
|
||||
if values:
|
||||
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
|
||||
self,
|
||||
userService: 'models.UserService',
|
||||
transport: 'models.Transport',
|
||||
ip: str,
|
||||
os: typing.Dict[str, str],
|
||||
user: 'models.User',
|
||||
password: str,
|
||||
request: 'HttpRequest'
|
||||
) -> typing.Tuple[str, str, typing.Dict[str, typing.Any]]:
|
||||
self,
|
||||
userService: 'models.UserService',
|
||||
transport: 'models.Transport',
|
||||
ip: str,
|
||||
os: typing.Dict[str, str],
|
||||
user: 'models.User',
|
||||
password: str,
|
||||
request: 'HttpRequest',
|
||||
) -> typing.Tuple[str, str, typing.Dict[str, typing.Any]]:
|
||||
|
||||
ci = self.getConnectionInfo(userService, user, password)
|
||||
username = ci['username']
|
||||
@ -120,13 +152,16 @@ class TX2GOTransport(BaseX2GOTransport):
|
||||
rootless=rootless,
|
||||
width=width,
|
||||
height=height,
|
||||
user=username
|
||||
user=username,
|
||||
)
|
||||
|
||||
tunpass = ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits) for _i in range(12))
|
||||
tunuser = TicketStore.create(tunpass)
|
||||
ticket = TicketStore.create_for_tunnel(
|
||||
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 = {
|
||||
@ -140,7 +175,7 @@ class TX2GOTransport(BaseX2GOTransport):
|
||||
'drives': self.exports.isTrue(),
|
||||
'fullScreen': width == -1 or height == -1,
|
||||
'this_server': request.build_absolute_uri('/'),
|
||||
'xf': xf
|
||||
'xf': xf,
|
||||
}
|
||||
|
||||
m = tools.DictAsObj(data)
|
||||
@ -152,17 +187,18 @@ class TX2GOTransport(BaseX2GOTransport):
|
||||
}.get(os['OS'])
|
||||
|
||||
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 = {
|
||||
'tunUser': tunuser,
|
||||
'tunPass': tunpass,
|
||||
'tunHost': sshHost,
|
||||
'tunPort': sshPort,
|
||||
'ip': ip,
|
||||
'port': '22',
|
||||
'tunHost': tunHost,
|
||||
'tunPort': tunPort,
|
||||
'tunWait': self.tunnelWait.num(),
|
||||
'tunChk': self.verifyCertificate.isTrue(),
|
||||
'ticket': ticket,
|
||||
'key': priv,
|
||||
'xf': xf
|
||||
'xf': xf,
|
||||
}
|
||||
|
||||
return self.getScript('scripts/{}/tunnel.py', osName, sp)
|
||||
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"directory": "bower_components"
|
||||
}
|
@ -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
|
1
server/templates/admin/.gitattributes
vendored
1
server/templates/admin/.gitattributes
vendored
@ -1 +0,0 @@
|
||||
* text=auto
|
4
server/templates/admin/.gitignore
vendored
4
server/templates/admin/.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
node_modules
|
||||
.tmp
|
||||
bower_components
|
||||
dist
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"generator-mocha": {}
|
||||
}
|
@ -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 |
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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%);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
*/
|
@ -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;
|
@ -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;
|
@ -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;
|
||||
}
|
195
server/templates/admin/app/css/bootstrap-switch.css
vendored
195
server/templates/admin/app/css/bootstrap-switch.css
vendored
@ -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;
|
||||
}
|
@ -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
@ -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;
|
||||
}
|
@ -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 |
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user