I have two domains on different hostings, domain A is the main website, domain B is the authorization server with simple frontend.
I have very strict security policy applied, which forces the users after 1 hour to re-authorize themselves. It's done by popup window in new tab, calling domain B from the frontend of the domain A.
I realized that the popup blocking policy and the fact, that not every browser behave the same, i found the only solution to bring the popup correctly (in the new tab) by this javascript call (when the timer reaches 60mins):
Object.assign(document.createElement('a'), { target: '_blank', href: 'https://domain_B/auth.php'}).click();
My problem is, that i am unable to check from the domain A, if the popup window is opened correctly and the user haven't closed it.
So i need to assign a variable to the new popup tab and check if it's still available, otherwise i need to re-open it from the domain A.
So i want to do something like this:
if(popup_win && !popup_win.closed)
{ //do my auth stuff
}
the problem is, that i am unable to assign the new popup to popup_win javascript variable. I can do it by calling a single window.open(url,"_blank") but as i mentioned above, the result then depends on popup-blockers and browser version/type.
Any help/suggestion appreciated!
Related
I have a page with a few links.
Each link opens in a new tab.
The next time I click a given link, I want it to recall the same tab where it was previously opened.
Is it possible? How?
All pages come from the same domain.
I've seen this answer:
Check if my website is open in another tab
It seems possible to store the URIs in localStorage, for repetitions detection.
I think this technique will allow me to detect repetitions, but I can't figure out how to aim at the specific tab (activate it, bring it to the front).
I don't control the server, need to implement it in the client (via Tampermonkey).
For the curious, I work a lot with BitBucket issues.
The page with the links is the issues listing, the other pages are the individual issues.
I want to be protected from opening the same issue twice, update both versions, and have a data loss.
Additionally, each page can have two different URIs, one for viewing and the other for editing. But I think I can solve it with JS.
Recalling a Browser Tab by Name
You can first specify a name for each tab you create, by using window.open():
let newWindow = window.open(newUrl, newWindowName);
or by using target attribute in an anchor tag:
Make New Window
If you then call window.open with the name of an existing tab, that will use the existing tab. If the window by that name doesn't exist, window.open will create a new window (or tab).
MDN web docs page for Window.open
Bringing Window to the Front
Using window.open() alone may not be enough to bring the window to the front. That may be possible with a different function, window.focus(), which issues a request to bring the window to the front. Combining the two:
window.open(myUrl, myWindowName).focus();
Caution: A browser's user preference setting may still prevent focus() from bringing the window to the front, so this is not guaranteed to work. From MDN web docs:
It may fail due to user settings and the window isn't guaranteed to be frontmost before this method returns.
You can get the previous page's URL with the following:
let prevURL = document.referrer;
You can get the URLs from all open tabs with the windows.getAll() function.
From this answer - You cannot programmatically focus the browser to a specific tab due to security concerns. Consider updating the title to notify the user with document.title = {{new title}}
The problem
I've had this issue for months now, but the concept is pretty straightforward: I want to block some Malicious Site™ from programmatically opening tabs or popup windows.
With the chrome.tabs API, I can listen with onCreated when a new tab is created, and I can easily check who (i.e. which tab) opened that particular tab accessing the openerTabId property of the Tab object passed to the callback function.
Now, I would like to do the exact same thing when a new window is created: I would like to know which tab opened the window (if any, because it could have been opened by the user too), check its URL to see if it is the Malicious Site™, and act accordingly (i.e. block the popup). I tried doing it in the exact same way: request the array of tabs in the new window and check their openerTabId property, but unfortunately such property is not defined! I searched the documentation and Googled for hours, but sadly it looks like there's no simple way to check who opened a window.
A very clumsy solution
Stated the above, the only way I was able to do something even remotely close to what I really want, is the following:
Every time a new window is created, its ID is added to an array called windowWatchlist.
Every time a tab is updated (NB: updated, not created), a script is injected inside it to check its document.referrer, which should contain the URL of the site which opened the tab: if the referrer URL contains the address of the Malicious Site™ I want to block popups from, the window is then closed and removed from the windowWatchlist.
Every time a window is closed, if its ID is in the windowWatchlist, it gets removed from it.
Here's the code (which runs in my background.js script):
// Called on chrome.windows.onCreated
function watchPopupWindow(window) {
windowWatchlist.push(window.id);
console.log('Added window #' + window.id + ' to watchlist.');
}
// Called on chrome.windows.onRemoved
function unwatchPopupWindow(windowID) {
var index = windowWatchlist.indexOf(windowID);
// If the windowID is in the watchlist:
if (index != -1) {
// Remove it:
windowWatchlist.splice(index, 1);
console.log('Removed window #' + windowID + ' from watchlist.');
}
}
// Called on chrome.tabs.onUpdated
function blockPopupWindow(tabID, info, tab) {
// If this tab is in a window which is in the watchlist:
if (windowWatchlist.indexOf(tab.windowId) != -1 && info.url && info.url != 'about:blank') {
// Check the referrer of this tab:
chrome.tabs.executeScript(tabID, {code: 'document.referrer;'}, function(ref) {
// If the referrer is the malicious site to block:
if (ref && ref[0] && ref[0].indexOf("http://MALICIOUS-SITE.XXX") != -1) {
// Close the popup window:
chrome.windows.remove(tab.windowId, function() {
console.log('Blocked popup window #' + tab.windowId + '.');
if (chrome.runtime.lastError)
console.error(chrome.runtime.lastError.message);
});;
}
});
}
}
var windowWatchlist = [];
chrome.windows.onCreated.addListener(watchPopupWindow, {windowTypes: ['popup']});
chrome.windows.onRemoved.addListener(unwatchPopupWindow, {windowTypes: ['popup']});
chrome.tabs.onUpdated.addListener(blockPopupWindow);
Now, you may be wondering: why do you need all this mess only to check a referrer? Couldn't you just check the tabs contained in the window when the window is opened and check their referrer directly inside the callback of chrome.window.onCreated? That's a clever question, and the answer is simple: the problem is that I cannot check the referrer of the tabs right when they are created, because they almost always need some time to load, and the referrer isn't loaded until the page starts loading inside the tab. Therefore, I need to check when a tab is updated, see if its window is in my watchlist, and then check its referrer. This is why chrome.tabs.onUpdated is needed, since it fires its listeners whenever a tab changes state (e.g. tab.status changes from "loading" to "complete").
Why this solution doesn't work
The reason why I call this solution "clumsy" and the reason why it doesn't really work should be already clear to anyone with some experience of JavaScript and web developing: document.referrer isn't reliable at all, and is very often undefined or (in case of multiple redirects) not the right one. This makes my script fail about 90% of the times, because it is unable to determine whether the popup window was opened by the Malicious Site™ or not.
Moreover, the Malicious Site™ often opens popups with URL about:blank or no URL at all, and only when they are loaded, injects data into them, making them basically impossible to detect, even with chrome.tabs.onUpdated which doesn't fire any listener in this situation.
I could decide to block any popup with URL about:blank or undefined, and this is what I'm doing right now indeed, but is a pretty bad compromise, since that I end up closing popups opened by any site which uses this method, and not only the Malicious Site™ I want to block.
In conclusion
My question is simple, but I don't know about its solution: does anyone know any other more reliable method which could be used to detect which tab opened a new window? Nothing comes to my mind, maybe something could be possible using the chrome.webRequest API? I don't really know. For months I've been accepting the fact that a simple solution just wasn't possible, and helplessly waited for an update or something, but I never actually thought about asking here, because the problem looked above the competence of an average Chrome Extension programmer, but hopefully I was wrong.
UPDATE: The solution to inject a script inside the site and replace the window.open function with something else isn't viable: if an <iframe> is loaded without a src attribute, but with an already written DOM inside the srcdoc attribute, Chrome will not execute a content script inside it, even if the call to chrome.tabs.executeScript is made with allFrames: true, and even if the content script is declared inside the extension's manifest.
I came across the same problem and found the webNavigation.onCreatedNavigationTarget event that yields the source tab/frame id when a new window is opened.
Solution found from this post: Is it possible to determine a tab's opener within a Google Chrome extension?
Since you are already doing code injection this is what I would do.
Inject code to override window.open and have it window.postMessage to child window telling them who opened them. Also will need to inject code to listen to the effect of window.addEventListener('message', messageHandler) which will decided if they should window.close().
On second though I think I would just override window.open and not even open the child windows if you don't want to allow a give site to open windows.
I need to spawn a tab using window.open('...', '_blank');
Then, I need that tab to CLOSE ITSELF, when the user click a button (button is in the new tab).
I have control over the codebase and server of both applications.
I tried the following:
in app#1:
window.tab = window.open('http://localhost:5007', '_blank');
in app#2:
function clickedButton() {
window.opener.tab.close();
}
Unfortunately I get security exception:
Error: Blocked a frame with origin "http://localhost:5007" from accessing a cross-origin frame.
How can I get around this error? Is there anyway I can use this library to overcome this? https://github.com/ternarylabs/porthole
I am simply going to quote documentation here, just for anyone who needs a reference click W3C and MDN.
function openWin() {
myWindow = window.open("", "myWindow", "width=200, height=100"); // Opens a new window
}
function closeWin() {
myWindow.close(); // Closes the new window
}
To break it down, the open and close functions use parameters than can be very useful, such as the URL, when desiring to open or close the current window, or in your case the opened window.
A practical example would be this stack overflow question. N
I hope it helps!
EDIT
To answer the OP's edit to the question: If it is a matter of triggering an event on a window which was opened, you can on the new window have an event handler which will trigger window.close() like so:
$('#anElementId').click(function() { window.opener.$('body').trigger('theCloseEvent', anyPassedData); })
However, if you truly do have control over the new tab, because it leads to a URL whose code base you are in control of, then it is only a matter of triggering an event there that you can trigger either once the window loads, or once you click a button... like so:
HTML
<button id="close-window">Close me</button>
Javascript/jQuery:
$(document).ready(function(){
$("#close-window").click(function(){
alert("ok");
window.close();
});
});
EDIT #2
To further extend the OP's edit, I want to include here an issue that can easily be encountered when attempting to trigger the opened window to close itself.
Quoted from How can I close a browser window without receiving the “Do you want to close this window” prompt?:
Scripts are not allowed to close a window that a user opened. This is considered a security risk. Though it isn't in any standard, all browser vendors follow this (Mozilla docs). If this happens in some browsers, it's a security bug that (ideally) gets patched very quickly.
None of the hacks in the answers on this question work any longer, and if someone would come up with another dirty hack, eventually it will stop working as well.
I suggest you don't waste energy fighting this and embrace the method that the browser so helpfully gives you — ask the user before you seemingly crash their page.
In other words, unless your webpage's script has control of the window which was opened, you should/cannot close said window. That is because the script running the window.close is not in control of the opened window.
EDIT #3
So many edits I know! But I am answering this in between my daily routine so bear with me. To answer the porthole.js question, it should be much more possible to do something with it, however you need to realize that you are working with iframes.
There is a significant difference when working with websites vs working with iframes, in which iframes are Widgets and websites (including mini sites) are given a URL. There are lots of considerations as well in terms of security and sandboxing, as can be seen on the portholejs demo here. This difference is also what does not allow you to work with different websites the way you want to initially.
My advise would be to evaluate your options with respect to your implementation: website to website vs website to widget.
Good luck!
Ok, I was able to accomplish this in the way I theorized by using porthole.js.
I believe this is the only cross-browser way to accomplish this without using hacks.
The solution consists of 2 apps (you must add code to both app for this to work).
app #1: http://localhost:4000
app #2: http://localhost:5000
In my case, I needed app#1 to spawn a need tab containing app#2. Then I needed app#2 to be able to CLOSE ITSELF upon clicking a button inside app#2.
If these apps were on the same domain (including same port), this would be relatively easy by saving a reference to the tab in app#1:
window.tab = window.open('...', '_blank');
And then accessing that reference from within app#2 via window.opener.tab.close()
However, for my case the apps needed to be on diff domains and doing this method resulted in a browser security exception. So instead, what I needed to do was host app#2 within an iframe inside app#1 (on some specific route, say /iframe), this way they ARE on the same domain as far as the browser windows are concerned, and now the second tab should be able to close itself using window.opener.tab.close().
However, a problem still remained because I needed the trigger to be a button INSIDE app#2 (aka a button inside the iframe), and since the hosting app and the iframe app are again not on the same domain, it seems like I would be back to square one... or maybe not.
In this case, porthole.js saves the day. You must load porthole.js into both apps (this is why you need access to both codebases). Here's the code:
in app#1 (http://localhost:4000/iframe)
// create a proxy window to send to and receive messages from the iFrame
var windowProxy;
window.onload = function() {
windowProxy = new Porthole.WindowProxy(
'http://localhost:5000', 'embedded-iframe');
windowProxy.addEventListener(function(event) {
//handle click event from iframe and close the tab
if(event == 'event:close-window') {
window.opener && window.opener.tab && window.opener.tab.close();
}
});
}
in app#2: (http://localhost:5000)
var windowProxy;
window.onload = function() {
windowProxy = new Porthole.WindowProxy(
'http://localhost:4000/#/iframe');
$('button').on('click', function() {
windowProxy.post('event:close-window');
});
}
And wa-lah, a self closing tab.
I have two bookmarklets that work individually
1)
javascript:(function(){window.open("http://mail.yahoo.com");})();
2)
javascript:(function(){;document.getElementsByClassName('btn-compose')[0].click()})();
(the above lines of code were put through a bookmarklet generator here:
http://ted.mielczarek.org/code/mozilla/bookmarklet.html
and each bookmarklet works fine)
but when they are together like so:
javascript:(function(){window.open("http://mail.yahoo.com");document.getElementsByClassName('btn-compose')[0].click()})();
or like so:
javascript:(function(){window.open("http://mail.yahoo.com");})();
javascript:(function(){;document.getElementsByClassName('btn-compose')[0].click()})();
the compose window does not open. I have a feeling the DOM is not ready.
but this fails:
javascript:(function(){window.open("http://mail.yahoo.com");})();
document.onreadystatechange = function () {
if (document.readyState == "complete") {
javascript:(function(){;document.getElementsByClassName('btn-compose')[0].click()})();
}
}
You have several issues going on.
window.open() opens a new window. If you wanted to operate on that window, you would have to get that window handle and then get the document from THAT window. Right now, you're trying to operate on the original window with your second script.
A script launched from one window cannot access a different domain in a different window due to browser security restrictions.
It appears to me that you will either have to manually launch the second script after the Yahoo window opens. Or, you will need to use a browser plugin that can access the new window.
It also appears that you're trying to solve a problem that is probably already solved (bringing up a compose window in Yahoo mail). There is probably a URL you can just open in a new window that will start the compose window directly without having to hack into the window to push a button.
See this post for info on a URL that will take you to a Yahoo compose window. The general form of the URL is this: http://compose.mail.yahoo.com/?to=TO&subject=SUBJECT&body=BODY
I'm stuck using a CMS that only gives me the ability to modify the content of the <body>, so when I want to redirect people, I've used this
<script type="text/javascript">
window.location = "http://www.example.com/"
</script>
So, yes, the page loads first, and then 5ms later, the redirect happens, and it's worked for all intensive purposes. Now, I'm wondering if I can use javascript to do something else.
Is it possible to open a new browser tab, with a specified URL, and then redirect the user back to the previous page, through Javascript?
Many thanks, SO.
EDIT - Whether it opens a new window or tab, to be honest, is not as important as it actually functioning. I need Javascript to determine the prior page (if possible), then open a new window/tab to a URL I specify, and then redirect the current window/tab to it's prior page. Some are saying that window.open only works on a click event, which will not work for what I am trying accomplish either... just fyi.
So, literally, without clicks, I need Javascript to do the following -
Determine the prior/previous/last page the user came from, store it as a variable
Open a new window or tab, to a specified URL
window.location back to the prior page, which I stored as a variable
Hope that makes sense.
Depending on the user's browser setting using window.open can open the new window in a new tab instead but you CANNOT directly control this through the browser. It is all down to the user's settings.
To open a new window:
window.open("http://www.google.com", "windowName", "window options (optional parameter)");
Then simply use:
history.back();
You can also use the referer property:
var previousUrl = document.referrer;
For more info on window.open, see: http://www.javascript-coder.com/window-popup/javascript-window-open.phtml
For more info on the document.referrer property, take a look at: http://www.netmechanic.com/news/vol4/javascript_no14.htm