mirror of
https://github.com/dkmstr/openuds.git
synced 2025-01-03 01:17:56 +03:00
Making more homogeneous the new window on brower-based transports
This commit is contained in:
parent
fca36ead57
commit
339eeb7967
@ -35,7 +35,7 @@ import time
|
||||
import typing
|
||||
from datetime import datetime
|
||||
|
||||
from . import actor, auth, cache, calendar, images, net, os, system, ticket, rest, services
|
||||
from . import actor, auth, cache, calendar, images, net, os, system, ticket, rest, services, transports
|
||||
|
||||
# Date related constants
|
||||
NEVER: typing.Final[datetime] = datetime(1972, 7, 1)
|
||||
|
36
server/src/uds/core/consts/transports.py
Normal file
36
server/src/uds/core/consts/transports.py
Normal file
@ -0,0 +1,36 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
#
|
||||
# Copyright (c) 2012-2023 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.U. 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
|
||||
|
||||
ON_NEW_WINDOW_VAR: typing.Final[str] = 'o_n_w'
|
||||
ON_SAME_WINDOW_VAR: typing.Final[str] = 'o_s_w'
|
@ -30,23 +30,23 @@
|
||||
"""
|
||||
@author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
"""
|
||||
import sys
|
||||
import codecs
|
||||
import logging
|
||||
import typing
|
||||
import collections.abc
|
||||
import logging
|
||||
import sys
|
||||
import typing
|
||||
|
||||
from django.utils.translation import gettext_noop as _
|
||||
|
||||
from uds.core import types, consts
|
||||
from uds import models
|
||||
from uds.core import consts, types
|
||||
from uds.core.module import Module
|
||||
from uds.core.util import net
|
||||
|
||||
# Not imported at runtime, just for type checking
|
||||
if typing.TYPE_CHECKING:
|
||||
from uds.core.types.requests import ExtendedHttpRequestWithUser
|
||||
from uds.core.environment import Environment
|
||||
from uds import models
|
||||
from uds.core.types.requests import ExtendedHttpRequestWithUser
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -310,3 +310,28 @@ class Transport(Module):
|
||||
If transport provides own link, this method provides the link itself
|
||||
"""
|
||||
return 'https://www.udsenterprise.com'
|
||||
|
||||
def update_link_window(
|
||||
self,
|
||||
link: str,
|
||||
*,
|
||||
on_same_window: bool = False,
|
||||
on_new_window: bool = False,
|
||||
uuid: typing.Optional[str] = None,
|
||||
default_uuid: typing.Optional[str] = None,
|
||||
) -> str:
|
||||
uuid = uuid or self.get_uuid()
|
||||
default_uuid = default_uuid or self.get_uuid()
|
||||
|
||||
amp = '&' if '?' in link else '?'
|
||||
|
||||
if not on_new_window and not on_same_window:
|
||||
return f'{link}{amp}{consts.transports.ON_SAME_WINDOW_VAR}={default_uuid}'
|
||||
|
||||
if on_same_window:
|
||||
return f'{link}{amp}{consts.transports.ON_SAME_WINDOW_VAR}=yes'
|
||||
|
||||
# Must be on new window
|
||||
return f'{link}{amp}{consts.transports.ON_NEW_WINDOW_VAR}={uuid}'
|
||||
|
||||
return link
|
||||
|
@ -112,6 +112,7 @@ class ManagedObjectModel(UUIDModel):
|
||||
|
||||
env = self.get_environment()
|
||||
obj = klass(env, values)
|
||||
obj.set_uuid(self.uuid) # Set the uuid of the object to the one stored in the database
|
||||
self.deserialize(obj, values)
|
||||
|
||||
self._cached_instance = obj
|
||||
|
@ -87,8 +87,6 @@ class Provider(ManagedObjectModel, TaggingMixin):
|
||||
prov: 'ServiceProvider' = typing.cast(
|
||||
'ServiceProvider', super().get_instance(values=values)
|
||||
)
|
||||
# Set uuid
|
||||
prov.set_uuid(self.uuid)
|
||||
return prov
|
||||
|
||||
def is_in_maintenance(self) -> bool:
|
||||
|
File diff suppressed because one or more lines are too long
@ -490,11 +490,11 @@ class HTML5RDPTransport(transports.Transport):
|
||||
|
||||
ticket = models.TicketStore.create(params, validity=self.ticket_validity.as_int())
|
||||
|
||||
onw = f'&o_n_w={transport.uuid}'
|
||||
onw = f'&{consts.transports.ON_NEW_WINDOW_VAR}={transport.uuid}'
|
||||
if self.force_new_window.value == consts.TRUE_STR:
|
||||
onw = f'&o_n_w={userservice.deployed_service.uuid}'
|
||||
onw = f'&{consts.transports.ON_NEW_WINDOW_VAR}={userservice.deployed_service.uuid}'
|
||||
elif self.force_new_window.value == 'overwrite':
|
||||
onw = '&o_s_w=yes'
|
||||
onw = f'&{consts.transports.ON_SAME_WINDOW_VAR}=yes'
|
||||
path = self.custom_glyptodon_path.value if self.use_glyptodon.as_bool() else '/guacamole'
|
||||
# Remove trailing /
|
||||
path = path.rstrip('/')
|
||||
|
@ -70,7 +70,7 @@ class HTML5SSHTransport(transports.Transport):
|
||||
|
||||
tunnel = fields.tunnel_field()
|
||||
|
||||
useGlyptodonTunnel = HTML5RDPTransport.use_glyptodon
|
||||
use_glyptodon = HTML5RDPTransport.use_glyptodon
|
||||
|
||||
username = gui.TextField(
|
||||
label=_('Username'),
|
||||
@ -225,16 +225,14 @@ class HTML5SSHTransport(transports.Transport):
|
||||
scrambler = CryptoManager().random_string(32)
|
||||
ticket = models.TicketStore.create(params, validity=self.ticket_validity.as_int())
|
||||
|
||||
onw = ''
|
||||
if self.force_new_window.value == 'true':
|
||||
onw = 'o_n_w={}'
|
||||
onw = f'&{consts.transports.ON_NEW_WINDOW_VAR}={transport.uuid}'
|
||||
if self.force_new_window.value == consts.TRUE_STR:
|
||||
onw = f'&{consts.transports.ON_NEW_WINDOW_VAR}={userservice.deployed_service.uuid}'
|
||||
elif self.force_new_window.value == 'overwrite':
|
||||
onw = 'o_s_w=yes'
|
||||
onw = onw.format(hash(transport.name))
|
||||
|
||||
path = self.custom_glyptodon_path.value if self.useGlyptodonTunnel.as_bool() else '/guacamole'
|
||||
onw = f'&{consts.transports.ON_SAME_WINDOW_VAR}=yes'
|
||||
path = self.custom_glyptodon_path.value if self.use_glyptodon.as_bool() else '/guacamole'
|
||||
# Remove trailing /
|
||||
path = path.rstrip('/')
|
||||
|
||||
tunnel_server = fields.get_tunnel_from_field(self.tunnel)
|
||||
return str(f'https://{tunnel_server.host}:{tunnel_server.port}{path}/#/?data={ticket}.{scrambler}{onw}')
|
||||
return f'https://{tunnel_server.host}:{tunnel_server.port}{path}/#/?data={ticket}.{scrambler}{onw}'
|
||||
|
@ -197,12 +197,14 @@ class HTML5VNCTransport(transports.Transport):
|
||||
scrambler = CryptoManager().random_string(32)
|
||||
ticket = models.TicketStore.create(params, validity=self.ticket_validity.as_int())
|
||||
|
||||
onw = ''
|
||||
if self.force_new_window.value == 'true':
|
||||
onw = 'o_n_w={}'
|
||||
onw = f'&{consts.transports.ON_NEW_WINDOW_VAR}={transport.uuid}'
|
||||
if self.force_new_window.value == consts.TRUE_STR:
|
||||
onw = f'&{consts.transports.ON_NEW_WINDOW_VAR}={userservice.deployed_service.uuid}'
|
||||
elif self.force_new_window.value == 'overwrite':
|
||||
onw = 'o_s_w=yes'
|
||||
onw = onw.format(hash(transport.name))
|
||||
onw = f'&{consts.transports.ON_SAME_WINDOW_VAR}=yes'
|
||||
path = self.custom_glyptodon_path.value if self.use_glyptodon.as_bool() else '/guacamole'
|
||||
# Remove trailing /
|
||||
path = path.rstrip('/')
|
||||
|
||||
path = self.custom_glyptodon_path.value if self.use_glyptodon.as_bool() else '/guacamole'
|
||||
# Remove trailing /
|
||||
|
@ -84,13 +84,8 @@ class TestTransport(transports.Transport):
|
||||
if not values:
|
||||
return
|
||||
# Strip spaces
|
||||
if not (
|
||||
self.test_url.value.startswith('http://')
|
||||
or self.test_url.value.startswith('https://')
|
||||
):
|
||||
raise exceptions.ui.ValidationError(
|
||||
_('The url must be http or https')
|
||||
)
|
||||
if not (self.test_url.value.startswith('http://') or self.test_url.value.startswith('https://')):
|
||||
raise exceptions.ui.ValidationError(_('The url must be http or https'))
|
||||
|
||||
# Same check as normal RDP transport
|
||||
def is_ip_allowed(self, userservice: 'models.UserService', ip: str) -> bool:
|
||||
@ -112,11 +107,10 @@ class TestTransport(transports.Transport):
|
||||
username: str = user.get_username_for_auth()
|
||||
username, password = userservice.process_user_password(username, password)
|
||||
|
||||
url = self.test_url.value.replace('_IP_', ip).replace('_USER_', username)
|
||||
|
||||
onw = (
|
||||
'&o_n_w={}'.format(hash(transport.name))
|
||||
if self.force_new_window.as_bool()
|
||||
else ''
|
||||
url = self.update_link_window(
|
||||
self.test_url.value.replace('_IP_', ip).replace('_USER_', username),
|
||||
on_same_window=False,
|
||||
on_new_window=self.force_new_window.as_bool(),
|
||||
)
|
||||
return str("{}{}".format(url, onw))
|
||||
|
||||
return url
|
||||
|
@ -72,28 +72,33 @@ class URLCustomTransport(transports.Transport):
|
||||
old_field_name='urlPattern', # Allows compat with old versions
|
||||
)
|
||||
|
||||
force_new_window = gui.CheckBoxField(
|
||||
label=_('Force new HTML Window'),
|
||||
force_new_window = gui.ChoiceField(
|
||||
order=91,
|
||||
tooltip=_(
|
||||
'If checked, every connection will try to open its own window instead of reusing the "global" one.'
|
||||
),
|
||||
default=False,
|
||||
label=_('Force new HTML Window'),
|
||||
tooltip=_('Select windows behavior for opening URL'),
|
||||
required=True,
|
||||
choices=[
|
||||
gui.choice_item(
|
||||
'false',
|
||||
_('Open every connection on the same window, but keeps UDS window.'),
|
||||
),
|
||||
gui.choice_item('true', _('Force every connection to be opened on a new window.')),
|
||||
gui.choice_item(
|
||||
'overwrite',
|
||||
_('Override UDS window and replace it with the connection.'),
|
||||
),
|
||||
],
|
||||
default='true',
|
||||
tab=types.ui.Tab.ADVANCED,
|
||||
old_field_name='forceNewWindow', # Allows compat with old versions
|
||||
old_field_name='forceNewWindow',
|
||||
)
|
||||
|
||||
def initialize(self, values: 'types.core.ValuesType') -> None:
|
||||
if not values:
|
||||
return
|
||||
# Strip spaces
|
||||
if not (
|
||||
self.url_pattern.value.startswith('http://')
|
||||
or self.url_pattern.value.startswith('https://')
|
||||
):
|
||||
raise exceptions.ui.ValidationError(
|
||||
_('The url must be http or https')
|
||||
)
|
||||
if not (self.url_pattern.value.startswith('http://') or self.url_pattern.value.startswith('https://')):
|
||||
raise exceptions.ui.ValidationError(_('The url must be http or https'))
|
||||
|
||||
# Same check as normal RDP transport
|
||||
def is_ip_allowed(self, userservice: 'models.UserService', ip: str) -> bool:
|
||||
@ -115,11 +120,10 @@ class URLCustomTransport(transports.Transport):
|
||||
username: str = user.get_username_for_auth()
|
||||
username, password = userservice.process_user_password(username, password)
|
||||
|
||||
url = self.url_pattern.value.replace('_IP_', ip).replace('_USER_', username)
|
||||
|
||||
onw = (
|
||||
'&o_n_w={}'.format(hash(transport.name))
|
||||
if self.force_new_window.as_bool()
|
||||
else ''
|
||||
return self.update_link_window(
|
||||
self.url_pattern.value.replace('_IP_', ip).replace('_USER_', username),
|
||||
on_same_window=self.force_new_window.value == 'overwrite',
|
||||
on_new_window=self.force_new_window.value == 'true',
|
||||
uuid=userservice.service_pool.uuid if self.force_new_window.value == 'true' else None,
|
||||
default_uuid=userservice.service_pool.uuid,
|
||||
)
|
||||
return str("{}{}".format(url, onw))
|
||||
|
Loading…
Reference in New Issue
Block a user