Say I have two html pages and open them in two tabs. I'd like to make them communicate. As example when I click on a button on the first page, then it should call a function that does something on the second page.
function Test() {
document.getElementById('test').innerHTML = "Test";
}
<!DOCTYPE html>
<html>
<head>
<script src="index.js"></script>
</head>
<body>
<button onclick="Test()">Click here</button>
</body>
</html>
And the second page:
<!DOCTYPE html>
<html>
<head>
<script src="index.js"></script>
</head>
<body>
<p id="test"></p>
</body>
</html>
When I click the button on the first page it should write Test in the p tag on the second page. They can use the same JavaScript file. But how can I achieve this?
You can't do this with just JavaScript. The point is: JS is a client-side language which means that it is downloaded by a client (a browser) and is run by it (not by server). For the 2 pages to communicate, you have establish the communication somehow, via some medium. The medium can be:
web itself. 2 clients can communicate directly, but only if they know each others' address. How would they get those? By the help of the server (which brings us to the second option below) or by manual configuration which is very impractical (some more details may be found in context of WebRTC)
your server. Ok, that's the most common approach but that involves more than just JS: this requires a server-side language (PHP, Python, C++, Java, whatever)
your browser. There's a special case where you can establish such a communication: if you open your second page in the same browser from your first page in a special way so that the second one is "under control" of the first one, you can "command" the second one to do some stuff from the first one
So, if you're interested in the third option, you should read about window.open, window.opener, window.parent.
var newWindow = window.open(url, name, params);
will open a new window (say your second page) and bring you a variable newWindow which is a reference to the window object of the opened window. Try for instance
newWindow.write("haha, I'm controlling this stuff!");
Likewise, in the second window you can use
var oldWindow = window.opener;
There's also a number of methods you can use (window``.close, .moveBy, .moveTo, .resizeBy, .resizeTo etc etc).
Remember, however, that this interaction will be limited to your browser: if you change something as it is displayed in your browser (like add some text to a page) this won't affect the actual pages stored on your server because this requires your server do something via some server-side scripts.
PS to advance this technique, you may want to read about window.postMessage but that's mostly designed for communication between pages that are cross-domain.
PPS Actually, there's more!
One thing to note is localStorage and sessionStorage have setItem method which generates 'storage' events on window (try localStorage.setItem('key', 'value'); and window.addEventListener('storage', event => console.log(event.key));).
Another, like Anderson Green has noted, is Broadcast Channel API (try const channel = new BroadcastChannel('my_channel'), channel.postMessage('Hi there!') and channel.addEventListener('message', event => console.log(event))).
There's also SharedWorkers and Service Workers.
Finally, you can use some off-the-shelve solutions like tabs-router, Hermes, Visibility, Duel and SE.
Those who speak Russian may also find more useful details in this article (wow!).
Try using cookies. It's the simplest way I can think of. This website might seem helpful: https://www.w3schools.com/js/js_cookies.asp
Related
Looking into using Google Cloud Print, it seems that it is quite complicated regarding OAuth2, the various tokens/client ids etc.
What is the simplest possible way to print a PDF from a web page?
Implemented client side in Javascript with AJAX (so with CORS) or server side with Java (but preferrably not too many jars needed)
PDF document can be sent as binary or referred to as publicly available URL
Preferrably no user login, must be with some kind of "service" authorization
The same application is already using API keys for google maps geocoding. So re-using these keys, if possible, would be the ideal option.
It would be great with some pointers on how to do this in the simplest possible manner possible.
The simplest possible scenario is using the GCP Web Element, as described in: https://developers.google.com/cloud-print/docs/gadget
It boils down to including the print gadget scripts, creating a container to host the button and creating the print gadget in it:
<html>
<head>
</head>
<body>
<div id="print_button_container"></div>
<script src="https://www.google.com/cloudprint/client/cpgadget.js">
</script>
<script>
window.onload = function() {
var gadget = new cloudprint.Gadget();
gadget.setPrintButton(
cloudprint.Gadget.createDefaultPrintButton("print_button_container")); // div id to contain the button
gadget.setPrintDocument("url", "Test Page", "https://www.google.com/landing/cloudprint/testpage.pdf");
}
</script>
</body>
</html>
If you are not logged-in your GCP account you will be shown the appropriate log-in dialog and then you'll select the target printer.
Check the fiddle here:
https://jsfiddle.net/0ncsuqra/
I have a web app that accepts JS plugins. That is, JavaScript code that someone else wrote that the user wants to load into my app.
Currently I am using eval() to evaluate their JS code into the runtime, but I know thats not secure. Is there a better method than eval() for doing this?
To be clear, the user is pointing me to a dry text file (a URL), and that JS in the file needs to come to life somehow.
There's only two ways I know of dynamically importing a JS script:
Use AJAX, get the JS code, then run eval() on it.
Dynamically add a <script> tag to the DOM
The purpose of the question is to figure out if one is more secure than the other or if there is a better way than the above 2 options.
Is one of these two more secure than the other?
No, they're equally bad (good) from a security perspective.
They differ in details that would lead to different approaches in making them more secure, but ultimately both do run code written by an untrusted third party in your environment, with all its privileges. It's basically a persisted XSS issue.
Is there a better way than the above 2 options?
Many. It depends mostly on what those plugins should do in your application, who writes them and who installs (enables) them. Neither you as the application provider nor the user wants arbitrary code run havoc on the user's data. If the plugins need to access the data, you need administrative measures to ensure that only trusted code will run, like plugin code audits. At least you will need to inform your users that they must trust the plugin authors before enabling the plugin, which puts the burden on them. Also you should ensure to have usable logs in case something went wrong.
If you really want to run arbitrary, untrusted code without giving it access to user data, you will want to consider sandboxing. There are various approaches that essentially do the execution in a virtual machine that the code cannot break out from.
For Chrome Extensions I would specifically use sandboxingEval which allows the loading of sandboxed files that can be accessed within an iframe that the extension hosts. The only message passing would be through normal iframe messaging.
For example, declare within the manifest.json which page to sandbox:
{
...
"sandbox": {
"pages": [
"plugin.html"
]
"content_security_policy":
"sandbox allow-scripts; script-src 'self' https://plugin.com/"
],
...
}
Make sure the external domain is white-listed so it could be embedded. In the CSP policy, allow-scripts is there if embedding <scripts> is needed.
Now within the sandboxed page plugin.html, do anything with the external script. In this case, the external plugin is downloaded, and passing messages back to the extension process through messaging.
<!doctype html>
<html>
<head>
<script src="https://plugin.com/mohamedmansour/plugin.js"></script>
</head>
<body>
<script>
// Whatever my plugin contract is, lets send something back to our extension
// that the plugin initialized.
Plugin.do.something.here(() => {
window.postMessage({
name: 'CustomInitEvent',
data: 'initializing'
}, *);
});
// Listen from your extension plugin.html page some events.
window.addEventListener('message', (event) => {
var command = event.data.command;
switch(command) {
case 'CustomCommandA':
event.source.postMessage({
command: 'CustomCommandHello',
data: 'pong command a'
}, event.origin);
break;
}
});
</script>
</body>
</html>
Now within the popup or anywhere, just embed the plugin.html. In this case, popup.html looks like this
<html>
<head>
<script src="plugin-manager.js"></script>
</head>
<body>
<iframe id="theFrame" src="plugin.html"></iframe>
</body>
</html>
Then your plugin-manager.js is responsible of controlling plugin.
const iframe = document.getElementById('theFrame');
window.addEventListener('message', function(event) {
switch(event.name) {
case 'CustomInitEvent':
console.log('Plugin Initialized');
break;
case 'CustomCommandHello':
console.log('Hey!');
break;
}
});
iframe.contentWindow.postMessage({
command: 'CustomCommandA'
});
iframe.contentWindow.postMessage({
command: 'CustomCommandB'
});
Something along those lines. If dynamic plugins is what is needed, just add query parameters to the iframe. Within plugin.html, just dynamically add the script element, and just call it this way:
<iframe id="theFrame" src="plugin.html?id=121212"></iframe>
I have a html like this that I deliver to the client from my web server
<html>
<head>
<script type="text/javascript">
var myapp = myapp || {};
myapp.settings = {"abc", "xyz", "123"};
</script>
</head>
</html>
In the rest of my client app, I have checks that look at the myapp.settings object.
Is myapp.settings secure? Can a hacker add strings or remove strings from myapp.settings? If so, what are some example ways to do so?
No, it is not secure. In fact, nothing in a web page is completely secure.
In your particular example, here are some examples for how your myapp object can be manipulated:
The end-user can open the browser console and type in a line of code to change that object.
The end-user can open the browser debugger, set a breakpoint and when it hits that breakpoint, edit that object.
The end-user can download or create a bookmarklet that when clicked on would modify the myapp object.
The end-user can set up a proxy that intercepts the incoming page, modifies it and then sends it on to the browser.
An attacker can intercept the page on its way to you and modify it (as it goes through your ISP for example). Note: this would be much less likely if you were using https.
Because nothing in the browser is completely secure, security issues have to be addressed with a specific need in mind and then options are explored to handle those specific concerns.
No, it is not secure.
Yes, a user can manipulate the state of your myapp.settings object rather easily.
As long as someone can execute a script in that app, they can modify myapp.settings. However, you can prevent this by using Object.freeze() function on it:
Object.freeze(myapp.settings);
myapp.settings.test = 42;
console.log(myapp.settings.test); // undefined
I was wondering how I would get the name of the current user in JavaScript as part of an HTML document.
In Java, one would type System.getProperty("user.name"); to achieve this. What is the alternative to this in JavaScript?
JavaScript runs in the context of the current HTML document, so it won't be able to determine anything about a current user unless it's in the current page or you do AJAX calls to a server-side script to get more information.
JavaScript will not be able to determine your Windows user name.
There is no fully compatible alternative in JavaScript as it posses an unsafe security issue to allow client-side code to become aware of the logged in user.
That said, the following code would allow you to get the logged in username, but it will only work on Windows, and only within Internet Explorer, as it makes use of ActiveX. Also Internet Explorer will most likely display a popup alerting you to the potential security problems associated with using this code, which won't exactly help usability.
<!doctype html>
<html>
<head>
<title>Windows Username</title>
</head>
<body>
<script type="text/javascript">
var WinNetwork = new ActiveXObject("WScript.Network");
alert(WinNetwork.UserName);
</script>
</body>
</html>
As Surreal Dreams suggested you could use AJAX to call a server-side method that serves back the username, or render the HTML with a hidden input with a value of the logged in user, for e.g.
(ASP.NET MVC 3 syntax)
<input id="username" type="hidden" value="#User.Identity.Name" />
If the script is running on Microsoft Windows in an HTA or similar, you can do this:
var wshshell=new ActiveXObject("wscript.shell");
var username=wshshell.ExpandEnvironmentStrings("%username%");
Otherwise, as others have pointed out, you're out of luck. This is considered to be private information and is not provided by the browser to the javascript engine.
I think is not possible to do that. It would be a huge security risk if a browser access to that kind of personal information
Working for me on IE:
<script type="text/javascript">
var WinNetwork = new ActiveXObject("WScript.Network");
document.write(WinNetwork.UserName);
</script>
...but ActiveX controls needs to be on in security settings.
Hello guys I have some problem with my website. Here's the situation:
Page 1
<script type="text/javascript" src="jscript.js">
<input type="button" value="change" onClick="changeAttr()">
Page 2
<script type="text/javascript" src="jscript.js">
<input type="text" value="Hello" id="dynamictext">
jscript.js
function changeAttr(){
document.getElemenyById('dynamictext').value="World";
}
Now these 2 pages are open on different tabs. What I want to happen is whenever the button on page 1 is clicked, the value of input text on page 2 will change to "World". How can I make this possible with Javascript or Jquery?
The 1st tab has the task to change a value in localStorage.
localStorage.setItem('superValue', 'world');
Meanwhile the 2nd tab would be "listen" to changes on that localStorage value:
var dinamictext = document.querySelector('dinamictext');
setInterval(function () {
if (dinamictext.value !== localStorage['superValue']) {
dinamictext.value = localStorage['superValue'];
}
}, 100);
This of course works only with pages on the same domain.
You cannot directly access DOM elements from one tab to another. That would be a serious security issue.
You can communicate between your two pages (assuming they are both under your control) using cookies. See this other SO question on the subject.
You can also use LocalStorage API, assuming you are targeting only modern browsers. See this SO answer.
Both methods will allow you to share data. Then, you will have to define your own protocol, in order to manipulate DOM according to the received command.
You can use HTML5 Storage. Here is a simple example
The other answers are perfect if both pages belong to the same site. If they're not on the same site however, you'd need a server solution. One page would send a request to the server, and the other page would also have to call the server looking for instructions, and execute those instructions when received. In that scenario, if they're on separate sites, AJAX probably wouldn't work, and you'd have to resort to something like JSONP.