Hooking Date() in XBL/CSS/JS

1 view
Skip to first unread message

Mike Perry

unread,
Mar 30, 2007, 1:01:34 AM3/30/07
to dev-te...@lists.mozilla.org, dev-ext...@lists.mozilla.org
Thus spake Mike Perry (mike...@fscked.org):

> Hello,
>
> I'm trying to develop a Firefox extension for the Tor network
> (http://tor.eff.org) that handles various Javascript objects and
> plugins that are dangerous to anonymity and privacy. (see in
> particular: http://gemal.dk/browserspy/date.html and
> http://gemal.dk/browserspy/css.html).
>
> The main issue I'm concerned about right now is the timezone
> information associated with Javascript's Date(). I'm trying to hook
> this object to return UTC values, but I've run into a couple of snags:
>
> 1. Date() is both a function and a class. I can hook the non-UTC
> methods with Date.prototype to point to their UTC versions, but the
> problem is that Date() itself can still be called as a function to
> return a string that contains the timezone. If I try to redefine a
> constructor function Date() with the prototype statements inside that
> function, I lose access to the original Date() implementation to get
> the UTC time.
>
> Should I try to use an XBL binding? If I create a binding with
> a constructor element, can I put my hook code inside a CDATA and hook
> it to a script tag with a CSS stylesheet installed with my extension?
> Will this constructor actually run before every script tag's
> javascript, and will its modifications to Date() be used by the code
> in each tag? Or do I need to do additional acrobatics to get the
> scoping right?

So I've made some progress. It seems you can in fact hook Date
globally from an XBL binding, if you abuse the 'var'-less semantics
like so:

<binding id="script-tag">
<implementation>
<constructor>
<![CDATA[
// TODO: set/check some global var to see if this has applied yet
var tmpDate = Date;
Date = function() {
var tmp = new tmpDate();
return tmp.toUTCString();
}
]]>
</constructor>
</implementation>
</binding>

link,script {
-moz-binding:
url("chrome://torbutton/content/jshooks.xbl#script-tag") !important;
}

Presumably I can fill out that function with the rest of the
object/prototypes as well, but I haven't done that yet, because I'm
having trouble getting my XBL binding to apply early enough. The XBL
bindings seem to be applying after the script tag executes, especially
if the script is being fetched from a src location.

This means that if the script tag is the first tag in the document, I can't
intercept the Date call, even if I were to try to write a css binding
for all tags...

Does anyone know how to give XBL bindings some kind of priority before
a src attribute fetch and/or before the evaluation of the javascript
contained therein? None of the DOM handle events seem to be right for
the job..

Or is it possible to create an XBL binding that applies to 'document'
before ANY content loads? Or some other hack to execute javascript
code in the context of a window before any remote javascript gets to
run?


--
Mike Perry
Mad Computer Scientist
fscked.org evil labs

Mike Perry

unread,
Mar 30, 2007, 4:51:10 AM3/30/07
to dev-te...@lists.mozilla.org, dev-ext...@lists.mozilla.org
Thus spake Boris Zbarsky (bzba...@mit.edu):

> Mike Perry wrote:
> > link,script {
> > -moz-binding:
> > url("chrome://torbutton/content/jshooks.xbl#script-tag") !important;
> > }
>

> What if neither is present in the document?

Forgive me, I'm not a web developer, in fact I just started learning
javascript 4 days ago. You just made me realize you can do something
as crazy as
<a href="/" onMouseOver="(function(){a=Date();})()">Touch me</a>.

So hooking specific tags is out. Fortunately, I don't need to evaluate
at every tag, just before the first one. Unfortunately, it appears
that even for the html tag, my constructor code STILL runs after the
javascript executes... So perhaps XBL is out.

> > Or some other hack to execute javascript
> > code in the context of a window before any remote javascript gets to
> > run?
>

> _This_ on the other hand, is more or less doable. There are various solutions
> out there, but I seem to recall that Greasemonkey in particular has this solved...

Do you have any ideas how it might be done? Greasemonkey was of course
the first thing I tried. However, it loads scripts on the 'load'
event, after all code on the page has already run...

I've tried setting a ProgressListener, which DOES fire a few times
before the script (once for STATE_START stateChange and also a few
calls to progressChange). However, modifying the 'window.Date' global
from within that handler in my extension doesn't seem to affect the
loaded page. In fact, even using the window from
getMostRecentWindow("navigator:browser") seems to be not applying to
the loaded javascript.

So it appears I'm running out of options. nsIContentPolicy is the only
event system I can find that's left, unless you are aware of others?

eric...@yahoo.com

unread,
Mar 30, 2007, 9:01:06 AM3/30/07
to dev-extensions
Mike,
You should be looking at the constructor property; e.g.,
function MyDate() {}
Date.prototype.constructor = MyDate;

As to the stylesheet question, which I don't think you posted to this list, you can override web page stylesheets without an extension. The CSS specification defines the concept of "origins" (author, reader, and user agent). From "CSS - The Definitive Guide, 3rd Ed": "Under normal circumstances, the author's styles win out over the reader's
styles. !important reader styles are stronger than any other styles,
including !important author styles. Both author and reader styles
override the user agent's default styles."

It's my understanding that the reader origin for FF is defined in userContent.css http://www.mozilla.org/support/firefox/edit#content

IIRC in the page you linked to, the author creates an anchor and then uses javascript to get the computed color style of the anchor. If it's the color of the a:visited pseudoclass, he knows you've visited the uri represented in the anchor. Is this correct? I would try editing a:visited in userContent.css (with !important) and see if his page has access to that rule. I suspect webpages shouldn't be able to determine the correctly computed styles when a reader origin is present.

_______________________________________________
dev-extensions mailing list
dev-ext...@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-extensions


Mike Perry

unread,
Mar 30, 2007, 6:58:41 PM3/30/07
to dev-extensions
Thus spake eric...@yahoo.com (eric...@yahoo.com):

> Mike,
> You should be looking at the constructor property; e.g.,
> function MyDate() {}
> Date.prototype.constructor = MyDate;

Yes, the major problem right now is getting a valid window at an early
enough time to do this hook. A script src tag in the document head is
read and executed before just about every event I can find. Some
progressListener events execute before the load, but they do not have
windows constructed at that point to recieve the new Date global.

> As to the stylesheet question, which I don't think you posted to
> this list, you can override web page stylesheets without an
> extension. The CSS specification defines the concept of "origins"
> (author, reader, and user agent). From "CSS - The Definitive Guide,
> 3rd Ed": "Under normal circumstances, the author's styles win out
> over the reader's styles. !important reader styles are stronger than
> any other styles, including !important author styles. Both author
> and reader styles override the user agent's default styles."
>
> It's my understanding that the reader origin for FF is defined in
> userContent.css http://www.mozilla.org/support/firefox/edit#content
>
> IIRC in the page you linked to, the author creates an anchor and
> then uses javascript to get the computed color style of the anchor.
> If it's the color of the a:visited pseudoclass, he knows you've
> visited the uri represented in the anchor. Is this correct? I would
> try editing a:visited in userContent.css (with !important) and see
> if his page has access to that rule. I suspect webpages shouldn't be
> able to determine the correctly computed styles when a reader origin
> is present.

Yeah, I tried this. The problem is that you can add additional
attributes even to !imporant stylesheets defined in userContent.css.
You just can't override existing attributes. This obviously is not
what I need. There are probably a million different attributes that
can be tacked on to a given style rule that the author can check for,
and defining them all will certainly make links look ridiculous for
many sites.

Mike Perry

unread,
Mar 30, 2007, 7:24:29 PM3/30/07
to dev-ext...@lists.mozilla.org
Thus spake Neil (ne...@parkwaycc.co.uk):

> Mike Perry wrote:
>
> >I've tried setting a ProgressListener, which DOES fire a few times before the script (once for STATE_START stateChange and also a few calls to progressChange). However, modifying the 'window.Date' global from within that handler in my extension doesn't seem to affect the loaded page. In fact, even using the window from getMostRecentWindow("navigator:browser") seems to be not applying to the loaded javascript.
> >
> >

> That's because those are your window, not the loaded page's window,
> which is I believe available as the DOMWindow attribute on the
> aWebProgress parameter.

aWebProgress is null for all progressChange events and for all but
stateChange STATE_START (in which DOMWindow refers to some other
window or is reset shortly thereafter) or STATE_STOP, which is too
late.

Does this count as a bug? Why can't I seem to get a window of the
current document while it's loading..

eric...@yahoo.com

unread,
Mar 30, 2007, 9:37:32 PM3/30/07
to Mike Perry, dev-extensions
> Mike,
> You should be looking at the constructor property; e.g.,
> function MyDate() {}
> Date.prototype.constructor = MyDate;

>>Yes, the major problem right now is getting a valid window at an early enough time to do this hook. A script src tag in the document head is read and executed before just about every event I can find. Some progressListener events execute before the load, but they do not have windows constructed at that point to recieve the new Date global.<<

Perhaps I'm missing something, but why don't you replace the Date prototype constructor in an overlay of browser.xul? This is executed before any web content loads. No events needed.

> As to the stylesheet question, which I don't think you posted to
> this list, you can override web page stylesheets without an
> extension. The CSS specification defines the concept of "origins"
> (author, reader, and user agent). From "CSS - The Definitive Guide,
> 3rd Ed": "Under normal circumstances, the author's styles win out
> over the reader's styles. !important reader styles are stronger than
> any other styles, including !important author styles. Both author
> and reader styles override the user agent's default styles."
>
> It's my understanding that the reader origin for FF is defined in
> userContent.css http://www.mozilla.org/support/firefox/edit#content
>
> IIRC in the page you linked to, the author creates an anchor and
> then uses javascript to get the computed color style of the anchor.
> If it's the color of the a:visited pseudoclass, he knows you've
> visited the uri represented in the anchor. Is this correct? I would
> try editing a:visited in userContent.css (with !important) and see
> if his page has access to that rule. I suspect webpages shouldn't be
> able to determine the correctly computed styles when a reader origin
> is present.

>>Yeah, I tried this. The problem is that you can add additional attributes even to !imporant stylesheets defined in userContent.css. You just can't override existing attributes. This obviously is not what I need. There are probably a million different attributes that can be tacked on to a given style rule that the author can check for, and defining them all will certainly make links look ridiculous for many sites.<<

Sorry, I don't have an answer then short of not keeping history. Perhaps you can open a bugzilla issue which describes a security feature around the exposure of CSS pseudoclasses .


eric...@yahoo.com

unread,
Mar 30, 2007, 9:45:21 PM3/30/07
to Mike Perry, dev-ext...@lists.mozilla.org
I believe window.Date === Date. IOW, you don't need to override window.Date.constructor. Date.constructor will suffice. You don't need a window context. As I wrote before, do this from a browser.xul overlay. Note: none of this is guaranteed, it's just my feeling from having written extensions :)

----- Original Message ----
From: Mike Perry <mike...@fscked.org>
To: dev-ext...@lists.mozilla.org
Sent: Friday, March 30, 2007 7:24:29 PM
Subject: Re: Hooking Date() in XBL/CSS/JS

Thus spake Neil (ne...@parkwaycc.co.uk):

Mike Perry

unread,
Mar 30, 2007, 10:24:44 PM3/30/07
to dev-extensions
Thus spake eric...@yahoo.com (eric...@yahoo.com):

> > Mike, You should be looking at the constructor property; e.g.,
> > function MyDate() {} Date.prototype.constructor = MyDate;
>
> >>Yes, the major problem right now is getting a valid window at an
> >>early enough time to do this hook. A script src tag in the
> >>document head is read and executed before just about every event I
> >>can find. Some progressListener events execute before the load,
> >>but they do not have windows constructed at that point to recieve
> >>the new Date global.<<
>
> Perhaps I'm missing something, but why don't you replace the Date
> prototype constructor in an overlay of browser.xul? This is executed
> before any web content loads. No events needed.

Where would I put the code for this? I just threw some stuff in the
<script> tag of my xul and it runs on browser start, but again, the
global variables are stored in 'window' of the current window only..
That object seems to get cleared every time a new document is loaded.

Is there any way to get a unique identifier of javascript object
instances in general or of 'window' in particular? Maybe I can try to
track my inability to get window references by printing out unique ids
for each one I touch.

Mike Perry

unread,
Mar 30, 2007, 10:28:21 PM3/30/07
to dev-extensions
Thus spake Mike Perry (mike...@fscked.org):

> Thus spake eric...@yahoo.com (eric...@yahoo.com):


>
> > > Mike, You should be looking at the constructor property; e.g.,
> > > function MyDate() {} Date.prototype.constructor = MyDate;
> >
> > >>Yes, the major problem right now is getting a valid window at an
> > >>early enough time to do this hook. A script src tag in the
> > >>document head is read and executed before just about every event I
> > >>can find. Some progressListener events execute before the load,
> > >>but they do not have windows constructed at that point to recieve
> > >>the new Date global.<<
> >
> > Perhaps I'm missing something, but why don't you replace the Date
> > prototype constructor in an overlay of browser.xul? This is executed
> > before any web content loads. No events needed.
>
> Where would I put the code for this? I just threw some stuff in the
> <script> tag of my xul and it runs on browser start, but again, the
> global variables are stored in 'window' of the current window only..
> That object seems to get cleared every time a new document is loaded.

Actually perhaps this is a permissions thing? regular js can't access
extension js functions. Maybe I need to set some permissions attribute
to say that my window.Date is accessible by non-privileged js?

eric...@yahoo.com

unread,
Mar 30, 2007, 11:23:15 PM3/30/07
to Mike Perry, dev-extensions
You need to read about overlays, a fundamental extension concept. Have a look through developer.mozilla.org. After you understand overlays, overlay browser.xul with your Date constructor (deferring to the original if so needed).

----- Original Message ----
From: Mike Perry <mike...@fscked.org>
To: dev-extensions <dev-ext...@lists.mozilla.org>
Sent: Friday, March 30, 2007 10:24:44 PM
Subject: Re: Hooking Date() in XBL/CSS/JS

Thus spake eric...@yahoo.com (eric...@yahoo.com):

> > Mike, You should be looking at the constructor property; e.g.,
> > function MyDate() {} Date.prototype.constructor = MyDate;
>
> >>Yes, the major problem right now is getting a valid window at an
> >>early enough time to do this hook. A script src tag in the
> >>document head is read and executed before just about every event I
> >>can find. Some progressListener events execute before the load,
> >>but they do not have windows constructed at that point to recieve
> >>the new Date global.<<
>
> Perhaps I'm missing something, but why don't you replace the Date
> prototype constructor in an overlay of browser.xul? This is executed
> before any web content loads. No events needed.

Where would I put the code for this? I just threw some stuff in the
<script> tag of my xul and it runs on browser start, but again, the
global variables are stored in 'window' of the current window only..
That object seems to get cleared every time a new document is loaded.

Is there any way to get a unique identifier of javascript object


instances in general or of 'window' in particular? Maybe I can try to
track my inability to get window references by printing out unique ids
for each one I touch.

--

Mike Perry
Mad Computer Scientist
fscked.org evil labs

Mike Perry

unread,
Mar 30, 2007, 11:58:17 PM3/30/07
to dev-extensions
Thus spake eric...@yahoo.com (eric...@yahoo.com):

> You need to read about overlays, a fundamental extension concept.
> Have a look through developer.mozilla.org. After you understand
> overlays, overlay browser.xul with your Date constructor (deferring
> to the original if so needed).

Yeah. Like I said, I did this. The fundamental problem seems to be
that global variables and functions created within extensions are not
available to unprivileged javascript. I got code executing in the
overlay script tag that added Date to window there, but the problem is
it is not visible to any loaded pages.

However, at long last I have a solution. It turns out I can manipulate
the partially formed dom and insert a <script> tag from
nsIWebProgressListener.onLocationChange(). Code executed in the
appended script tag is unprivileged javascript, and thus can add
global variables to window that are visible to other javascript on the
page. If I simply create a window.Date global inside onLocationChange it
doesn't work, hinting to me it's a permissions issue.

So long, and thanks for all the script! ;)

Neil

unread,
Mar 31, 2007, 5:30:22 PM3/31/07
to
eric...@yahoo.com wrote:

>Perhaps you can open a bugzilla issue which describes a security feature around the exposure of CSS pseudoclasses
>

Bug 224954.

--
Warning: May contain traces of nuts.

Reply all
Reply to author
Forward
0 new messages