forked from shaba/openuds
adapting UDS to new tunnel
This commit is contained in:
parent
b830b0ee0a
commit
7a377b0065
@ -91,9 +91,9 @@ class MetaPools(ModelHandler):
|
|||||||
if item.servicesPoolGroup.image is not None:
|
if item.servicesPoolGroup.image is not None:
|
||||||
poolGroupThumb = item.servicesPoolGroup.image.thumb64
|
poolGroupThumb = item.servicesPoolGroup.image.thumb64
|
||||||
|
|
||||||
allPools = item.pools.all()
|
allPools = item.members.all()
|
||||||
userServicesCount = sum((i.userServices.exclude(state__in=State.INFO_STATES).count() for i in allPools))
|
userServicesCount = sum((i.pool.userServices.exclude(state__in=State.INFO_STATES).count() for i in allPools))
|
||||||
userServicesInPreparation = sum((i.userServices.filter(state=State.PREPARING).count()) for i in allPools)
|
userServicesInPreparation = sum((i.pool.userServices.filter(state=State.PREPARING).count()) for i in allPools)
|
||||||
|
|
||||||
val = {
|
val = {
|
||||||
'id': item.uuid,
|
'id': item.uuid,
|
||||||
|
@ -899,7 +899,8 @@ class ModelHandler(BaseModelHandler):
|
|||||||
res = self.item_as_dict(item)
|
res = self.item_as_dict(item)
|
||||||
self.fillIntanceFields(item, res)
|
self.fillIntanceFields(item, res)
|
||||||
yield res
|
yield res
|
||||||
except Exception: # maybe an exception is thrown to skip an item
|
except Exception as e: # maybe an exception is thrown to skip an item
|
||||||
|
logger.debug('Got exception processing item from model: %s', e)
|
||||||
# logger.exception('Exception getting item from {0}'.format(self.model))
|
# logger.exception('Exception getting item from {0}'.format(self.model))
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -185,7 +185,7 @@ class TicketStore(UUIDModel):
|
|||||||
): # Delete only really old tickets. Avoid "revalidate" issues
|
): # Delete only really old tickets. Avoid "revalidate" issues
|
||||||
v.delete()
|
v.delete()
|
||||||
cleanSince = now - datetime.timedelta(seconds=TicketStore.MAX_VALIDITY)
|
cleanSince = now - datetime.timedelta(seconds=TicketStore.MAX_VALIDITY)
|
||||||
# Also remove too long tickets (12 hours is the default)
|
# Also remove too long tickets, even if they are not (12 hours is the default)
|
||||||
TicketStore.objects.filter(stamp__lt=cleanSince).delete()
|
TicketStore.objects.filter(stamp__lt=cleanSince).delete()
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
|
@ -60,6 +60,7 @@ class HTML5RDPTransport(transports.Transport):
|
|||||||
Provides access via RDP to service.
|
Provides access via RDP 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 = _('HTML5 RDP')
|
typeName = _('HTML5 RDP')
|
||||||
typeType = 'HTML5RDPTransport'
|
typeType = 'HTML5RDPTransport'
|
||||||
typeDescription = _('RDP protocol using HTML5 client')
|
typeDescription = _('RDP protocol using HTML5 client')
|
||||||
@ -70,18 +71,110 @@ class HTML5RDPTransport(transports.Transport):
|
|||||||
protocol = transports.protocols.RDP
|
protocol = transports.protocols.RDP
|
||||||
group = transports.TUNNELED_GROUP
|
group = transports.TUNNELED_GROUP
|
||||||
|
|
||||||
guacamoleServer = gui.TextField(label=_('Tunnel Server'), order=1, tooltip=_('Host of the tunnel server (use http/https & port if needed) as accesible from users'), defvalue='https://', length=64, required=True, tab=gui.TUNNEL_TAB)
|
guacamoleServer = gui.TextField(
|
||||||
useEmptyCreds = gui.CheckBoxField(label=_('Empty creds'), order=2, tooltip=_('If checked, the credentials used to connect will be emtpy'), tab=gui.CREDENTIALS_TAB)
|
label=_('Tunnel Server'),
|
||||||
fixedName = gui.TextField(label=_('Username'), order=3, tooltip=_('If not empty, this username will be always used as credential'), tab=gui.CREDENTIALS_TAB)
|
order=1,
|
||||||
fixedPassword = gui.PasswordField(label=_('Password'), order=4, tooltip=_('If not empty, this password will be always used as credential'), tab=gui.CREDENTIALS_TAB)
|
tooltip=_(
|
||||||
withoutDomain = gui.CheckBoxField(label=_('Without Domain'), order=5, tooltip=_('If checked, the domain part will always be emptied (to connecto to xrdp for example is needed)'), tab=gui.CREDENTIALS_TAB)
|
'Host of the tunnel server (use http/https & port if needed) as accesible from users'
|
||||||
fixedDomain = gui.TextField(label=_('Domain'), order=6, tooltip=_('If not empty, this domain will be always used as credential (used as DOMAIN\\user)'), tab=gui.CREDENTIALS_TAB)
|
),
|
||||||
wallpaper = gui.CheckBoxField(label=_('Show wallpaper'), order=20, tooltip=_('If checked, the wallpaper and themes will be shown on machine (better user experience, more bandwidth)'), tab=gui.PARAMETERS_TAB)
|
defvalue='https://',
|
||||||
desktopComp = gui.CheckBoxField(label=_('Allow Desk.Comp.'), order=22, tooltip=_('If checked, desktop composition will be allowed'), tab=gui.PARAMETERS_TAB)
|
length=64,
|
||||||
smooth = gui.CheckBoxField(label=_('Font Smoothing'), order=23, tooltip=_('If checked, fonts smoothing will be allowed (windows clients only)'), tab=gui.PARAMETERS_TAB)
|
required=True,
|
||||||
enableAudio = gui.CheckBoxField(label=_('Enable Audio'), order=24, tooltip=_('If checked, the audio will be redirected to client (if client browser supports it)'), tab=gui.PARAMETERS_TAB)
|
tab=gui.TUNNEL_TAB,
|
||||||
enablePrinting = gui.CheckBoxField(label=_('Enable Printing'), order=25, tooltip=_('If checked, the printing will be redirected to client (if client browser supports it)'), tab=gui.PARAMETERS_TAB)
|
)
|
||||||
enableFileSharing = gui.CheckBoxField(label=_('Enable File Sharing'), order=8, tooltip=_('If checked, the user will be able to upload/download files (if client browser supports it)'), tab=gui.PARAMETERS_TAB)
|
useEmptyCreds = gui.CheckBoxField(
|
||||||
|
label=_('Empty creds'),
|
||||||
|
order=2,
|
||||||
|
tooltip=_('If checked, the credentials used to connect will be emtpy'),
|
||||||
|
tab=gui.CREDENTIALS_TAB,
|
||||||
|
)
|
||||||
|
fixedName = gui.TextField(
|
||||||
|
label=_('Username'),
|
||||||
|
order=3,
|
||||||
|
tooltip=_('If not empty, this username will be always used as credential'),
|
||||||
|
tab=gui.CREDENTIALS_TAB,
|
||||||
|
)
|
||||||
|
fixedPassword = gui.PasswordField(
|
||||||
|
label=_('Password'),
|
||||||
|
order=4,
|
||||||
|
tooltip=_('If not empty, this password will be always used as credential'),
|
||||||
|
tab=gui.CREDENTIALS_TAB,
|
||||||
|
)
|
||||||
|
withoutDomain = gui.CheckBoxField(
|
||||||
|
label=_('Without Domain'),
|
||||||
|
order=5,
|
||||||
|
tooltip=_(
|
||||||
|
'If checked, the domain part will always be emptied (to connecto to xrdp for example is needed)'
|
||||||
|
),
|
||||||
|
tab=gui.CREDENTIALS_TAB,
|
||||||
|
)
|
||||||
|
fixedDomain = gui.TextField(
|
||||||
|
label=_('Domain'),
|
||||||
|
order=6,
|
||||||
|
tooltip=_(
|
||||||
|
'If not empty, this domain will be always used as credential (used as DOMAIN\\user)'
|
||||||
|
),
|
||||||
|
tab=gui.CREDENTIALS_TAB,
|
||||||
|
)
|
||||||
|
wallpaper = gui.CheckBoxField(
|
||||||
|
label=_('Show wallpaper'),
|
||||||
|
order=20,
|
||||||
|
tooltip=_(
|
||||||
|
'If checked, the wallpaper and themes will be shown on machine (better user experience, more bandwidth)'
|
||||||
|
),
|
||||||
|
tab=gui.PARAMETERS_TAB,
|
||||||
|
)
|
||||||
|
desktopComp = gui.CheckBoxField(
|
||||||
|
label=_('Allow Desk.Comp.'),
|
||||||
|
order=22,
|
||||||
|
tooltip=_('If checked, desktop composition will be allowed'),
|
||||||
|
tab=gui.PARAMETERS_TAB,
|
||||||
|
)
|
||||||
|
smooth = gui.CheckBoxField(
|
||||||
|
label=_('Font Smoothing'),
|
||||||
|
order=23,
|
||||||
|
tooltip=_('If checked, fonts smoothing will be allowed (windows clients only)'),
|
||||||
|
tab=gui.PARAMETERS_TAB,
|
||||||
|
)
|
||||||
|
enableAudio = gui.CheckBoxField(
|
||||||
|
label=_('Enable Audio'),
|
||||||
|
order=24,
|
||||||
|
tooltip=_(
|
||||||
|
'If checked, the audio will be redirected to remote session (if client browser supports it)'
|
||||||
|
),
|
||||||
|
tab=gui.PARAMETERS_TAB,
|
||||||
|
defvalue=gui.TRUE,
|
||||||
|
)
|
||||||
|
enableAudioInput = gui.CheckBoxField(
|
||||||
|
label=_('Enable Microphone'),
|
||||||
|
order=24,
|
||||||
|
tooltip=_(
|
||||||
|
'If checked, the microphone will be redirected to remote session (if client browser supports it)'
|
||||||
|
),
|
||||||
|
tab=gui.PARAMETERS_TAB,
|
||||||
|
)
|
||||||
|
enablePrinting = gui.CheckBoxField(
|
||||||
|
label=_('Enable Printing'),
|
||||||
|
order=25,
|
||||||
|
tooltip=_(
|
||||||
|
'If checked, the printing will be redirected to remote session (if client browser supports it)'
|
||||||
|
),
|
||||||
|
tab=gui.PARAMETERS_TAB,
|
||||||
|
)
|
||||||
|
enableFileSharing = gui.ChoiceField(
|
||||||
|
label=_('File Sharing'),
|
||||||
|
order=22,
|
||||||
|
tooltip=_('File upload/download redirection policy'),
|
||||||
|
defvalue='false',
|
||||||
|
values=[
|
||||||
|
{'id': 'false', 'text': 'Disable file sharing'},
|
||||||
|
{'id': 'down', 'text': 'Allow download only'},
|
||||||
|
{'id': 'up', 'text': 'Allow upload only'},
|
||||||
|
{'id': 'true', 'text': 'Enable file sharing'},
|
||||||
|
],
|
||||||
|
tab=gui.PARAMETERS_TAB,
|
||||||
|
)
|
||||||
|
|
||||||
serverLayout = gui.ChoiceField(
|
serverLayout = gui.ChoiceField(
|
||||||
order=26,
|
order=26,
|
||||||
label=_('Layout'),
|
label=_('Layout'),
|
||||||
@ -104,7 +197,7 @@ class HTML5RDPTransport(transports.Transport):
|
|||||||
gui.choiceItem('failsafe', _('Failsafe')),
|
gui.choiceItem('failsafe', _('Failsafe')),
|
||||||
],
|
],
|
||||||
defvalue='-',
|
defvalue='-',
|
||||||
tab=gui.PARAMETERS_TAB
|
tab=gui.PARAMETERS_TAB,
|
||||||
)
|
)
|
||||||
security = gui.ChoiceField(
|
security = gui.ChoiceField(
|
||||||
order=27,
|
order=27,
|
||||||
@ -112,13 +205,29 @@ class HTML5RDPTransport(transports.Transport):
|
|||||||
tooltip=_('Connection security mode for Guacamole RDP connection'),
|
tooltip=_('Connection security mode for Guacamole RDP connection'),
|
||||||
required=True,
|
required=True,
|
||||||
values=[
|
values=[
|
||||||
gui.choiceItem('any', _('Any (Allow the server to choose the type of auth)')),
|
gui.choiceItem(
|
||||||
gui.choiceItem('rdp', _('RDP (Standard RDP encryption. Should be supported by all servers)')),
|
'any', _('Any (Allow the server to choose the type of auth)')
|
||||||
gui.choiceItem('nla', _('NLA (Network Layer authentication. Requires VALID username&password, or connection will fail)')),
|
),
|
||||||
|
gui.choiceItem(
|
||||||
|
'rdp',
|
||||||
|
_('RDP (Standard RDP encryption. Should be supported by all servers)'),
|
||||||
|
),
|
||||||
|
gui.choiceItem(
|
||||||
|
'nla',
|
||||||
|
_(
|
||||||
|
'NLA (Network Layer authentication. Requires VALID username&password, or connection will fail)'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
gui.choiceItem(
|
||||||
|
'nla-ext',
|
||||||
|
_(
|
||||||
|
'NLA extended (Network Layer authentication. Requires VALID username&password, or connection will fail)'
|
||||||
|
),
|
||||||
|
),
|
||||||
gui.choiceItem('tls', _('TLS (Transport Security Layer encryption)')),
|
gui.choiceItem('tls', _('TLS (Transport Security Layer encryption)')),
|
||||||
],
|
],
|
||||||
defvalue='rdp',
|
defvalue='rdp',
|
||||||
tab=gui.PARAMETERS_TAB
|
tab=gui.PARAMETERS_TAB,
|
||||||
)
|
)
|
||||||
|
|
||||||
ticketValidity = gui.NumericField(
|
ticketValidity = gui.NumericField(
|
||||||
@ -126,17 +235,21 @@ class HTML5RDPTransport(transports.Transport):
|
|||||||
label=_('Ticket Validity'),
|
label=_('Ticket Validity'),
|
||||||
defvalue='60',
|
defvalue='60',
|
||||||
order=90,
|
order=90,
|
||||||
tooltip=_('Allowed time, in seconds, for HTML5 client to reload data from UDS Broker. The default value of 60 is recommended.'),
|
tooltip=_(
|
||||||
|
'Allowed time, in seconds, for HTML5 client to reload data from UDS Broker. The default value of 60 is recommended.'
|
||||||
|
),
|
||||||
required=True,
|
required=True,
|
||||||
minValue=60,
|
minValue=60,
|
||||||
tab=gui.ADVANCED_TAB
|
tab=gui.ADVANCED_TAB,
|
||||||
)
|
)
|
||||||
forceNewWindow = gui.CheckBoxField(
|
forceNewWindow = gui.CheckBoxField(
|
||||||
label=_('Force new HTML Window'),
|
label=_('Force new HTML Window'),
|
||||||
order=91,
|
order=91,
|
||||||
tooltip=_('If checked, every connection will try to open its own window instead of reusing the "global" one.'),
|
tooltip=_(
|
||||||
|
'If checked, every connection will try to open its own window instead of reusing the "global" one.'
|
||||||
|
),
|
||||||
defvalue=gui.FALSE,
|
defvalue=gui.FALSE,
|
||||||
tab=gui.ADVANCED_TAB
|
tab=gui.ADVANCED_TAB,
|
||||||
)
|
)
|
||||||
|
|
||||||
def initialize(self, values: 'Module.ValuesType'):
|
def initialize(self, values: 'Module.ValuesType'):
|
||||||
@ -145,9 +258,15 @@ class HTML5RDPTransport(transports.Transport):
|
|||||||
# Strip spaces
|
# Strip spaces
|
||||||
self.guacamoleServer.value = self.guacamoleServer.value.strip()
|
self.guacamoleServer.value = self.guacamoleServer.value.strip()
|
||||||
if self.guacamoleServer.value[0:4] != 'http':
|
if self.guacamoleServer.value[0:4] != 'http':
|
||||||
raise transports.Transport.ValidationException(_('The server must be http or https'))
|
raise transports.Transport.ValidationException(
|
||||||
|
_('The server must be http or https')
|
||||||
|
)
|
||||||
if self.useEmptyCreds.isTrue() and self.security.value != 'rdp':
|
if self.useEmptyCreds.isTrue() and self.security.value != 'rdp':
|
||||||
raise transports.Transport.ValidationException(_('Empty credentials (on Credentials tab) is only allowed with Security level (on Parameters tab) set to "RDP"'))
|
raise transports.Transport.ValidationException(
|
||||||
|
_(
|
||||||
|
'Empty credentials (on Credentials tab) is only allowed with Security level (on Parameters tab) set to "RDP"'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
# Same check as normal RDP transport
|
# Same check as normal RDP transport
|
||||||
def isAvailableFor(self, userService: 'models.UserService', ip: str) -> bool:
|
def isAvailableFor(self, userService: 'models.UserService', ip: str) -> bool:
|
||||||
@ -165,11 +284,15 @@ class HTML5RDPTransport(transports.Transport):
|
|||||||
self.cache.put(ip, 'N', READY_CACHE_TIMEOUT)
|
self.cache.put(ip, 'N', READY_CACHE_TIMEOUT)
|
||||||
return ready == 'Y'
|
return ready == 'Y'
|
||||||
|
|
||||||
def processedUser(self, userService: 'models.UserService', user: 'models.User') -> str:
|
def processedUser(
|
||||||
|
self, userService: 'models.UserService', user: 'models.User'
|
||||||
|
) -> str:
|
||||||
v = self.processUserAndPassword(userService, user, '')
|
v = self.processUserAndPassword(userService, user, '')
|
||||||
return v['username']
|
return v['username']
|
||||||
|
|
||||||
def processUserAndPassword(self, userService: 'models.UserService', user: 'models.User', password: str) -> typing.Dict[str, str]:
|
def processUserAndPassword(
|
||||||
|
self, userService: 'models.UserService', user: 'models.User', password: str
|
||||||
|
) -> typing.Dict[str, str]:
|
||||||
username: str = user.getUsernameForAuth()
|
username: str = user.getUsernameForAuth()
|
||||||
|
|
||||||
if self.fixedName.value != '':
|
if self.fixedName.value != '':
|
||||||
@ -199,20 +322,29 @@ class HTML5RDPTransport(transports.Transport):
|
|||||||
# Fix username/password acording to os manager
|
# Fix username/password acording to os manager
|
||||||
username, password = userService.processUserPassword(username, password)
|
username, password = userService.processUserPassword(username, password)
|
||||||
|
|
||||||
return {'protocol': self.protocol, 'username': username, 'password': password, 'domain': domain}
|
return {
|
||||||
|
'protocol': self.protocol,
|
||||||
|
'username': username,
|
||||||
|
'password': password,
|
||||||
|
'domain': domain,
|
||||||
|
}
|
||||||
|
|
||||||
def getLink( # pylint: disable=too-many-locals
|
def getLink( # pylint: disable=too-many-locals
|
||||||
self,
|
self,
|
||||||
userService: 'models.UserService',
|
userService: 'models.UserService',
|
||||||
transport: 'models.Transport',
|
transport: 'models.Transport',
|
||||||
ip: str,
|
ip: str,
|
||||||
os: typing.Dict[str, str],
|
os: typing.Dict[str, str],
|
||||||
user: 'models.User',
|
user: 'models.User',
|
||||||
password: str,
|
password: str,
|
||||||
request: 'HttpRequest'
|
request: 'HttpRequest',
|
||||||
) -> str:
|
) -> str:
|
||||||
credsInfo = self.processUserAndPassword(userService, user, password)
|
credsInfo = self.processUserAndPassword(userService, user, password)
|
||||||
username, password, domain = credsInfo['username'], credsInfo['password'], credsInfo['domain']
|
username, password, domain = (
|
||||||
|
credsInfo['username'],
|
||||||
|
credsInfo['password'],
|
||||||
|
credsInfo['domain'],
|
||||||
|
)
|
||||||
|
|
||||||
scrambler = cryptoManager().randomString(32)
|
scrambler = cryptoManager().randomString(32)
|
||||||
passwordCrypted = cryptoManager().symCrypt(password, scrambler)
|
passwordCrypted = cryptoManager().symCrypt(password, scrambler)
|
||||||
@ -223,47 +355,58 @@ class HTML5RDPTransport(transports.Transport):
|
|||||||
'hostname': ip,
|
'hostname': ip,
|
||||||
'username': username,
|
'username': username,
|
||||||
'password': passwordCrypted,
|
'password': passwordCrypted,
|
||||||
|
'resize-method': 'display-update',
|
||||||
'ignore-cert': 'true',
|
'ignore-cert': 'true',
|
||||||
'security': self.security.value,
|
'security': self.security.value,
|
||||||
'drive-path': '/share/{}'.format(user.uuid),
|
'drive-path': '/share/{}'.format(user.uuid),
|
||||||
'create-drive-path': 'true'
|
'create-drive-path': 'true',
|
||||||
}
|
}
|
||||||
|
|
||||||
if domain:
|
if domain:
|
||||||
params['domain'] = domain
|
params['domain'] = domain
|
||||||
|
|
||||||
if self.enableFileSharing.isTrue():
|
if self.enableFileSharing.value == 'true':
|
||||||
params['enable-drive'] = 'true'
|
params['enable-drive'] = 'true'
|
||||||
|
elif self.enableFileSharing.value == 'down':
|
||||||
|
params['enable-drive'] = 'true'
|
||||||
|
params['disable-upload'] = 'true'
|
||||||
|
elif self.enableFileSharing.value == 'up':
|
||||||
|
params['enable-drive'] = 'true'
|
||||||
|
params['disable-download'] = 'true'
|
||||||
|
|
||||||
|
|
||||||
if self.serverLayout.value != '-':
|
if self.serverLayout.value != '-':
|
||||||
params['server-layout'] = self.serverLayout.value
|
params['server-layout'] = self.serverLayout.value
|
||||||
|
|
||||||
if self.enableAudio.isTrue() is False:
|
if not self.enableAudio.isTrue():
|
||||||
params['disable-audio'] = 'true'
|
params['disable-audio'] = 'true'
|
||||||
|
elif self.enableAudioInput.isTrue():
|
||||||
|
params['enable-audio-input'] = 'true'
|
||||||
|
|
||||||
if self.enablePrinting.isTrue() is True:
|
if self.enablePrinting.isTrue():
|
||||||
params['enable-printing'] = 'true'
|
params['enable-printing'] = 'true'
|
||||||
params['printer-name'] = 'UDS-Printer'
|
params['printer-name'] = 'UDS-Printer'
|
||||||
|
|
||||||
if self.wallpaper.isTrue() is True:
|
if self.wallpaper.isTrue():
|
||||||
params['enable-wallpaper'] = 'true'
|
params['enable-wallpaper'] = 'true'
|
||||||
|
|
||||||
if self.desktopComp.isTrue() is True:
|
if self.desktopComp.isTrue():
|
||||||
params['enable-desktop-composition'] = 'true'
|
params['enable-desktop-composition'] = 'true'
|
||||||
|
|
||||||
if self.smooth.isTrue() is True:
|
if self.smooth.isTrue():
|
||||||
params['enable-font-smoothing'] = 'true'
|
params['enable-font-smoothing'] = 'true'
|
||||||
|
|
||||||
logger.debug('RDP Params: %s', params)
|
logger.debug('RDP Params: %s', params)
|
||||||
|
|
||||||
ticket = models.TicketStore.create(params, validity=self.ticketValidity.num())
|
ticket = models.TicketStore.create(params, validity=self.ticketValidity.num())
|
||||||
|
|
||||||
onw = 'o_n_w={};'.format(hash(transport.name)) if self.forceNewWindow.isTrue() else ''
|
onw = (
|
||||||
|
'&o_n_w={};'.format(hash(transport.name))
|
||||||
|
if self.forceNewWindow.isTrue()
|
||||||
|
else ''
|
||||||
|
)
|
||||||
return str(
|
return str(
|
||||||
"{}/transport/?{}.{}&{}".format(
|
"{}/guacamole/#/?data={}.{}{}".format(
|
||||||
self.guacamoleServer.value,
|
self.guacamoleServer.value, ticket, scrambler, onw
|
||||||
ticket,
|
|
||||||
scrambler,
|
|
||||||
onw
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -185,9 +185,9 @@ class HTML5VNCTransport(transports.Transport):
|
|||||||
scrambler = cryptoManager().randomString(32)
|
scrambler = cryptoManager().randomString(32)
|
||||||
ticket = models.TicketStore.create(params, validity=self.ticketValidity.num())
|
ticket = models.TicketStore.create(params, validity=self.ticketValidity.num())
|
||||||
|
|
||||||
onw = 'o_n_w={};'.format(hash(transport.name)) if self.forceNewWindow.isTrue() else ''
|
onw = '&o_n_w={};'.format(hash(transport.name)) if self.forceNewWindow.isTrue() else ''
|
||||||
return str(
|
return str(
|
||||||
"{}/transport/?{}.{}&{}".format(
|
"{}/guacamole/#/?data={}.{}{}".format(
|
||||||
self.guacamoleServer.value,
|
self.guacamoleServer.value,
|
||||||
ticket,
|
ticket,
|
||||||
scrambler,
|
scrambler,
|
||||||
|
Loading…
Reference in New Issue
Block a user