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]
|
remote: typing.Tuple[str, int]
|
||||||
ticket: str
|
ticket: str
|
||||||
stop_flag: threading.Event
|
stop_flag: threading.Event
|
||||||
|
can_stop: bool
|
||||||
timeout: int
|
timeout: int
|
||||||
timer: typing.Optional[threading.Timer]
|
timer: typing.Optional[threading.Timer]
|
||||||
check_certificate: bool
|
check_certificate: bool
|
||||||
@ -79,20 +80,22 @@ class ForwardServer(socketserver.ThreadingTCPServer):
|
|||||||
)
|
)
|
||||||
self.remote = remote
|
self.remote = remote
|
||||||
self.ticket = ticket
|
self.ticket = ticket
|
||||||
self.timeout = int(time.time()) + timeout if timeout else 0
|
# Negative values for timeout, means "accept always connections"
|
||||||
|
# "but if no connection is stablished on timeout (positive)"
|
||||||
|
# "stop the listener"
|
||||||
|
self.timeout = int(time.time()) + timeout if timeout > 0 else 0
|
||||||
self.check_certificate = check_certificate
|
self.check_certificate = check_certificate
|
||||||
self.stop_flag = threading.Event() # False initial
|
self.stop_flag = threading.Event() # False initial
|
||||||
self.current_connections = 0
|
self.current_connections = 0
|
||||||
|
|
||||||
self.status = TUNNEL_LISTENING
|
self.status = TUNNEL_LISTENING
|
||||||
|
self.can_stop = False
|
||||||
|
|
||||||
if timeout:
|
timeout = abs(timeout) or 60
|
||||||
self.timer = threading.Timer(
|
self.timer = threading.Timer(
|
||||||
timeout, ForwardServer.__checkStarted, args=(self,)
|
abs(timeout), ForwardServer.__checkStarted, args=(self,)
|
||||||
)
|
)
|
||||||
self.timer.start()
|
self.timer.start()
|
||||||
else:
|
|
||||||
self.timer = None
|
|
||||||
|
|
||||||
def stop(self) -> None:
|
def stop(self) -> None:
|
||||||
if not self.stop_flag.is_set():
|
if not self.stop_flag.is_set():
|
||||||
@ -120,6 +123,9 @@ class ForwardServer(socketserver.ThreadingTCPServer):
|
|||||||
return context.wrap_socket(rsocket, server_hostname=self.remote[0])
|
return context.wrap_socket(rsocket, server_hostname=self.remote[0])
|
||||||
|
|
||||||
def check(self) -> bool:
|
def check(self) -> bool:
|
||||||
|
if self.status == TUNNEL_ERROR:
|
||||||
|
return False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with self.connect() as ssl_socket:
|
with self.connect() as ssl_socket:
|
||||||
ssl_socket.sendall(HANDSHAKE_V1 + b'TEST')
|
ssl_socket.sendall(HANDSHAKE_V1 + b'TEST')
|
||||||
@ -135,11 +141,14 @@ class ForwardServer(socketserver.ThreadingTCPServer):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def stoppable(self) -> bool:
|
def stoppable(self) -> bool:
|
||||||
return self.timeout != 0 and int(time.time()) > self.timeout
|
logger.debug('Is stoppable: %s', self.can_stop)
|
||||||
|
return self.can_stop or (self.timeout != 0 and int(time.time()) > self.timeout)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __checkStarted(fs: 'ForwardServer') -> None:
|
def __checkStarted(fs: 'ForwardServer') -> None:
|
||||||
|
logger.debug('New connection limit reached')
|
||||||
fs.timer = None
|
fs.timer = None
|
||||||
|
fs.can_stop = True
|
||||||
if fs.current_connections <= 0:
|
if fs.current_connections <= 0:
|
||||||
fs.stop()
|
fs.stop()
|
||||||
|
|
||||||
@ -150,15 +159,17 @@ class Handler(socketserver.BaseRequestHandler):
|
|||||||
|
|
||||||
# server: ForwardServer
|
# server: ForwardServer
|
||||||
def handle(self) -> None:
|
def handle(self) -> None:
|
||||||
self.server.current_connections += 1
|
|
||||||
self.server.status = TUNNEL_OPENING
|
self.server.status = TUNNEL_OPENING
|
||||||
|
|
||||||
# If server processing is over time
|
# If server processing is over time
|
||||||
if self.server.stoppable:
|
if self.server.stoppable:
|
||||||
logger.info('Rejected timedout connection try')
|
self.server.status = TUNNEL_ERROR
|
||||||
|
logger.info('Rejected timedout connection')
|
||||||
self.request.close() # End connection without processing it
|
self.request.close() # End connection without processing it
|
||||||
return
|
return
|
||||||
|
|
||||||
|
self.server.current_connections += 1
|
||||||
|
|
||||||
# Open remote connection
|
# Open remote connection
|
||||||
try:
|
try:
|
||||||
logger.debug('Ticket %s', self.server.ticket)
|
logger.debug('Ticket %s', self.server.ticket)
|
||||||
@ -169,7 +180,9 @@ class Handler(socketserver.BaseRequestHandler):
|
|||||||
data = ssl_socket.recv(2)
|
data = ssl_socket.recv(2)
|
||||||
if data != b'OK':
|
if data != b'OK':
|
||||||
data += ssl_socket.recv(128)
|
data += ssl_socket.recv(128)
|
||||||
raise Exception(f'Error received: {data.decode(errors="ignore")}') # Notify error
|
raise Exception(
|
||||||
|
f'Error received: {data.decode(errors="ignore")}'
|
||||||
|
) # Notify error
|
||||||
|
|
||||||
# All is fine, now we can tunnel data
|
# All is fine, now we can tunnel data
|
||||||
self.process(remote=ssl_socket)
|
self.process(remote=ssl_socket)
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2014-2019 Virtual Cable S.L.
|
# Copyright (c) 2014-2021 Virtual Cable S.L.
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
# Redistribution and use in source and binary forms, with or without modification,
|
# Redistribution and use in source and binary forms, with or without modification,
|
||||||
@ -423,6 +422,13 @@ class Login(LoginLogout):
|
|||||||
"""
|
"""
|
||||||
name = 'login'
|
name = 'login'
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def process_login(userService: UserService, username: str) -> typing.Optional[osmanagers.OSManager]:
|
||||||
|
osManager: typing.Optional[osmanagers.OSManager] = userService.getOsManagerInstance()
|
||||||
|
if not userService.in_use: # If already logged in, do not add a second login (windows does this i.e.)
|
||||||
|
osmanagers.OSManager.loggedIn(userService, username)
|
||||||
|
return osManager
|
||||||
|
|
||||||
def action(self) -> typing.MutableMapping[str, typing.Any]:
|
def action(self) -> typing.MutableMapping[str, typing.Any]:
|
||||||
isManaged = self._params.get('type') != UNMANAGED
|
isManaged = self._params.get('type') != UNMANAGED
|
||||||
ip = hostname = ''
|
ip = hostname = ''
|
||||||
@ -432,9 +438,7 @@ class Login(LoginLogout):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
userService: UserService = self.getUserService()
|
userService: UserService = self.getUserService()
|
||||||
osManager: typing.Optional[osmanagers.OSManager] = userService.getOsManagerInstance()
|
osManager = Login.process_login(userService, self._params.get('username') or '')
|
||||||
if not userService.in_use: # If already logged in, do not add a second login (windows does this i.e.)
|
|
||||||
osmanagers.OSManager.loggedIn(userService, self._params.get('username') or '')
|
|
||||||
|
|
||||||
maxIdle = osManager.maxIdle() if osManager else None
|
maxIdle = osManager.maxIdle() if osManager else None
|
||||||
|
|
||||||
@ -462,21 +466,29 @@ class Logout(LoginLogout):
|
|||||||
"""
|
"""
|
||||||
name = 'logout'
|
name = 'logout'
|
||||||
|
|
||||||
def action(self) -> typing.MutableMapping[str, typing.Any]:
|
@staticmethod
|
||||||
isManaged = self._params.get('type') != UNMANAGED
|
def process_logout(userService: UserService, username: str) -> None:
|
||||||
|
"""
|
||||||
logger.debug('Args: %s, Params: %s', self._args, self._params)
|
This method is static so can be invoked from elsewhere
|
||||||
try:
|
"""
|
||||||
userService: UserService = self.getUserService()
|
|
||||||
osManager: typing.Optional[osmanagers.OSManager] = userService.getOsManagerInstance()
|
osManager: typing.Optional[osmanagers.OSManager] = userService.getOsManagerInstance()
|
||||||
if userService.in_use: # If already logged out, do not add a second logout (windows does this i.e.)
|
if userService.in_use: # If already logged out, do not add a second logout (windows does this i.e.)
|
||||||
osmanagers.OSManager.loggedOut(userService, self._params.get('username') or '')
|
osmanagers.OSManager.loggedOut(userService, username)
|
||||||
if osManager:
|
if osManager:
|
||||||
if osManager.isRemovableOnLogout(userService):
|
if osManager.isRemovableOnLogout(userService):
|
||||||
logger.debug('Removable on logout: %s', osManager)
|
logger.debug('Removable on logout: %s', osManager)
|
||||||
userService.remove()
|
userService.remove()
|
||||||
else:
|
else:
|
||||||
userService.remove()
|
userService.remove()
|
||||||
|
|
||||||
|
|
||||||
|
def action(self) -> typing.MutableMapping[str, typing.Any]:
|
||||||
|
isManaged = self._params.get('type') != UNMANAGED
|
||||||
|
|
||||||
|
logger.debug('Args: %s, Params: %s', self._args, self._params)
|
||||||
|
try:
|
||||||
|
userService: UserService = self.getUserService()
|
||||||
|
Logout.process_logout(userService, self._params.get('username') or '')
|
||||||
except Exception: # If unamanaged host, lest do a bit more work looking for a service with the provided parameters...
|
except Exception: # If unamanaged host, lest do a bit more work looking for a service with the provided parameters...
|
||||||
if isManaged:
|
if isManaged:
|
||||||
raise
|
raise
|
||||||
|
@ -177,7 +177,7 @@ class OSManager(Module):
|
|||||||
Helper method that informs if the os manager transforms the username and/or the password.
|
Helper method that informs if the os manager transforms the username and/or the password.
|
||||||
This is used from ServicePool
|
This is used from ServicePool
|
||||||
"""
|
"""
|
||||||
return cls.processUserPassword != OSManager.processUserPassword
|
return hash(cls.processUserPassword) != hash(OSManager.processUserPassword)
|
||||||
|
|
||||||
def processUserPassword(self, userService: 'UserService', username: str, password: str) -> typing.Tuple[str, str]:
|
def processUserPassword(self, userService: 'UserService', username: str, password: str) -> typing.Tuple[str, str]:
|
||||||
"""
|
"""
|
||||||
@ -299,5 +299,5 @@ class OSManager(Module):
|
|||||||
"""
|
"""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
return "Base OS Manager"
|
return "Base OS Manager"
|
||||||
|
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":
|
elif message == "log":
|
||||||
self.doLog(userService, data, log.ACTOR)
|
self.doLog(userService, data, log.ACTOR)
|
||||||
elif message == "login":
|
elif message == "login":
|
||||||
osmanagers.OSManager.loggedIn(userService, data)
|
osmanagers.OSManager.loggedIn(userService, typing.cast(str, data))
|
||||||
ip, hostname = userService.getConnectionSource()
|
ip, hostname = userService.getConnectionSource()
|
||||||
deadLine = userService.deployed_service.getDeadline()
|
deadLine = userService.deployed_service.getDeadline()
|
||||||
ret = "{}\t{}\t{}".format(ip, hostname, 0 if deadLine is None else deadLine)
|
ret = "{}\t{}\t{}".format(ip, hostname, 0 if deadLine is None else deadLine)
|
||||||
elif message == "logout":
|
elif message == "logout":
|
||||||
osmanagers.OSManager.loggedOut(userService, data)
|
osmanagers.OSManager.loggedOut(userService, typing.cast(str, data))
|
||||||
doRemove = self.isRemovableOnLogout(userService)
|
doRemove = self.isRemovableOnLogout(userService)
|
||||||
elif message == "ip":
|
elif message == "ip":
|
||||||
# This ocurss on main loop inside machine, so userService is usable
|
# This ocurss on main loop inside machine, so userService is usable
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2017-2019 Virtual Cable S.L.
|
# Copyright (c) 2017-2021 Virtual Cable S.L.U.
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
# Redistribution and use in source and binary forms, with or without modification,
|
# Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2012 Virtual Cable S.L.
|
# Copyright (c) 2015-2021 Virtual Cable S.L.U.
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
# Redistribution and use in source and binary forms, with or without modification,
|
# Redistribution and use in source and binary forms, with or without modification,
|
||||||
@ -34,6 +34,7 @@ import logging
|
|||||||
import typing
|
import typing
|
||||||
|
|
||||||
from uds.core.services import UserDeployment
|
from uds.core.services import UserDeployment
|
||||||
|
from uds.core.managers import cryptoManager
|
||||||
from uds.core.util.state import State
|
from uds.core.util.state import State
|
||||||
from uds.core.util import log
|
from uds.core.util import log
|
||||||
from uds.models.util import getSqlDatetimeAsUnix
|
from uds.models.util import getSqlDatetimeAsUnix
|
||||||
@ -47,7 +48,7 @@ if typing.TYPE_CHECKING:
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
opCreate, opError, opFinish, opRemove, opRetry = range(5)
|
opCreate, opError, opFinish, opRemove, opRetry, opStart = range(6)
|
||||||
|
|
||||||
|
|
||||||
class OGDeployment(UserDeployment):
|
class OGDeployment(UserDeployment):
|
||||||
@ -71,7 +72,9 @@ class OGDeployment(UserDeployment):
|
|||||||
_stamp: int = 0
|
_stamp: int = 0
|
||||||
_reason: str = ''
|
_reason: str = ''
|
||||||
|
|
||||||
_queue: typing.List[int] # Do not initialize mutable, just declare and it is initialized on "initialize"
|
_queue: typing.List[
|
||||||
|
int
|
||||||
|
] # Do not initialize mutable, just declare and it is initialized on "initialize"
|
||||||
_uuid: str
|
_uuid: str
|
||||||
|
|
||||||
def initialize(self) -> None:
|
def initialize(self) -> None:
|
||||||
@ -93,7 +96,8 @@ class OGDeployment(UserDeployment):
|
|||||||
"""
|
"""
|
||||||
Does nothing right here, we will use environment storage in this sample
|
Does nothing right here, we will use environment storage in this sample
|
||||||
"""
|
"""
|
||||||
return b'\1'.join([
|
return b'\1'.join(
|
||||||
|
[
|
||||||
b'v1',
|
b'v1',
|
||||||
self._name.encode('utf8'),
|
self._name.encode('utf8'),
|
||||||
self._ip.encode('utf8'),
|
self._ip.encode('utf8'),
|
||||||
@ -101,8 +105,9 @@ class OGDeployment(UserDeployment):
|
|||||||
self._machineId.encode('utf8'),
|
self._machineId.encode('utf8'),
|
||||||
self._reason.encode('utf8'),
|
self._reason.encode('utf8'),
|
||||||
str(self._stamp).encode('utf8'),
|
str(self._stamp).encode('utf8'),
|
||||||
pickle.dumps(self._queue, protocol=0)
|
pickle.dumps(self._queue, protocol=0),
|
||||||
])
|
]
|
||||||
|
)
|
||||||
|
|
||||||
def unmarshal(self, data: bytes) -> None:
|
def unmarshal(self, data: bytes) -> None:
|
||||||
"""
|
"""
|
||||||
@ -135,11 +140,34 @@ class OGDeployment(UserDeployment):
|
|||||||
OpenGnsys will try it best by sending an WOL
|
OpenGnsys will try it best by sending an WOL
|
||||||
"""
|
"""
|
||||||
dbs = self.dbservice()
|
dbs = self.dbservice()
|
||||||
deadline = dbs.deployed_service.getDeadline() if dbs else 0
|
if not dbs:
|
||||||
self.service().notifyDeadline(self._machineId, deadline)
|
|
||||||
|
|
||||||
return State.FINISHED
|
return State.FINISHED
|
||||||
|
|
||||||
|
try:
|
||||||
|
# First, check Machine is alive..
|
||||||
|
status = self.__checkMachineReady()
|
||||||
|
if status == State.FINISHED:
|
||||||
|
self.service().notifyDeadline(
|
||||||
|
self._machineId, dbs.deployed_service.getDeadline()
|
||||||
|
)
|
||||||
|
return State.FINISHED
|
||||||
|
|
||||||
|
if status == State.ERROR:
|
||||||
|
return State.ERROR
|
||||||
|
|
||||||
|
# Machine powered off, check what to do...
|
||||||
|
if self.service().isRemovableIfUnavailable():
|
||||||
|
return self.__error(
|
||||||
|
'Machine is unavailable and service has "Remove if unavailable" flag active.'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Try to start it, and let's see
|
||||||
|
self._queue = [opStart, opFinish]
|
||||||
|
return self.__executeQueue()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return self.__error('Error setting ready state: {}'.format(e))
|
||||||
|
|
||||||
def deployForUser(self, user: 'models.User') -> str:
|
def deployForUser(self, user: 'models.User') -> str:
|
||||||
"""
|
"""
|
||||||
Deploys an service instance for an user.
|
Deploys an service instance for an user.
|
||||||
@ -159,7 +187,11 @@ class OGDeployment(UserDeployment):
|
|||||||
self._queue = [opCreate, opFinish]
|
self._queue = [opCreate, opFinish]
|
||||||
|
|
||||||
def __checkMachineReady(self) -> str:
|
def __checkMachineReady(self) -> str:
|
||||||
logger.debug('Checking that state of machine %s (%s) is ready', self._machineId, self._name)
|
logger.debug(
|
||||||
|
'Checking that state of machine %s (%s) is ready',
|
||||||
|
self._machineId,
|
||||||
|
self._name,
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
status = self.service().status(self._machineId)
|
status = self.service().status(self._machineId)
|
||||||
@ -202,7 +234,11 @@ class OGDeployment(UserDeployment):
|
|||||||
logger.debug('Setting error state, reason: %s', reason)
|
logger.debug('Setting error state, reason: %s', reason)
|
||||||
self.doLog(log.ERROR, reason)
|
self.doLog(log.ERROR, reason)
|
||||||
|
|
||||||
# TODO: Unreserve machine?? Maybe it just better to keep it assigned so UDS don't get it again in a while...
|
if self._machineId:
|
||||||
|
try:
|
||||||
|
self.service().unreserve(self._machineId)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
self._queue = [opError]
|
self._queue = [opError]
|
||||||
self._reason = str(reason)
|
self._reason = str(reason)
|
||||||
@ -222,13 +258,16 @@ class OGDeployment(UserDeployment):
|
|||||||
opCreate: self.__create,
|
opCreate: self.__create,
|
||||||
opRetry: self.__retry,
|
opRetry: self.__retry,
|
||||||
opRemove: self.__remove,
|
opRemove: self.__remove,
|
||||||
|
opStart: self.__start,
|
||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
execFnc: typing.Optional[typing.Callable[[], str]] = fncs.get(op, None)
|
execFnc: typing.Optional[typing.Callable[[], str]] = fncs.get(op)
|
||||||
|
|
||||||
if execFnc is None:
|
if execFnc is None:
|
||||||
return self.__error('Unknown operation found at execution queue ({0})'.format(op))
|
return self.__error(
|
||||||
|
'Unknown operation found at execution queue ({0})'.format(op)
|
||||||
|
)
|
||||||
|
|
||||||
execFnc()
|
execFnc()
|
||||||
|
|
||||||
@ -252,10 +291,11 @@ class OGDeployment(UserDeployment):
|
|||||||
"""
|
"""
|
||||||
Deploys a machine from template for user/cache
|
Deploys a machine from template for user/cache
|
||||||
"""
|
"""
|
||||||
try:
|
|
||||||
r: typing.Any = None
|
r: typing.Any = None
|
||||||
|
token = cryptoManager().randomString(32)
|
||||||
|
try:
|
||||||
r = self.service().reserve()
|
r = self.service().reserve()
|
||||||
self.service().notifyEvents(r['id'], self._uuid)
|
self.service().notifyEvents(r['id'], token, self._uuid)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# logger.exception('Creating machine')
|
# logger.exception('Creating machine')
|
||||||
if r: # Reservation was done, unreserve it!!!
|
if r: # Reservation was done, unreserve it!!!
|
||||||
@ -274,18 +314,35 @@ class OGDeployment(UserDeployment):
|
|||||||
self._ip = r['ip']
|
self._ip = r['ip']
|
||||||
self._stamp = getSqlDatetimeAsUnix()
|
self._stamp = getSqlDatetimeAsUnix()
|
||||||
|
|
||||||
|
self.doLog(
|
||||||
|
log.INFO,
|
||||||
|
f'Reserved machine {self._name}: id: {self._machineId}, mac: {self._mac}, ip: {self._ip}',
|
||||||
|
)
|
||||||
|
|
||||||
# Store actor version & Known ip
|
# Store actor version & Known ip
|
||||||
dbs = self.dbservice()
|
dbs = self.dbservice()
|
||||||
if dbs:
|
if dbs:
|
||||||
dbs.setProperty('actor_version', '1.0-OpenGnsys')
|
dbs.setProperty('actor_version', '1.1-OpenGnsys')
|
||||||
|
dbs.setProperty('token', token)
|
||||||
dbs.logIP(self._ip)
|
dbs.logIP(self._ip)
|
||||||
|
|
||||||
return State.RUNNING
|
return State.RUNNING
|
||||||
|
|
||||||
|
def __start(self) -> str:
|
||||||
|
if self._machineId:
|
||||||
|
self.service().powerOn(self._machineId)
|
||||||
|
return State.RUNNING
|
||||||
|
|
||||||
def __remove(self) -> str:
|
def __remove(self) -> str:
|
||||||
"""
|
"""
|
||||||
Removes a machine from system
|
Removes a machine from system
|
||||||
|
Avoids "double unreserve" in case the reservation was made from release
|
||||||
"""
|
"""
|
||||||
|
dbs = self.dbservice()
|
||||||
|
if dbs:
|
||||||
|
# On release callback, we will set a property on DB called "from_release"
|
||||||
|
# so we can avoid double unreserve
|
||||||
|
if dbs.getProperty('from_release') is None:
|
||||||
self.service().unreserve(self._machineId)
|
self.service().unreserve(self._machineId)
|
||||||
return State.RUNNING
|
return State.RUNNING
|
||||||
|
|
||||||
@ -296,6 +353,9 @@ class OGDeployment(UserDeployment):
|
|||||||
"""
|
"""
|
||||||
return self.__checkMachineReady()
|
return self.__checkMachineReady()
|
||||||
|
|
||||||
|
# Alias for poweron check
|
||||||
|
__checkStart = __checkCreate
|
||||||
|
|
||||||
def __checkRemoved(self) -> str:
|
def __checkRemoved(self) -> str:
|
||||||
"""
|
"""
|
||||||
Checks if a machine has been removed
|
Checks if a machine has been removed
|
||||||
@ -319,13 +379,18 @@ class OGDeployment(UserDeployment):
|
|||||||
opCreate: self.__checkCreate,
|
opCreate: self.__checkCreate,
|
||||||
opRetry: self.__retry,
|
opRetry: self.__retry,
|
||||||
opRemove: self.__checkRemoved,
|
opRemove: self.__checkRemoved,
|
||||||
|
opStart: self.__checkStart,
|
||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
chkFnc: typing.Optional[typing.Optional[typing.Callable[[], str]]] = fncs.get(op, None)
|
chkFnc: typing.Optional[
|
||||||
|
typing.Optional[typing.Callable[[], str]]
|
||||||
|
] = fncs.get(op)
|
||||||
|
|
||||||
if chkFnc is None:
|
if chkFnc is None:
|
||||||
return self.__error('Unknown operation found at check queue ({0})'.format(op))
|
return self.__error(
|
||||||
|
'Unknown operation found at check queue ({0})'.format(op)
|
||||||
|
)
|
||||||
|
|
||||||
state = chkFnc()
|
state = chkFnc()
|
||||||
if state == State.FINISHED:
|
if state == State.FINISHED:
|
||||||
@ -379,4 +444,12 @@ class OGDeployment(UserDeployment):
|
|||||||
}.get(op, '????')
|
}.get(op, '????')
|
||||||
|
|
||||||
def __debug(self, txt) -> None:
|
def __debug(self, txt) -> None:
|
||||||
logger.debug('State at %s: name: %s, ip: %s, mac: %s, machine:%s, queue: %s', txt, self._name, self._ip, self._mac, self._machineId, [OGDeployment.__op2str(op) for op in self._queue])
|
logger.debug(
|
||||||
|
'State at %s: name: %s, ip: %s, mac: %s, machine:%s, queue: %s',
|
||||||
|
txt,
|
||||||
|
self._name,
|
||||||
|
self._ip,
|
||||||
|
self._mac,
|
||||||
|
self._machineId,
|
||||||
|
[OGDeployment.__op2str(op) for op in self._queue],
|
||||||
|
)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2012 Virtual Cable S.L.
|
# Copyright (c) 2015-2021 Virtual Cable S.L.U.
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
# Redistribution and use in source and binary forms, with or without modification,
|
# Redistribution and use in source and binary forms, with or without modification,
|
||||||
@ -53,8 +53,12 @@ def getResources(parameters: typing.Any) -> typing.List[typing.Dict[str, typing.
|
|||||||
|
|
||||||
api = provider.api
|
api = provider.api
|
||||||
|
|
||||||
labs = [gui.choiceItem('0', _('All Labs'))] + [gui.choiceItem(l['id'], l['name']) for l in api.getLabs(ou=parameters['ou'])]
|
labs = [gui.choiceItem('0', _('All Labs'))] + [
|
||||||
images = [gui.choiceItem(z['id'], z['name']) for z in api.getImages(ou=parameters['ou'])]
|
gui.choiceItem(l['id'], l['name']) for l in api.getLabs(ou=parameters['ou'])
|
||||||
|
]
|
||||||
|
images = [
|
||||||
|
gui.choiceItem(z['id'], z['name']) for z in api.getImages(ou=parameters['ou'])
|
||||||
|
]
|
||||||
|
|
||||||
data = [
|
data = [
|
||||||
{'name': 'lab', 'values': labs},
|
{'name': 'lab', 'values': labs},
|
||||||
|
@ -56,17 +56,22 @@ def ensureConnected(fnc: typing.Callable[..., RT]) -> typing.Callable[..., RT]:
|
|||||||
def inner(*args, **kwargs) -> RT:
|
def inner(*args, **kwargs) -> RT:
|
||||||
args[0].connect()
|
args[0].connect()
|
||||||
return fnc(*args, **kwargs)
|
return fnc(*args, **kwargs)
|
||||||
|
|
||||||
return inner
|
return inner
|
||||||
|
|
||||||
|
|
||||||
# Result checker
|
# Result checker
|
||||||
def ensureResponseIsValid(response: requests.Response, errMsg: typing.Optional[str] = None) -> typing.Any:
|
def ensureResponseIsValid(
|
||||||
|
response: requests.Response, errMsg: typing.Optional[str] = None
|
||||||
|
) -> typing.Any:
|
||||||
if not response.ok:
|
if not response.ok:
|
||||||
if not errMsg:
|
if not errMsg:
|
||||||
errMsg = 'Invalid response'
|
errMsg = 'Invalid response'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
err = response.json()['message'] # Extract any key, in case of error is expected to have only one top key so this will work
|
err = response.json()[
|
||||||
|
'message'
|
||||||
|
] # Extract any key, in case of error is expected to have only one top key so this will work
|
||||||
except Exception:
|
except Exception:
|
||||||
err = response.content
|
err = response.content
|
||||||
errMsg = '{}: {}, ({})'.format(errMsg, err, response.status_code)
|
errMsg = '{}: {}, ({})'.format(errMsg, err, response.status_code)
|
||||||
@ -76,7 +81,11 @@ def ensureResponseIsValid(response: requests.Response, errMsg: typing.Optional[s
|
|||||||
try:
|
try:
|
||||||
return json.loads(response.content)
|
return json.loads(response.content)
|
||||||
except Exception:
|
except Exception:
|
||||||
raise Exception('Error communicating with OpenGnsys: {}'.format(response.content[:128].decode()))
|
raise Exception(
|
||||||
|
'Error communicating with OpenGnsys: {}'.format(
|
||||||
|
response.content[:128].decode()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class OpenGnsysClient:
|
class OpenGnsysClient:
|
||||||
@ -88,7 +97,14 @@ class OpenGnsysClient:
|
|||||||
verifyCert: bool
|
verifyCert: bool
|
||||||
cachedVersion: typing.Optional[str]
|
cachedVersion: typing.Optional[str]
|
||||||
|
|
||||||
def __init__(self, username: str, password: str, endpoint: str, cache: 'Cache', verifyCert: bool = False):
|
def __init__(
|
||||||
|
self,
|
||||||
|
username: str,
|
||||||
|
password: str,
|
||||||
|
endpoint: str,
|
||||||
|
cache: 'Cache',
|
||||||
|
verifyCert: bool = False,
|
||||||
|
):
|
||||||
self.username = username
|
self.username = username
|
||||||
self.password = password
|
self.password = password
|
||||||
self.endpoint = endpoint
|
self.endpoint = endpoint
|
||||||
@ -108,11 +124,18 @@ class OpenGnsysClient:
|
|||||||
def _ogUrl(self, path: str) -> str:
|
def _ogUrl(self, path: str) -> str:
|
||||||
return self.endpoint + '/' + path
|
return self.endpoint + '/' + path
|
||||||
|
|
||||||
def _post(self, path: str, data: typing.Any, errMsg: typing.Optional[str] = None) -> typing.Any:
|
def _post(
|
||||||
|
self, path: str, data: typing.Any, errMsg: typing.Optional[str] = None
|
||||||
|
) -> typing.Any:
|
||||||
if not FAKE:
|
if not FAKE:
|
||||||
return ensureResponseIsValid(
|
return ensureResponseIsValid(
|
||||||
requests.post(self._ogUrl(path), data=json.dumps(data), headers=self.headers, verify=self.verifyCert),
|
requests.post(
|
||||||
errMsg=errMsg
|
self._ogUrl(path),
|
||||||
|
data=json.dumps(data),
|
||||||
|
headers=self.headers,
|
||||||
|
verify=self.verifyCert,
|
||||||
|
),
|
||||||
|
errMsg=errMsg,
|
||||||
)
|
)
|
||||||
# FAKE Connection :)
|
# FAKE Connection :)
|
||||||
return fake.post(path, data, errMsg)
|
return fake.post(path, data, errMsg)
|
||||||
@ -120,8 +143,10 @@ class OpenGnsysClient:
|
|||||||
def _get(self, path: str, errMsg: typing.Optional[str] = None) -> typing.Any:
|
def _get(self, path: str, errMsg: typing.Optional[str] = None) -> typing.Any:
|
||||||
if not FAKE:
|
if not FAKE:
|
||||||
return ensureResponseIsValid(
|
return ensureResponseIsValid(
|
||||||
requests.get(self._ogUrl(path), headers=self.headers, verify=self.verifyCert),
|
requests.get(
|
||||||
errMsg=errMsg
|
self._ogUrl(path), headers=self.headers, verify=self.verifyCert
|
||||||
|
),
|
||||||
|
errMsg=errMsg,
|
||||||
)
|
)
|
||||||
# FAKE Connection :)
|
# FAKE Connection :)
|
||||||
return fake.get(path, errMsg)
|
return fake.get(path, errMsg)
|
||||||
@ -129,8 +154,10 @@ class OpenGnsysClient:
|
|||||||
def _delete(self, path: str, errMsg: typing.Optional[str] = None) -> typing.Any:
|
def _delete(self, path: str, errMsg: typing.Optional[str] = None) -> typing.Any:
|
||||||
if not FAKE:
|
if not FAKE:
|
||||||
return ensureResponseIsValid(
|
return ensureResponseIsValid(
|
||||||
requests.delete(self._ogUrl(path), headers=self.headers, verify=self.verifyCert),
|
requests.delete(
|
||||||
errMsg=errMsg
|
self._ogUrl(path), headers=self.headers, verify=self.verifyCert
|
||||||
|
),
|
||||||
|
errMsg=errMsg,
|
||||||
)
|
)
|
||||||
return fake.delete(path, errMsg)
|
return fake.delete(path, errMsg)
|
||||||
|
|
||||||
@ -145,11 +172,8 @@ class OpenGnsysClient:
|
|||||||
|
|
||||||
auth = self._post(
|
auth = self._post(
|
||||||
urls.LOGIN,
|
urls.LOGIN,
|
||||||
data={
|
data={'username': self.username, 'password': self.password},
|
||||||
'username': self.username,
|
errMsg='Loggin in',
|
||||||
'password': self.password
|
|
||||||
},
|
|
||||||
errMsg='Loggin in'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
self.auth = auth['apikey']
|
self.auth = auth['apikey']
|
||||||
@ -179,7 +203,11 @@ class OpenGnsysClient:
|
|||||||
# /ous/{ouid}/labs
|
# /ous/{ouid}/labs
|
||||||
# Take into accout that we must exclude the ones with "inremotepc" set to false.
|
# Take into accout that we must exclude the ones with "inremotepc" set to false.
|
||||||
errMsg = 'Getting list of labs from ou {}'.format(ou)
|
errMsg = 'Getting list of labs from ou {}'.format(ou)
|
||||||
return [{'id': l['id'], 'name': l['name']} for l in self._get(urls.LABS.format(ou=ou), errMsg=errMsg) if l.get('inremotepc', False) is True]
|
return [
|
||||||
|
{'id': l['id'], 'name': l['name']}
|
||||||
|
for l in self._get(urls.LABS.format(ou=ou), errMsg=errMsg)
|
||||||
|
if l.get('inremotepc', False) is True
|
||||||
|
]
|
||||||
|
|
||||||
@ensureConnected
|
@ensureConnected
|
||||||
def getImages(self, ou: str) -> typing.List[typing.MutableMapping[str, str]]:
|
def getImages(self, ou: str) -> typing.List[typing.MutableMapping[str, str]]:
|
||||||
@ -187,20 +215,23 @@ class OpenGnsysClient:
|
|||||||
# /ous/{ouid}/images
|
# /ous/{ouid}/images
|
||||||
# Take into accout that we must exclude the ones with "inremotepc" set to false.
|
# Take into accout that we must exclude the ones with "inremotepc" set to false.
|
||||||
errMsg = 'Getting list of images from ou {}'.format(ou)
|
errMsg = 'Getting list of images from ou {}'.format(ou)
|
||||||
return [{'id': l['id'], 'name': l['name']} for l in self._get(urls.IMAGES.format(ou=ou), errMsg=errMsg) if l.get('inremotepc', False) is True]
|
return [
|
||||||
|
{'id': l['id'], 'name': l['name']}
|
||||||
|
for l in self._get(urls.IMAGES.format(ou=ou), errMsg=errMsg)
|
||||||
|
if l.get('inremotepc', False) is True
|
||||||
|
]
|
||||||
|
|
||||||
@ensureConnected
|
@ensureConnected
|
||||||
def reserve(self, ou: str, image: str, lab: int = 0, maxtime: int = 24) -> typing.MutableMapping[str, typing.Union[str, int]]:
|
def reserve(
|
||||||
|
self, ou: str, image: str, lab: int = 0, maxtime: int = 24
|
||||||
|
) -> typing.MutableMapping[str, typing.Union[str, int]]:
|
||||||
# This method is inteded to "get" a machine from OpenGnsys
|
# This method is inteded to "get" a machine from OpenGnsys
|
||||||
# The method used is POST
|
# The method used is POST
|
||||||
# invokes /ous/{ouid}}/images/{imageid}/reserve
|
# invokes /ous/{ouid}}/images/{imageid}/reserve
|
||||||
# also remember to store "labid"
|
# also remember to store "labid"
|
||||||
# Labid can be "0" that means "all laboratories"
|
# Labid can be "0" that means "all laboratories"
|
||||||
errMsg = 'Reserving image {} in ou {}'.format(image, ou)
|
errMsg = 'Reserving image {} in ou {}'.format(image, ou)
|
||||||
data = {
|
data = {'labid': lab, 'maxtime': maxtime}
|
||||||
'labid': lab,
|
|
||||||
'maxtime': maxtime
|
|
||||||
}
|
|
||||||
res = self._post(urls.RESERVE.format(ou=ou, image=image), data, errMsg=errMsg)
|
res = self._post(urls.RESERVE.format(ou=ou, image=image), data, errMsg=errMsg)
|
||||||
return {
|
return {
|
||||||
'ou': ou,
|
'ou': ou,
|
||||||
@ -210,7 +241,7 @@ class OpenGnsysClient:
|
|||||||
'id': '.'.join((str(ou), str(res['lab']['id']), str(res['id']))),
|
'id': '.'.join((str(ou), str(res['lab']['id']), str(res['id']))),
|
||||||
'name': res['name'],
|
'name': res['name'],
|
||||||
'ip': res['ip'],
|
'ip': res['ip'],
|
||||||
'mac': ':'.join(re.findall('..', res['mac']))
|
'mac': ':'.join(re.findall('..', res['mac'])),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ensureConnected
|
@ensureConnected
|
||||||
@ -219,29 +250,48 @@ class OpenGnsysClient:
|
|||||||
# Invoked every time we need to release a reservation (i mean, if a reservation is done, this will be called with the obtained id from that reservation)
|
# Invoked every time we need to release a reservation (i mean, if a reservation is done, this will be called with the obtained id from that reservation)
|
||||||
ou, lab, client = machineId.split('.')
|
ou, lab, client = machineId.split('.')
|
||||||
errMsg = 'Unreserving client {} in lab {} in ou {}'.format(client, lab, ou)
|
errMsg = 'Unreserving client {} in lab {} in ou {}'.format(client, lab, ou)
|
||||||
return self._delete(urls.UNRESERVE.format(ou=ou, lab=lab, client=client), errMsg=errMsg)
|
return self._delete(
|
||||||
|
urls.UNRESERVE.format(ou=ou, lab=lab, client=client), errMsg=errMsg
|
||||||
|
)
|
||||||
|
|
||||||
|
def powerOn(self, machineId, image):
|
||||||
|
# This method ask to poweron a machine to openGnsys
|
||||||
|
ou, lab, client = machineId.split('.')
|
||||||
|
errMsg = 'Powering on client {} in lab {} in ou {}'.format(client, lab, ou)
|
||||||
|
try:
|
||||||
|
data = {
|
||||||
|
'image': image,
|
||||||
|
}
|
||||||
|
return self._post(
|
||||||
|
urls.START.format(ou=ou, lab=lab, client=client), data, errMsg=errMsg
|
||||||
|
)
|
||||||
|
except Exception: # For now, if this fails, ignore it to keep backwards compat
|
||||||
|
return 'OK'
|
||||||
|
|
||||||
@ensureConnected
|
@ensureConnected
|
||||||
def notifyURLs(self, machineId: str, loginURL: str, logoutURL: str) -> typing.Any:
|
def notifyURLs(
|
||||||
|
self, machineId: str, loginURL: str, logoutURL: str, releaseURL: str
|
||||||
|
) -> typing.Any:
|
||||||
ou, lab, client = machineId.split('.')
|
ou, lab, client = machineId.split('.')
|
||||||
errMsg = 'Notifying login/logout urls'
|
errMsg = 'Notifying login/logout urls'
|
||||||
data = {
|
data = {'urlLogin': loginURL, 'urlLogout': logoutURL, 'urlRelease': releaseURL}
|
||||||
'urlLogin': loginURL,
|
|
||||||
'urlLogout': logoutURL
|
|
||||||
}
|
|
||||||
|
|
||||||
return self._post(urls.EVENTS.format(ou=ou, lab=lab, client=client), data, errMsg=errMsg)
|
return self._post(
|
||||||
|
urls.EVENTS.format(ou=ou, lab=lab, client=client), data, errMsg=errMsg
|
||||||
|
)
|
||||||
|
|
||||||
@ensureConnected
|
@ensureConnected
|
||||||
def notifyDeadline(self, machineId: str, deadLine: typing.Optional[int]) -> typing.Any:
|
def notifyDeadline(
|
||||||
|
self, machineId: str, deadLine: typing.Optional[int]
|
||||||
|
) -> typing.Any:
|
||||||
ou, lab, client = machineId.split('.')
|
ou, lab, client = machineId.split('.')
|
||||||
deadLine = deadLine or 0
|
deadLine = deadLine or 0
|
||||||
errMsg = 'Notifying deadline'
|
errMsg = 'Notifying deadline'
|
||||||
data = {
|
data = {'deadLine': deadLine}
|
||||||
'deadLine': deadLine
|
|
||||||
}
|
|
||||||
|
|
||||||
return self._post(urls.SESSIONS.format(ou=ou, lab=lab, client=client), data, errMsg=errMsg)
|
return self._post(
|
||||||
|
urls.SESSIONS.format(ou=ou, lab=lab, client=client), data, errMsg=errMsg
|
||||||
|
)
|
||||||
|
|
||||||
@ensureConnected
|
@ensureConnected
|
||||||
def status(self, id_: str) -> typing.Any:
|
def status(self, id_: str) -> typing.Any:
|
||||||
|
@ -40,20 +40,13 @@ from . import urls
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
AUTH = {
|
AUTH = {"userid": 1001, "apikey": "fakeAPIKeyJustForDeveloping"}
|
||||||
"userid": 1001,
|
|
||||||
"apikey": "fakeAPIKeyJustForDeveloping"
|
|
||||||
}
|
|
||||||
|
|
||||||
INFO = {
|
INFO = {
|
||||||
"project": "OpenGnsys",
|
"project": "OpenGnsys",
|
||||||
"version": "1.1.0pre",
|
"version": "1.1.0pre",
|
||||||
"release": "r5299",
|
"release": "r5299",
|
||||||
"services": [
|
"services": ["server", "repository", "tracker"],
|
||||||
"server",
|
|
||||||
"repository",
|
|
||||||
"tracker"
|
|
||||||
],
|
|
||||||
"oglive": [
|
"oglive": [
|
||||||
{
|
{
|
||||||
"distribution": "xenial",
|
"distribution": "xenial",
|
||||||
@ -61,7 +54,7 @@ INFO = {
|
|||||||
"architecture": "amd64",
|
"architecture": "amd64",
|
||||||
"revision": "r5225",
|
"revision": "r5225",
|
||||||
"directory": "ogLive-xenial-4.8.0-amd64-r5225",
|
"directory": "ogLive-xenial-4.8.0-amd64-r5225",
|
||||||
"iso": "ogLive-xenial-4.8.0-39-generic-amd64-r5225.iso"
|
"iso": "ogLive-xenial-4.8.0-39-generic-amd64-r5225.iso",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"iso": "ogLive-precise-3.2.0-23-generic-r4820.iso",
|
"iso": "ogLive-precise-3.2.0-23-generic-r4820.iso",
|
||||||
@ -69,19 +62,14 @@ INFO = {
|
|||||||
"revision": "r4820",
|
"revision": "r4820",
|
||||||
"architecture": "i386",
|
"architecture": "i386",
|
||||||
"kernel": "3.2.0-23-generic",
|
"kernel": "3.2.0-23-generic",
|
||||||
"distribution": "precise"
|
"distribution": "precise",
|
||||||
}]
|
},
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
OUS = [
|
OUS = [
|
||||||
{
|
{"id": "1", "name": "Unidad Organizativa (Default)"},
|
||||||
"id": "1",
|
{"id": "2", "name": "Unidad Organizatva VACIA"},
|
||||||
"name": "Unidad Organizativa (Default)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "2",
|
|
||||||
"name": "Unidad Organizatva VACIA"
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
|
|
||||||
LABS = [
|
LABS = [
|
||||||
@ -89,58 +77,32 @@ LABS = [
|
|||||||
"id": "1",
|
"id": "1",
|
||||||
"name": "Sala de control",
|
"name": "Sala de control",
|
||||||
"inremotepc": True,
|
"inremotepc": True,
|
||||||
"group": {
|
"group": {"id": "0"},
|
||||||
"id": "0"
|
"ou": {"id": "1"},
|
||||||
},
|
|
||||||
"ou": {
|
|
||||||
"id": "1"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "2",
|
"id": "2",
|
||||||
"name": "Sala de computación cuántica",
|
"name": "Sala de computación cuántica",
|
||||||
"inremotepc": True,
|
"inremotepc": True,
|
||||||
"group": {
|
"group": {"id": "0"},
|
||||||
"id": "0"
|
"ou": {"id": "1"},
|
||||||
},
|
},
|
||||||
"ou": {
|
|
||||||
"id": "1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
|
||||||
IMAGES = [
|
IMAGES = [
|
||||||
{
|
{"id": "1", "name": "Basica1604", "inremotepc": True, "ou": {"id": "1"}},
|
||||||
"id": "1",
|
{"id": "2", "name": "Ubuntu16", "inremotepc": True, "ou": {"id": "1"}},
|
||||||
"name": "Basica1604",
|
|
||||||
"inremotepc": True,
|
|
||||||
"ou": {
|
|
||||||
"id": "1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "2",
|
|
||||||
"name": "Ubuntu16",
|
|
||||||
"inremotepc": True,
|
|
||||||
"ou": {
|
|
||||||
"id": "1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "3",
|
"id": "3",
|
||||||
"name": "Ubuntu64 Not in Remote",
|
"name": "Ubuntu64 Not in Remote",
|
||||||
"inremotepc": False,
|
"inremotepc": False,
|
||||||
"ou": {
|
"ou": {"id": "1"},
|
||||||
"id": "1"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "4",
|
"id": "4",
|
||||||
"name": "Ubuntu96 Not In Remote",
|
"name": "Ubuntu96 Not In Remote",
|
||||||
"inremotepc": False,
|
"inremotepc": False,
|
||||||
"ou": {
|
"ou": {"id": "1"},
|
||||||
"id": "1"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -149,58 +111,50 @@ RESERVE: typing.Dict[str, typing.Any] = {
|
|||||||
"name": "pcpruebas",
|
"name": "pcpruebas",
|
||||||
"mac": "4061860521FE",
|
"mac": "4061860521FE",
|
||||||
"ip": "10.1.14.31",
|
"ip": "10.1.14.31",
|
||||||
"lab": {
|
"lab": {"id": 1},
|
||||||
"id": 1
|
"ou": {"id": 1},
|
||||||
},
|
|
||||||
"ou": {
|
|
||||||
"id": 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UNRESERVE = ''
|
UNRESERVE = ''
|
||||||
|
|
||||||
STATUS_OFF = {
|
STATUS_OFF = {"id": 4, "ip": "10.1.14.31", "status": "off", "loggedin": False}
|
||||||
"id": 4,
|
|
||||||
"ip": "10.1.14.31",
|
|
||||||
"status": "off",
|
|
||||||
"loggedin": False
|
|
||||||
}
|
|
||||||
|
|
||||||
# A couple of status for testing
|
# A couple of status for testing
|
||||||
STATUS_READY_LINUX = {
|
STATUS_READY_LINUX = {"id": 4, "ip": "10.1.14.31", "status": "linux", "loggedin": False}
|
||||||
"id": 4,
|
|
||||||
"ip": "10.1.14.31",
|
|
||||||
"status": "linux",
|
|
||||||
"loggedin": False
|
|
||||||
}
|
|
||||||
|
|
||||||
STATUS_READY_WINDOWS = {
|
STATUS_READY_WINDOWS = {
|
||||||
"id": 4,
|
"id": 4,
|
||||||
"ip": "10.1.14.31",
|
"ip": "10.1.14.31",
|
||||||
"status": "windows",
|
"status": "windows",
|
||||||
"loggedin": False
|
"loggedin": False,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# FAKE post
|
# FAKE post
|
||||||
def post(path: str, data: typing.Any, errMsg: typing.Optional[str] = None) -> typing.Any:
|
def post(
|
||||||
|
path: str, data: typing.Any, errMsg: typing.Optional[str] = None
|
||||||
|
) -> typing.Any:
|
||||||
logger.info('FAKE POST request to %s with %s data. (%s)', path, data, errMsg)
|
logger.info('FAKE POST request to %s with %s data. (%s)', path, data, errMsg)
|
||||||
if path == urls.LOGIN:
|
if path == urls.LOGIN:
|
||||||
return AUTH
|
return AUTH
|
||||||
|
|
||||||
if path == urls.RESERVE.format(ou=1, image=1) or path == urls.RESERVE.format(ou=1, image=2):
|
if path == urls.RESERVE.format(ou=1, image=1) or path == urls.RESERVE.format(
|
||||||
|
ou=1, image=2
|
||||||
|
):
|
||||||
res = copy.deepcopy(RESERVE)
|
res = copy.deepcopy(RESERVE)
|
||||||
res['name'] += str(random.randint(5000, 100000))
|
res['name'] += str(random.randint(5000, 100000))
|
||||||
res['mac'] = ''.join(random.choice('0123456789ABCDEF') for _ in range(12))
|
res['mac'] = ''.join(random.choice('0123456789ABCDEF') for _ in range(12))
|
||||||
res['ip'] = '1.2.3.4'
|
res['ip'] = '1.2.3.4'
|
||||||
return res
|
return res
|
||||||
|
|
||||||
# raise Exception('Unknown FAKE URL on POST: {}'.format(path))
|
# Ignore rest of responses
|
||||||
return ''
|
return {'status': 'ok'}
|
||||||
|
|
||||||
|
|
||||||
# FAKE get
|
# FAKE get
|
||||||
def get(path, errMsg: typing.Optional[str]) -> typing.Any: # pylint: disable=too-many-return-statements
|
def get(
|
||||||
|
path, errMsg: typing.Optional[str]
|
||||||
|
) -> typing.Any: # pylint: disable=too-many-return-statements
|
||||||
logger.info('FAKE GET request to %s. (%s)', path, errMsg)
|
logger.info('FAKE GET request to %s. (%s)', path, errMsg)
|
||||||
if path == urls.INFO:
|
if path == urls.INFO:
|
||||||
return INFO
|
return INFO
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2017-2019 Virtual Cable S.L.
|
# Copyright (c) 2017-2021 Virtual Cable S.L.U.
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
# Redistribution and use in source and binary forms, with or without modification,
|
# Redistribution and use in source and binary forms, with or without modification,
|
||||||
@ -43,3 +42,5 @@ UNRESERVE = '/ous/{ou}/labs/{lab}/clients/{client}/unreserve'
|
|||||||
STATUS = '/ous/{ou}/labs/{lab}/clients/{client}/status'
|
STATUS = '/ous/{ou}/labs/{lab}/clients/{client}/status'
|
||||||
EVENTS = '/ous/{ou}/labs/{lab}/clients/{client}/events'
|
EVENTS = '/ous/{ou}/labs/{lab}/clients/{client}/events'
|
||||||
SESSIONS = '/ous/{ou}/labs/{lab}/clients/{client}/session'
|
SESSIONS = '/ous/{ou}/labs/{lab}/clients/{client}/session'
|
||||||
|
# TODO: fix this
|
||||||
|
START = '/ous/{ou}/labs/{lab}/clients/{client}/init'
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2012-2019 Virtual Cable S.L.
|
# Copyright (c) 2012-2021 Virtual Cable S.L.U.
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
# Redistribution and use in source and binary forms, with or without modification,
|
# Redistribution and use in source and binary forms, with or without modification,
|
||||||
@ -51,6 +50,7 @@ if typing.TYPE_CHECKING:
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class OGProvider(ServiceProvider):
|
class OGProvider(ServiceProvider):
|
||||||
"""
|
"""
|
||||||
This class represents the sample services provider
|
This class represents the sample services provider
|
||||||
@ -68,6 +68,7 @@ class OGProvider(ServiceProvider):
|
|||||||
we MUST register it at package __init__.
|
we MUST register it at package __init__.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# : What kind of services we offer, this are classes inherited from Service
|
# : What kind of services we offer, this are classes inherited from Service
|
||||||
offers = [OGService]
|
offers = [OGService]
|
||||||
# : Name to show the administrator. This string will be translated BEFORE
|
# : Name to show the administrator. This string will be translated BEFORE
|
||||||
@ -92,17 +93,81 @@ class OGProvider(ServiceProvider):
|
|||||||
# but used for sample purposes
|
# but used for sample purposes
|
||||||
# If we don't indicate an order, the output order of fields will be
|
# If we don't indicate an order, the output order of fields will be
|
||||||
# "random"
|
# "random"
|
||||||
host = gui.TextField(length=64, label=_('Host'), order=1, tooltip=_('OpenGnsys Host'), required=True)
|
host = gui.TextField(
|
||||||
port = gui.NumericField(length=5, label=_('Port'), defvalue='443', order=2, tooltip=_('OpenGnsys Port (default is 443, and only ssl connection is allowed)'), required=True)
|
length=64, label=_('Host'), order=1, tooltip=_('OpenGnsys Host'), required=True
|
||||||
checkCert = gui.CheckBoxField(label=_('Check Cert.'), order=3, tooltip=_('If checked, ssl certificate of OpenGnsys server must be valid (not self signed)'))
|
)
|
||||||
username = gui.TextField(length=32, label=_('Username'), order=4, tooltip=_('User with valid privileges on OpenGnsys'), required=True)
|
port = gui.NumericField(
|
||||||
password = gui.PasswordField(lenth=32, label=_('Password'), order=5, tooltip=_('Password of the user of OpenGnsys'), required=True)
|
length=5,
|
||||||
udsServerAccessUrl = gui.TextField(length=32, label=_('UDS Server URL'), order=6, tooltip=_('URL used by OpenGnsys to access UDS. If empty, UDS will guess it.'), required=False, tab=gui.PARAMETERS_TAB)
|
label=_('Port'),
|
||||||
|
defvalue='443',
|
||||||
|
order=2,
|
||||||
|
tooltip=_(
|
||||||
|
'OpenGnsys Port (default is 443, and only ssl connection is allowed)'
|
||||||
|
),
|
||||||
|
required=True,
|
||||||
|
)
|
||||||
|
checkCert = gui.CheckBoxField(
|
||||||
|
label=_('Check Cert.'),
|
||||||
|
order=3,
|
||||||
|
tooltip=_(
|
||||||
|
'If checked, ssl certificate of OpenGnsys server must be valid (not self signed)'
|
||||||
|
),
|
||||||
|
)
|
||||||
|
username = gui.TextField(
|
||||||
|
length=32,
|
||||||
|
label=_('Username'),
|
||||||
|
order=4,
|
||||||
|
tooltip=_('User with valid privileges on OpenGnsys'),
|
||||||
|
required=True,
|
||||||
|
)
|
||||||
|
password = gui.PasswordField(
|
||||||
|
lenth=32,
|
||||||
|
label=_('Password'),
|
||||||
|
order=5,
|
||||||
|
tooltip=_('Password of the user of OpenGnsys'),
|
||||||
|
required=True,
|
||||||
|
)
|
||||||
|
udsServerAccessUrl = gui.TextField(
|
||||||
|
length=32,
|
||||||
|
label=_('UDS Server URL'),
|
||||||
|
order=6,
|
||||||
|
tooltip=_('URL used by OpenGnsys to access UDS. If empty, UDS will guess it.'),
|
||||||
|
required=False,
|
||||||
|
tab=gui.PARAMETERS_TAB,
|
||||||
|
)
|
||||||
|
|
||||||
maxPreparingServices = gui.NumericField(length=3, label=_('Creation concurrency'), defvalue='10', minValue=1, maxValue=65536, order=50, tooltip=_('Maximum number of concurrently creating VMs'), required=True, tab=gui.ADVANCED_TAB)
|
maxPreparingServices = gui.NumericField(
|
||||||
maxRemovingServices = gui.NumericField(length=3, label=_('Removal concurrency'), defvalue='8', minValue=1, maxValue=65536, order=51, tooltip=_('Maximum number of concurrently removing VMs'), required=True, tab=gui.ADVANCED_TAB)
|
length=3,
|
||||||
|
label=_('Creation concurrency'),
|
||||||
|
defvalue='10',
|
||||||
|
minValue=1,
|
||||||
|
maxValue=65536,
|
||||||
|
order=50,
|
||||||
|
tooltip=_('Maximum number of concurrently creating VMs'),
|
||||||
|
required=True,
|
||||||
|
tab=gui.ADVANCED_TAB,
|
||||||
|
)
|
||||||
|
maxRemovingServices = gui.NumericField(
|
||||||
|
length=3,
|
||||||
|
label=_('Removal concurrency'),
|
||||||
|
defvalue='8',
|
||||||
|
minValue=1,
|
||||||
|
maxValue=65536,
|
||||||
|
order=51,
|
||||||
|
tooltip=_('Maximum number of concurrently removing VMs'),
|
||||||
|
required=True,
|
||||||
|
tab=gui.ADVANCED_TAB,
|
||||||
|
)
|
||||||
|
|
||||||
timeout = gui.NumericField(length=3, label=_('Timeout'), defvalue='10', order=90, tooltip=_('Timeout in seconds of connection to OpenGnsys'), required=True, tab=gui.ADVANCED_TAB)
|
timeout = gui.NumericField(
|
||||||
|
length=3,
|
||||||
|
label=_('Timeout'),
|
||||||
|
defvalue='10',
|
||||||
|
order=90,
|
||||||
|
tooltip=_('Timeout in seconds of connection to OpenGnsys'),
|
||||||
|
required=True,
|
||||||
|
tab=gui.ADVANCED_TAB,
|
||||||
|
)
|
||||||
|
|
||||||
# Own variables
|
# Own variables
|
||||||
_api: typing.Optional[og.OpenGnsysClient] = None
|
_api: typing.Optional[og.OpenGnsysClient] = None
|
||||||
@ -137,7 +202,13 @@ class OGProvider(ServiceProvider):
|
|||||||
@property
|
@property
|
||||||
def api(self) -> og.OpenGnsysClient:
|
def api(self) -> og.OpenGnsysClient:
|
||||||
if not self._api:
|
if not self._api:
|
||||||
self._api = og.OpenGnsysClient(self.username.value, self.password.value, self.endpoint, self.cache, self.checkCert.isTrue())
|
self._api = og.OpenGnsysClient(
|
||||||
|
self.username.value,
|
||||||
|
self.password.value,
|
||||||
|
self.endpoint,
|
||||||
|
self.cache,
|
||||||
|
self.checkCert.isTrue(),
|
||||||
|
)
|
||||||
|
|
||||||
logger.debug('Api: %s', self._api)
|
logger.debug('Api: %s', self._api)
|
||||||
return self._api
|
return self._api
|
||||||
@ -155,7 +226,12 @@ class OGProvider(ServiceProvider):
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
if self.api.version[0:5] < '1.1.0':
|
if self.api.version[0:5] < '1.1.0':
|
||||||
return [False, 'OpenGnsys version is not supported (required version 1.1.0 or newer and found {})'.format(self.api.version)]
|
return [
|
||||||
|
False,
|
||||||
|
'OpenGnsys version is not supported (required version 1.1.0 or newer and found {})'.format(
|
||||||
|
self.api.version
|
||||||
|
),
|
||||||
|
]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception('Error')
|
logger.exception('Error')
|
||||||
return [False, '{}'.format(e)]
|
return [False, '{}'.format(e)]
|
||||||
@ -184,16 +260,25 @@ class OGProvider(ServiceProvider):
|
|||||||
def getUDSServerAccessUrl(self) -> str:
|
def getUDSServerAccessUrl(self) -> str:
|
||||||
return self.udsServerAccessUrl.value
|
return self.udsServerAccessUrl.value
|
||||||
|
|
||||||
def reserve(self, ou: str, image: str, lab: int = 0, maxtime: int = 0) -> typing.Any:
|
def reserve(
|
||||||
|
self, ou: str, image: str, lab: int = 0, maxtime: int = 0
|
||||||
|
) -> typing.Any:
|
||||||
return self.api.reserve(ou, image, lab, maxtime)
|
return self.api.reserve(ou, image, lab, maxtime)
|
||||||
|
|
||||||
def unreserve(self, machineId: str) -> typing.Any:
|
def unreserve(self, machineId: str) -> typing.Any:
|
||||||
return self.api.unreserve(machineId)
|
return self.api.unreserve(machineId)
|
||||||
|
|
||||||
def notifyEvents(self, machineId: str, loginURL: str, logoutURL: str) -> typing.Any:
|
def powerOn(self, machineId: str, image: str) -> typing.Any:
|
||||||
return self.api.notifyURLs(machineId, loginURL, logoutURL)
|
return self.api.powerOn(machineId, image)
|
||||||
|
|
||||||
def notifyDeadline(self, machineId: str, deadLine: typing.Optional[int]) -> typing.Any:
|
def notifyEvents(
|
||||||
|
self, machineId: str, loginURL: str, logoutURL: str, releaseURL: str
|
||||||
|
) -> typing.Any:
|
||||||
|
return self.api.notifyURLs(machineId, loginURL, logoutURL, releaseURL)
|
||||||
|
|
||||||
|
def notifyDeadline(
|
||||||
|
self, machineId: str, deadLine: typing.Optional[int]
|
||||||
|
) -> typing.Any:
|
||||||
return self.api.notifyDeadline(machineId, deadLine)
|
return self.api.notifyDeadline(machineId, deadLine)
|
||||||
|
|
||||||
def status(self, machineId: str) -> typing.Any:
|
def status(self, machineId: str) -> typing.Any:
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2017-2019 Virtual Cable S.L.
|
# Copyright (c) 2017-2021 Virtual Cable S.L.U.
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
# Redistribution and use in source and binary forms, with or without modification,
|
# Redistribution and use in source and binary forms, with or without modification,
|
||||||
@ -48,9 +47,12 @@ class OGPublication(Publication):
|
|||||||
"""
|
"""
|
||||||
This class provides the publication of a oVirtLinkedService
|
This class provides the publication of a oVirtLinkedService
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_name: str = ''
|
_name: str = ''
|
||||||
|
|
||||||
suggestedTime = 5 # : Suggested recheck time if publication is unfinished in seconds
|
suggestedTime = (
|
||||||
|
5 # : Suggested recheck time if publication is unfinished in seconds
|
||||||
|
)
|
||||||
|
|
||||||
def service(self) -> 'OGService':
|
def service(self) -> 'OGService':
|
||||||
return typing.cast('OGService', super().service())
|
return typing.cast('OGService', super().service())
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2017-2019 Virtual Cable S.L.
|
# Copyright (c) 2017-2021 Virtual Cable S.L.U.
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
# Redistribution and use in source and binary forms, with or without modification,
|
# Redistribution and use in source and binary forms, with or without modification,
|
||||||
@ -55,6 +54,7 @@ class OGService(Service):
|
|||||||
"""
|
"""
|
||||||
OpenGnsys Service
|
OpenGnsys Service
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# : Name to show the administrator. This string will be translated BEFORE
|
# : Name to show the administrator. This string will be translated BEFORE
|
||||||
# : sending it to administration interface, so don't forget to
|
# : sending it to administration interface, so don't forget to
|
||||||
# : mark it as _ (using ugettext_noop)
|
# : mark it as _ (using ugettext_noop)
|
||||||
@ -102,20 +102,17 @@ class OGService(Service):
|
|||||||
label=_("OU"),
|
label=_("OU"),
|
||||||
order=100,
|
order=100,
|
||||||
fills={
|
fills={
|
||||||
'callbackName' : 'osFillData',
|
'callbackName': 'osFillData',
|
||||||
'function' : helpers.getResources,
|
'function': helpers.getResources,
|
||||||
'parameters' : ['ov', 'ev', 'ou']
|
'parameters': ['ov', 'ev', 'ou'],
|
||||||
},
|
},
|
||||||
tooltip=_('Organizational Unit'),
|
tooltip=_('Organizational Unit'),
|
||||||
required=True
|
required=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Lab is not required, but maybe used as filter
|
# Lab is not required, but maybe used as filter
|
||||||
lab = gui.ChoiceField(
|
lab = gui.ChoiceField(
|
||||||
label=_("lab"),
|
label=_("lab"), order=101, tooltip=_('Laboratory'), required=False
|
||||||
order=101,
|
|
||||||
tooltip=_('Laboratory'),
|
|
||||||
required=False
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Required, this is the base image
|
# Required, this is the base image
|
||||||
@ -123,22 +120,33 @@ class OGService(Service):
|
|||||||
label=_("OS Image"),
|
label=_("OS Image"),
|
||||||
order=102,
|
order=102,
|
||||||
tooltip=_('OpenGnsys Operating System Image'),
|
tooltip=_('OpenGnsys Operating System Image'),
|
||||||
required=True
|
required=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
maxReservationTime = gui.NumericField(
|
maxReservationTime = gui.NumericField(
|
||||||
length=3,
|
length=3,
|
||||||
label=_("Max. reservation time"),
|
label=_("Max. reservation time"),
|
||||||
order=110,
|
order=110,
|
||||||
tooltip=_('Security parameter for OpenGnsys to keep reservations at most this hours. Handle with care!'),
|
tooltip=_(
|
||||||
|
'Security parameter for OpenGnsys to keep reservations at most this hours. Handle with care!'
|
||||||
|
),
|
||||||
defvalue='2400', # 1 hundred days
|
defvalue='2400', # 1 hundred days
|
||||||
minValue='24',
|
minValue='24',
|
||||||
tab=_('Advanced'),
|
tab=_('Advanced'),
|
||||||
required=False
|
required=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
startIfUnavailable = gui.CheckBoxField(
|
||||||
|
label=_('Start if unavailable'),
|
||||||
|
defvalue=gui.TRUE,
|
||||||
|
order=111,
|
||||||
|
tooltip=_('If active, machines that are not available on user connect (on some OS) will try to power on through OpenGnsys.'),
|
||||||
)
|
)
|
||||||
|
|
||||||
ov = gui.HiddenField(value=None)
|
ov = gui.HiddenField(value=None)
|
||||||
ev = gui.HiddenField(value=None) # We need to keep the env so we can instantiate the Provider
|
ev = gui.HiddenField(
|
||||||
|
value=None
|
||||||
|
) # We need to keep the env so we can instantiate the Provider
|
||||||
|
|
||||||
def initGui(self) -> None:
|
def initGui(self) -> None:
|
||||||
"""
|
"""
|
||||||
@ -157,27 +165,49 @@ class OGService(Service):
|
|||||||
return self.parent().status(machineId)
|
return self.parent().status(machineId)
|
||||||
|
|
||||||
def reserve(self) -> typing.Any:
|
def reserve(self) -> typing.Any:
|
||||||
return self.parent().reserve(self.ou.value, self.image.value, self.lab.value, self.maxReservationTime.num())
|
return self.parent().reserve(
|
||||||
|
self.ou.value,
|
||||||
|
self.image.value,
|
||||||
|
self.lab.value,
|
||||||
|
self.maxReservationTime.num(),
|
||||||
|
)
|
||||||
|
|
||||||
def unreserve(self, machineId: str) -> typing.Any:
|
def unreserve(self, machineId: str) -> typing.Any:
|
||||||
return self.parent().unreserve(machineId)
|
return self.parent().unreserve(machineId)
|
||||||
|
|
||||||
def notifyEvents(self, machineId: str, serviceUUID: str) -> typing.Any:
|
def notifyEvents(self, machineId: str, token: str, uuid: str) -> typing.Any:
|
||||||
return self.parent().notifyEvents(machineId, self.getLoginNotifyURL(serviceUUID), self.getLogoutNotifyURL(serviceUUID))
|
return self.parent().notifyEvents(
|
||||||
|
machineId,
|
||||||
|
self.getLoginNotifyURL(uuid, token),
|
||||||
|
self.getLogoutNotifyURL(uuid, token),
|
||||||
|
self.getReleaseURL(uuid, token)
|
||||||
|
)
|
||||||
|
|
||||||
def notifyDeadline(self, machineId: str, deadLine: typing.Optional[int]) -> typing.Any:
|
def notifyDeadline(
|
||||||
|
self, machineId: str, deadLine: typing.Optional[int]
|
||||||
|
) -> typing.Any:
|
||||||
return self.parent().notifyDeadline(machineId, deadLine)
|
return self.parent().notifyDeadline(machineId, deadLine)
|
||||||
|
|
||||||
def _notifyURL(self, uuid: str, message: str) -> str:
|
def powerOn(self, machineId: str) -> typing.Any:
|
||||||
|
return self.parent().powerOn(machineId, self.image.value)
|
||||||
|
|
||||||
|
def _notifyURL(self, uuid: str, token:str, message: str) -> str:
|
||||||
# The URL is "GET messages URL".
|
# The URL is "GET messages URL".
|
||||||
return '{accessURL}rest/actor/PostThoughGet/{uuid}/{message}'.format(
|
return '{accessURL}uds/ognotify/{message}/{token}/{uuid}'.format(
|
||||||
accessURL=self.parent().getUDSServerAccessUrl(),
|
accessURL=self.parent().getUDSServerAccessUrl(),
|
||||||
uuid=uuid,
|
uuid=uuid,
|
||||||
|
token=token,
|
||||||
message=message
|
message=message
|
||||||
)
|
)
|
||||||
|
|
||||||
def getLoginNotifyURL(self, serviceUUID: str) -> str:
|
def getLoginNotifyURL(self, uuid: str, token: str) -> str:
|
||||||
return self._notifyURL(serviceUUID, 'login')
|
return self._notifyURL(uuid, token, 'login')
|
||||||
|
|
||||||
def getLogoutNotifyURL(self, serviceUUID: str) -> str:
|
def getLogoutNotifyURL(self, uuid: str, token: str) -> str:
|
||||||
return self._notifyURL(serviceUUID, 'logout')
|
return self._notifyURL(uuid, token, 'logout')
|
||||||
|
|
||||||
|
def getReleaseURL(self, uuid: str, token: str) -> str:
|
||||||
|
return self._notifyURL(uuid, token, 'release')
|
||||||
|
|
||||||
|
def isRemovableIfUnavailable(self):
|
||||||
|
return self.startIfUnavailable.isTrue()
|
||||||
|
@ -30,7 +30,7 @@ MIT
|
|||||||
MIT
|
MIT
|
||||||
The MIT License
|
The MIT License
|
||||||
|
|
||||||
Copyright (c) 2020 Google LLC.
|
Copyright (c) 2021 Google LLC.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
@ -64,7 +64,7 @@ MIT
|
|||||||
MIT
|
MIT
|
||||||
The MIT License
|
The MIT License
|
||||||
|
|
||||||
Copyright (c) 2020 Google LLC.
|
Copyright (c) 2021 Google LLC.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -30,7 +30,7 @@ MIT
|
|||||||
MIT
|
MIT
|
||||||
The MIT License
|
The MIT License
|
||||||
|
|
||||||
Copyright (c) 2020 Google LLC.
|
Copyright (c) 2021 Google LLC.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
@ -64,7 +64,7 @@ MIT
|
|||||||
MIT
|
MIT
|
||||||
The MIT License
|
The MIT License
|
||||||
|
|
||||||
Copyright (c) 2020 Google LLC.
|
Copyright (c) 2021 Google LLC.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -25,7 +25,7 @@ gettext("Error launching service");
|
|||||||
gettext("Please wait until the service is launched.");
|
gettext("Please wait until the service is launched.");
|
||||||
gettext("Your connection is being prepared. It will open on a new window when ready.");
|
gettext("Your connection is being prepared. It will open on a new window when ready.");
|
||||||
gettext("The service is now being prepared. (It is at #).'.replace('#', '' + data.running + '%");
|
gettext("The service is now being prepared. (It is at #).'.replace('#', '' + data.running + '%");
|
||||||
gettext("Please, tray again in a few moments.");
|
gettext("Please, try again in a few moments.");
|
||||||
gettext("Error launching service");
|
gettext("Error launching service");
|
||||||
// HTML
|
// HTML
|
||||||
gettext("You can access UDS Open Source code at");
|
gettext("You can access UDS Open Source code at");
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,7 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2012-2019 Virtual Cable S.L.
|
# Copyright (c) 2012-2021 Virtual Cable S.L.U.
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
# Redistribution and use in source and binary forms, with or without modification,
|
# Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
@ -84,34 +84,23 @@ class TSNXTransport(BaseNXTransport):
|
|||||||
label=_('Tunnel wait time'),
|
label=_('Tunnel wait time'),
|
||||||
defvalue='30',
|
defvalue='30',
|
||||||
minValue=5,
|
minValue=5,
|
||||||
maxValue=65536,
|
maxValue=3600 * 24,
|
||||||
order=2,
|
order=2,
|
||||||
tooltip=_('Maximum time to wait before closing the tunnel listener'),
|
tooltip=_('Maximum time to wait before closing the tunnel listener'),
|
||||||
required=True,
|
required=True,
|
||||||
tab=gui.TUNNEL_TAB,
|
tab=gui.TUNNEL_TAB,
|
||||||
)
|
)
|
||||||
|
|
||||||
ticketValidity = gui.NumericField(
|
|
||||||
length=3,
|
|
||||||
label=_('Tunnel ticket validity time (seconds)'),
|
|
||||||
defvalue='7200',
|
|
||||||
minValue=60, # One minute as min
|
|
||||||
maxValue=7*60*60*24, # one week as max
|
|
||||||
order=3,
|
|
||||||
tooltip=_('Maximum validity time for user ticket to allow reconnection'),
|
|
||||||
required=True,
|
|
||||||
tab=gui.TUNNEL_TAB,
|
|
||||||
)
|
|
||||||
|
|
||||||
verifyCertificate = gui.CheckBoxField(
|
verifyCertificate = gui.CheckBoxField(
|
||||||
label=_('Force SSL certificate verification'),
|
label=_('Force SSL certificate verification'),
|
||||||
order=23,
|
order=23,
|
||||||
tooltip=_('If enabled, the certificate of tunnel server will be verified (recommended).'),
|
tooltip=_(
|
||||||
|
'If enabled, the certificate of tunnel server will be verified (recommended).'
|
||||||
|
),
|
||||||
defvalue=gui.TRUE,
|
defvalue=gui.TRUE,
|
||||||
tab=gui.TUNNEL_TAB
|
tab=gui.TUNNEL_TAB,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
useEmptyCreds = gui.CheckBoxField(
|
useEmptyCreds = gui.CheckBoxField(
|
||||||
label=_('Empty creds'),
|
label=_('Empty creds'),
|
||||||
order=3,
|
order=3,
|
||||||
@ -217,7 +206,6 @@ class TSNXTransport(BaseNXTransport):
|
|||||||
_cacheMem: str = ''
|
_cacheMem: str = ''
|
||||||
_screenSize: str = ''
|
_screenSize: str = ''
|
||||||
_tunnelWait: int = 30
|
_tunnelWait: int = 30
|
||||||
_ticketValidity: int = 60
|
|
||||||
_verifyCertificate: bool = False
|
_verifyCertificate: bool = False
|
||||||
|
|
||||||
def initialize(self, values: 'Module.ValuesType'):
|
def initialize(self, values: 'Module.ValuesType'):
|
||||||
@ -228,7 +216,6 @@ class TSNXTransport(BaseNXTransport):
|
|||||||
)
|
)
|
||||||
self._tunnelServer = values['tunnelServer']
|
self._tunnelServer = values['tunnelServer']
|
||||||
self._tunnelWait = int(values['tunnelWait'])
|
self._tunnelWait = int(values['tunnelWait'])
|
||||||
self._ticketValidity = int(values['ticketValidity'])
|
|
||||||
self._verifyCertificate = gui.strToBool(values['verifyCertificate'])
|
self._verifyCertificate = gui.strToBool(values['verifyCertificate'])
|
||||||
self._tunnelCheckServer = ''
|
self._tunnelCheckServer = ''
|
||||||
self._useEmptyCreds = gui.strToBool(values['useEmptyCreds'])
|
self._useEmptyCreds = gui.strToBool(values['useEmptyCreds'])
|
||||||
@ -241,7 +228,6 @@ class TSNXTransport(BaseNXTransport):
|
|||||||
self._cacheMem = values['cacheMem']
|
self._cacheMem = values['cacheMem']
|
||||||
self._screenSize = values['screenSize']
|
self._screenSize = values['screenSize']
|
||||||
|
|
||||||
|
|
||||||
def marshal(self) -> bytes:
|
def marshal(self) -> bytes:
|
||||||
"""
|
"""
|
||||||
Serializes the transport data so we can store it in database
|
Serializes the transport data so we can store it in database
|
||||||
@ -262,7 +248,6 @@ class TSNXTransport(BaseNXTransport):
|
|||||||
self._tunnelCheckServer,
|
self._tunnelCheckServer,
|
||||||
self._screenSize,
|
self._screenSize,
|
||||||
str(self._tunnelWait),
|
str(self._tunnelWait),
|
||||||
str(self._ticketValidity),
|
|
||||||
gui.boolToStr(self._verifyCertificate),
|
gui.boolToStr(self._verifyCertificate),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@ -288,10 +273,9 @@ class TSNXTransport(BaseNXTransport):
|
|||||||
values[11] if values[0] == 'v2' else CommonPrefs.SZ_FULLSCREEN
|
values[11] if values[0] == 'v2' else CommonPrefs.SZ_FULLSCREEN
|
||||||
)
|
)
|
||||||
if values[0] == 'v3':
|
if values[0] == 'v3':
|
||||||
self._tunnelWait, self._ticketValidity, self._verifyCertificate = (
|
self._tunnelWait, self._verifyCertificate = (
|
||||||
int(values[12]),
|
int(values[12]),
|
||||||
int(values[13]),
|
gui.strToBool(values[13]),
|
||||||
gui.strToBool(values[14])
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def valuesDict(self) -> gui.ValuesDictType:
|
def valuesDict(self) -> gui.ValuesDictType:
|
||||||
@ -306,7 +290,6 @@ class TSNXTransport(BaseNXTransport):
|
|||||||
'cacheMem': self._cacheMem,
|
'cacheMem': self._cacheMem,
|
||||||
'tunnelServer': self._tunnelServer,
|
'tunnelServer': self._tunnelServer,
|
||||||
'tunnelWait': str(self._tunnelWait),
|
'tunnelWait': str(self._tunnelWait),
|
||||||
'ticketValidity': str(self._ticketValidity),
|
|
||||||
'verifyCertificate': gui.boolToStr(self._verifyCertificate),
|
'verifyCertificate': gui.boolToStr(self._verifyCertificate),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,8 +317,8 @@ class TSNXTransport(BaseNXTransport):
|
|||||||
|
|
||||||
ticket = TicketStore.create_for_tunnel(
|
ticket = TicketStore.create_for_tunnel(
|
||||||
userService=userService,
|
userService=userService,
|
||||||
port=3389,
|
port=int(self._listenPort),
|
||||||
validity=self.ticketValidity.num()
|
validity=self._tunnelWait + 60, # Ticket overtime
|
||||||
)
|
)
|
||||||
|
|
||||||
tunHost, tunPort = self.tunnelServer.value.split(':')
|
tunHost, tunPort = self.tunnelServer.value.split(':')
|
||||||
@ -367,10 +350,9 @@ class TSNXTransport(BaseNXTransport):
|
|||||||
'ip': ip,
|
'ip': ip,
|
||||||
'tunHost': tunHost,
|
'tunHost': tunHost,
|
||||||
'tunPort': tunPort,
|
'tunPort': tunPort,
|
||||||
'tunWait': self.tunnelWait.num(),
|
'tunWait': self._tunnelWait,
|
||||||
'tunChk': self.verifyCertificate.isTrue(),
|
'tunChk': self._verifyCertificate,
|
||||||
'ticket': ticket,
|
'ticket': ticket,
|
||||||
'port': self._listenPort,
|
|
||||||
'as_file_for_format': r.as_file_for_format,
|
'as_file_for_format': r.as_file_for_format,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,13 +18,13 @@ except Exception:
|
|||||||
''')
|
''')
|
||||||
|
|
||||||
# Open tunnel
|
# Open tunnel
|
||||||
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk'])
|
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
|
||||||
|
|
||||||
# Check that tunnel works..
|
# Check that tunnel works..
|
||||||
if fs.check() is False:
|
if fs.check() is False:
|
||||||
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
|
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
|
||||||
|
|
||||||
theFile = sp['as_file_for_format'].format(
|
theFile = sp['as_file_for_format'].format( # type: ignore
|
||||||
address='127.0.0.1',
|
address='127.0.0.1',
|
||||||
port=fs.server_address[1]
|
port=fs.server_address[1]
|
||||||
)
|
)
|
||||||
|
@ -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 subprocess
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from uds import tools # @UnresolvedImport
|
from uds import tools # type: ignore
|
||||||
|
|
||||||
|
|
||||||
cmd = '/Applications/OpenNX/OpenNX.app/Contents/MacOS/OpenNXapp'
|
cmd = '/Applications/OpenNX/OpenNX.app/Contents/MacOS/OpenNXapp'
|
||||||
@ -16,6 +16,6 @@ if os.path.isfile(cmd) is False:
|
|||||||
''')
|
''')
|
||||||
|
|
||||||
|
|
||||||
filename = tools.saveTempFile(sp['as_file']) # @UndefinedVariable
|
filename = tools.saveTempFile(sp['as_file']) # type: ignore
|
||||||
tools.addTaskToWait(subprocess.Popen([cmd, '--session={{}}'.format(filename), '--autologin', '--killerrors']))
|
tools.addTaskToWait(subprocess.Popen([cmd, '--session={{}}'.format(filename), '--autologin', '--killerrors'])) # type: ignore
|
||||||
tools.addFileToUnlink(filename)
|
tools.addFileToUnlink(filename)
|
||||||
|
@ -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
|
# Open tunnel
|
||||||
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk'])
|
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
|
||||||
|
|
||||||
# Check that tunnel works..
|
# Check that tunnel works..
|
||||||
if fs.check() is False:
|
if fs.check() is False:
|
||||||
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
|
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
|
||||||
|
|
||||||
theFile = sp['as_file_for_format'].format(
|
theFile = sp['as_file_for_format'].format( # type: ignore
|
||||||
address='127.0.0.1',
|
address='127.0.0.1',
|
||||||
port=fs.server_address[1]
|
port=fs.server_address[1]
|
||||||
)
|
)
|
||||||
|
@ -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
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
# pylint: disable=import-error, no-name-in-module
|
# pylint: disable=import-error, no-name-in-module
|
||||||
import _winreg
|
try:
|
||||||
|
import winreg as wreg
|
||||||
|
except ImportError: # Python 2.7 fallback
|
||||||
|
import _winreg as wreg # type: ignore
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from uds import tools # @UnresolvedImport
|
from uds import tools # type: ignore
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
k = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, 'Software\\Classes\\NXClient.session\\shell\\open\\command') # @UndefinedVariable
|
k = wreg.OpenKey(wreg.HKEY_CURRENT_USER, 'Software\\Classes\\NXClient.session\\shell\\open\\command') # @UndefinedVariable
|
||||||
cmd = _winreg.QueryValue(k, '') # @UndefinedVariable
|
cmd = wreg.QueryValue(k, '') # type: ignore
|
||||||
|
wreg.CloseKey(k)
|
||||||
except Exception:
|
except Exception:
|
||||||
raise Exception('''<p>You need to have installed NX Client version 3.5 in order to connect to this UDS service.</p>
|
raise Exception('''<p>You need to have installed NX Client version 3.5 in order to connect to this UDS service.</p>
|
||||||
<p>Please, install appropriate package for your system.</p>
|
<p>Please, install appropriate package for your system.</p>
|
||||||
''')
|
''')
|
||||||
|
|
||||||
filename = tools.saveTempFile(sp['as_file']) # @UndefinedVariable
|
filename = tools.saveTempFile(sp['as_file']) # type: ignore
|
||||||
cmd = cmd.replace('%1', filename)
|
cmd = cmd.replace('%1', filename)
|
||||||
tools.addTaskToWait(subprocess.Popen(cmd))
|
tools.addTaskToWait(subprocess.Popen(cmd))
|
||||||
tools.addFileToUnlink(filename)
|
tools.addFileToUnlink(filename)
|
||||||
|
@ -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
|
from uds import tools # type: ignore
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
k = wreg.OpenKey(wreg.HKEY_CURRENT_USER, 'Software\\Classes\\NXClient.session\\shell\\open\\command') # @UndefinedVariable
|
k = wreg.OpenKey(wreg.HKEY_CURRENT_USER, 'Software\\Classes\\NXClient.session\\shell\\open\\command')
|
||||||
cmd = wreg.QueryValue(k, '')
|
cmd = wreg.QueryValue(k, '')
|
||||||
|
wreg.CloseKey(k)
|
||||||
except Exception:
|
except Exception:
|
||||||
raise Exception('''<p>You need to have installed NX Client version 3.5 in order to connect to this UDS service.</p>
|
raise Exception('''<p>You need to have installed NX Client version 3.5 in order to connect to this UDS service.</p>
|
||||||
<p>Please, install appropriate package for your system.</p>
|
<p>Please, install appropriate package for your system.</p>
|
||||||
''')
|
''')
|
||||||
|
|
||||||
# Open tunnel
|
# Open tunnel
|
||||||
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk'])
|
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
|
||||||
|
|
||||||
# Check that tunnel works..
|
# Check that tunnel works..
|
||||||
if fs.check() is False:
|
if fs.check() is False:
|
||||||
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
|
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
|
||||||
|
|
||||||
theFile = sp['as_file_for_format'].format(
|
theFile = sp['as_file_for_format'].format( # type: ignore
|
||||||
address='127.0.0.1',
|
address='127.0.0.1',
|
||||||
port=fs.server_address[1]
|
port=fs.server_address[1]
|
||||||
)
|
)
|
||||||
|
@ -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,
|
tab=gui.TUNNEL_TAB,
|
||||||
)
|
)
|
||||||
# tunnelCheckServer = gui.TextField(label=_('Tunnel host check'), order=2, tooltip=_('If not empty, this server will be used to check if service is running before assigning it to user. (use HOST:PORT format)'), tab=gui.TUNNEL_TAB)
|
|
||||||
|
|
||||||
tunnelWait = gui.NumericField(
|
tunnelWait = gui.NumericField(
|
||||||
length=3,
|
length=3,
|
||||||
@ -88,27 +87,16 @@ class TRDPTransport(BaseRDPTransport):
|
|||||||
tab=gui.TUNNEL_TAB,
|
tab=gui.TUNNEL_TAB,
|
||||||
)
|
)
|
||||||
|
|
||||||
ticketValidity = gui.NumericField(
|
|
||||||
length=3,
|
|
||||||
label=_('Tunnel ticket validity time (seconds)'),
|
|
||||||
defvalue='7200',
|
|
||||||
minValue=60, # One minute as min
|
|
||||||
maxValue=7*60*60*24, # one week as max
|
|
||||||
order=3,
|
|
||||||
tooltip=_('Maximum validity time for user ticket to allow reconnection'),
|
|
||||||
required=True,
|
|
||||||
tab=gui.TUNNEL_TAB,
|
|
||||||
)
|
|
||||||
|
|
||||||
verifyCertificate = gui.CheckBoxField(
|
verifyCertificate = gui.CheckBoxField(
|
||||||
label=_('Force SSL certificate verification'),
|
label=_('Force SSL certificate verification'),
|
||||||
order=23,
|
order=23,
|
||||||
tooltip=_('If enabled, the certificate of tunnel server will be verified (recommended).'),
|
tooltip=_(
|
||||||
|
'If enabled, the certificate of tunnel server will be verified (recommended).'
|
||||||
|
),
|
||||||
defvalue=gui.TRUE,
|
defvalue=gui.TRUE,
|
||||||
tab=gui.TUNNEL_TAB
|
tab=gui.TUNNEL_TAB,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
useEmptyCreds = BaseRDPTransport.useEmptyCreds
|
useEmptyCreds = BaseRDPTransport.useEmptyCreds
|
||||||
fixedName = BaseRDPTransport.fixedName
|
fixedName = BaseRDPTransport.fixedName
|
||||||
fixedPassword = BaseRDPTransport.fixedPassword
|
fixedPassword = BaseRDPTransport.fixedPassword
|
||||||
@ -175,12 +163,11 @@ class TRDPTransport(BaseRDPTransport):
|
|||||||
ticket = TicketStore.create_for_tunnel(
|
ticket = TicketStore.create_for_tunnel(
|
||||||
userService=userService,
|
userService=userService,
|
||||||
port=3389,
|
port=3389,
|
||||||
validity=self.ticketValidity.num()
|
validity=self.tunnelWait.num() + 60, # Ticket overtime
|
||||||
)
|
)
|
||||||
|
|
||||||
tunHost, tunPort = self.tunnelServer.value.split(':')
|
tunHost, tunPort = self.tunnelServer.value.split(':')
|
||||||
|
|
||||||
|
|
||||||
r = RDPFile(
|
r = RDPFile(
|
||||||
width == '-1' or height == '-1', width, height, depth, target=os['OS']
|
width == '-1' or height == '-1', width, height, depth, target=os['OS']
|
||||||
)
|
)
|
||||||
|
@ -2,24 +2,22 @@
|
|||||||
# Saved as .py for easier editing
|
# Saved as .py for easier editing
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
# pylint: disable=import-error, no-name-in-module, too-many-format-args, undefined-variable, invalid-sequence-index
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import re
|
|
||||||
|
|
||||||
from uds import tools
|
from uds import tools # type: ignore
|
||||||
|
|
||||||
# Inject local passed sp into globals for inner functions
|
# Inject local passed sp into globals for inner functions
|
||||||
globals()['sp'] = sp # type: ignore # pylint: disable=undefined-variable
|
globals()['sp'] = sp # type: ignore # pylint: disable=undefined-variable
|
||||||
|
|
||||||
def execUdsRdp(udsrdp):
|
def execUdsRdp(udsrdp):
|
||||||
import subprocess # @Reimport
|
import subprocess # @Reimport
|
||||||
params = [udsrdp] + sp['as_new_xfreerdp_params'] + ['/v:{}'.format(sp['address'])] # @UndefinedVariable
|
params = [udsrdp] + sp['as_new_xfreerdp_params'] + ['/v:{}'.format(sp['address'])] # type: ignore
|
||||||
tools.addTaskToWait(subprocess.Popen(params))
|
tools.addTaskToWait(subprocess.Popen(params))
|
||||||
|
|
||||||
|
|
||||||
def execNewXFreeRdp(xfreerdp):
|
def execNewXFreeRdp(xfreerdp):
|
||||||
import subprocess # @Reimport
|
import subprocess # @Reimport
|
||||||
params = [xfreerdp] + sp['as_new_xfreerdp_params'] + ['/v:{}'.format(sp['address'])] # @UndefinedVariable
|
params = [xfreerdp] + sp['as_new_xfreerdp_params'] + ['/v:{}'.format(sp['address'])] # type: ignore
|
||||||
tools.addTaskToWait(subprocess.Popen(params))
|
tools.addTaskToWait(subprocess.Popen(params))
|
||||||
|
|
||||||
# Try to locate a "valid" version of xfreerdp as first option (<1.1 does not allows drive redirections, so it will not be used if found)
|
# Try to locate a "valid" version of xfreerdp as first option (<1.1 does not allows drive redirections, so it will not be used if found)
|
||||||
|
@ -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
|
# Saved as .py for easier editing
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
# pylint: disable=import-error, no-name-in-module, too-many-format-args, undefined-variable, invalid-sequence-index
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import re
|
|
||||||
from uds.tunnel import forward # type: ignore
|
from uds.tunnel import forward # type: ignore
|
||||||
|
|
||||||
from uds import tools # type: ignore
|
from uds import tools # type: ignore
|
||||||
@ -14,13 +12,13 @@ globals()['sp'] = sp # type: ignore # pylint: disable=undefined-variable
|
|||||||
|
|
||||||
def execUdsRdp(udsrdp, port):
|
def execUdsRdp(udsrdp, port):
|
||||||
import subprocess # @Reimport
|
import subprocess # @Reimport
|
||||||
params = [udsrdp] + sp['as_new_xfreerdp_params'] + ['/v:127.0.0.1:{}'.format(port)] # @UndefinedVariable
|
params = [udsrdp] + sp['as_new_xfreerdp_params'] + ['/v:127.0.0.1:{}'.format(port)] # type: ignore
|
||||||
tools.addTaskToWait(subprocess.Popen(params))
|
tools.addTaskToWait(subprocess.Popen(params))
|
||||||
|
|
||||||
|
|
||||||
def execNewXFreeRdp(xfreerdp, port):
|
def execNewXFreeRdp(xfreerdp, port):
|
||||||
import subprocess # @Reimport
|
import subprocess # @Reimport
|
||||||
params = [xfreerdp] + sp['as_new_xfreerdp_params'] + ['/v:127.0.0.1:{}'.format(port)] # @UndefinedVariable
|
params = [xfreerdp] + sp['as_new_xfreerdp_params'] + ['/v:127.0.0.1:{}'.format(port)] # type: ignore
|
||||||
tools.addTaskToWait(subprocess.Popen(params))
|
tools.addTaskToWait(subprocess.Popen(params))
|
||||||
|
|
||||||
# Try to locate a "valid" version of xfreerdp as first option (<1.1 does not allows drive redirections, so it will not be used if found)
|
# Try to locate a "valid" version of xfreerdp as first option (<1.1 does not allows drive redirections, so it will not be used if found)
|
||||||
@ -41,7 +39,7 @@ if app is None or fnc is None:
|
|||||||
''')
|
''')
|
||||||
else:
|
else:
|
||||||
# Open tunnel
|
# Open tunnel
|
||||||
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk'])
|
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
|
||||||
|
|
||||||
# Check that tunnel works..
|
# Check that tunnel works..
|
||||||
if fs.check() is False:
|
if fs.check() is False:
|
||||||
|
@ -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 shutil
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from uds import tools # @UnresolvedImport
|
from uds import tools # type: ignore
|
||||||
|
|
||||||
# Inject local passed sp into globals for functions
|
# Inject local passed sp into globals for functions
|
||||||
globals()['sp'] = sp # type: ignore # pylint: disable=undefined-variable
|
globals()['sp'] = sp # type: ignore # pylint: disable=undefined-variable
|
||||||
@ -20,18 +20,18 @@ def fixResolution():
|
|||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
results = str(subprocess.Popen(['system_profiler SPDisplaysDataType'],stdout=subprocess.PIPE, shell=True).communicate()[0])
|
results = str(subprocess.Popen(['system_profiler SPDisplaysDataType'],stdout=subprocess.PIPE, shell=True).communicate()[0])
|
||||||
res = re.search(': \d* x \d*', results).group(0).split(' ')
|
res = re.search(r': \d* x \d*', results).group(0).split(' ')
|
||||||
width, height = str(int(res[1])-4), str(int(int(res[3])-128)) # Width and Height
|
width, height = str(int(res[1])-4), str(int(int(res[3])-128)) # Width and Height
|
||||||
return list(map(lambda x: x.replace('#WIDTH#', width).replace('#HEIGHT#', height), sp['as_new_xfreerdp_params']))
|
return list(map(lambda x: x.replace('#WIDTH#', width).replace('#HEIGHT#', height), sp['as_new_xfreerdp_params'])) # type: ignore
|
||||||
|
|
||||||
# Check first xfreerdp, allow password redir
|
# Check first xfreerdp, allow password redir
|
||||||
if os.path.isfile(xfreerdp):
|
if os.path.isfile(xfreerdp):
|
||||||
executable = xfreerdp
|
executable = xfreerdp
|
||||||
elif os.path.isfile(msrdc) and sp['as_file']:
|
elif os.path.isfile(msrdc) and sp['as_file']: # type: ignore
|
||||||
executable = msrdc
|
executable = msrdc
|
||||||
|
|
||||||
if executable is None:
|
if executable is None:
|
||||||
if sp['as_file']:
|
if sp['as_file']: # type: ignore
|
||||||
raise Exception('''<p><b>Microsoft Remote Desktop or xfreerdp not found</b></p>
|
raise Exception('''<p><b>Microsoft Remote Desktop or xfreerdp not found</b></p>
|
||||||
<p>In order to connect to UDS RDP Sessions, you need to have a<p>
|
<p>In order to connect to UDS RDP Sessions, you need to have a<p>
|
||||||
<ul>
|
<ul>
|
||||||
@ -63,7 +63,7 @@ if executable is None:
|
|||||||
</ul>
|
</ul>
|
||||||
''')
|
''')
|
||||||
elif executable == msrdc:
|
elif executable == msrdc:
|
||||||
theFile = sp['as_file']
|
theFile = sp['as_file'] # type: ignore
|
||||||
filename = tools.saveTempFile(theFile)
|
filename = tools.saveTempFile(theFile)
|
||||||
# Rename as .rdp, so open recognizes it
|
# Rename as .rdp, so open recognizes it
|
||||||
shutil.move(filename, filename + '.rdp')
|
shutil.move(filename, filename + '.rdp')
|
||||||
@ -75,8 +75,8 @@ elif executable == xfreerdp:
|
|||||||
try:
|
try:
|
||||||
xfparms = fixResolution()
|
xfparms = fixResolution()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
xfparms = list(map(lambda x: x.replace('#WIDTH#', '1400').replace('#HEIGHT#', '800'), sp['as_new_xfreerdp_params']))
|
xfparms = list(map(lambda x: x.replace('#WIDTH#', '1400').replace('#HEIGHT#', '800'), sp['as_new_xfreerdp_params'])) # type: ignore
|
||||||
|
|
||||||
params = [executable] + xfparms + ['/v:{}'.format(sp['address'])] # @UndefinedVariable
|
params = [executable] + xfparms + ['/v:{}'.format(sp['address'])] # type: ignore
|
||||||
subprocess.Popen(params)
|
subprocess.Popen(params)
|
||||||
|
|
||||||
|
@ -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 re
|
||||||
import subprocess
|
import subprocess
|
||||||
results = str(subprocess.Popen(['system_profiler SPDisplaysDataType'],stdout=subprocess.PIPE, shell=True).communicate()[0])
|
results = str(subprocess.Popen(['system_profiler SPDisplaysDataType'],stdout=subprocess.PIPE, shell=True).communicate()[0])
|
||||||
res = re.search(': \d* x \d*', results).group(0).split(' ')
|
res = re.search(r': \d* x \d*', results).group(0).split(' ')
|
||||||
width, height = str(int(res[1])-4), str(int(int(res[3])-128)) # Width and Height
|
width, height = str(int(res[1])-4), str(int(int(res[3])-128)) # Width and Height
|
||||||
return list(map(lambda x: x.replace('#WIDTH#', width).replace('#HEIGHT#', height), sp['as_new_xfreerdp_params']))
|
return list(map(lambda x: x.replace('#WIDTH#', width).replace('#HEIGHT#', height), sp['as_new_xfreerdp_params'])) # type: ignore
|
||||||
|
|
||||||
|
|
||||||
msrdc = '/Applications/Microsoft Remote Desktop.app/Contents/MacOS/Microsoft Remote Desktop'
|
msrdc = '/Applications/Microsoft Remote Desktop.app/Contents/MacOS/Microsoft Remote Desktop'
|
||||||
@ -30,11 +30,11 @@ executable = None
|
|||||||
# Check first xfreerdp, allow password redir
|
# Check first xfreerdp, allow password redir
|
||||||
if os.path.isfile(xfreerdp):
|
if os.path.isfile(xfreerdp):
|
||||||
executable = xfreerdp
|
executable = xfreerdp
|
||||||
elif os.path.isfile(msrdc) and sp['as_file']:
|
elif os.path.isfile(msrdc) and sp['as_file']: # type: ignore
|
||||||
executable = msrdc
|
executable = msrdc
|
||||||
|
|
||||||
if executable is None:
|
if executable is None:
|
||||||
if sp['as_rdp_url']:
|
if sp['as_rdp_url']: # type: ignore
|
||||||
raise Exception('''<p><b>Microsoft Remote Desktop or xfreerdp not found</b></p>
|
raise Exception('''<p><b>Microsoft Remote Desktop or xfreerdp not found</b></p>
|
||||||
<p>In order to connect to UDS RDP Sessions, you need to have a<p>
|
<p>In order to connect to UDS RDP Sessions, you need to have a<p>
|
||||||
<ul>
|
<ul>
|
||||||
@ -67,15 +67,16 @@ if executable is None:
|
|||||||
''')
|
''')
|
||||||
|
|
||||||
# Open tunnel
|
# Open tunnel
|
||||||
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk'])
|
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
|
||||||
|
address = '127.0.0.1:{}'.format(fs.server_address[1])
|
||||||
|
|
||||||
# Check that tunnel works..
|
# Check that tunnel works..
|
||||||
if fs.check() is False:
|
if fs.check() is False:
|
||||||
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
|
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
|
||||||
|
|
||||||
if executable == msrdc:
|
if executable == msrdc:
|
||||||
theFile = theFile = sp['as_file'].format(
|
theFile = theFile = sp['as_file'].format( # type: ignore
|
||||||
address='127.0.0.1:{}'.format(fs.server_address[1])
|
address=address
|
||||||
)
|
)
|
||||||
|
|
||||||
filename = tools.saveTempFile(theFile)
|
filename = tools.saveTempFile(theFile)
|
||||||
@ -89,7 +90,7 @@ elif executable == xfreerdp:
|
|||||||
try:
|
try:
|
||||||
xfparms = fixResolution()
|
xfparms = fixResolution()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
xfparms = list(map(lambda x: x.replace('#WIDTH#', '1400').replace('#HEIGHT#', '800'), sp['as_new_xfreerdp_params']))
|
xfparms = list(map(lambda x: x.replace('#WIDTH#', '1400').replace('#HEIGHT#', '800'), sp['as_new_xfreerdp_params'])) # type: ignore
|
||||||
|
|
||||||
params = [executable] + xfparms + ['/v:{}'.format(address)]
|
params = [executable] + xfparms + ['/v:{}'.format(address)]
|
||||||
subprocess.Popen(params)
|
subprocess.Popen(params)
|
||||||
|
@ -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
|
import six
|
||||||
|
|
||||||
|
thePass = six.binary_type(sp['password'].encode('UTF-16LE')) # type: ignore
|
||||||
|
|
||||||
try:
|
try:
|
||||||
thePass = six.binary_type(sp['password'].encode('UTF-16LE')) # type: ignore
|
|
||||||
password = codecs.encode(win32crypt.CryptProtectData(thePass, None, None, None, None, 0x01), 'hex').decode()
|
password = codecs.encode(win32crypt.CryptProtectData(thePass, None, None, None, None, 0x01), 'hex').decode()
|
||||||
except Exception:
|
except Exception:
|
||||||
# logger.info('Cannot encrypt for user, trying for machine')
|
# logger.info('Cannot encrypt for user, trying for machine')
|
||||||
password = codecs.encode(win32crypt.CryptProtectData(thePass, None, None, None, None, 0x05), 'hex').decode()
|
password = codecs.encode(win32crypt.CryptProtectData(thePass, None, None, None, None, 0x05), 'hex').decode()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
key = wreg.OpenKey(wreg.HKEY_CURRENT_USER, 'Software\\Microsoft\\Terminal Server Client\\LocalDevices', 0, wreg.KEY_SET_VALUE) # @UndefinedVariable
|
key = wreg.OpenKey(wreg.HKEY_CURRENT_USER, 'Software\\Microsoft\\Terminal Server Client\\LocalDevices', 0, wreg.KEY_SET_VALUE)
|
||||||
wreg.SetValueEx(key, sp['ip'], 0, wreg.REG_DWORD, 255) # @UndefinedVariable
|
wreg.SetValueEx(key, sp['ip'], 0, wreg.REG_DWORD, 255) # type: ignore
|
||||||
wreg.CloseKey(key) # @UndefinedVariable
|
wreg.CloseKey(key)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# logger.warn('Exception fixing redirection dialog: %s', e)
|
# logger.warn('Exception fixing redirection dialog: %s', e)
|
||||||
pass # Key does not exists, ok...
|
pass # Key does not exists, ok...
|
||||||
|
|
||||||
# The password must be encoded, to be included in a .rdp file, as 'UTF-16LE' before protecting (CtrpyProtectData) it in order to work with mstsc
|
# The password must be encoded, to be included in a .rdp file, as 'UTF-16LE' before protecting (CtrpyProtectData) it in order to work with mstsc
|
||||||
theFile = sp['as_file'].format(# @UndefinedVariable
|
theFile = sp['as_file'].format( # type: ignore
|
||||||
password=password
|
password=password
|
||||||
)
|
)
|
||||||
filename = tools.saveTempFile(theFile)
|
filename = tools.saveTempFile(theFile)
|
||||||
|
@ -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
|
import six
|
||||||
|
|
||||||
# Open tunnel
|
# Open tunnel
|
||||||
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk'])
|
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
|
||||||
|
|
||||||
# Check that tunnel works..
|
# Check that tunnel works..
|
||||||
if fs.check() is False:
|
if fs.check() is False:
|
||||||
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
|
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
|
||||||
|
|
||||||
|
thePass = six.binary_type(sp['password'].encode('UTF-16LE')) # type: ignore
|
||||||
|
|
||||||
try:
|
try:
|
||||||
thePass = six.binary_type(sp['password'].encode('UTF-16LE')) # @UndefinedVariable
|
|
||||||
password = codecs.encode(win32crypt.CryptProtectData(thePass, None, None, None, None, 0x01), 'hex').decode()
|
password = codecs.encode(win32crypt.CryptProtectData(thePass, None, None, None, None, 0x01), 'hex').decode()
|
||||||
except Exception:
|
except Exception:
|
||||||
# Cannot encrypt for user, trying for machine
|
# Cannot encrypt for user, trying for machine
|
||||||
password = codecs.encode(win32crypt.CryptProtectData(thePass, None, None, None, None, 0x05), 'hex').decode()
|
password = codecs.encode(win32crypt.CryptProtectData(thePass, None, None, None, None, 0x05), 'hex').decode()
|
||||||
|
|
||||||
# The password must be encoded, to be included in a .rdp file, as 'UTF-16LE' before protecting (CtrpyProtectData) it in order to work with mstsc
|
# The password must be encoded, to be included in a .rdp file, as 'UTF-16LE' before protecting (CtrpyProtectData) it in order to work with mstsc
|
||||||
theFile = sp['as_file'].format(# @UndefinedVariable
|
theFile = sp['as_file'].format( # type: ignore
|
||||||
password=password,
|
password=password,
|
||||||
address='127.0.0.1:{}'.format(fs.server_address[1])
|
address='127.0.0.1:{}'.format(fs.server_address[1])
|
||||||
)
|
)
|
||||||
@ -45,9 +46,9 @@ if executable is None:
|
|||||||
raise Exception('Unable to find mstsc.exe. Check that path points to your SYSTEM32 folder')
|
raise Exception('Unable to find mstsc.exe. Check that path points to your SYSTEM32 folder')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
key = wreg.OpenKey(wreg.HKEY_CURRENT_USER, 'Software\Microsoft\Terminal Server Client\LocalDevices', 0, wreg.KEY_SET_VALUE) # @UndefinedVariable
|
key = wreg.OpenKey(wreg.HKEY_CURRENT_USER, 'Software\\Microsoft\\Terminal Server Client\\LocalDevices', 0, wreg.KEY_SET_VALUE)
|
||||||
wreg.SetValueEx(key, '127.0.0.1', 0, wreg.REG_DWORD, 255) # @UndefinedVariable
|
wreg.SetValueEx(key, '127.0.0.1', 0, wreg.REG_DWORD, 255) # type: ignore
|
||||||
wreg.CloseKey(key) # @UndefinedVariable
|
wreg.CloseKey(key)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# logger.warn('Exception fixing redirection dialog: %s', e)
|
# logger.warn('Exception fixing redirection dialog: %s', e)
|
||||||
pass # Key does not exists, but it's ok
|
pass # Key does not exists, but it's ok
|
||||||
|
@ -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
|
# pylint: disable=import-error, no-name-in-module
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from uds import tools # @UnresolvedImport
|
from uds import tools # type: ignore
|
||||||
|
|
||||||
executable = tools.findApp('remote-viewer')
|
executable = tools.findApp('remote-viewer')
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ if executable is None:
|
|||||||
</p>
|
</p>
|
||||||
''')
|
''')
|
||||||
|
|
||||||
theFile = sp['as_file']
|
theFile = sp['as_file'] # type: ignore
|
||||||
|
|
||||||
filename = tools.saveTempFile(theFile)
|
filename = tools.saveTempFile(theFile)
|
||||||
|
|
||||||
|
@ -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
|
# pylint: disable=import-error, no-name-in-module, undefined-variable
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from uds import tools # @UnresolvedImport
|
from uds import tools # type: ignore
|
||||||
from uds.forward import forward # @UnresolvedImport
|
from uds.tunnel import forward # type: ignore
|
||||||
|
|
||||||
executable = tools.findApp('remote-viewer')
|
executable = tools.findApp('remote-viewer')
|
||||||
|
|
||||||
@ -21,31 +21,28 @@ if executable is None:
|
|||||||
''')
|
''')
|
||||||
|
|
||||||
|
|
||||||
theFile = sp['as_file_ns']
|
theFile = sp['as_file_ns'] # type: ignore
|
||||||
if sp['port'] != '-1':
|
fs = None
|
||||||
forwardThread1, port = forward(sp['tunHost'], sp['tunPort'], sp['tunUser'], sp['tunPass'], sp['ip'], sp['port'])
|
if sp['ticket']: # type: ignore
|
||||||
|
# Open tunnel
|
||||||
|
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
|
||||||
|
|
||||||
|
# Check that tunnel works..
|
||||||
|
if fs.check() is False:
|
||||||
|
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
|
||||||
|
|
||||||
if forwardThread1.status == 2:
|
fss = None
|
||||||
raise Exception('Unable to open tunnel')
|
if sp['ticket_secure']: # type: ignore
|
||||||
else:
|
# Open tunnel
|
||||||
port = -1
|
fss = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket_secure'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
|
||||||
|
|
||||||
if sp['secure_port'] != '-1':
|
# Check that tunnel works..
|
||||||
theFile = sp['as_file']
|
if fss.check() is False:
|
||||||
if port != -1:
|
raise Exception('<p>Could not connect to tunnel server 2.</p><p>Please, check your network settings.</p>')
|
||||||
forwardThread2, secure_port = forwardThread1.clone(sp['ip'], sp['secure_port'])
|
|
||||||
else:
|
|
||||||
forwardThread2, secure_port = forward(sp['tunHost'], sp['tunPort'], sp['tunUser'], sp['tunPass'], sp['ip'], sp['secure_port'])
|
|
||||||
|
|
||||||
if forwardThread2.status == 2:
|
|
||||||
raise Exception('Unable to open tunnel')
|
|
||||||
else:
|
|
||||||
secure_port = -1
|
|
||||||
|
|
||||||
theFile = theFile.format(
|
theFile = theFile.format(
|
||||||
secure_port=secure_port,
|
secure_port='-1' if not fss else fss.server_address[1],
|
||||||
port=port
|
port='-1' if not fs else fs.server_address[1]
|
||||||
)
|
)
|
||||||
|
|
||||||
filename = tools.saveTempFile(theFile)
|
filename = tools.saveTempFile(theFile)
|
||||||
|
@ -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 os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from uds import tools # @UnresolvedImport
|
from uds import tools # type: ignore
|
||||||
|
|
||||||
remoteViewer = '/Applications/RemoteViewer.app/Contents/MacOS/RemoteViewer'
|
remoteViewer = '/Applications/RemoteViewer.app/Contents/MacOS/RemoteViewer'
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ if not os.path.isfile(remoteViewer):
|
|||||||
''')
|
''')
|
||||||
|
|
||||||
|
|
||||||
theFile = sp['as_file']
|
theFile = sp['as_file'] # type: ignore
|
||||||
|
|
||||||
filename = tools.saveTempFile(theFile)
|
filename = tools.saveTempFile(theFile)
|
||||||
|
|
||||||
|
@ -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 os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from uds import tools # @UnresolvedImport
|
from uds import tools # type: ignore
|
||||||
from uds.forward import forward # @UnresolvedImport
|
from uds.tunnel import forward # type: ignore
|
||||||
|
|
||||||
remoteViewer = '/Applications/RemoteViewer.app/Contents/MacOS/RemoteViewer'
|
remoteViewer = '/Applications/RemoteViewer.app/Contents/MacOS/RemoteViewer'
|
||||||
|
|
||||||
@ -25,31 +25,28 @@ if not os.path.isfile(remoteViewer):
|
|||||||
</p>
|
</p>
|
||||||
''')
|
''')
|
||||||
|
|
||||||
theFile = sp['as_file_ns']
|
theFile = sp['as_file_ns'] # type: ignore
|
||||||
if sp['port'] != '-1':
|
fs = None
|
||||||
forwardThread1, port = forward(sp['tunHost'], sp['tunPort'], sp['tunUser'], sp['tunPass'], sp['ip'], sp['port'])
|
if sp['ticket']: # type: ignore
|
||||||
|
# Open tunnel
|
||||||
|
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
|
||||||
|
|
||||||
|
# Check that tunnel works..
|
||||||
|
if fs.check() is False:
|
||||||
|
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
|
||||||
|
|
||||||
if forwardThread1.status == 2:
|
fss = None
|
||||||
raise Exception('Unable to open tunnel')
|
if sp['ticket_secure']: # type: ignore
|
||||||
else:
|
# Open tunnel
|
||||||
port = -1
|
fss = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket_secure'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
|
||||||
|
|
||||||
if sp['secure_port'] != '-1':
|
# Check that tunnel works..
|
||||||
theFile = sp['as_file']
|
if fss.check() is False:
|
||||||
if port != -1:
|
raise Exception('<p>Could not connect to tunnel server 2.</p><p>Please, check your network settings.</p>')
|
||||||
forwardThread2, secure_port = forwardThread1.clone(sp['ip'], sp['secure_port'])
|
|
||||||
else:
|
|
||||||
forwardThread2, secure_port = forward(sp['tunHost'], sp['tunPort'], sp['tunUser'], sp['tunPass'], sp['ip'], sp['secure_port'])
|
|
||||||
|
|
||||||
if forwardThread2.status == 2:
|
|
||||||
raise Exception('Unable to open tunnel')
|
|
||||||
else:
|
|
||||||
secure_port = -1
|
|
||||||
|
|
||||||
theFile = theFile.format(
|
theFile = theFile.format(
|
||||||
secure_port=secure_port,
|
secure_port='-1' if not fss else fss.server_address[1],
|
||||||
port=port
|
port='-1' if not fs else fs.server_address[1]
|
||||||
)
|
)
|
||||||
|
|
||||||
filename = tools.saveTempFile(theFile)
|
filename = tools.saveTempFile(theFile)
|
||||||
|
@ -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 glob
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from uds import tools # @UnresolvedImport
|
from uds import tools # type: ignore
|
||||||
|
|
||||||
# Lets find remote viewer
|
# Lets find remote viewer
|
||||||
# There is a bug that when installed, the remote viewer (at least 64 bits version) does not store correctly its path, so lets find it "a las bravas"
|
# There is a bug that when installed, the remote viewer (at least 64 bits version) does not store correctly its path, so lets find it "a las bravas"
|
||||||
extraPaths = ()
|
extraPaths = ()
|
||||||
for env in ('PROGRAMFILES', 'PROGRAMW6432'):
|
for env in ('PROGRAMFILES', 'PROGRAMW6432'):
|
||||||
if env in os.environ:
|
if env in os.environ:
|
||||||
extraPaths += tuple(p + '\\bin' for p in glob.glob(os.environ[env] + '\\VirtViewer*'))
|
extraPaths += tuple(p + '\\bin' for p in glob.glob(os.environ[env] + '\\VirtViewer*')) # type: ignore
|
||||||
|
|
||||||
executable = tools.findApp('remote-viewer.exe', extraPaths)
|
executable = tools.findApp('remote-viewer.exe', extraPaths)
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ if executable is None:
|
|||||||
</p>
|
</p>
|
||||||
''')
|
''')
|
||||||
|
|
||||||
theFile = sp['as_file']
|
theFile = sp['as_file'] # type: ignore
|
||||||
|
|
||||||
filename = tools.saveTempFile(theFile)
|
filename = tools.saveTempFile(theFile)
|
||||||
|
|
||||||
|
@ -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 glob
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from uds import tools # @UnresolvedImport
|
from uds import tools # type: ignore
|
||||||
from uds.forward import forward # @UnresolvedImport
|
from uds.tunnel import forward # type: ignore
|
||||||
|
|
||||||
# Lets find remote viewer
|
# Lets find remote viewer
|
||||||
# There is a bug that when installed, the remote viewer (at least 64 bits version) does not store correctly its path, so lets find it "a las bravas"
|
# There is a bug that when installed, the remote viewer (at least 64 bits version) does not store correctly its path, so lets find it "a las bravas"
|
||||||
extraPaths = ()
|
extraPaths = ()
|
||||||
for env in ('PROGRAMFILES', 'PROGRAMW6432'):
|
for env in ('PROGRAMFILES', 'PROGRAMW6432'):
|
||||||
if env in os.environ:
|
if env in os.environ:
|
||||||
extraPaths += tuple(p + '\\bin' for p in glob.glob(os.environ[env] + '\\VirtViewer*'))
|
extraPaths += tuple(p + '\\bin' for p in glob.glob(os.environ[env] + '\\VirtViewer*')) # type: ignore
|
||||||
|
|
||||||
executable = tools.findApp('remote-viewer.exe', extraPaths)
|
executable = tools.findApp('remote-viewer.exe', extraPaths)
|
||||||
|
|
||||||
@ -28,31 +28,28 @@ if executable is None:
|
|||||||
<a href="http://virt-manager.org/download/">Open download page</a>
|
<a href="http://virt-manager.org/download/">Open download page</a>
|
||||||
</p>
|
</p>
|
||||||
''')
|
''')
|
||||||
theFile = sp['as_file_ns']
|
theFile = sp['as_file_ns'] # type: ignore
|
||||||
if sp['port'] != '-1':
|
fs = None
|
||||||
forwardThread1, port = forward(sp['tunHost'], sp['tunPort'], sp['tunUser'], sp['tunPass'], sp['ip'], sp['port'])
|
if sp['ticket']: # type: ignore
|
||||||
|
# Open tunnel
|
||||||
|
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
|
||||||
|
|
||||||
|
# Check that tunnel works..
|
||||||
|
if fs.check() is False:
|
||||||
|
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
|
||||||
|
|
||||||
if forwardThread1.status == 2:
|
fss = None
|
||||||
raise Exception('Unable to open tunnel')
|
if sp['ticket_secure']: # type: ignore
|
||||||
else:
|
# Open tunnel
|
||||||
port = -1
|
fss = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket_secure'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
|
||||||
|
|
||||||
if sp['secure_port'] != '-1':
|
# Check that tunnel works..
|
||||||
theFile = sp['as_file']
|
if fss.check() is False:
|
||||||
if port != -1:
|
raise Exception('<p>Could not connect to tunnel server 2.</p><p>Please, check your network settings.</p>')
|
||||||
forwardThread2, secure_port = forwardThread1.clone(sp['ip'], sp['secure_port'])
|
|
||||||
else:
|
|
||||||
forwardThread2, secure_port = forward(sp['tunHost'], sp['tunPort'], sp['tunUser'], sp['tunPass'], sp['ip'], sp['secure_port'])
|
|
||||||
|
|
||||||
if forwardThread2.status == 2:
|
|
||||||
raise Exception('Unable to open tunnel')
|
|
||||||
else:
|
|
||||||
secure_port = -1
|
|
||||||
|
|
||||||
theFile = theFile.format(
|
theFile = theFile.format(
|
||||||
secure_port=secure_port,
|
secure_port='-1' if not fss else fss.server_address[1],
|
||||||
port=port
|
port='-1' if not fs else fs.server_address[1]
|
||||||
)
|
)
|
||||||
|
|
||||||
filename = tools.saveTempFile(theFile)
|
filename = tools.saveTempFile(theFile)
|
||||||
|
@ -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 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2012-2019 Virtual Cable S.L.
|
# Copyright (c) 2012-2021 Virtual Cable S.L.U.
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
# Redistribution and use in source and binary forms, with or without modification,
|
# Redistribution and use in source and binary forms, with or without modification,
|
||||||
@ -57,15 +56,44 @@ logger = logging.getLogger(__name__)
|
|||||||
class TSPICETransport(BaseSpiceTransport):
|
class TSPICETransport(BaseSpiceTransport):
|
||||||
"""
|
"""
|
||||||
Provides access via SPICE to service.
|
Provides access via SPICE to service.
|
||||||
This transport can use an domain. If username processed by authenticator contains '@', it will split it and left-@-part will be username, and right password
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
typeName = _('SPICE')
|
typeName = _('SPICE')
|
||||||
typeType = 'TSSPICETransport'
|
typeType = 'TSSPICETransport'
|
||||||
typeDescription = _('SPICE Protocol. Tunneled connection.')
|
typeDescription = _('SPICE Protocol. Tunneled connection.')
|
||||||
protocol = transports.protocols.SPICE
|
protocol = transports.protocols.SPICE
|
||||||
group: typing.ClassVar[str] = transports.TUNNELED_GROUP
|
group: typing.ClassVar[str] = transports.TUNNELED_GROUP
|
||||||
|
|
||||||
tunnelServer = gui.TextField(label=_('Tunnel server'), order=1, tooltip=_('IP or Hostname of tunnel server sent to client device ("public" ip) and port. (use HOST:PORT format)'), tab=gui.TUNNEL_TAB)
|
tunnelServer = gui.TextField(
|
||||||
|
label=_('Tunnel server'),
|
||||||
|
order=1,
|
||||||
|
tooltip=_(
|
||||||
|
'IP or Hostname of tunnel server sent to client device ("public" ip) and port. (use HOST:PORT format)'
|
||||||
|
),
|
||||||
|
tab=gui.TUNNEL_TAB,
|
||||||
|
)
|
||||||
|
|
||||||
|
tunnelWait = gui.NumericField(
|
||||||
|
length=3,
|
||||||
|
label=_('Tunnel wait time'),
|
||||||
|
defvalue='30',
|
||||||
|
minValue=5,
|
||||||
|
maxValue=65536,
|
||||||
|
order=2,
|
||||||
|
tooltip=_('Maximum time to wait before closing the tunnel listener'),
|
||||||
|
required=True,
|
||||||
|
tab=gui.TUNNEL_TAB,
|
||||||
|
)
|
||||||
|
|
||||||
|
verifyCertificate = gui.CheckBoxField(
|
||||||
|
label=_('Force SSL certificate verification'),
|
||||||
|
order=23,
|
||||||
|
tooltip=_(
|
||||||
|
'If enabled, the certificate of tunnel server will be verified (recommended).'
|
||||||
|
),
|
||||||
|
defvalue=gui.TRUE,
|
||||||
|
tab=gui.TUNNEL_TAB,
|
||||||
|
)
|
||||||
|
|
||||||
serverCertificate = BaseSpiceTransport.serverCertificate
|
serverCertificate = BaseSpiceTransport.serverCertificate
|
||||||
fullScreen = BaseSpiceTransport.fullScreen
|
fullScreen = BaseSpiceTransport.fullScreen
|
||||||
@ -76,7 +104,9 @@ class TSPICETransport(BaseSpiceTransport):
|
|||||||
def initialize(self, values: 'Module.ValuesType'):
|
def initialize(self, values: 'Module.ValuesType'):
|
||||||
if values:
|
if values:
|
||||||
if values['tunnelServer'].count(':') != 1:
|
if values['tunnelServer'].count(':') != 1:
|
||||||
raise transports.Transport.ValidationException(_('Must use HOST:PORT in Tunnel Server Field'))
|
raise transports.Transport.ValidationException(
|
||||||
|
_('Must use HOST:PORT in Tunnel Server Field')
|
||||||
|
)
|
||||||
|
|
||||||
def getUDSTransportScript( # pylint: disable=too-many-locals
|
def getUDSTransportScript( # pylint: disable=too-many-locals
|
||||||
self,
|
self,
|
||||||
@ -86,24 +116,40 @@ class TSPICETransport(BaseSpiceTransport):
|
|||||||
os: typing.Dict[str, str],
|
os: typing.Dict[str, str],
|
||||||
user: 'models.User',
|
user: 'models.User',
|
||||||
password: str,
|
password: str,
|
||||||
request: 'HttpRequest'
|
request: 'HttpRequest',
|
||||||
) -> typing.Tuple[str, str, typing.Dict[str, typing.Any]]:
|
) -> typing.Tuple[str, str, typing.Dict[str, typing.Any]]:
|
||||||
userServiceInstance: typing.Any = userService.getInstance()
|
userServiceInstance: typing.Any = userService.getInstance()
|
||||||
|
|
||||||
# Spice connection
|
# Spice connection
|
||||||
con = userServiceInstance.getConsoleConnection()
|
con = userServiceInstance.getConsoleConnection()
|
||||||
port: str = con['port'] or '-1'
|
|
||||||
secure_port: str = con['secure_port'] or '-1'
|
|
||||||
|
|
||||||
# Ticket
|
# We MAY need two tickets, one for 'insecure' port an one for secure
|
||||||
tunpass = ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits) for _i in range(12))
|
ticket = ''
|
||||||
tunuser = TicketStore.create(tunpass)
|
if con['port']:
|
||||||
|
ticket = TicketStore.create_for_tunnel(
|
||||||
|
userService=userService,
|
||||||
|
port=int(con['port']),
|
||||||
|
validity=self.tunnelWait.num() + 60, # Ticket overtime
|
||||||
|
)
|
||||||
|
|
||||||
sshHost, sshPort = self.tunnelServer.value.split(':')
|
ticket_secure = ''
|
||||||
|
if con['secure_port']:
|
||||||
|
ticket_secure = TicketStore.create_for_tunnel(
|
||||||
|
userService=userService,
|
||||||
|
port=int(con['secure_port']),
|
||||||
|
validity=self.tunnelWait.num() + 60, # Ticket overtime
|
||||||
|
)
|
||||||
|
|
||||||
|
tunHost, tunPort = self.tunnelServer.value.split(':')
|
||||||
|
|
||||||
r = RemoteViewerFile(
|
r = RemoteViewerFile(
|
||||||
'127.0.0.1', '{port}', '{secure_port}', con['ticket']['value'],
|
'127.0.0.1',
|
||||||
self.serverCertificate.value.strip(), con['cert_subject'], fullscreen=self.fullScreen.isTrue()
|
'{port}',
|
||||||
|
'{secure_port}',
|
||||||
|
con['ticket']['value'], # This is secure ticket from kvm, not UDS ticket
|
||||||
|
self.serverCertificate.value.strip(),
|
||||||
|
con['cert_subject'],
|
||||||
|
fullscreen=self.fullScreen.isTrue(),
|
||||||
)
|
)
|
||||||
r.usb_auto_share = self.usbShare.isTrue()
|
r.usb_auto_share = self.usbShare.isTrue()
|
||||||
r.new_usb_auto_share = self.autoNewUsbShare.isTrue()
|
r.new_usb_auto_share = self.autoNewUsbShare.isTrue()
|
||||||
@ -112,11 +158,13 @@ class TSPICETransport(BaseSpiceTransport):
|
|||||||
osName = {
|
osName = {
|
||||||
OsDetector.Windows: 'windows',
|
OsDetector.Windows: 'windows',
|
||||||
OsDetector.Linux: 'linux',
|
OsDetector.Linux: 'linux',
|
||||||
OsDetector.Macintosh: 'macosx'
|
OsDetector.Macintosh: 'macosx',
|
||||||
}.get(os['OS'])
|
}.get(os['OS'])
|
||||||
|
|
||||||
if osName is None:
|
if osName is None:
|
||||||
return super().getUDSTransportScript(userService, transport, ip, os, user, password, request)
|
return super().getUDSTransportScript(
|
||||||
|
userService, transport, ip, os, user, password, request
|
||||||
|
)
|
||||||
|
|
||||||
# if sso: # If SSO requested, and when supported by platform
|
# if sso: # If SSO requested, and when supported by platform
|
||||||
# userServiceInstance.desktopLogin(user, password, '')
|
# userServiceInstance.desktopLogin(user, password, '')
|
||||||
@ -124,13 +172,12 @@ class TSPICETransport(BaseSpiceTransport):
|
|||||||
sp = {
|
sp = {
|
||||||
'as_file': r.as_file,
|
'as_file': r.as_file,
|
||||||
'as_file_ns': r.as_file_ns,
|
'as_file_ns': r.as_file_ns,
|
||||||
'tunUser': tunuser,
|
'tunHost': tunHost,
|
||||||
'tunPass': tunpass,
|
'tunPort': tunPort,
|
||||||
'tunHost': sshHost,
|
'tunWait': self.tunnelWait.num(),
|
||||||
'tunPort': sshPort,
|
'tunChk': self.verifyCertificate.isTrue(),
|
||||||
'ip': con['address'],
|
'ticket': ticket,
|
||||||
'port': port,
|
'ticket_secure': ticket_secure,
|
||||||
'secure_port': secure_port
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.getScript('scripts/{}/tunnel.py', osName, sp)
|
return self.getScript('scripts/{}/tunnel.py', osName, sp)
|
||||||
|
@ -6,11 +6,11 @@ from __future__ import unicode_literals
|
|||||||
import subprocess
|
import subprocess
|
||||||
from os.path import expanduser
|
from os.path import expanduser
|
||||||
|
|
||||||
from uds import tools # @UnresolvedImport
|
from uds import tools # type: ignore
|
||||||
|
|
||||||
home = expanduser('~') + ':1;/media:1;'
|
home = expanduser('~') + ':1;/media:1;'
|
||||||
keyFile = tools.saveTempFile(sp['key'])
|
keyFile = tools.saveTempFile(sp['key']) # type: ignore
|
||||||
theFile = sp['xf'].format(export=home, keyFile=keyFile.replace('\\', '/'), ip=sp['ip'], port=sp['port'])
|
theFile = sp['xf'].format(export=home, keyFile=keyFile.replace('\\', '/'), ip=sp['ip'], port=sp['port']) # type: ignore
|
||||||
filename = tools.saveTempFile(theFile)
|
filename = tools.saveTempFile(theFile)
|
||||||
|
|
||||||
# HOME=[temporal folder, where we create a .x2goclient folder and a sessions inside] pyhoca-cli -P UDS/test-session
|
# HOME=[temporal folder, where we create a .x2goclient folder and a sessions inside] pyhoca-cli -P UDS/test-session
|
||||||
|
@ -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
|
# pylint: disable=import-error, no-name-in-module, too-many-format-args, undefined-variable
|
||||||
|
|
||||||
import subprocess
|
import subprocess
|
||||||
from uds.forward import forward # @UnresolvedImport
|
from uds.tunnel import forward # type: ignore
|
||||||
from os.path import expanduser
|
from os.path import expanduser
|
||||||
|
|
||||||
from uds import tools # @UnresolvedImport
|
from uds import tools # type: ignore
|
||||||
|
|
||||||
forwardThread, port = forward(sp['tunHost'], sp['tunPort'], sp['tunUser'], sp['tunPass'], sp['ip'], sp['port'])
|
# Open tunnel
|
||||||
|
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
|
||||||
|
|
||||||
if forwardThread.status == 2:
|
# Check that tunnel works..
|
||||||
raise Exception('Unable to open tunnel')
|
if fs.check() is False:
|
||||||
|
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
|
||||||
|
|
||||||
tools.addTaskToWait(forwardThread)
|
|
||||||
home = expanduser('~') + ':1;/media:1;'
|
home = expanduser('~') + ':1;/media:1;'
|
||||||
keyFile = tools.saveTempFile(sp['key'])
|
keyFile = tools.saveTempFile(sp['key']) # type: ignore
|
||||||
theFile = sp['xf'].format(export=home, keyFile=keyFile.replace('\\', '/'), ip='127.0.0.1', port=port)
|
theFile = sp['xf'].format(export=home, keyFile=keyFile.replace('\\', '/'), ip='127.0.0.1', port=fs.server_address[1]) # type: ignore
|
||||||
filename = tools.saveTempFile(theFile)
|
filename = tools.saveTempFile(theFile)
|
||||||
|
|
||||||
# HOME=[temporal folder, where we create a .x2goclient folder and a sessions inside] pyhoca-cli -P UDS/test-session
|
# HOME=[temporal folder, where we create a .x2goclient folder and a sessions inside] pyhoca-cli -P UDS/test-session
|
||||||
|
@ -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
|
import subprocess
|
||||||
from os.path import expanduser
|
from os.path import expanduser
|
||||||
|
|
||||||
from uds import tools # @UnresolvedImport
|
from uds import tools # type: ignore
|
||||||
|
|
||||||
home = expanduser('~').replace('\\', '\\\\') + '#1;'
|
home = expanduser('~').replace('\\', '\\\\') + '#1;'
|
||||||
keyFile = tools.saveTempFile(sp['key'])
|
keyFile = tools.saveTempFile(sp['key']) # type: ignore
|
||||||
# On windows, the separator beween active and not is "#"
|
# On windows, the separator beween active and not is "#"
|
||||||
theFile = sp['xf'].format(export='c:\\\\#1;', keyFile=keyFile.replace('\\', '/'), ip=sp['ip'], port=sp['port'])
|
theFile = sp['xf'].format(export='c:\\\\#1;', keyFile=keyFile.replace('\\', '/'), ip=sp['ip'], port=sp['port']) # type: ignore
|
||||||
filename = tools.saveTempFile(theFile)
|
filename = tools.saveTempFile(theFile)
|
||||||
|
|
||||||
x2goPath = os.environ['PROGRAMFILES(X86)'] + '\\x2goclient'
|
x2goPath = os.environ['PROGRAMFILES(X86)'] + '\\x2goclient'
|
||||||
|
@ -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 os
|
||||||
import subprocess
|
import subprocess
|
||||||
from uds.forward import forward # @UnresolvedImport
|
from uds.tunnel import forward # type: ignore
|
||||||
from os.path import expanduser
|
from os.path import expanduser
|
||||||
|
|
||||||
from uds import tools # @UnresolvedImport
|
from uds import tools # type: ignore
|
||||||
|
|
||||||
|
# Open tunnel
|
||||||
|
fs = forward(remote=(sp['tunHost'], int(sp['tunPort'])), ticket=sp['ticket'], timeout=sp['tunWait'], check_certificate=sp['tunChk']) # type: ignore
|
||||||
|
|
||||||
forwardThread, port = forward(sp['tunHost'], sp['tunPort'], sp['tunUser'], sp['tunPass'], sp['ip'], sp['port'])
|
# Check that tunnel works..
|
||||||
|
if fs.check() is False:
|
||||||
|
raise Exception('<p>Could not connect to tunnel server.</p><p>Please, check your network settings.</p>')
|
||||||
|
|
||||||
if forwardThread.status == 2:
|
# Care, expanduser is encoding using "mcbs", so treat it as bytes on python 2.7
|
||||||
raise Exception('Unable to open tunnel')
|
|
||||||
|
|
||||||
tools.addTaskToWait(forwardThread)
|
|
||||||
# Care, expanduser is encoding using "mcbs", so treat it as bytes always
|
|
||||||
home = expanduser('~').replace('\\', '\\\\') + '#1;'
|
home = expanduser('~').replace('\\', '\\\\') + '#1;'
|
||||||
keyFile = tools.saveTempFile(sp['key'])
|
keyFile = tools.saveTempFile(sp['key']) # type: ignore
|
||||||
theFile = sp['xf'].format(export=home, keyFile=keyFile.replace('\\', '/'), ip='127.0.0.1', port=port)
|
theFile = sp['xf'].format(export=home, keyFile=keyFile.replace('\\', '/'), ip='127.0.0.1', port=fs.server_address[1]) # type: ignore
|
||||||
filename = tools.saveTempFile(theFile)
|
filename = tools.saveTempFile(theFile)
|
||||||
|
|
||||||
x2goPath = os.environ['PROGRAMFILES(X86)'] + '\\x2goclient'
|
x2goPath = os.environ['PROGRAMFILES(X86)'] + '\\x2goclient'
|
||||||
|
@ -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 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (c) 2016-2019 Virtual Cable S.L.
|
# Copyright (c) 2016-2021 Virtual Cable S.L.U.
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
# Redistribution and use in source and binary forms, with or without modification,
|
# Redistribution and use in source and binary forms, with or without modification,
|
||||||
@ -60,12 +59,43 @@ class TX2GOTransport(BaseX2GOTransport):
|
|||||||
Provides access via X2GO to service.
|
Provides access via X2GO to service.
|
||||||
This transport can use an domain. If username processed by authenticator contains '@', it will split it and left-@-part will be username, and right password
|
This transport can use an domain. If username processed by authenticator contains '@', it will split it and left-@-part will be username, and right password
|
||||||
"""
|
"""
|
||||||
|
|
||||||
typeName = _('X2Go')
|
typeName = _('X2Go')
|
||||||
typeType = 'TX2GOTransport'
|
typeType = 'TX2GOTransport'
|
||||||
typeDescription = _('X2Go access (Experimental). Tunneled connection.')
|
typeDescription = _('X2Go access (Experimental). Tunneled connection.')
|
||||||
group = transports.TUNNELED_GROUP
|
group = transports.TUNNELED_GROUP
|
||||||
|
|
||||||
tunnelServer = gui.TextField(label=_('Tunnel server'), order=1, tooltip=_('IP or Hostname of tunnel server sent to client device ("public" ip) and port. (use HOST:PORT format)'), tab=gui.TUNNEL_TAB)
|
tunnelServer = gui.TextField(
|
||||||
|
label=_('Tunnel server'),
|
||||||
|
order=1,
|
||||||
|
tooltip=_(
|
||||||
|
'IP or Hostname of tunnel server sent to client device ("public" ip) and port. (use HOST:PORT format)'
|
||||||
|
),
|
||||||
|
tab=gui.TUNNEL_TAB,
|
||||||
|
)
|
||||||
|
|
||||||
|
tunnelWait = gui.NumericField(
|
||||||
|
length=3,
|
||||||
|
label=_('Tunnel wait time'),
|
||||||
|
defvalue='30',
|
||||||
|
minValue=5,
|
||||||
|
maxValue=65536,
|
||||||
|
order=2,
|
||||||
|
tooltip=_('Maximum time to wait before closing the tunnel listener'),
|
||||||
|
required=True,
|
||||||
|
tab=gui.TUNNEL_TAB,
|
||||||
|
)
|
||||||
|
|
||||||
|
verifyCertificate = gui.CheckBoxField(
|
||||||
|
label=_('Force SSL certificate verification'),
|
||||||
|
order=23,
|
||||||
|
tooltip=_(
|
||||||
|
'If enabled, the certificate of tunnel server will be verified (recommended).'
|
||||||
|
),
|
||||||
|
defvalue=gui.TRUE,
|
||||||
|
tab=gui.TUNNEL_TAB,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
fixedName = BaseX2GOTransport.fixedName
|
fixedName = BaseX2GOTransport.fixedName
|
||||||
screenSize = BaseX2GOTransport.screenSize
|
screenSize = BaseX2GOTransport.screenSize
|
||||||
@ -83,7 +113,9 @@ class TX2GOTransport(BaseX2GOTransport):
|
|||||||
def initialize(self, values: 'Module.ValuesType'):
|
def initialize(self, values: 'Module.ValuesType'):
|
||||||
if values:
|
if values:
|
||||||
if values['tunnelServer'].count(':') != 1:
|
if values['tunnelServer'].count(':') != 1:
|
||||||
raise BaseX2GOTransport.ValidationException(_('Must use HOST:PORT in Tunnel Server Field'))
|
raise BaseX2GOTransport.ValidationException(
|
||||||
|
_('Must use HOST:PORT in Tunnel Server Field')
|
||||||
|
)
|
||||||
|
|
||||||
def getUDSTransportScript( # pylint: disable=too-many-locals
|
def getUDSTransportScript( # pylint: disable=too-many-locals
|
||||||
self,
|
self,
|
||||||
@ -93,7 +125,7 @@ class TX2GOTransport(BaseX2GOTransport):
|
|||||||
os: typing.Dict[str, str],
|
os: typing.Dict[str, str],
|
||||||
user: 'models.User',
|
user: 'models.User',
|
||||||
password: str,
|
password: str,
|
||||||
request: 'HttpRequest'
|
request: 'HttpRequest',
|
||||||
) -> typing.Tuple[str, str, typing.Dict[str, typing.Any]]:
|
) -> typing.Tuple[str, str, typing.Dict[str, typing.Any]]:
|
||||||
|
|
||||||
ci = self.getConnectionInfo(userService, user, password)
|
ci = self.getConnectionInfo(userService, user, password)
|
||||||
@ -120,13 +152,16 @@ class TX2GOTransport(BaseX2GOTransport):
|
|||||||
rootless=rootless,
|
rootless=rootless,
|
||||||
width=width,
|
width=width,
|
||||||
height=height,
|
height=height,
|
||||||
user=username
|
user=username,
|
||||||
)
|
)
|
||||||
|
|
||||||
tunpass = ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits) for _i in range(12))
|
ticket = TicketStore.create_for_tunnel(
|
||||||
tunuser = TicketStore.create(tunpass)
|
userService=userService,
|
||||||
|
port=22,
|
||||||
|
validity=self.tunnelWait.num() + 60, # Ticket overtime
|
||||||
|
)
|
||||||
|
|
||||||
sshHost, sshPort = self.tunnelServer.value.split(':')
|
tunHost, tunPort = self.tunnelServer.value.split(':')
|
||||||
|
|
||||||
# data
|
# data
|
||||||
data = {
|
data = {
|
||||||
@ -140,7 +175,7 @@ class TX2GOTransport(BaseX2GOTransport):
|
|||||||
'drives': self.exports.isTrue(),
|
'drives': self.exports.isTrue(),
|
||||||
'fullScreen': width == -1 or height == -1,
|
'fullScreen': width == -1 or height == -1,
|
||||||
'this_server': request.build_absolute_uri('/'),
|
'this_server': request.build_absolute_uri('/'),
|
||||||
'xf': xf
|
'xf': xf,
|
||||||
}
|
}
|
||||||
|
|
||||||
m = tools.DictAsObj(data)
|
m = tools.DictAsObj(data)
|
||||||
@ -152,17 +187,18 @@ class TX2GOTransport(BaseX2GOTransport):
|
|||||||
}.get(os['OS'])
|
}.get(os['OS'])
|
||||||
|
|
||||||
if osName is None:
|
if osName is None:
|
||||||
return super().getUDSTransportScript(userService, transport, ip, os, user, password, request)
|
return super().getUDSTransportScript(
|
||||||
|
userService, transport, ip, os, user, password, request
|
||||||
|
)
|
||||||
|
|
||||||
sp = {
|
sp = {
|
||||||
'tunUser': tunuser,
|
'tunHost': tunHost,
|
||||||
'tunPass': tunpass,
|
'tunPort': tunPort,
|
||||||
'tunHost': sshHost,
|
'tunWait': self.tunnelWait.num(),
|
||||||
'tunPort': sshPort,
|
'tunChk': self.verifyCertificate.isTrue(),
|
||||||
'ip': ip,
|
'ticket': ticket,
|
||||||
'port': '22',
|
|
||||||
'key': priv,
|
'key': priv,
|
||||||
'xf': xf
|
'xf': xf,
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.getScript('scripts/{}/tunnel.py', osName, sp)
|
return self.getScript('scripts/{}/tunnel.py', osName, sp)
|
||||||
|
@ -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