GM_setValue/GM_getValue not working in event listener set with addEventListener?!?

243 views
Skip to first unread message

cc

unread,
Jul 26, 2009, 7:37:50 PM7/26/09
to greasemon...@googlegroups.com
This problem puzzles me a great deal, as I had thought I'd gotten this
technique to work (and responded to someone else here recently
accordingly). But apparently I hadn't finished debugging it yet, so
perhaps my advice should have been marked "untested" or something. :-[

I stripped down a test case, which triggers a "Greasemonkey access
violation: unsafeWindow cannot call GM_setValue." error in the JS
Console every time it runs, and exhibits some really bizarre behavior
with GM_getValue. Does anyone know how to explain this? (Namely, on GM
0.8.20090123.1 the second GM_getValue("type") returns the injected
textContent of the <script> tag, which is one of the strangest things
I've seen in any program I've ever written.)

Here it is:

// Attempts to set the type config entry to the value of the most recently passed element text
function listener(e) {
GM_setValue("type", e.target.textContent);
}

document.body.addEventListener("DOMNodeInserted", listener, true);

// Fires the DOM event by adding a node
function trigger(type) {
var n = document.createElement("span");
n.style.display = "none";
n.textContent = type.toString();
document.body.appendChild(n);
}

trigger('in GM script context');
alert("Type: " + GM_getValue("type"));
// Inject script, including trigger function, and execute
var nodScript = document.createElement("script");
nodScript.textContent = trigger + "\n\ntrigger('in injected page script');";
alert("nodScript: " + nodScript.textContent);
document.body.removeChild(document.body.appendChild(nodScript));
alert("Type: " + GM_getValue("type"));


cc

unread,
Jul 26, 2009, 8:07:06 PM7/26/09
to greasemon...@googlegroups.com
Here's a variant, making use of the location hack
(http://wiki.greasespot.net/Location_hack) instead of <script>
injection. Still has the problem with GM_functions being disallowed (is
this a deliberate security choice?), but doesn't have the insane problem
the <script> injection does with GM_setValue setting the calling
context's source instead of its parameter.

function listener(e) {
GM_setValue("type", e.target.textContent);
}

function trigger(type) { var n = document.createElement("span");


n.style.display = "none";
n.textContent = type.toString();
document.body.appendChild(n);
}

function showType() {


alert("Type: " + GM_getValue("type"));
}

document.body.addEventListener("DOMNodeInserted", listener, true);

trigger('in GM script context');
showType();
location.href = "javascript:" + trigger + "\n\ntrigger('in location hack context');"
showType();


cc

unread,
Aug 2, 2009, 9:29:06 PM8/2/09
to greasemon...@googlegroups.com
Well, I've dug around a bit more and found out why things aren't
working... now I just want to know how to work around this. I'm thinking
of .NET's concept of being able to validate and elevate a caller's
privileges -- a trusted agent, as it were. I guess userscripts aren't
trusted /that/ much? Maybe that's sensible, really.

cc wrote:
> Still has the problem with GM_functions being disallowed (is
> this a deliberate security choice?)

Digging into the GM source code, it sure looks like it was a deliberate
choice (which I'd rather like to hear the reasoning behind; I can't
myself quite figure it out). It's possible that it was originally
designed to allow this kind of thing but Firefox's stack-walk code
changed under GM_apiLeakCheck; I very much doubt this, though, as it'd
take quite a bit of changes to make this much of a difference. (Right
now, the stack starts in a javascript: URI for the location hack, which
makes perfect sense; therefore, because the root is untrusted, the whole
tree is untrusted.)

So I guess I'll have to fall back to a polling design.... On the upside,
if I get some good code working, maybe I can work it into a generalized
library for this kind of thing. Before I do that, though, anyone know of
a library that already exists for that? ;-)

Anthony Lieuallen

unread,
Aug 2, 2009, 9:42:03 PM8/2/09
to greasemon...@googlegroups.com
On 8/2/2009 9:29 PM, cc wrote:
> Digging into the GM source code, it sure looks like it was a deliberate
> choice (which I'd rather like to hear the reasoning behind; I can't
> myself quite figure it out).

In reverse-chronological but less-to-more-useful order:
http://groups.google.com/group/greasemonkey-dev/t/3eee8cfb32677bf1
http://groups.google.com/group/greasemonkey-dev/t/68a9fc3101cfdade
http://groups.google.com/group/greasemonkey-dev/t/933ecdb307c4386d

Note that the links here provide a direct and (mostly) straightforward
workaround, though it certainly could be easier to find.

cc

unread,
Aug 8, 2009, 1:41:55 PM8/8/09
to greasemon...@googlegroups.com
All right, so I've read through those threads, and I can understand
pretty well why this decision was made (and that it was indeed *made*,
not merely blundered into by accident ;-)). It makes a lot of sense.
However, I'm not seeing the workaround you mentioned.
In point of fact, my script requires something very like the failure
mode mentioned in the second thread, as you've probably noticed: I'm
spinning off a long-running task from inside the page itself (for
various reasons, which I'll probably re-examine; they may not be enough
to warrant this kind of enormous effort), and needing to get results
when the task is done (e.g. time taken and other basic stats). I need to
re-examine why I am in fact injecting functions and waiting for
callbacks; I believe the original reason was for performance, but I'm
not at all sure it's worth this much effort.

Still, performance is a big issue here; my script is O(n) [gag, I know],
and can easily reach the hundreds of milliseconds range on a large page
with a few tens of thousands of nodes (e.g. W3C standards pages).
Statistics are mostly performance-related, for diagnosing problems.

Taking a deep breath, stepping back, and looking at the whole project, I
can see several possible solutions:
1. Drop the statistics-logging. Possible, somewhat annoying, trivial.
1a) Only use statistics logging on my own machine, and use
unsafeWindow or similar kludgy [and VERY DANGEROUS!!!] hack, enabled by
a config setting.
2. Rework back to a previous design, and skip the entire injection
mechanism entirely. I'll have to check performance and other impacts of
this solution.
3. Find some other workaround, such as the one you mentioned, that
allows me to keep logging and injecting, but without using unsafeWindow.

I have gotten (1a) to work, pretty much, so I may be able to just use
that. I'd still greatly appreciate knowing what the workaround was, though.

P.S. At several points in the threads, upgrading to FF3beta was
mentioned as a way for userscript authors to avoid the problems
introduced by call-chain analysis and so forth, (apparently) without
suffering security holes. What happened to that, and why would that have
worked?
> ____________________________________________________________________________________
> Super simple small business
> invoicing for Mac OS X.
> http://click.lavabit.com/?pub=78&ad=1&url=aHR0cDovL3RoZS1kcmVhbS5jby51ay9pbnZvbGVyLw==
> ____________________________________________________________________________________
>

cc

unread,
Aug 29, 2009, 7:40:37 PM8/29/09
to greasemon...@googlegroups.com
Sorry it's taken so long to get back to the list on this. I think I've
finally figured out the workaround, purely by accident: use e.g.
window.setInterval() to wait for creation of the node. Makes sense, and
sure does seem to work. So /that's/ all right.

And just to clarify, I found out just exactly why I had wanted to inject
the script in the first place. As I suspected, it had been a performance
reason. On a test page with 128K nodes, it makes the difference between
a run time of 32000+ milliseconds (if working through the wrappers) and
~6500 milliseconds (if injected). (On a side note, I'm still trying to
figure out why it takes so long right now to run even in the injected
case; I'm almost positive I remember timings far lower than that, on the
same page, with a previous version of the script, more on the order of
~750 milliseconds -- still long, but tolerable.)

Anthony Lieuallen

unread,
Aug 29, 2009, 11:09:49 PM8/29/09
to greasemon...@googlegroups.com
On 8/29/2009 7:40 PM, cc wrote:
> Sorry it's taken so long to get back to the list on this. I think I've
> finally figured out the workaround, purely by accident: use e.g.
> window.setInterval() ..

Actually this is documented, if not in a wonderful location:

http://wiki.greasespot.net/0.7.20080121.0_compatibility#Workaround

Sorry you had trouble.

Reply all
Reply to author
Forward
0 new messages