I'm using the apache guacamole-common-js library to allow rdp access to VMs within my web application via Apache Guacamole. I have an instance of guacamole and the client up and running on a server and I'm attempting to connect to tunnel to my instance via web sockets. I can see from the developer tools and server side logs that the web socket connection is working and that commands are being passed b/t my web application and the server, however the UI is never displayed.
I'm following all the examples I've been able to find, to no avail. I am testing this locally with a connection to the server, so it is a cross domain scenario, however as I mentioned the traffic b/t client and server appears to be working as expected. It's simply not rendering anything visually. When I look at the DOM, I can see elements injected that represent the guacamole client display elements. My code is as follows:
<!DOCTYPE HTML>
<html>
<head>
<link rel="stylesheet" type="text/css" href="guacamole.css">
<title>Guacamole (EXAMPLE)</title>
</head>
<body>
<!-- Display -->
<div id="display" style="background-color: #f0f0f0; height: 500px; width: 500px;"></div>
<!-- Guacamole JavaScript API -->
<script type="text/javascript" src="https://myserver.com/guacamole-common-js/all.min.js"></script>
<!-- Init -->
<script type="text/javascript"> /* <![CDATA[ */
// Get display div from document
var display = document.getElementById("display");
var wsFullUrl = "wss://myserver.com/websocket-tunnel?token=CB3A548656A5A0F5470AD0A51BE79883B864A4FF8B0308F87F53F8FBC49BA74F&GUAC_DATA_SOURCE=mysql&GUAC_ID=3&GUAC_TYPE=c&GUAC_WIDTH=500&GUAC_HEIGHT=500&GUAC_DPI=192&GUAC_TIMEZONE=America/Chicago&GUAC_AUDIO=audio/L8&GUAC_AUDIO=audio/L16&GUAC_IMAGE=image/jpeg&GUAC_IMAGE=image/png&GUAC_IMAGE=image/webp";
// Instantiate client, using an HTTP tunnel for communications.
var guac = new Guacamole.Client(
new Guacamole.WebSocketTunnel(wsFullUrl)
);
var element = guac.getDisplay().getElement();
// Add client to display div
display.appendChild(element);
// Error handler
guac.onerror = function (error) {
alert(error);
};
// Connect
guac.connect();
// Disconnect on close
window.onunload = function () {
guac.disconnect();
}
// Mouse
var mouse = new Guacamole.Mouse(guac.getDisplay().getElement());
mouse.onEach(['mousedown', 'mouseup', 'mousemove'], function sendMouseEvent(e) {
guac.sendMouseState(e.state);
});
// Keyboard
var keyboard = new Guacamole.Keyboard(document);
keyboard.onkeydown = function (keysym) {
guac.sendKeyEvent(1, keysym);
};
keyboard.onkeyup = function (keysym) {
guac.sendKeyEvent(0, keysym);
};
/* ]]> */</script>
</body>
</html>
Any insight anyone might have would be much appreciated!
I just started working on my school assignment with some regular expressions in Javascript. I can't seem to figure out how to actually read data from a text file into variable using jQuery method .get(). When I try my code out nothing happens. It seems like it never enters .get() section. Here is my code:
JS file:
document.getElementById('file').onchange = function(){
var file = "New Text Document.txt"; //this will later be the selected file
$.get(file,function(data){
var myVar = data;
$("#123").html(myVar);
});
};
HTML file:
<!DOCTYPE html>
<html>
<head>
<title>animacija</title>
<meta charset="UTF-8">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
</head>
<body>
<input type="file" name="file" id="file">
<script type="text/javascript" src="func.js"></script>
<div id="123"></div>
</body>
</html>
The code snippet seems to be ok, but it will not work locally since $.get is for ajax requests and requires full available server path.
I rather recommend you the use of FileReader API.
HTML
<title>animacija</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<body>
<input type="file" name="file" id="file">
<div id="123"></div>
</body>
JavaScript
document.getElementById('file').onchange = function() {
var file = this.files[0];
var FR = new FileReader();
FR.readAsText(file);
FR.onload = function(data) {
var myVar = data.target.result;
$("#123").html(myVar);
}
};
JSFiddle
Hope it works for you!
Most browsers will not allow file: resources to read other local files. This is to prevent attacks where a downloaded HTML document could start reading (and transmitting) the contents of your hard drive (or at least your Downloads folder) as soon as you open it.
The other thing you need to know here is that $.get is used for getting resources from an HTTP server, while file inputs are used to allow a user to select a file from their local drive. I realize in your case it's a little confusing, because your web page is on your local hard drive, but imagine if your HTML and scripts were being hosted online, and some other user (not you) was using them to process their own locally-stored files.
MDN has a good tutorial on how to get started with <input type="file"> inputs.
The code won't work locally due to cross-origin limitations.
It works fine when run on a remote server and all files are in the same folder.
If you want to read local files (aka. files selected by user through the file input) you can read more about FileAPI here:
https://www.html5rocks.com/en/tutorials/file/dndfiles/
I'm porting my application from WebKit to WebEngine (seems that one is much better for rendering angular-basad html).
I faced with problem that i can't enable QtWebEngine to load local iframe, despite the fact that i've setup all possible settings that i found:
Code from mainwindow.cpp
view->page()->settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessFileUrls, true);
view->page()->settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessRemoteUrls, true);
view->page()->settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, true);
view->settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessFileUrls, true);
view->settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessRemoteUrls, true);
view->settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, true);
The easiest example is to take WebEngine-based FancyBrowser (\Examples\Qt-5.4\webenginewidgets\fancybrowser) and try to load in it local html file like this:
Index.html:
<html>
<head>
<title>Hi there</title>
</head>
<body>
This is a page
a simple page
<iframe id="some_idrame" width="0" height="0" style="border: none" src="some_iframe.html" name="target" sandbox="allow-scripts"></iframe>
</body>
</html>
some_iframe.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>La-la-la</title>
</head>
<body>
Lalala
</body>
</html>
If you setup env var QTWEBENGINE_REMOTE_DEBUGGING to some port, then you can open 127.0.0.1:port and see in console this error:
"Not allowed to load local resource".
I really have no idea how to solve this problem now... there should be some way to pass to WebEngine something like "--disable-web-security"...
Thanks for any help!
this Qt forum link help you .
you should pass argument to application "--disable-web-security"
https://forum.qt.io/topic/60691/not-allowed-to-load-local-resource-for-iframe-how-to-disable-web-security/4
If you need to load local resource(s) by WebEngine, then you need to pass --disable-web-security argument to QApplication, e.g.:
char ARG_DISABLE_WEB_SECURITY[] = "--disable-web-security";
int newArgc = argc+1+1;
char** newArgv = new char*[newArgc];
for(int i=0; i<argc; i++) {
newArgv[i] = argv[i];
}
newArgv[argc] = ARG_DISABLE_WEB_SECURITY;
newArgv[argc+1] = nullptr;
QApplication myApplication(newArgc, newArgv);
Another option is to load the original page from the filesystem as well. I was having issues loading images from Qt's resource system, so I subclassed QWebEngineView and created this function:
void WebEngineView::setLocalHtml(const QString &html)
{
if(html.isEmpty())
{
setHtml(QString());
return;
}
// Save html to a local file
QString filePath;
{
QTemporaryFile tempFile(QDir::toNativeSeparators(QDir::tempPath() + "/ehr_temp.XXXXXX.html"));
tempFile.setAutoRemove(false);
tempFile.open();
QTextStream out(&tempFile);
out << html;
filePath = tempFile.fileName();
}
// delete the file after it has been loaded
QMetaObject::Connection * const conn = new QMetaObject::Connection;
*conn = connect(this, &WebEngineView::loadFinished, [filePath, conn](){
disconnect(*conn);
delete conn;
QFile::remove(filePath);
});
load(QUrl::fromLocalFile(filePath));
}
Since the main page is a local file as well, this gets around the CORS security problem.
Hi i'm trying to implement the rainyday.js into a project i'm working on however I have no experience with Javascript so i'm struggling.
Basically the code currently calls an online image (from imgur) and this works fine. But when I try and call a local image it does not display the effect, just the local image.
Is there any easy way to make this code call a local image rather than a web image?
Here's the code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>rainyday.js</title>
<link rel="stylesheet" type="text/css" href="../styles/animation.css"/>
<script src="../misc/jquery.min.js" type="text/javascript"></script>
<script src="rainyday.min.js"></script>
<script>
function run() {
var image = document.getElementById('background');
image.onload = function() {
var engine = new RainyDay({
image: this
});
engine.rain([ [3, 3, 0.88], [5, 5, 0.9], [6, 2, 1] ], 100);
};
image.crossOrigin = 'anonymous';
image.src = 'http://i.imgur.com/f7bpv.jpg';
}
</script>
</head>
<body onload="run();">
<div class="rainWrapper1">
<img id="background" alt="background" src="" />
</div>
</body>
</html>
A link to the JS on Github:
https://github.com/maroslaw/rainyday.js/blob/master/rainyday.js
Thanks for the help!
Have you tried it in Firefox? It works for me there, however in Chrome the js execution is denied by the error "Cross-origin image load denied by Cross-Origin Resource Sharing policy." This means, that the Server you're using (i.e. none) does not send a valid cross-origin header. See also this related question. If you're just using this for development you can start chrome with the flag --disable-web-security which should allow you to circumvent same origin policy. Otherwise you will have to run a server supporting CORS somewhere.
In order to solve Cross Domain security woes of JavaScript, I am implementing the following method
On Domain [ abc.com ]
On domain abc.com I have a page called main_page.html. Its code is as follows -
<script>
function SendMsg(id)
{
frames["invisible_iframe"].location = "http://xyz.com/invisible_iframe.html#"+id;
}
</script>
<body>
<input type="button" id="Test" value="Call iFrame" onclick="SendMsg(this.id);">
<iframe src="ttp://xyz.com/visible_iframe.html" name="visible_iframe" height="250" width="500"></iframe>
<iframe name="invisible_iframe" height="0" width="0" style="display:none;"></iframe>
</body>
On Domain [ xyz.com ]
On domain xyz.com I have a page called visible_iframe.html. Its code is as follows -
<script>
function Hi()
{
alert("Hi there!");
}
</script>
<body>
<h1>Visible iFrame on xyz.com
<iframe name="d2_invisible_iframe" id="d2_invisible_iframe" class="iFrame" src="http://xyz.com/invisible_iframe.html" height="310" width="520"></iframe>
</body>
Now I want to access the function Hi() from invisible_iframe.html (which is on the same domain)
The code of invisible_iframe.html is as follows
<script>
var sActionText = "";
function CheckForMessages()
{
if(location.hash != sActionText)
{
sActionText = location.hash;
var sAction = "";
var oSplitActionText = sActionText.split("#");
sAction = oSplitActionText[1];
if (sAction == "Test")
{
parent.Hi();
}
}
}
setInterval(CheckForMessages, 200);
</script>
<body>
<h1>Invisible iFrame on xyz.com</h1>
</body>
I am using hidden iFrame in visible_iframe.html because I don't want the URL of visible_iframe.html to change.
Now I expect when the button on main_page.html is clicked, I'd get alert message. But that doesn't happen. In firefox it says - Permission denied to access property 'Hi'
The strange thing is when I put parent.Hi(); outside CheckForMessages() function, the Hi() function can be accessed and alert box is shown.
What should I do to resolve this ?
Why not using easyXDM? This library should make your life really easy and help to avoid the security limitations when dealling with cross domain issues. Specially if you have control over the two domains.
easyXDM is a Javascript library that enables you as a developer to
easily work around the limitation set in place by the Same Origin
Policy, in turn making it easy to communicate and expose javascript
API’s across domain boundaries.
[This is one of the best and easy to use APIs] available for Cross Domain Communication between web applications.
easyXDM is easy to use, light weight, flexible, writing good quality code etc. I strongly think if you are going to continue with cross domain scenario, then you should adapt a robust cross domain apis such as easyXDM.
[easyXDM vs PostMessage Transport?]
easyXDM will use the PostMessageTransport method if this feature is enabled by the browser such as (IE8+, Opera 9+, Firefox 3+, Safari 4+,Chrome 2+) on the other side it will use different transport methods for the un supported browsers such as (Firefox 1-2 - using the FrameElementTransport) other transport methods will be used as needed such as FlashTransport, NameTransport, and HashTransport).
This clearly makes easyXDM superior in terms on browser support specially the old browsers.
To demonstrate cross-domain access using easyXDM (Domain1 [abc.com] calls a method on a remote domain [xyz.com]):
*On Domain [ abc.com ] - main domain*
<script type="text/javascript">
/**
* Request the use of the JSON object
*/
easyXDM.DomHelper.requiresJSON("../json2.js");
</script>
<script type="text/javascript">
var remote;
window.onload = function(){
/**
* When the window is finished loading start setting up the interface
*/
remote = new easyXDM.Interface(/** The channel configuration */{
/**
* Register the url to hash.html, this must be an absolute path
* or a path relative to the root.
* #field
*/
local: "/hash.html",
/**
* Register the url to the remote interface
* #field
*/
remote: "http://YOUR.OTHER.DOMAIN/YOUR_APPLICATION/YourRemoteApplication.html",
/**
* Register the DOMElement that the generated IFrame should be inserted into
*/
container: document.getElementById("embedded")
}, /** The interface configuration */ {
remote: {
remoteApplicationMethod: {},
noOp: {
isVoid: true
}
},
local: {
alertMessage: {
method: function(msg){
alert(msg);
},
isVoid: true
}
}
},/**The onReady handler*/ function(){
/**
* Call a method on the other side
*/
remote.noOp();
});
}
function callRemoteApplicationMethod(Value1, Value2){
remote.remoteApplicationMethod(Value1, Value2, function(result){
alert("Results from remote application" + result);
});
}
</script>
In the body
<input type="button" onclick="callRemoteApplicationMethod(3,5)" value="call remoteApplicationMethod on remote domain"/>
Now on your remote domain side you need to define your remote client as follows
*On Domain [ xyz.com ] - Remote domain*
This should go into the page YOUR_APPLICATION/YourRemoteApplication.html
<script type="text/javascript">
/**
* Request the use of the JSON object
*/
easyXDM.DomHelper.requiresJSON("../json2.js");
</script>
<script type="text/javascript">
var channel, remote;
/**
* When the window is finished loading start setting up the channel
*/
window.onload = function(){
/**
* When the channel is ready we create the interface
*/
remote = new easyXDM.Interface(/** The channel configuration*/{}, /** The configuration */ {
remote: {
alertMessage: {
isVoid: true
}
},
local: {
remoteApplicationMethod: {
method: doSomething(value1, value2){
// do somethigs with values
return "i'm return value from remote domain";
}
},
noOp: {
isVoid: true,
method: function(){
alert("Method not returning any data");
}
}
}
});
}
</script>
I suppose there is no need to suport old browsers, right?
You can use window.postMessage in modern browsers to support cross-origin communication.
You won't believe the cause. On main_page.html (abc.com) you define two iframes but you don't close them (missing </iframe>). Now there are two cases:
Case 1:
iframes are independent so your main_page.html code should be
<iframe src="http://xyz.com/visible_iframe.html" ...></iframe>
<iframe src="http://xyz.com/invisible_iframe.html" ...></iframe>
and the javascript call from invisible_iframe.html should be
parent.frames["visible_iframe"].Hi();
Case 2:
iframes are parent and child so main_page.html code should be
<iframe src="http://xyz.com/visible_iframe.html" ...></iframe>
visible_iframe.html code sould include
<iframe src="http://xyz.com/invisible_iframe.html" ...></iframe>
and the javascript call from invisible_iframe.html should be
parent.Hi();
That's all. The choice is yours.
Assuming your onlcick works on your input (just a typo there): from invisible_frame, you should address visible_frame's Hi() with parent.frames['visible_frame'].Hi().
For now, parent.Hi() tries to access a Hi() located on abc.com's page (as it is the frame's parent), so you're poked with the hard stick of Same Origin Policy.
Hope this helps and works ;)
Try creating these three files:
http://abc.com/main.html:
<!DOCTYPE html>
<html>
<head>
<script>
function SendMsg(id) {
window.frames.invisible.location = 'http://xyz.com/invisible.html#' + id;
}
</script>
</head>
<body>
<input type="button" id="Test" value="Call iFrame" onclick="SendMsg(this.id);">
<iframe src="http://xyz.com/visible.html" name="visible" height="250" width="500"></iframe>
<iframe name="invisible" height="0" width="0" style="display:none;"></iframe>
</body>
</html>
http://xyz.com/visible.html:
<!DOCTYPE html>
<html>
<head>
<script>
function Hi() {
alert('Hi there!');
}
</script>
</head>
<body>
<h1>Visible on xyz.com</h1>
</body>
</html>
http://xyz.com/invisible.html:
<!DOCTYPE html>
<html>
<head>
<script>
var sActionText = "";
function CheckForMessages() {
if (location.hash != sActionText) {
sActionText = location.hash;
var sAction = "";
var oSplitActionText = sActionText.split("#");
sAction = oSplitActionText[1];
if (sAction == "Test") {
parent.frames.visible.Hi();
}
}
}
setInterval(CheckForMessages, 200);
</script>
</head>
<body>
<h1>Invisible on xyz.com</h1>
</body>
</html>
Notice that the frame structure is:
main
/ \
/ \
visible invisible
And so if you need to access visible from invisible, you need to go:
parent.frames.visible.Hi()
Moving forward, I suggest using easyXDM or the jQuery postMessage plugin for cross-domain communication instead of reinventing the wheel.
There is a reason it is not letting you access the function because of the same origin policy. It would cause real security issues if you could.
CORS (Cross-Origin Resource Sharing) or window.postMessage (ref: Docs on MDN or another simple postMessage example) are definitely worth investigating if you don't care about IE7 support; you could also use a postMessage shim for older IE browsers.
However, I'll stick with an iframe solution in an attempt to more precisely answer your question.
Unfortunately you should not be able to access the parent (window scope) properties/methods from a cross domain iframe. However you can access window scopes via iframes on the same domain ...at any depth. Thus, one solution is to leverage vertical iframe tunnels.
If you create three html documents:
Top level - abc.com
<script>
function sendMsg( id ) {
frames["invisible_iframe"].location = "//xyz.com/mid_level.html#" + id;
}
window.ACTIONS = {
Test: function() {
alert("hello");
// This action could also start an interaction with another
// visible iframe by setting a hash, etc
}
};
</script>
<input type="button" id="Test" value="Call iFrame" onclick="sendMsg(this.id);">
<iframe name="invisible_iframe" height="0" width="0" frameborder="0" style="visibility:hidden;" src="//xyz.com/mid_level.html"></iframe>
Mid Level - xyz.com
<script>
function sendMsg( id ) {
frames["invisible_iframe"].location = "//abc.com/low_level.html#" + id;
}
var sActionText = "";
function checkForMessages() {
if(location.hash != sActionText) {
sActionText = location.hash.replace(/^#/, "");
location.hash = "";
sendMsg(sActionText);
}
}
setInterval(checkForMessages, 20);
</script>
<iframe name="invisible_iframe" height="0" width="0" frameborder="0" style="visibility:hidden;" src="//abc.com/low_level.html"></iframe>
Low Level - abc.com
<script>
function runActionInTop( action ) {
try {
window.top.ACTIONS[action]();
} catch ( err ) {
// Bad action!
}
}
var sActionText = "";
function checkForMessages() {
if(location.hash != sActionText) {
sActionText = location.hash.replace(/^#/, "");
location.hash = "";
runActionInTop(sActionText);
}
}
setInterval(checkForMessages, 20);
</script>
These three iframes can communicate - the first and third can communicate directly and the second indirectly (via hash in this example).
I know this is a variation from what you were originally trying to show with the "visible iframe". I wanted to focus on illustrating the layering necessary for the cross-site communication. If you still need the visible iframe, you could add communication hooks at the top level and also send additional information (in the hash) back from the middle frame to the lowest frame (the lowest frame could then communicate the information directly back to the top page).
Yes, I know this is convoluted - that is one of the reasons why CORS and postMessage exist :)
I've also changed a few minor aspects of your original code that I think are worth pointing out:
Using // instead of http:// means that this system will work on either http or https.
Some browsers (I believe I first ran into this with Safari 3) may not actually load the iframe with display:none; setting the frameborder attribute and visibility:hidden will keep the iframe from being visible.
Some browsers will load about:blank (or a similar page) if you do not specify the iframe src attribute in the markup. On https pages, this can cause insecure content warnings to be thrown in IE.
An alternative, Proxying.
In server-side grab the external file and echo it back. Now it is on your domain so no issues.
for example in php
<?php
$external-site = file_get_contents('http://xyz.com/');
echo $external-site;
?>
I think I would delete any iframes and use jsonp maybe with a library.
1. No Cross-domain errors
2. You could get data as objects (easy to play with 'em
3. You could even get JS code that u could parse.
4. Would be even mobile ready ( iframes are last century solutions... )
But then well maybe you are not able to take away the iframes for any reasons, so I advice to use a ready-made library solution.
Goodluck