Permission denied to access property 'Arbiter' - javascript

I have an iframe FB app. We have three places where we develop it: My localhost, stage server where we test the app, production server. Localhost and production have HTTPS. Localhost and stage apps have sandbox mode enabled. All versions of app are identical, code is the same. Stage and production are totally the same server machine with the same settings except of the HTTPS.
Now what is happening only at my stage server app: When I click on something where jQuery UI dialog should be summoned, it raises following error in my Firebug: Permission denied to access property 'Arbiter'. No dialog is summoned then. It's raised in somehow dynamically loaded canvas_proxy.php, within this code:
/**
* Parses the fragment and calls Arbiter.inform(method, params)
*
* #author ptarjan
*/
function doFragmentSend() {
var
location = window.location.toString(),
fragment = location.substr(location.indexOf('#') + 1),
params = {},
parts = fragment.split('&'),
i,
pair;
lowerPageDomain();
for (i=0; i<parts.length; i++) {
pair = parts[i].split('=', 2);
params[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
}
var p = params.relation ? resolveRelation(params.relation) : parent.parent;
// The user is not inside a frame (probably testing on their own domain)
if (p == parent || !p.Arbiter || !p.JSON) {
return;
}
p.Arbiter.inform(
'Connect.Unsafe.'+params.method,
p.JSON.parse(params.params),
getBehavior(p, params.behavior));
}
The line if (p == parent || !p.Arbiter || !p.JSON) { raises it. My script code linking the JS API looks like this:
<script src="https://connect.facebook.net/en_US/all.js#appId=APPID"></script>
Have anyone any clue why this could be happening? I found this and this, but these issues doesn't seem to be helpful to me (or I just don't get it). Could it be because of the HTTPS? Why it worked the day before yesterday? I am desperate :-(

whenever you have a permission denied message and you are dealing with frames or iframes, it's a document domain issue. One document belongs to domain x and the other is domain y. And notice that www.domain.com and domain.com are not the same document domains!
When you are tapping into the DOM of one framed document from another one, (whether it is for the purpose of changing the values of a page element or simply reading the values of some hidden variable or url etc), you will get a permission denied message unless both framed documents are served from the same/identical domains.
So, if one frame belongs to www.mydomain.com and the other happens to be just mydomain.com or www.someotherdomain.com, you get that bloody permission denied error.
And there is no way around it. And If there were, the identity theft problem would have sky-rocketed in no time.

Related

Popup to Parent Window Communication in Internet Explorer

I have an iframe embedded into a legacy application. Inside of the iframe I need to do oauth (I'm capturing authentication tokens for later use). In order to do oauth from within an iframe I need to use a popup window. What I need is for that popup window to communicate back to the iframe when oauth completes so the page within the iframe can refresh its data. I need to support IE 10+, Chrome, and Firefox, and everything I've tried works fine in Chrome/Firefox but fails in IE. My current solution (which almost works) looks like this:
/** From within the iframe **/
var storageName = 'SoProOauth';
var addAccountDeferred;
$window.addEventListener('storage', function (evt) {
if (evt.key == storageName) {
localStorage.removeItem(storageName);
getAccounts().then(function () {
addAccountDeferred.resolve();
});
}
});
// ... later ...
addAccount: function (type) {
addAccountDeferred = $q.defer();
var uri = util.format('/oauth/%s/connect?auth=%s&return_uri=%s',
type, configuration.get('auth'), encodeURI('/configure/oauthcomplete'));
if (Boolean(configuration.get('debug'))) {
uri += '&debug=true';
}
localStorage.removeItem(storageName);
var oauthWindow = $window.open(uri, 'oauth', 'width=800,height=600');
if (oauthWindow && oauthWindow.focus) oauthWindow.focus();
return addAccountDeferred.promise;
}
/** From within the popup **/
localStorage.setItem('SoProOauth', 'done');
$timeout(function () {
setInfo('This window can be closed');
$window.open('', '_self', '');
$window.close();
}, 500);
Basically, I'm writing to local storage from within the popup window, and listening for the write event in the parent window. This almost works - it works great in my local test environment but fails when I deploy it to the dev cluster. There could be two reasons why it fails: 1) when I run locally everything is over HTTP, but in the dev cluster it is over HTTPS (worse, the page that hosts the iframe is HTTP but the iframe contents are HTTPS), or 2) when I run locally everything is localhost, but in the dev cluster the iframe host is one machine (local intranet) and the contents of the iframe are public internet (AWS).
Other things I've tried: cookies (same result - works locally but fails deployed), and all of the window properties (window.opener, window.parent, and testing for window.closed() from within the iframe) - these don't work in IE as things get reset once the domain changes (which happens because we're doing oauth).
As you can see the UI code is AngularJS, but what you can't see is it is hosted by Node.js. So I've considered using something like socket.io but it seems so heavy-hitting - I really just need to send a quick event from the popup to the parent within the iframe. Any thoughts?

Deleting the local storage of a specific domain

I'm making an extension and while I can delete all the cookies of a specified domain, I can't delete its local storage.
So for example, if I visited The Telegraph's website, it keeps a local storage in my machine:
Origin: http://www.telegraph.co.uk/
Size on disk: 6.0 KB
I have tried using the remove() method from the storage api:
StorageArea.remove("http://www.telegraph.co.uk/");
and I'm getting the following error:
Error in event handler for browserAction.onClicked: StorageArea is not defined
Stack trace: ReferenceError: StorageArea is not defined
How can I programmatically make this work?
chrome.storage is a completely different API compared to localStorage. The former is only available to extensions, while the latter is specific to the domain of the website.
If you want to modify or clear the data in localStorage for a specific domain, then just insert a content script in the page that invokes localStorage.clear().
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(tab.id, {code: 'localStorage.clear()'});
});
If you want to clear the localStorage of a different origin, you have to load a page from that origin in a tab or frame and insert a content script in it. For example:
// background.js
var f = document.createElement('iframe');
f.sandbox = ''; // Sandboxed = disable scripts, etc.
f.src = 'http://example.com/#someuniqueid';
f.onloadend = function() {
f.remove();
};
// content script, declared in manifest file (read the documentation)
if (location.hash === '#someuniqueid') {
localStorage.clear();
}
try using
StorageArea.clear(function callback)
.remove accepts key string or array of keys to remove specific items.
Also i'm not sure if it will access storage of specific domains.
Try to check url before clearing

Access Dom constructed with iframes

There is page with economic calendar.
Scenario:
I am loading page in browser. For example this: http://www.dukascopy.com/swiss/english/marketwatch/calendars/eccalendar/
Look through it. And if there is interesting data for me, I click button and save all html with loaded iframe-data for parsing.
The problem is that necessary data on this page loaded with iframe. I read here that chrome denies iframe access with js-injects. But I can easy access necessary tables with "inspect element" from right-click menu. Is it possible to access it without js-injects? Just like automatic "inspect DOM element" or inner HTML?
I solved this issue in pyside (python qt webkit interface) this way:
def print_content():
res = web.page().mainFrame().childFrames()
for i in res:
s = i.documentElement().toOuterXml()
print(s)
But now I want do it from chrome(chromium) extension. Is there similar functional in modern chrome(chromium)?
For example:
chrome.web.page().mainFrame().childFrames() etc...
UPD:
Tried recomendation. Corrected manifest and add to content script:
chrome.runtime.sendMessage({greeting: "hello"}, function(response) {
var res = document.querySelectorAll("iframe");
var len = res.length;
for (var i = 0; i < len; i++) {
//alert(myStringArray[i]);
console.log(res[i].contentDocument);
//Do something
}
//console.log(res);
Getting this error:
Error in event handler for (unknown): Error: Blocked a frame with origin "dukascopy.com"; from accessing a cross-origin frame. at chrome-extension://bgoddjjeokncninlaacmjamgkohmcecb/content.js:19:23 at extensions::messaging:323:11 at Function.target.(anonymous function) (extensions::SafeBuiltins:19:14) at Event.dispatchToListener (extensions::event_bindings:386:22) at Event.dispatch_ (extensions::event_bindings:371:27) at Event.dispatch (extensions::event_bindings:392:17) at dispatchOnDisconnect
You need to inject your content script into the inner frame to access it. This is perfectly possible, it's just that the outer document's script cannot access the iframe contents.
This question covers how to do this in case of manifest-based injection.
For programmatic injection, you can pass all_frames: true in InjectDetails object for chrome.tabs.executeScript.

How to access performance object of every resource in a web page?

I can see, in Chrome Developer tools, loading time, time it took to get a particular resource from server and other info, for all of the resources in a webpage.
I want to capture these stats using JavaScript. How is it possible?
there is window.performance object available, but only for the requested page, not for page resources.
Is there any way to access performance object of all of the page resources.
You should be able to use window.performance.getEntries() to get resource-specific stats:
var resource = window.performance.getEntries()[0];
console.log(resource.entryType); // "resource"
console.log(resource.duration); // 39.00000000430737
console.log(resource.startTime); // 218.0000000007567
Sample from the above link:
There is still a bug in latest version of chrome - 29.0.1547.76 m
When you raise an xmlhttprequest, lets say while downloading an image, you can see that the resource is downloaded with status code 200 OK in network tab, but the performance.getEntries() or performance.getEntriesByName(resourceUrl) doesn't list the resource entry. When the page load is complete and you evaluate performance.getEntriesByName(resourceUrl) in console, it lists properly. So, there is a lag in chrome while populating the resource entries in performance entries?
In IE10, this works perfectly fine.
window.performance.getEntries()
may return not all resources. after bufferful some records is disapear
need check it before it happend
head code part
var storedEntries = [];
var updateStoredEntries = p => {
storedEntries.concat(
p.getEntries().filter(rec => /yourRegExp/.test(rec.name))
)
};
performance.addEventListener('resourcetimingbufferfull', e => {
updateStoredEntries(e.target)
});
...
later part
updateStoredEntries(performance)

Accessing Google Analytics window._gaq from Chrome Extension

I'm writing a chrome extension, mostly for learning purpose which will show me the Google analytics tracking id (UA-xxxxxx-x) if Google Analytics is installed.
I understand that I need to use sendRequest to a content script in the page to retrieve information, and have successfully implemented that functionality
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
// analytics request check GA and send back
if(request.requestDetail == "analytics") {
console.log(window._gaq);
console.log(window._gaq._getAsyncTracker()._getAccount());
// unknown response, send back nothing!
} else {
sendResponse({});
}
});
The listener is receiving the request, Google Analytics is definately installed on the webpage I'm testing, window._gaq and window._gaq._getAsyncTracker()._getAccount() are both accessible via the console and returns what I expect.
Why is window._gaq undefined when accessing via the listener? How should I access it from a chrome extension?
I've got an idea that there is a security reason for this so have also tried modifying the manifest to include the below but still no luck
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"
I suppose a secondary question would be:
Is what I'm trying to achieve possible in the manner I am using (I have managed to get a similar result using regex matching on the contents of the page, but would like to access the objects directly)
This has nothing to do with Content Security Policy. I think you're injecting a content script into web pages and trying to access variables in the web page. Because of content scripts are executed in an isolated world, you cannot directly do this. See https://developer.chrome.com/trunk/extensions/content_scripts.html#execution-environment for more detail.
To access variables in web pages (necessary in your case), you must inject a <script> tag in the page. Retrieve Google Analytics ID in that script, and communicate with the content script (https://developer.chrome.com/trunk/extensions/content_scripts.html#host-page-communication) to have the content script send it back to your extension.
Here's a simple example (Disclaimer: Just to illustrate how to do it. I didn't test it myself.):
window.addEventListener("message", function(event) {
if (event.source != window)
return;
if (event.data.type && (event.data.type == "FROM_PAGE")) {
chrome.extension.sendMessage(...); // Send analytics ID (in event.data.googleAnalyticsId) to your extension here
}, false);
var script = document.createElement('script');
script.appendChild(document.createTextNode('window.postMessage({googleAnalyticsId: (window._gaq ? window._gaq._getAsyncTracker()._getAccount() : ""), type: "FROM_PAGE"}, "*");');
document.appendChild(script);
Also note that chrome.extension.onRequest/sendRequest has been deprecated for a long time (https://developer.chrome.com/trunk/extensions/whats_new.html#20). You should use onMessage/sendMessage instead.
Though I'm not particularly proud of this one, it works; I don't think you can access the variables on the page without injecting another script into the page.
var find_ga_account = function(){
var scripts = document.querySelectorAll('script:not([src])'),
i = 0,
match,
ua = false;
for( ; i < scripts.length; i++){
match = scripts[i].textContent.match(/_setAccount['"]+,[\s]?['"]+(.*)['"]+/)
if(match && match.length > 0){
ua = match[1];
}
}
return ua;
}

Categories

Resources