Get URL of popup window opened from a Chrome Extension - javascript

I've got a Chrome extension that creates a popup window that the user needs to use for a login system. You click on the extension icon and it opens up its application (AngularJS in my case). The user then clicks on a button which calls chrome.windows.create() to open a popup.
I would like the main extension app to monitor the URL of that popup for changes.
I create the popup from the extension this way:
chrome.windows.create(
{
url: 'https://some.external.url.com/whatever',
type: 'panel',
width: 600,
height: 600
},
function (windowReference) {
console.log('My Window:', windowReference);
// start monitoring URL of windowReference somehow
// could be as simple as a setInterval() loop
}
)
The problem is that the windowReference object passed to the callback doesn't have the current URL of the popup. Since the user can interact with the page in the popup (I'm pointing it at out OAuth2 system), the URL will change at times. I want to see that - either actively as changes are made, or by simply querying the current URL periodically.
This is what the windowReference object contains:
{
alwaysOnTop:false,
focused:false,
height:600,
id:1089,
incognito:false,
left:61,
state:"normal",
top:23,
type:"popup",
width:600
}
You can see that there is an ID there, and that, to me, suggest that I might be able to use it to call some other method to get the real URL information I'm after.
Any help would be appreciated.

So the answer turns out to be pretty simple. As Rob W mentioned in a comment, you use the chrome.tabs.query() method to do the search as you would for any other tab.
The missing part for me was that you can use the id from the window reference you get when the popup is created to get the desired results from the tabs query:
chrome.tabs.query(
{ windowId: windowReference.id },
function callback(tabs) {
var popup = tabs[0];
$log.debug("Popup URL:", popup.url);
}
);
You can see that I passed the ID as the value of the windowId parameter in the search query object.

Related

open new window using window.open by "Post" parameters

i want to open a new window using window.open(). but the issue is i don't want to show the URL to user, so i have to use POST URL for this. but window.open() function opens the new window and shows the URL in URL bar. i have to hide the URL.
here is the Example :
window.open(URL,"_blank",'status=0,toolbar=0,resizable=0,menubar=0,titlebar=0,width=1180,height=770');
No, you can't hide address bar in modern browser.
location=no paramter will not working.
See the MDN document.
https://developer.mozilla.org/en-US/docs/Web/API/Window/open
In Firefox 3, dom.disable_window_open_feature.location now defaults to
true, forcing the presence of the Location Bar much like in IE7.
location parameter is also always enabled (means location=yes) in Google Chrome.
But you can assign a fake URL:
var win = window.open('/path/page.htm');
win.addEventListener('DOMContentLoaded', function () {
win.history.replaceState(null, null, '/fake.htm'); // must be same domain (or ignore domain)
});

window.location.state does not work as expected

I have one situation,where i need to pass some json from one window to new window in the same domain.I have first window lets say it window1 and second window,let say it window2.
I have following code in window1:
var params = [
'height=750',
'width=720',
'scrollbars=yes',
'left=0',
'top=0',
'fullscreen=no', // only works in IE, but here for completeness
'location=no'
].join(',');
var port = location.port;
var url = "http://" + hostName + ':' + port + "/isecalreport" + location.search;
var newWindow = window.open(url,'photocal_report',params);
while(true){
if(newWindow! == undefined) {
newWindow.location.state={payloadFromIseCalWeekly : payloadFromIseCalWeekly,instrumentIdObj : instrumentIdObj};
break;
}
}
Code in window2:
var payloadFromIseCalWeekly = location.state.payloadFromIseCalWeekly ? location.state.payloadFromIseCalWeekly : {};
I want to make use of the json set in window.location.state.
So the problem is ,It works fine in chrome ,mozilla,but fails in IE 11(when debugger is not open.)
When i open debugger in IE11 ,it works fine.
I debugged it and found out that after the instruction which is opening the new window ,the next instruction get run and it doesnot find the new window object.
Its strange as it works when developer console is open.
It would be good if i can get insights about how to resolve the issue.
My aim is to open a new window ,to which i need to pass some data and using that data i want to do an API call.
With few exceptions, you cannot tell one window, tab or frame to talk to another directly. This is to prevent malicious scripts in one of these contexts from hijacking another across pages.
To cope with this, you have two options, you can use postMessage() or simply pass your data via the URL that you open in the new window. There are technically more options if you're on the same domain, but I recommend against going down that rabbit hole.
Sending data via the URL is a one-way affair. You can send query string variables in the URL that the new window can read, but it can't send anything back to the window that created it.
postMessage(), on the other hand, can be used to communicate between multiple contexts and across domains. It is considered secure because it requires that all participants be listening for messages, rather than allowing direct code access.
Your various pages can listen for messages with a simple event listener.
// listen for incoming messages on this page
window.addEventListener('message', function(e) {
// this is the handler function
// do we trust where this was sent from?
if (event.origin !== "http://example.com") {
// if so, print the resulting event object
console.log('message received', e);
}
}, false);
You can then send a message from another page to your window.
// the * is the targetOrigin, read the docs!
newWindow.postMessage("some message data", "*");

How to run function on new tab from main tab? (Google Chrome)

I need to open console and run one function on new tab, that I opened using javascrip. The opening part is easy, but how to run function on other tab?
var google = window.open("http://google.com")
Upon reading your question, it seems you're looking to open the dev console for the popup? Assuming this is what you're looking for, you should just be able to right-click the popped-up window and hit 'Inspect Element'. Then go to the console from there.
If you're trying to programatically run a function from the parent onto the popup window, here's an idea for you.
Assuming the new window is on the same domain as yours, this solution may work for you. (browser support is limited)
On the parent page:
//store the function in localStorage
localStorage.runThis = function(){ alert("Hello world"); }
//open the popup window
newWindow = window.open("http://your-domain.com/your-page");
On the page to open in the popup:
//check if the function has been stored
if(typeof localStorage.runThis === "function"){
//run the function in localStorage
localStorage.runThis();
}
One issue is that this method relies on this criteria being met:
Browser supports localStorage
Parent page and Popup page come from the same origin
Popup page must actually look for the function in question and execute the function itself
One drawback of this is that if someone were to go to the Javascript Console and set their own function into localStorage, the popup page would see their function and run potentially dangerous code - a security hole.
A common solution is using localstorage.
if (typeof(Storage) !== "undefined") {
// Code for localStorage/sessionStorage.
localStorage.setItem("lastname", "Smith");
var lastname = localStorage.getItem("lastname");
} else {
// Sorry! No Web Storage support..
}

How Pinterest extension store (temporarily) images from a web page and then access them in an iframe?

I've been trying to create a Pin It button (extension of Pinterest) like chrome extension. What i tried is firing a script when extension is clicked which can iterate through all available images on a webpage, store it in localStorage. Now i need to call an iframe (different domain ofcourse) and access these images. Since one can access localstorage only from same domain, i'm quite confused how Pinterest manages to store all images from a web page (temporarily and not on their server) and then use it in an iframe.
I also saw the code of PinIt Button extension but i can't understand a thing from it as it is too much obfuscated/encrypted or whatever.
I've read about chrome.storage api and i haven't been able to understand it quite well. I'm not even sure if this is the thing i need to do in this case. (This is the first time i'm developing a chrome extension). Can anybody please throw some light on this and guide me the best possible way to achieve this functionality?
P.S. I've completed this extension without using <iframe> however i need to do it with <iframe>.
EDIT 1: I can't write complete code here but here is the flow/structure/my attempts
I start with background.js
chrome.browserAction.onClicked.addListener(function (tab) { /*This fxn fires when extension is clicked*/
chrome.tabs.executeScript(tab.id, {
"file": "bookmarklet.js"/*Calls this file*/
})
});
In bookmarklet.js:
jQuery('body').append('<iframe class="vw_parent" id="image-grabber-container" src="" style="height: 100% !important; width: 100% !important; position: fixed !important; margin: 0% auto !important; background: rgba(17, 17, 17, 0.9) !important; left: 0 !important; right: 0 !important; z-index: 999999999 !important; top: 0% !important;"></iframe>');
jQuery('img').each(function() {
//do some checks to determine what images need to be stored
var allImgs = jQuery(this);
localStorage.setItem('myLocalImgs', allImgs);
})
vwgrid = "https://mydomain/FileToBeInjectedInIframe.php";
jQuery('#image-grabber-container').attr('src', vwgrid);
Now in FileToBeInjectedInIframe.php
var abcde = localStorage.getItem('myLocalImgs');
console.log(abcde);
//This gives NULL value
EDIT 2: As per comments and answer by DelightedD0D, i want to explain How this extension works/should work
1. User is on any webpage and then clicks the extension
2. All the images available on that webpage are displayed in an iFrame
3. User can select multiple images from this iFrame and then post them to my website
4. Reason for iFrame: If user clicks on POST IMAGE button available in iFrame and he is not logged into our website for posting the image, he should see a login popup in the same iFrame
5. If not iFrame, how would i check if the user is logged in my website as i won't be able to read session/cookie of a different domain on a different domain.
For same reasons i believe (i'm not sure though), pinterest also display images in an iFrame
TL;DR, link to an example extension at the bottom ;)
Ok, your question is a bit broad but I'll try to explain the approach I would take if I wanted to do this.
First, I'd drop the iFrame. I can't see any reason to use one here and I just dont like them personally.
I would:
have a content script that is injected into all pages (or specific one if needed, whatever)
the script would have a javascript class that adds a chrome.runtime.onMessage.addListener to the page
this class would listen for messages from the extension
messages would be sent to this class to trigger functions and send back a response
for example a message like {pageAction:"getImages"} would trigger the getImages function in the injected class
getImages would get all the images and send them back to the extension
One note here, I prefer to work with images encoded as base64 strings with stuff like this rather than image urls from a whole bunch of different domains and all the CORRs, link protection,....etc. For that reason, I would have the getImages make an ajax call to encodeImagesToBase64.php a server passing an array of image urls. encodeImagesToBase64.php would return an array of base64 images which are then sent to the extension.
Now that the extension has an array of base64 images, Id save them to chrome.storage.local in the extension's storage area.
Now you can show them in the popup, show them in a new tab for editing, or whatever
If you want to show them on the page in an overlay, just make a function to do that in the javascript listener class we made and send a message to it with the images to display
To get you started, here is a javascript listener class I use to do similar things in my extensions.
(note that this relies on John Resig's Simple JavaScript Inheritance which I highly recommend using when writing Classes )
// IMPORTANT NOTE you must reload your extension via chrome://extensions
// AND reload the browser tab in order for changes to this file to be seen!!
var PageActionListener = Class.extend({
/**
* This class is meant to be injected into a webpage
* once there, it listens for messages from an extension
* messages must pass like {pageAction:"someAction", ... }
* where someAction should map to a function in this class
* responses should take the form
* {success:true, pageAction:"someAction", data:"someData", ... }
*/
attachListener: function() {
/**
* Attaches a chrome message listener to the current page
* this allows the extension to call
* the functions in this class from the context of the page
* and receive responses from those functions via messaging
*/
var _this=this;
// Listen for messages from the popup
chrome.runtime.onMessage.addListener(function (msg, sender, extensionCallback) {
// First, validate the message links to a function
if (msg.pageAction) {
// then make sure its a legit function in this class
if(typeof _this[msg.pageAction] === "function"){
// call that fucntion
_this[msg.pageAction](msg,function(response){
extensionCallback(response);
});
}
else extensionCallback({success:false,msg:msg,error:"Action not found"});
return true;
}
});
},
getImages:function(msg,callback){
/**
* Traverses the DOM looking for images and returning them
* as an array of base64 strings
* #param object msg The message that triggered this action
* #param function callback A function to be called when the action below is complete
* passes to callback the images gathered from the page
*/
var images = [];
var $images= $('img');
$images.each(function(){
var url = this.src;
images.push(url);
});
// convert images to base64
$.ajax({
type: "POST",
url: "https://somedomain.com/shared-resources/php/encodeImagesToBase64.php", // you'll need to update this to your path
data: {urls:images},
success: function(response) {
response.msg=msg;
send the response back to the extension
callback(response);
},
error: function(xhr, status, error) {
callback({success:false,msg:msg,error:error.Message})
}
});
},
// add other functions that need to be called by the extension here
});
And here is the contents of encodeImagesToBase64.php to convert the images to base64:
<?php
if (isset($_POST['urls']) ){
$imageStrings=[];
foreach($_POST['urls'] as $url){
$imageStrings[]=base64_encode(file_get_contents($url));
}
echo json_encode(['success'=>true,'images'=>$imageStrings]);
}else{
echo json_encode(['success'=>false,'error'=>'Error: No images to encode']);;
}
Here is an example extension that kindof does what you want.
It'll need a ways to go to meet your actual needs but, it should be enough for you to understand the concepts and the approach Ive proposed above.
NOTE the example extension uses a copy of encodeImagesToBase64.php that is hosted on my server, you'll need to host your own and update the ajax call with the path to it. Ill leave mine up for now so you can test it out, but dont count on it being around forever :)

How to modify current url location in chrome via extensions

I want to create an extension that redirects the user to another website if he clicks on the extension button. So far I have only seen extensions which create a new tab for each click.
Is it possible to redirect the user to another website using the active tab?
I tried something like this:
chrome.browserAction.onClicked.addListener(function(tab) {
var url = "https://www.mipanga.com/Content/Submit?url="
+ encodeURIComponent(tab.url)
+ "&title=" + encodeURIComponent(tab.title);
document.location.href = url; // <-- this does not work
});
Attention: If you develop cross-browser extensions (I hope you do!), I recommend that you use chrome.tabs.query(). Please see Jean-Marc Amon's answer for more information. This answer still works in both Firefox and Chrome, but query() is more commonly used, has more options, and works in background pages and popup views.
From the chrome.tabs API, you can use getCurrent(), query(), or update().
Right now, I prefer update() as this allows you to update the current tab without needing to do much else.
NB: You cannot use update() from content scripts.
If updating the url from a content script is required then you should look to use query instead. Jean-Marc Amon's answer provides a wonderful example of how to get the active tab in this case (don't forget to upvote him!).
update()
let myNewUrl = `https://www.mipanga.com/Content/Submit?url=${encodeURIComponent(tab.url)}&title=${encodeURIComponent(tab.title)}`;
chrome.tabs.update(undefined, { url: myNewUrl });
Here, we have set the first argument of update to undefined. This is the tab id that you're wanting to update. If it's undefined then Chrome will update the current tab in the current window.
Please see Domino's answer for more information on update and also note that undefined is not needed. Again, please don't forget to upvote their answer as wellif you find it useful.
getCurrent()
getCurrent also cannot be called from a non-tab context (eg a background page or popup view).
Once you have the current tab, simply pass update().
chrome.tabs.getCurrent(function (tab) {
//Your code below...
let myNewUrl = `https://www.mipanga.com/Content/Submit?url=${encodeURIComponent(tab.url)}&title=${encodeURIComponent(tab.title)}`;
//Update the url here.
chrome.tabs.update(tab.id, { url: myNewUrl });
});
NB: In order to use this this functionality, you must ensure that you have the tabs permission enabled in your manifest.json file:
"permissions": [
"tabs"
],
You can use chrome.tabs.query too
chrome.tabs.query({currentWindow: true, active: true}, function (tab) {
chrome.tabs.update(tab.id, {url: your_new_url});
});
The chrome.tabs.update method will automatically run on the current active tab if no tab id is passed.
This has the added advantage of not requiring the tabs permission. Extensions with this permission warn the user that they can read the browsing history, so you should avoid asking for it if you don't need to.
Changing the current tab's URL is as simple as writing this:
chrome.tabs.update(undefined, {url: 'http://example.com'});
Or as mentionned by farwayer in the comments, you don't need to put two arguments at all.
chrome.tabs.update({url: 'http://example.com'});
The answers given here no longer work: the Chrome Tabs API can no longer be used by content scripts, only by service workers and extension pages.
Instead, you can send a message to a service worker to get it to update the location of the current tab: see https://stackoverflow.com/a/62461987.
See this for a simple working example.

Categories