Advancing on web part of new no-java version of UDS

This commit is contained in:
Adolfo Gómez García 2015-03-26 14:24:03 +01:00
parent 67393e88db
commit 151623e407
13 changed files with 871 additions and 132 deletions

View File

@ -36,6 +36,12 @@ import sys
from PyQt4 import QtCore, QtGui
import six
from uds.rest import RestRequest
def done(data):
QtGui.QMessageBox.critical(None, 'Notice', six.text_type(data.data), QtGui.QMessageBox.Ok)
sys.exit(0)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
@ -47,16 +53,20 @@ if __name__ == "__main__":
raise Exception()
ssl = uri[3] == 's'
host, ticket, scrambler, trans = uri.split('//')[1].split('/')
host, ticket, scrambler = uri.split('//')[1].split('/')
except Exception:
QtGui.QMessageBox.critical(None, 'Notice', 'This program is designed to be used by UDS', QtGui.QMessageBox.Ok)
sys.exit(1)
QtGui.QMessageBox.critical(None, 'Notice', '{} {} {} {} {}'.format(host, ticket, scrambler, trans, ssl), QtGui.QMessageBox.Ok)
# Build base REST
RestRequest.restApiUrl = '{}://{}/rest/client'.format(['http', 'https'][ssl], host)
sys.exit(1)
v = RestRequest('', done)
v.get()
# sys.exit(1)
# myapp = UDSConfigDialog(cfg)
# myapp.show()
# sys.exit(app.exec_())
sys.exit(app.exec_())

View File

75
client/src/uds/rest.py Normal file
View File

@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2012 Virtual Cable S.L.
# 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 __future__ import unicode_literals
from PyQt4.QtCore import pyqtSignal
from PyQt4.QtCore import QObject, QUrl
from PyQt4.Qt import QString
from PyQt4.QtNetwork import QNetworkAccessManager, QNetworkRequest
class RestRequest(QObject):
restApiUrl = '' #
done = pyqtSignal(QObject)
def __init__(self, url, done): # parent not used
super(RestRequest, self).__init__()
# private
self._manager = QNetworkAccessManager()
self.data = None
self.url = QUrl(RestRequest.restApiUrl + url)
# connect asynchronous result, when a request finishes
self._manager.finished.connect(self._finished)
self.done.connect(done)
# private slot, no need to declare as slot
def _finished(self, reply):
'''
Handle signal 'finished'. A network request has finished.
'''
self.data = reply.readAll()
reply.deleteLater() # schedule for delete from main event loop
self.done.emit(self)
'''
Public API
'''
def get(self):
print self.url
request = QNetworkRequest(self.url)
self._manager.get(request)

View File

@ -36,6 +36,7 @@ from django.utils.translation import ugettext as _
from uds.core.util import log
from uds.core.util.stats import events
from django.core.urlresolvers import reverse
from uds.REST import Handler
from uds.REST import RequestError
from uds.models import TicketStore
@ -51,13 +52,16 @@ import logging
logger = logging.getLogger(__name__)
CLIENT_VERSION = '1.7.0'
MIN_CLIENT_VERSION = '1.7.0'
# Enclosed methods under /actor path
class Client(Handler):
'''
Processes actor requests
'''
authenticated = False # Actor requests are not authenticated
authenticated = False # Client requests are not authenticated
@staticmethod
def result(result=None, error=None):
@ -85,6 +89,10 @@ class Client(Handler):
'''
logger.debug("Client args for GET: {0}".format(self._args))
if len(self._args) == 0:
url = self._request.build_absolute_uri(reverse('ClientDownload'))
return Client.result({'version': CLIENT_VERSION, 'min_version': MIN_CLIENT_VERSION, 'download_url': url})
if len(self._args) != 3:
raise RequestError('Invalid request')

View File

@ -33,6 +33,7 @@
from __future__ import unicode_literals
from django.utils.translation import get_language
from django.core.urlresolvers import reverse
from django.utils import formats
import re
@ -41,14 +42,18 @@ import logging
logger = logging.getLogger(__name__)
def udsLink(request, ticket, scrambler, transport):
def udsLink(request, ticket, scrambler):
if request.is_secure():
proto = 'udss'
else:
proto = 'uds'
return "{}://{}{}/{}/{}".format(proto, request.build_absolute_uri('/').split('//')[1], ticket, scrambler, transport.uuid)
return "{}://{}{}/{}".format(proto, request.build_absolute_uri('/').split('//')[1], ticket, scrambler)
def udsAccessLink(request, serviceId, transportId):
return 'udsa://{}/{}'.format(serviceId, transportId)
def parseDate(dateToParse):

View File

@ -0,0 +1,618 @@
/*!
* jQuery blockUI plugin
* Version 2.66.0-2013.10.09
* Requires jQuery v1.7 or later
*
* Examples at: http://malsup.com/jquery/block/
* Copyright (c) 2007-2013 M. Alsup
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
* Thanks to Amir-Hossein Sobhi for some excellent contributions!
*/
;(function() {
"use strict";
function setup($) {
$.fn._fadeIn = $.fn.fadeIn;
var noOp = $.noop || function() {};
// this bit is to ensure we don't call setExpression when we shouldn't (with extra muscle to handle
// confusing userAgent strings on Vista)
var msie = /MSIE/.test(navigator.userAgent);
var ie6 = /MSIE 6.0/.test(navigator.userAgent) && ! /MSIE 8.0/.test(navigator.userAgent);
var mode = document.documentMode || 0;
var setExpr = $.isFunction( document.createElement('div').style.setExpression );
// global $ methods for blocking/unblocking the entire page
$.blockUI = function(opts) { install(window, opts); };
$.unblockUI = function(opts) { remove(window, opts); };
// convenience method for quick growl-like notifications (http://www.google.com/search?q=growl)
$.growlUI = function(title, message, timeout, onClose) {
var $m = $('<div class="growlUI"></div>');
if (title) $m.append('<h1>'+title+'</h1>');
if (message) $m.append('<h2>'+message+'</h2>');
if (timeout === undefined) timeout = 3000;
// Added by konapun: Set timeout to 30 seconds if this growl is moused over, like normal toast notifications
var callBlock = function(opts) {
opts = opts || {};
$.blockUI({
message: $m,
fadeIn : typeof opts.fadeIn !== 'undefined' ? opts.fadeIn : 700,
fadeOut: typeof opts.fadeOut !== 'undefined' ? opts.fadeOut : 1000,
timeout: typeof opts.timeout !== 'undefined' ? opts.timeout : timeout,
centerY: false,
showOverlay: false,
onUnblock: onClose,
css: $.blockUI.defaults.growlCSS
});
};
callBlock();
var nonmousedOpacity = $m.css('opacity');
$m.mouseover(function() {
callBlock({
fadeIn: 0,
timeout: 30000
});
var displayBlock = $('.blockMsg');
displayBlock.stop(); // cancel fadeout if it has started
displayBlock.fadeTo(300, 1); // make it easier to read the message by removing transparency
}).mouseout(function() {
$('.blockMsg').fadeOut(1000);
});
// End konapun additions
};
// plugin method for blocking element content
$.fn.block = function(opts) {
if ( this[0] === window ) {
$.blockUI( opts );
return this;
}
var fullOpts = $.extend({}, $.blockUI.defaults, opts || {});
this.each(function() {
var $el = $(this);
if (fullOpts.ignoreIfBlocked && $el.data('blockUI.isBlocked'))
return;
$el.unblock({ fadeOut: 0 });
});
return this.each(function() {
if ($.css(this,'position') == 'static') {
this.style.position = 'relative';
$(this).data('blockUI.static', true);
}
this.style.zoom = 1; // force 'hasLayout' in ie
install(this, opts);
});
};
// plugin method for unblocking element content
$.fn.unblock = function(opts) {
if ( this[0] === window ) {
$.unblockUI( opts );
return this;
}
return this.each(function() {
remove(this, opts);
});
};
$.blockUI.version = 2.66; // 2nd generation blocking at no extra cost!
// override these in your code to change the default behavior and style
$.blockUI.defaults = {
// message displayed when blocking (use null for no message)
message: '<h1>Please wait...</h1>',
title: null, // title string; only used when theme == true
draggable: true, // only used when theme == true (requires jquery-ui.js to be loaded)
theme: false, // set to true to use with jQuery UI themes
// styles for the message when blocking; if you wish to disable
// these and use an external stylesheet then do this in your code:
// $.blockUI.defaults.css = {};
css: {
padding: 0,
margin: 0,
width: '30%',
top: '40%',
left: '35%',
textAlign: 'center',
color: '#000',
border: '3px solid #aaa',
backgroundColor:'#fff',
cursor: 'wait'
},
// minimal style set used when themes are used
themedCSS: {
width: '30%',
top: '40%',
left: '35%'
},
// styles for the overlay
overlayCSS: {
backgroundColor: '#000',
opacity: 0.6,
cursor: 'wait'
},
// style to replace wait cursor before unblocking to correct issue
// of lingering wait cursor
cursorReset: 'default',
// styles applied when using $.growlUI
growlCSS: {
width: '350px',
top: '10px',
left: '',
right: '10px',
border: 'none',
padding: '5px',
opacity: 0.6,
cursor: 'default',
color: '#fff',
backgroundColor: '#000',
'-webkit-border-radius':'10px',
'-moz-border-radius': '10px',
'border-radius': '10px'
},
// IE issues: 'about:blank' fails on HTTPS and javascript:false is s-l-o-w
// (hat tip to Jorge H. N. de Vasconcelos)
/*jshint scripturl:true */
iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank',
// force usage of iframe in non-IE browsers (handy for blocking applets)
forceIframe: false,
// z-index for the blocking overlay
baseZ: 1000,
// set these to true to have the message automatically centered
centerX: true, // <-- only effects element blocking (page block controlled via css above)
centerY: true,
// allow body element to be stetched in ie6; this makes blocking look better
// on "short" pages. disable if you wish to prevent changes to the body height
allowBodyStretch: true,
// enable if you want key and mouse events to be disabled for content that is blocked
bindEvents: true,
// be default blockUI will supress tab navigation from leaving blocking content
// (if bindEvents is true)
constrainTabKey: true,
// fadeIn time in millis; set to 0 to disable fadeIn on block
fadeIn: 200,
// fadeOut time in millis; set to 0 to disable fadeOut on unblock
fadeOut: 400,
// time in millis to wait before auto-unblocking; set to 0 to disable auto-unblock
timeout: 0,
// disable if you don't want to show the overlay
showOverlay: true,
// if true, focus will be placed in the first available input field when
// page blocking
focusInput: true,
// elements that can receive focus
focusableElements: ':input:enabled:visible',
// suppresses the use of overlay styles on FF/Linux (due to performance issues with opacity)
// no longer needed in 2012
// applyPlatformOpacityRules: true,
// callback method invoked when fadeIn has completed and blocking message is visible
onBlock: null,
// callback method invoked when unblocking has completed; the callback is
// passed the element that has been unblocked (which is the window object for page
// blocks) and the options that were passed to the unblock call:
// onUnblock(element, options)
onUnblock: null,
// callback method invoked when the overlay area is clicked.
// setting this will turn the cursor to a pointer, otherwise cursor defined in overlayCss will be used.
onOverlayClick: null,
// don't ask; if you really must know: http://groups.google.com/group/jquery-en/browse_thread/thread/36640a8730503595/2f6a79a77a78e493#2f6a79a77a78e493
quirksmodeOffsetHack: 4,
// class name of the message block
blockMsgClass: 'blockMsg',
// if it is already blocked, then ignore it (don't unblock and reblock)
ignoreIfBlocked: false
};
// private data and functions follow...
var pageBlock = null;
var pageBlockEls = [];
function install(el, opts) {
var css, themedCSS;
var full = (el == window);
var msg = (opts && opts.message !== undefined ? opts.message : undefined);
opts = $.extend({}, $.blockUI.defaults, opts || {});
if (opts.ignoreIfBlocked && $(el).data('blockUI.isBlocked'))
return;
opts.overlayCSS = $.extend({}, $.blockUI.defaults.overlayCSS, opts.overlayCSS || {});
css = $.extend({}, $.blockUI.defaults.css, opts.css || {});
if (opts.onOverlayClick)
opts.overlayCSS.cursor = 'pointer';
themedCSS = $.extend({}, $.blockUI.defaults.themedCSS, opts.themedCSS || {});
msg = msg === undefined ? opts.message : msg;
// remove the current block (if there is one)
if (full && pageBlock)
remove(window, {fadeOut:0});
// if an existing element is being used as the blocking content then we capture
// its current place in the DOM (and current display style) so we can restore
// it when we unblock
if (msg && typeof msg != 'string' && (msg.parentNode || msg.jquery)) {
var node = msg.jquery ? msg[0] : msg;
var data = {};
$(el).data('blockUI.history', data);
data.el = node;
data.parent = node.parentNode;
data.display = node.style.display;
data.position = node.style.position;
if (data.parent)
data.parent.removeChild(node);
}
$(el).data('blockUI.onUnblock', opts.onUnblock);
var z = opts.baseZ;
// blockUI uses 3 layers for blocking, for simplicity they are all used on every platform;
// layer1 is the iframe layer which is used to supress bleed through of underlying content
// layer2 is the overlay layer which has opacity and a wait cursor (by default)
// layer3 is the message content that is displayed while blocking
var lyr1, lyr2, lyr3, s;
if (msie || opts.forceIframe)
lyr1 = $('<iframe class="blockUI" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;position:absolute;width:100%;height:100%;top:0;left:0" src="'+opts.iframeSrc+'"></iframe>');
else
lyr1 = $('<div class="blockUI" style="display:none"></div>');
if (opts.theme)
lyr2 = $('<div class="blockUI blockOverlay ui-widget-overlay" style="z-index:'+ (z++) +';display:none"></div>');
else
lyr2 = $('<div class="blockUI blockOverlay" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;width:100%;height:100%;top:0;left:0"></div>');
if (opts.theme && full) {
s = '<div class="blockUI ' + opts.blockMsgClass + ' blockPage ui-dialog ui-widget ui-corner-all" style="z-index:'+(z+10)+';display:none;position:fixed">';
if ( opts.title ) {
s += '<div class="ui-widget-header ui-dialog-titlebar ui-corner-all blockTitle">'+(opts.title || '&nbsp;')+'</div>';
}
s += '<div class="ui-widget-content ui-dialog-content"></div>';
s += '</div>';
}
else if (opts.theme) {
s = '<div class="blockUI ' + opts.blockMsgClass + ' blockElement ui-dialog ui-widget ui-corner-all" style="z-index:'+(z+10)+';display:none;position:absolute">';
if ( opts.title ) {
s += '<div class="ui-widget-header ui-dialog-titlebar ui-corner-all blockTitle">'+(opts.title || '&nbsp;')+'</div>';
}
s += '<div class="ui-widget-content ui-dialog-content"></div>';
s += '</div>';
}
else if (full) {
s = '<div class="blockUI ' + opts.blockMsgClass + ' blockPage" style="z-index:'+(z+10)+';display:none;position:fixed"></div>';
}
else {
s = '<div class="blockUI ' + opts.blockMsgClass + ' blockElement" style="z-index:'+(z+10)+';display:none;position:absolute"></div>';
}
lyr3 = $(s);
// if we have a message, style it
if (msg) {
if (opts.theme) {
lyr3.css(themedCSS);
lyr3.addClass('ui-widget-content');
}
else
lyr3.css(css);
}
// style the overlay
if (!opts.theme /*&& (!opts.applyPlatformOpacityRules)*/)
lyr2.css(opts.overlayCSS);
lyr2.css('position', full ? 'fixed' : 'absolute');
// make iframe layer transparent in IE
if (msie || opts.forceIframe)
lyr1.css('opacity',0.0);
//$([lyr1[0],lyr2[0],lyr3[0]]).appendTo(full ? 'body' : el);
var layers = [lyr1,lyr2,lyr3], $par = full ? $('body') : $(el);
$.each(layers, function() {
this.appendTo($par);
});
if (opts.theme && opts.draggable && $.fn.draggable) {
lyr3.draggable({
handle: '.ui-dialog-titlebar',
cancel: 'li'
});
}
// ie7 must use absolute positioning in quirks mode and to account for activex issues (when scrolling)
var expr = setExpr && (!$.support.boxModel || $('object,embed', full ? null : el).length > 0);
if (ie6 || expr) {
// give body 100% height
if (full && opts.allowBodyStretch && $.support.boxModel)
$('html,body').css('height','100%');
// fix ie6 issue when blocked element has a border width
if ((ie6 || !$.support.boxModel) && !full) {
var t = sz(el,'borderTopWidth'), l = sz(el,'borderLeftWidth');
var fixT = t ? '(0 - '+t+')' : 0;
var fixL = l ? '(0 - '+l+')' : 0;
}
// simulate fixed position
$.each(layers, function(i,o) {
var s = o[0].style;
s.position = 'absolute';
if (i < 2) {
if (full)
s.setExpression('height','Math.max(document.body.scrollHeight, document.body.offsetHeight) - (jQuery.support.boxModel?0:'+opts.quirksmodeOffsetHack+') + "px"');
else
s.setExpression('height','this.parentNode.offsetHeight + "px"');
if (full)
s.setExpression('width','jQuery.support.boxModel && document.documentElement.clientWidth || document.body.clientWidth + "px"');
else
s.setExpression('width','this.parentNode.offsetWidth + "px"');
if (fixL) s.setExpression('left', fixL);
if (fixT) s.setExpression('top', fixT);
}
else if (opts.centerY) {
if (full) s.setExpression('top','(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"');
s.marginTop = 0;
}
else if (!opts.centerY && full) {
var top = (opts.css && opts.css.top) ? parseInt(opts.css.top, 10) : 0;
var expression = '((document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + '+top+') + "px"';
s.setExpression('top',expression);
}
});
}
// show the message
if (msg) {
if (opts.theme)
lyr3.find('.ui-widget-content').append(msg);
else
lyr3.append(msg);
if (msg.jquery || msg.nodeType)
$(msg).show();
}
if ((msie || opts.forceIframe) && opts.showOverlay)
lyr1.show(); // opacity is zero
if (opts.fadeIn) {
var cb = opts.onBlock ? opts.onBlock : noOp;
var cb1 = (opts.showOverlay && !msg) ? cb : noOp;
var cb2 = msg ? cb : noOp;
if (opts.showOverlay)
lyr2._fadeIn(opts.fadeIn, cb1);
if (msg)
lyr3._fadeIn(opts.fadeIn, cb2);
}
else {
if (opts.showOverlay)
lyr2.show();
if (msg)
lyr3.show();
if (opts.onBlock)
opts.onBlock();
}
// bind key and mouse events
bind(1, el, opts);
if (full) {
pageBlock = lyr3[0];
pageBlockEls = $(opts.focusableElements,pageBlock);
if (opts.focusInput)
setTimeout(focus, 20);
}
else
center(lyr3[0], opts.centerX, opts.centerY);
if (opts.timeout) {
// auto-unblock
var to = setTimeout(function() {
if (full)
$.unblockUI(opts);
else
$(el).unblock(opts);
}, opts.timeout);
$(el).data('blockUI.timeout', to);
}
}
// remove the block
function remove(el, opts) {
var count;
var full = (el == window);
var $el = $(el);
var data = $el.data('blockUI.history');
var to = $el.data('blockUI.timeout');
if (to) {
clearTimeout(to);
$el.removeData('blockUI.timeout');
}
opts = $.extend({}, $.blockUI.defaults, opts || {});
bind(0, el, opts); // unbind events
if (opts.onUnblock === null) {
opts.onUnblock = $el.data('blockUI.onUnblock');
$el.removeData('blockUI.onUnblock');
}
var els;
if (full) // crazy selector to handle odd field errors in ie6/7
els = $('body').children().filter('.blockUI').add('body > .blockUI');
else
els = $el.find('>.blockUI');
// fix cursor issue
if ( opts.cursorReset ) {
if ( els.length > 1 )
els[1].style.cursor = opts.cursorReset;
if ( els.length > 2 )
els[2].style.cursor = opts.cursorReset;
}
if (full)
pageBlock = pageBlockEls = null;
if (opts.fadeOut) {
count = els.length;
els.stop().fadeOut(opts.fadeOut, function() {
if ( --count === 0)
reset(els,data,opts,el);
});
}
else
reset(els, data, opts, el);
}
// move blocking element back into the DOM where it started
function reset(els,data,opts,el) {
var $el = $(el);
if ( $el.data('blockUI.isBlocked') )
return;
els.each(function(i,o) {
// remove via DOM calls so we don't lose event handlers
if (this.parentNode)
this.parentNode.removeChild(this);
});
if (data && data.el) {
data.el.style.display = data.display;
data.el.style.position = data.position;
if (data.parent)
data.parent.appendChild(data.el);
$el.removeData('blockUI.history');
}
if ($el.data('blockUI.static')) {
$el.css('position', 'static'); // #22
}
if (typeof opts.onUnblock == 'function')
opts.onUnblock(el,opts);
// fix issue in Safari 6 where block artifacts remain until reflow
var body = $(document.body), w = body.width(), cssW = body[0].style.width;
body.width(w-1).width(w);
body[0].style.width = cssW;
}
// bind/unbind the handler
function bind(b, el, opts) {
var full = el == window, $el = $(el);
// don't bother unbinding if there is nothing to unbind
if (!b && (full && !pageBlock || !full && !$el.data('blockUI.isBlocked')))
return;
$el.data('blockUI.isBlocked', b);
// don't bind events when overlay is not in use or if bindEvents is false
if (!full || !opts.bindEvents || (b && !opts.showOverlay))
return;
// bind anchors and inputs for mouse and key events
var events = 'mousedown mouseup keydown keypress keyup touchstart touchend touchmove';
if (b)
$(document).bind(events, opts, handler);
else
$(document).unbind(events, handler);
// former impl...
// var $e = $('a,:input');
// b ? $e.bind(events, opts, handler) : $e.unbind(events, handler);
}
// event handler to suppress keyboard/mouse events when blocking
function handler(e) {
// allow tab navigation (conditionally)
if (e.type === 'keydown' && e.keyCode && e.keyCode == 9) {
if (pageBlock && e.data.constrainTabKey) {
var els = pageBlockEls;
var fwd = !e.shiftKey && e.target === els[els.length-1];
var back = e.shiftKey && e.target === els[0];
if (fwd || back) {
setTimeout(function(){focus(back);},10);
return false;
}
}
}
var opts = e.data;
var target = $(e.target);
if (target.hasClass('blockOverlay') && opts.onOverlayClick)
opts.onOverlayClick(e);
// allow events within the message content
if (target.parents('div.' + opts.blockMsgClass).length > 0)
return true;
// allow events for content that is not being blocked
return target.parents().children().filter('div.blockUI').length === 0;
}
function focus(back) {
if (!pageBlockEls)
return;
var e = pageBlockEls[back===true ? pageBlockEls.length-1 : 0];
if (e)
e.focus();
}
function center(el, x, y) {
var p = el.parentNode, s = el.style;
var l = ((p.offsetWidth - el.offsetWidth)/2) - sz(p,'borderLeftWidth');
var t = ((p.offsetHeight - el.offsetHeight)/2) - sz(p,'borderTopWidth');
if (x) s.left = l > 0 ? (l+'px') : '0';
if (y) s.top = t > 0 ? (t+'px') : '0';
}
function sz(el, p) {
return parseInt($.css(el,p),10)||0;
}
}
/*global define:true */
if (typeof define === 'function' && define.amd && define.amd.jQuery) {
define(['jquery'], setup);
} else {
setup(jQuery);
}
})();

View File

@ -25,6 +25,16 @@ uds.firefox = false
)()
blockUI = (message) ->
message = message or "<h1><span class=\"fa fa-spinner fa-spin\"></span> " + gettext("Just a moment...") + "</h1>"
$.blockUI
message: message
return
unblockUI = ->
$.unblockUI()
return
#Default State
isSupported = false
@ -96,7 +106,6 @@ launchIE = (el, url, alt) ->
return
#Handle Firefox
launchMozilla = (el, url, alt) ->
if $('#hiddenUdsLauncherIFrame').length is 0
$('body').append('<iframe id="hiddenUdsLauncherIFrame" src="about:blank" style="display:none"></iframe>')
@ -115,7 +124,6 @@ launchMozilla = (el, url, alt) ->
return
#Handle Chrome
launchChrome = (el, url, alt) ->
isSupported = false
el.focus()
@ -137,6 +145,7 @@ launchChrome = (el, url, alt) ->
), 800
return
# Handle safari
launchSafari = (el, url, alt) ->
if $('#hiddenUdsLauncherIFrame').length is 0
$('body').append('<iframe id="hiddenUdsLauncherIFrame" src="about:blank" style="display:none"></iframe>')
@ -154,7 +163,7 @@ launchSafari = (el, url, alt) ->
setTimeout (->
window.onblur = null
result(alt)
), 800
), 1800
uds.launch = (el) ->
@ -162,6 +171,27 @@ uds.launch = (el) ->
url = if url? then url else el.attr('href')
alt = el.attr('data-href-alt')
blockUI()
# First get using REST the ticket for client
url = clientRest + '/' + url.split('//')[1]
$.ajax
url: url
type: "GET"
dataType: "json"
success: (data) ->
unblockUI()
alert data
return
error: (jqXHR, textStatus, errorThrown) ->
unblockUI()
alert gettext('Error accessing service: ') + textStatus
return
return
if uds.firefox
launchMozilla el, url, alt
else if uds.chrome

View File

@ -201,7 +201,7 @@
url = el.attr('data-href');
url = url != null ? url : el.attr('href');
if ( url.substring(0, 3) == 'uds' ) {
if ( url.substring(0, 7) == 'udsa://' ) {
uds.launch(el);
} else {
window.location = url;
@ -225,7 +225,7 @@
url = el.attr('data-href');
url = url != null ? url : el.attr('href');
if ( url.substring(0, 3) == 'uds' ) {
if ( url.substring(0, 7) == 'udsa://' ) {
uds.launch(el);
} else {
window.location = url;

View File

@ -87,9 +87,11 @@
<script src="{% get_static_prefix %}js/jquery-1.10.2.min.js"></script>
<script src="{% get_static_prefix %}js/jquery-ui.min.js"></script>
<script src="{% get_static_prefix %}js/jquery.cookie.js"></script>
<script src="{% get_static_prefix %}js/jquery.blockUI.js"></script>
<script src="{% get_static_prefix %}js/bootstrap.min.js"></script>
<script src="{% get_static_prefix %}js/bootstrap-switch.min.js"></script>
<script src="{% get_static_prefix %}js/bootstrap-select.min.js"></script>
<script>var clientRest = "/" + "{% url 'ClientAccessEnabler' 'x' 'x' %}".split("/")[1];</script>
<script type="text/coffeescript" charset="utf-8" src="{% get_static_prefix %}js/uds-client.coffee"></script>
<script>

View File

@ -64,11 +64,13 @@ urlpatterns = patterns(
(r'^prefs$', 'web.views.prefs'),
# Change Language
(r'^i18n/', include('django.conf.urls.i18n')),
# Downloadables
# Downloads
(r'^idown/(?P<idDownload>[a-zA-Z0-9-]*)$', 'web.views.download'),
# for client
(r'^down$', 'web.views.client_downloads'),
# downloads for client
url(r'^down$', 'web.views.client_downloads', name='ClientDownload'),
(r'^down/(?P<os>[a-zA-Z0-9-]*)$', 'web.views.client_downloads'),
# Client access enabler
url(r'^enable/(?P<idService>.+)/(?P<idTransport>.+)$', 'web.views.clientEnabler', name='ClientAccessEnabler'),
# Custom authentication callback
(r'^auth/(?P<authName>.+)', 'web.views.authCallback'),

View File

@ -30,7 +30,7 @@
'''
from __future__ import unicode_literals
__updated__ = '2015-03-23'
__updated__ = '2015-03-26'
import logging
@ -39,7 +39,7 @@ logger = logging.getLogger(__name__)
from .login import login, logout, customAuth
from .index import index, about
from .prefs import prefs
from .service import service, trans, transcomp, sernotify, transportIcon, serviceImage
from .service import service, trans, transcomp, sernotify, transportIcon, serviceImage, clientEnabler
from .auth import authCallback, authInfo, authJava, ticketAuth
from .download import download
from .client_download import client_downloads

View File

@ -30,7 +30,7 @@
'''
from __future__ import unicode_literals
__updated__ = '2015-03-23'
__updated__ = '2015-03-26'
from django.shortcuts import render_to_response
from django.shortcuts import render
@ -72,14 +72,6 @@ def index(request):
# Session data
os = request.os
scrambler = cryptoManager().randomString(32)
password = cryptoManager().xor(webPassword(request), scrambler)
if request.is_secure():
proto = 'udss'
else:
proto = 'uds'
# We look for services for this authenticator groups. User is logged in in just 1 authenticator, so his groups must coincide with those assigned to ds
groups = list(request.user.getGroups())
availServices = DeployedService.getDeployedServicesForGroups(groups)
@ -103,24 +95,14 @@ def index(request):
services = []
# Select assigned user services
for svr in availUserServices:
# Generate ticket
data = {
'type': 'A',
'service': svr.uuid,
'user': request.user.uuid,
'password': password
}
ticket = TicketStore.create(data)
trans = []
for t in svr.transports.all().order_by('priority'):
typeTrans = t.getType()
if t.validForIp(request.ip) and typeTrans.supportsOs(os['OS']):
if typeTrans.ownLink is True:
link = reverse('TransportOwnLink', args=('A' + svr.uuid, trans.uuid))
link = reverse('TransportOwnLink', args=('A' + svr.uuid, t.uuid))
else:
link = html.udsLink(request, ticket, scrambler, t)
link = html.udsAccessLink(request, 'A' + svr.uuid, t.uuid)
trans.append(
{
'id': t.uuid,
@ -148,14 +130,6 @@ def index(request):
# Now generic user service
for svr in availServices:
# Generate ticket
data = {
'type': 'F',
'service': svr.uuid,
'user': request.user.uuid,
'password': password
}
ticket = TicketStore.create(data)
trans = []
for t in svr.transports.all().order_by('priority'):
@ -164,7 +138,7 @@ def index(request):
if typeTrans.ownLink is True:
link = reverse('TransportOwnLink', args=('F' + svr.uuid, t.uuid))
else:
link = html.udsLink(request, ticket, scrambler, t)
link = html.udsAccessLink(request, 'F' + svr.uuid, t.uuid)
trans.append(
{
'id': t.uuid,
@ -211,8 +185,6 @@ def index(request):
'ip': request.ip,
'nets': nets,
'transports': validTrans,
'host': proto + '://' + request.build_absolute_uri('/').split('//')[1],
'scrambler': scrambler,
},
context_instance=RequestContext(request)
)

View File

@ -30,16 +30,18 @@
'''
from __future__ import unicode_literals
__updated__ = '2015-03-23'
__updated__ = '2015-03-26'
from django.utils.translation import ugettext as _
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.views.decorators.cache import cache_page
from django.views.decorators.cache import cache_page, never_cache
from uds.core.auths.auth import webLoginRequired, webPassword
from uds.core.services.Exceptions import ServiceInMaintenanceMode
from uds.core.managers.UserServiceManager import UserServiceManager
from uds.models import TicketStore
from uds.core.ui.images import DEFAULT_IMAGE
from uds.core.ui import theme
from uds.core.util.Config import GlobalConfig
@ -47,9 +49,12 @@ from uds.core.util.stats import events
from uds.core.util import log
from uds.core.util import OsDetector
from uds.models import DeployedService, Transport, UserService, Image
from uds.core.util import html
import uds.web.errors as errors
from uds.core.managers import cryptoManager
import six
import logging
logger = logging.getLogger(__name__)
@ -57,103 +62,81 @@ logger = logging.getLogger(__name__)
__updated__ = '2015-02-22'
def getService(request, idService, idTransport):
kind, idService = idService[0], idService[1:]
logger.debug('Kind of service: {0}, idService: {1}'.format(kind, idService))
if kind == 'A': # This is an assigned service
logger.debug('Getting A service {}'.format(idService))
ads = UserService.objects.get(uuid=idService)
else:
ds = DeployedService.objects.get(uuid=idService)
# We first do a sanity check for this, if the user has access to this service
# If it fails, will raise an exception
ds.validateUser(request.user)
# Now we have to locate an instance of the service, so we can assign it to user.
ads = UserServiceManager.manager().getAssignationForUser(ds, request.user)
if ads.isInMaintenance() is True:
raise ServiceInMaintenanceMode()
logger.debug('Found service: {0}'.format(ads))
trans = Transport.objects.get(uuid=idTransport)
# Test if the service is ready
if ads.isReady():
log.doLog(ads, log.INFO, "User {0} from {1} has initiated access".format(request.user.name, request.ip), log.WEB)
# If ready, show transport for this service, if also ready ofc
iads = ads.getInstance()
ip = iads.getIp()
events.addEvent(ads.deployed_service, events.ET_ACCESS, username=request.user.name, srcip=request.ip, dstip=ip, uniqueid=ads.unique_id)
if ip is not None:
itrans = trans.getInstance()
if itrans.isAvailableFor(ip):
ads.setConnectionSource(request.ip, 'unknown')
log.doLog(ads, log.INFO, "User service ready", log.WEB)
UserServiceManager.manager().notifyPreconnect(ads, itrans.processedUser(ads, request.user), itrans.protocol)
return (ip, ads, iads, trans, itrans)
else:
log.doLog(ads, log.WARN, "User service is not accessible (ip {0})".format(ip), log.TRANSPORT)
logger.debug('Transport is not ready for user service {0}'.format(ads))
else:
logger.debug('Ip not available from user service {0}'.format(ads))
else:
log.doLog(ads, log.WARN, "User {0} from {1} tried to access, but machine was not ready".format(request.user.name, request.ip), log.WEB)
return None
@webLoginRequired(admin=False)
def service(request, idService, idTransport):
kind, idService = idService[0], idService[1:]
try:
logger.debug('Kind of service: {0}, idService: {1}'.format(kind, idService))
if kind == 'A': # This is an assigned service
ads = UserService.objects.get(uuid=idService)
else:
ds = DeployedService.objects.get(uuid=idService)
# We first do a sanity check for this, if the user has access to this service
# If it fails, will raise an exception
ds.validateUser(request.user)
# Now we have to locate an instance of the service, so we can assign it to user.
ads = UserServiceManager.manager().getAssignationForUser(ds, request.user)
res = getService(request, idService, idTransport)
if res is not None:
ip, ads, iads, trans, itrans = res
if ads.isInMaintenance() is True:
raise ServiceInMaintenanceMode()
logger.debug('Found service: {0}'.format(ads))
trans = Transport.objects.get(uuid=idTransport)
# Test if the service is ready
if ads.isReady():
log.doLog(ads, log.INFO, "User {0} from {1} has initiated access".format(request.user.name, request.ip), log.WEB)
# If ready, show transport for this service, if also ready ofc
iads = ads.getInstance()
ip = iads.getIp()
events.addEvent(ads.deployed_service, events.ET_ACCESS, username=request.user.name, srcip=request.ip, dstip=ip, uniqueid=ads.unique_id)
if ip is not None:
itrans = trans.getInstance()
if itrans.isAvailableFor(ip):
ads.setConnectionSource(request.ip, 'unknown')
log.doLog(ads, log.INFO, "User service ready, rendering transport", log.WEB)
transportHtml = itrans.renderAsHtml(ads, trans, ip, request)
UserServiceManager.manager().notifyPreconnect(ads, itrans.processedUser(ads, request.user), itrans.protocol)
return render_to_response(theme.template('show_transport.html'), {'transport': transportHtml, 'nolang': True}, context_instance=RequestContext(request))
else:
log.doLog(ads, log.WARN, "User service is not accessible (ip {0})".format(ip), log.TRANSPORT)
logger.debug('Transport is not ready for user service {0}'.format(ads))
else:
logger.debug('Ip not available from user service {0}'.format(ads))
else:
log.doLog(ads, log.WARN, "User {0} from {1} tried to access, but machine was not ready".format(request.user.name, request.ip), log.WEB)
# Not ready, show message and return to this page in a while
return render_to_response(theme.template('service_not_ready.html'), context_instance=RequestContext(request))
transportHtml = itrans.renderAsHtml(ads, trans, ip, request)
return render_to_response(theme.template('show_transport.html'), {'transport': transportHtml, 'nolang': True}, context_instance=RequestContext(request))
except Exception, e:
logger.exception("Exception")
return errors.exceptionView(request, e)
# Not ready, show message and return to this page in a while
return render_to_response(theme.template('service_not_ready.html'), context_instance=RequestContext(request))
@webLoginRequired(admin=False)
def trans(request, idService, idTransport):
kind, idService = idService[0], idService[1:]
try:
logger.debug('Kind of service: {0}, idService: {1}'.format(kind, idService))
if kind == 'A': # This is an assigned service
ads = UserService.objects.get(uuid=idService)
else:
ds = DeployedService.objects.get(uuid=idService)
# We first do a sanity check for this, if the user has access to this service
# If it fails, will raise an exception
ds.validateUser(request.user)
# Now we have to locate an instance of the service, so we can assign it to user.
ads = UserServiceManager.manager().getAssignationForUser(ds, request.user)
if ads.isInMaintenance() is True:
raise ServiceInMaintenanceMode()
logger.debug('Found service: {0}'.format(ads))
trans = Transport.objects.get(uuid=idTransport)
# Test if the service is ready
if ads.isReady():
log.doLog(ads, log.INFO, "User {0} from {1} has initiated access".format(request.user.name, request.ip), log.WEB)
# If ready, show transport for this service, if also ready ofc
iads = ads.getInstance()
ip = iads.getIp()
events.addEvent(ads.deployed_service, events.ET_ACCESS, username=request.user.name, srcip=request.ip, dstip=ip, uniqueid=ads.unique_id)
if ip is not None:
itrans = trans.getInstance()
if itrans.isAvailableFor(ip):
ads.setConnectionSource(request.ip, 'unknown')
log.doLog(ads, log.INFO, "User service ready, rendering transport", log.WEB)
UserServiceManager.manager().notifyPreconnect(ads, itrans.processedUser(ads, request.user), itrans.protocol)
return itrans.getLink(ads, trans, ip, request.os, request.user, webPassword(request), request)
else:
log.doLog(ads, log.WARN, "User service is not accessible (ip {0})".format(ip), log.TRANSPORT)
logger.debug('Transport is not ready for user service {0}'.format(ads))
else:
logger.debug('Ip not available from user service {0}'.format(ads))
else:
log.doLog(ads, log.WARN, "User {0} from {1} tried to access, but machine was not ready".format(request.user.name, request.ip), log.WEB)
# Not ready, show message and return to this page in a while
return render_to_response(theme.template('service_not_ready.html'), context_instance=RequestContext(request))
res = getService(request, idService, idTransport)
if res is not None:
ip, ads, iads, trans, itrans = res
return itrans.getLink(ads, trans, ip, request.os, request.user, webPassword(request), request)
except Exception, e:
logger.exception("Exception")
return errors.exceptionView(request, e)
return render_to_response(theme.template('service_not_ready.html'), context_instance=RequestContext(request))
@webLoginRequired(admin=False)
def transcomp(request, idTransport, componentId):
@ -219,3 +202,37 @@ def serviceImage(request, idImage):
return HttpResponse(icon, content_type='image/png')
except Exception:
return HttpResponse(DEFAULT_IMAGE, content_type='image/png')
@webLoginRequired(admin=False)
@never_cache
def clientEnabler(request, idService, idTransport):
# Maybe we could even protect this even more by limiting referer to own server /? (just a meditation..)
response = ''
error = _('Service not ready. Please, try again in a while.')
try:
res = getService(request, idService, idTransport)
if res is not None:
scrambler = cryptoManager().randomString(32)
password = cryptoManager().xor(webPassword(request), scrambler)
ip, ads, iads, trans, itrans = res
data = {
'service': ads.uuid,
'transport': trans.uuid,
'user': request.user.uuid,
'password': password
}
ticket = TicketStore.create(data)
error = ''
response = html.udsLink(request, ticket, scrambler)
except Exception as e:
error = six.text_type(e)
# Not ready, show message and return to this page in a while
return HttpResponse('{{ "response": "{}", "error": "{}" }}'.format(response, error), content_type='application/json')