Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Components.utils.evalInSandbox: Relative URLs, and "global" variables

601 views
Skip to first unread message

Peter Valdemar Mørch

unread,
Apr 30, 2011, 9:02:14 AM4/30/11
to
I'm developing a "Remote Control" extension[1]. I'd like to be able to
run javascript provided by the user on a page safely, and for that I
use Components.utils.evalInSandbox().

I'm expecting that any javascript run in the sandbox behaves *exactly*
like it would if run on the page itself. Is that a reasonable
expectation? How can I achieve it?

Problem 1) Relative URLs
========================================

I expect that on e.g. http://www.mozilla.org a command of
window.location='foo.html' should open http://www.mozilla.org/foo.html
. That is what would happen if it were called on the page. But instead
it redirects to jar:file:///usr/lib/firefox-3.6.17/chrome/browser.jar!/
content/browser/foo.html . I've seen this asked other places too [2]
[3], but I didn't find any good answers. In [3], Boris Zbarsky says
> When we change the base URI behavior to match the W3C proposal and take the base
> URI from the window the XMLHttpRequest object was created on, this might get better.
But as my window.location example illustrates, this seems broader than
XMLHttpRequest.

Anything I should do differently in my code [4] to make relative URLs
work properly?

Problem 2) "Global" variables
========================================
The sandbox doesn't seem to be able to set/get "global" variables
properly. E.g.

foo={a:23, b:34}

Sets window.foo on the page, but not when run in the extension.
However, if foo already exists like above, (e.g. set through firebug),
then

foo.a = 83

run in the sandbox *does' change the global foo. Also,

window.foo={a:23, b:34}

does work. (!?)

How can I get "global" variables to work properly, so that
variable = something
and
window.variable = something
both do the same thing as each other and as they would if run on the
page?

Thank you for your time reading this far.

1: https://addons.mozilla.org/en-US/firefox/addon/remote-control/
2: http://forums.mozillazine.org/viewtopic.php?f=19&t=1517525
3:
http://groups.google.com/group/mozilla.dev.tech.xpcom/browse_frm/thread/1883519f1b24f91d/23fd1e82e31f84ff?lnk=gst&q=help+with+evalInSandbox#23fd1e82e31f84ff
4: https://github.com/pmorch/FF-Remote-Control/blob/V_0.1/chrome/content/overlay.js#L232

RodMcguire

unread,
Apr 30, 2011, 1:03:39 PM4/30/11
to
"I'm expecting that any javascript run in the sandbox behaves *exactly*
like it would if run on the page itself. Is that a reasonable
expectation? How can I achieve it?"

Greasemonkey does a lot of what you appear to want to do. Some javascript that runs correctly on a page won't in a sandbox because of XPCNativeWrapper problems, though there ways to write "proper javascript" that avoids these problems.

The initial versions of Greasemonkey injected a userscript directly into a page and wrapped the userscript in a anonymous function to isolate its variables etc from the other scripts on that page. When Greasemonkey changed to running userscripts in a sandbox, this wrapping was kept for backwards compatibility purposes - a main one being that it allows a toplevel "return;" statement for early script termination.

Then at one point Greasemonkey was changed to do away with the function wrapper and all sorts of weirdness started showing up with regard to what what basic javascipt functions the sandbox could see and I recall that Mozilla sandbox bugs seemed implicated. See for example[1]

"The function wrapper does two things: one good, one bad.
The good one is that it protects the script's scope from global
identifiers in the GM sandbox (which for some reason -- probably
Mozilla bugs -- is heavily polluted with identifiers we can't
override)."

Greasemonkey was changed so that the default behavior was to wrap a userscript in an anonymous function. This could be prevented by including the metadata keyword "@unwrap" and I don't recall if the Moz sandbox bugs were ever tracked down or if anybody has checked to see if they have been fixed.


http://wiki.greasespot.net/Avoid_Common_Pitfalls_in_Greasemonkey
http://commons.oreilly.com/wiki/index.php/Greasemonkey_Hacks/Getting_Started#Pitfall_.231:_Auto-eval_Strings
http://wiki.greasespot.net/Global_object

[1] https://groups.google.com/forum/#!msg/greasemonkey-dev/A6RwuonRvXw/JjMAQHxwEdYJ

Peter Valdemar Mørch

unread,
May 1, 2011, 7:38:50 PM5/1/11
to
Thanks, Rod, for your input.

I tried installing greasemonkey v. 0.9.2 (been wanting to do that for
a long time anyway), and it too experienced the same problems. So I'm
not the only one. The mere presence of http://wiki.greasespot.net/Avoid_Common_Pitfalls_in_Greasemonkey
leads me to conclude that my original assumption:

> I'm expecting that any javascript run in the sandbox behaves *exactly*
> like it would if run on the page itself. Is that a reasonable
> expectation?

was naive. evalInSandbox can not be used to execute javascript
*exactly* like in a page.

http://commons.oreilly.com/wiki/index.php/Greasemonkey_Hacks/Getting_Started#Pitfall_.238:_Calling_Remote_Page_Scripts
says:
"You should never call methods on unsafeWindow unless you completely
trust the remote page not to mess with you."

:-) I don't trust the (external) source of my javascript. I only want
them to be able to mess with untrusted page stuff.

Firebug does not experience these problems though, and it is an
extension too, so I got the tracing version of Firebug, enabled
tracing and issued:
window.location="bogus.html"
in Firebug. It works. As does everything else I can think of. In the
trace I can see that Firebug uses evaluateByEventPassing(), and not
evaluateInSandbox() (that calls evalInSandbox()). So Firebug got it to
work by not using evalInSandbox() at all!

Next step I guess is to see how firebug wrote
evaluateByEventPassing()... But it's 01:10 and I'm off to bed...

Peter

PS: Here are some details of what I tried with greasemonkey:

Re my problem 1: Relative URLs
=================================
A greasemonkey script whose only line is window.location="bogus.html"
also redirected to jar:file:///usr/lib/firefox-3.6.17/chrome/
browser.jar!/content/browser/bogus.html
so greasemonkey also has my problem 1.

BTW, window.location worked fine, I didn't need window.location.href
as it says in http://commons.oreilly.com/wiki/index.php/Greasemonkey_Hacks/Getting_Started#Pitfall_.237:_location

Re my problem 2: "Global" variables
======================================
If I create this HTML:

--------------------------------
<html>
<head>
<title>Test page</title>
<script type="text/javascript"><!--
function logSomething(msg) {
console.log("logSomething:" + msg);
}
logSomething("directly in page");
function showA() {
console.log("A is", A);
}
--></script>
</head>
<body>
<span style="color:red">Test page body</span>
<div onclick="showA()">clickme</div>
</body>
</html>
--------------------------------

And run this in a greasemonkey script:

--------------------------------------------
console.log("Trying to call logSomething");
A="from greasemonkey";
try {
logSomething("from greasemonkey script");
} catch (e) {
console.log("Exception", e);
}
--------------------------------------------

I get this in the log:

--------------------------------
logSomething:directly in page
Trying to call logSomething
Exception ReferenceError: logSomething is not defined
{ message="logSomething is not defined", more...}
--------------------------------

When I then click on clickme, I get this in the log:

--------------------------------
A is not defined
--------------------------------

I need this instead:

--------------------------------
console.log("Trying to call logSomething");
unsafeWindow.A="from greasemonkey";
try {
unsafeWindow.logSomething("from greasemonkey script");
} catch (e) {
console.log("Exception", e);
}
--------------------------------

I'm actually surprised i needed unsafeWindow.logSomething() but I
guess that is a topic for a separate thread.

0 new messages