Addon UI vs. content scripts

92 views
Skip to first unread message

Ben Bucksch

unread,
Feb 7, 2012, 5:31:53 PM2/7/12
to Jetpack Mailing-List, Myk Melez
I had understood why content scripts are needed for webpages. It's
fairly complicated and cumbersome, but it's needed for security and to
separate processes, so there's a real inherent need, so all the extra
work is justified.

However, I was quite astonished today to learn that even the addon's own
UI - i.e. Widget, Panel etc. loading data/foo.html - is running as
content script. This means I have to go though the same security
barriers just to talk to my own UI.

For example, I want to show a list of several email accounts, each with
several folders, each with a new mail count. I already have that nicely
as |Account| object holding |Folder|s with a nice cute API that it's
designed with love and I am happy with. I also have functions on the
object to trigger stuff like "show account/folder" etc.. Just that I
can't actually use it from the UI anymore. I have to marshall all
information I need to JSON or similar and pass that from lib/ to my UI
code. In the UI code, I now have a similar, but somewhat different API
than the |Account| object. What's more, I can't call any functions on
the |Account|, but I have to emit messages back, let lib/ catch them and
invoke |Account|.

That seems like a horribly complex way to do things and a complete waste
of time, because I have to replicate the Account API using JSON and
events, on both sides. A lot of code for what could be just passing the
obj and invoking a function on it, using the known and documented API.

In fact, in my XUL extension, I do just that. I don't see why it
couldn't be like that in Jetpack. The data/foo.html file and its JS file
are part of the addon, they can and should have the same security
context. There's no point in separating them for security. (There would
be, if the content script was a webpage on a server, but that's a
completely different case..)

I don't think it would matter either when there are several Mozilla
processes.
For example, if you look at
https://static.addons.mozilla.net/en-US/developers/docs/sdk/1.4/static-files/media/screenshots/modules/widget-content-osx.png
, then I don't think anybody in his right mind would make the "10:34 AM"
a separate Gecko process. Each webpage in a different process: yes, I
can see that. But all of chrome should be in the same process. Even if
there was one content process and one chrome process, it wouldn't make
sense to place the Addon bar in the chrome process and then place the
"10:34 AM" in a content process. The widget *is* chrome (by definition,
actually) and belongs in the chrome process.

So, I don't see any reason to let JetPack developers suffer so much just
to let them communicate with their own, local UI. Can this be solved
more like XUL extensions work, please? That I can get a reference to the
JS scope (|window object| or whatever) of the Widget and Panel content
and let them directly communicate?

Regards,

Ben

Jeff Griffiths

unread,
Feb 12, 2012, 6:59:32 PM2/12/12
to mozilla-la...@googlegroups.com
In 1.4 we introduced initial support for what we call 'Bypass Content
Scripts for Trusted Content':

https://wiki.mozilla.org/Labs/Jetpack/Release_Notes/1.4#New_stuff

Will added a fairly long description of how this currently works. We
consider the feature to be experimental currently; we'd be interested
in any comments you might have.

cheers, Jeff

> --
> You received this message because you are subscribed to the Google Groups
> "mozilla-labs-jetpack" group.
> To post to this group, send email to mozilla-la...@googlegroups.com.
> To unsubscribe from this group, send email to
> mozilla-labs-jet...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/mozilla-labs-jetpack?hl=en.
>

Ben Bucksch

unread,
Feb 12, 2012, 8:00:49 PM2/12/12
to mozilla-la...@googlegroups.com
On 13.02.2012 00:59, Jeff Griffiths wrote:
> In 1.4 we introduced initial support for what we call 'Bypass Content
> Scripts for Trusted Content':
>
> https://wiki.mozilla.org/Labs/Jetpack/Release_Notes/1.4#New_stuff
>
> Will added a fairly long description of how this currently works. We
> consider the feature to be experimental currently; we'd be interested
> in any comments you might have.

Thanks! I don't really understand it, though. It says:

> The key difference is that the page script accesses |port| and
> |postMessage| using the global |addon| object, rather than the global
> |self| object

I don't understand how that would help. Do I understand this correctly
that even with this feature, I have to use postMessage() or port.on() to
communicate with my UI, instead of just passing objects?
Or can I pass objects from the addon scope and have the UI JS call
functions on them directly?

Ben

Jeff Griffiths

unread,
Feb 12, 2012, 10:51:13 PM2/12/12
to mozilla-la...@googlegroups.com
On Sun, Feb 12, 2012 at 5:00 PM, Ben Bucksch
<ben.buck...@beonex.com> wrote:
...

> I don't understand how that would help. Do I understand this correctly that
> even with this feature, I have to use postMessage() or port.on() to
> communicate with my UI, instead of just passing objects?
> Or can I pass objects from the addon scope and have the UI JS call functions
> on them directly?

In its current state, you cannot pass objects around directly.

The port / postMessage style of separating lower-privileged content
code and main.js does not change, you're right. This is a major
difference in the design of the SDK ( which has intentional barriers
on communication ) and non-SDK addons. The changes we made in 1.4 are
more of a first step in the direction of making it easier to work with
content serverd from your addon's data folder than a complete
solution.

Thanks for the feedback!

Jeff

Ben Bucksch

unread,
Feb 13, 2012, 9:02:53 AM2/13/12
to mozilla-la...@googlegroups.com
On 13.02.2012 04:51, Jeff Griffiths wrote:
> The port / postMessage style of separating lower-privileged content
> code and main.js does not change, you're right. This is a major
> difference in the design of the SDK ( which has intentional barriers
> on communication ) and non-SDK addons

Yup, I understand. In general I agree and it's great.
I just think it's unnecessary in the "addon UI in data/ dir" case, and
that one case makes development a *lot* harder.

It's great to see that you make changes. I would like some feedback
whether you agree with my assessment and would allow some changes to
remove this problem.

Alexandre poirot

unread,
Feb 13, 2012, 10:48:06 AM2/13/12
to mozilla-la...@googlegroups.com
There isn't only a security reason to do so. There is e10s and multi-processes.
If we want to move addon code, i.e. common JS modules living in lib/, to another "addon process",
we would need to have such message passing API between modules and UI documents.
FYI, we were really really close to have addons working in another process some months ago,
but we froze this work due to e10s roadmap freeze.

I think the new `addon` global appearing in trusted UI document ease it a lot.
Another way to ease Jetpack usages would be to enable using CommonJS modules in UI documents too. (Having a `require` statement in these documents).
Then, I agree, this message passing communication tends to complexify addons code, but before removing it, we will need to ensure that giving raw access will be e10s-compatible.




2012/2/13 Ben Bucksch <ben.buck...@beonex.com>
--
You received this message because you are subscribed to the Google Groups "mozilla-labs-jetpack" group.
To post to this group, send email to mozilla-labs-jetpack@googlegroups.com.
To unsubscribe from this group, send email to mozilla-labs-jetpack+unsub...@googlegroups.com.

Andrew Sutherland

unread,
Feb 13, 2012, 11:40:18 PM2/13/12
to mozilla-la...@googlegroups.com
On 02/13/2012 07:48 AM, Alexandre poirot wrote:
> Another way to ease Jetpack usages would be to enable using CommonJS
> modules in UI documents too. (Having a `require` statement in these
> documents).

No enabling is required; you can already do so, it's just orthogonal to
Jetpack. I use RequireJS (http://requirejs.org/) in my (run-as-content)
UIs for about:nosy (https://github.com/asutherland/about-nosy) and the
deuxdrop messaging experiment (https://github.com/mozilla/deuxdrop).
I'm sure people would appreciate examples, templates, or an easy way to
accomplish that setup, of course!

Andrew

Jeff Griffiths

unread,
Feb 13, 2012, 11:50:24 PM2/13/12
to mozilla-la...@googlegroups.com

But, this would not allow someone to require modules from addon-kit,
right? I think what Alex is implying is that a document loaded from
./data would be viewed as 'privileged', and that we would then allow
those pages to use the SDK's loader infrastructure.

Aside: about:nosy rocks!

Andrew Sutherland

unread,
Feb 14, 2012, 1:14:10 AM2/14/12
to mozilla-la...@googlegroups.com
On 02/13/2012 08:50 PM, Jeff Griffiths wrote:
> But, this would not allow someone to require modules from addon-kit,
> right? I think what Alex is implying is that a document loaded from
> ./data would be viewed as 'privileged', and that we would then allow
> those pages to use the SDK's loader infrastructure.

Right. You could try and have any web-compatible CommonJS loader (that
does not require a define() wrapper) load modules from add-on kit, but
they would live in a separate universe from the jetpack universe and
would probably fail once the dependency chain reached something
requiring chrome.

I think both Alex's (presumed) meaning and my own are potentially useful.

The system jetpack loader is obviously vital if you need to do anything
with chrome privileges directly or transitively. It provides the chrome
access, the hardened implementation, and the security graph to make
review and auditing tractable for extensions. But it's also largely its
own little API universe. (And one that is effectively beyond the reach
of debuggers at this time.)

In the cases where developers simply desire the structuring provided by
modularized Javascript, and especially if they want to avoid coupling
their UI intimately to Firefox/Jetpack, RequireJS and other web/content
loaders can be a better alternative. Of course, this does assume your
implementation is already living in a fairly abstracted world.

A potential concern is that if Jetpack were only to make it easy to gain
access to the system loader from content, people would likely end up
just using that and doing themselves and the platform a disservice.

Andrew

Andrew Sutherland

unread,
Feb 14, 2012, 1:33:16 AM2/14/12
to mozilla-la...@googlegroups.com
On 02/13/2012 06:02 AM, Ben Bucksch wrote:
> Yup, I understand. In general I agree and it's great.
> I just think it's unnecessary in the "addon UI in data/ dir" case, and
> that one case makes development a *lot* harder.

Reading between the lines, it sounds to me like the problem is that the
current platform setup is trying to force you to draw a very serious
abstraction boundary in a place where you don't think you need one.
Given your work on Thunderbird, I'm quite confident you understand the
architectural need to get things off of a single central main thread,
but that you are unable to do so because the platform also makes that
infeasible.

What chrome privileges/special powers does your app need? More
specifically, what would it take for you to be able to move your backend
implementation with the nicely designed Account/Folder API into its own
process? Because if they lived in their own process, preferably one
with very few chrome privileges, it would not be a big deal for your UI
to live in that same process and synchronously interact with your API, etc.

For example, the deuxdrop messaging client's 'daemon process' lives in
its own hidden iframe so that it can be persistently operational. It
uses IndexedDB for storage and WebSockets for communication, so it does
not actually need chrome privileges* and would be
electrolysis-friendly. However, if it was trying to speak IMAP or
something that required a raw TCP socket, that would not work for it at
this time, and it would definitely need to live in the main process
where it can get at these things.

Andrew

*This is a simplification. Our crypto operations are provided by a
js-ctypes binding that is exposed into the non-chrome iframe, and that
is not electrolysis friendly.

Ben Bucksch

unread,
Feb 14, 2012, 8:32:24 AM2/14/12
to mozilla-la...@googlegroups.com
On 14.02.2012 07:33, Andrew Sutherland wrote:
> What chrome privileges/special powers does your app need? More
> specifically, what would it take for you to be able to move your
> backend implementation with the nicely designed Account/Folder API
> into its own process? Because if they lived in their own process,
> preferably one with very few chrome privileges, it would not be a big
> deal for your UI to live in that same process and synchronously
> interact with your API, etc.

1. In the "separate processes" world, each top-level Firefox window
would hopefully be its own process, right? But my Account is logged in
only once for the whole browser. So, if I placed all my code into that
containment, I'd get one containment per window, which means my addon
makes a login whenever the user open a new window.

2. I also implement XMPP in JS using nsISocket* . I don't think I have
raw sockets in a webbish context. (And no, I don't want to depend BOSH
and stuff.)

3. The account preferences are stored in Mozilla preferences and Firefox
password manager, as they should be.

4. Some of my code needs to interact with existing windows. E.g. you can
go to a certain webapp page directly from the addon, but I'm searching
for an existing open tab of the webapp, and then fire an event into that
to cause the desired state of the webapp.

This is just from the top of my head, there's probably more.
Plus, there's the implementation burden. It eased the transition to
Jetpack a *lot* to be able to use XPCOM, I could reuse most of my code
unchanged, there were only slight adaption for Components.utils.import()
-> require() etc.. Even if all of the above was possible in the sandbox,
I'd still need to rewrite all the code (most of that is already
abstracted in a certain way, but I bet there's still a lot remaining
that isn't).

Ben

Andrew Sutherland

unread,
Feb 27, 2012, 6:53:21 PM2/27/12
to mozilla-la...@googlegroups.com
On 02/14/2012 05:32 AM, Ben Bucksch wrote:
> 1. In the "separate processes" world, each top-level Firefox window
> would hopefully be its own process, right? But my Account is logged in
> only once for the whole browser. So, if I placed all my code into that
> containment, I'd get one containment per window, which means my addon
> makes a login whenever the user open a new window.

I'm not sure that top-level windows would end up with their own
processes; that would likely be problematic for the platform widgeting
toolkits. In any event, there would still be app-wide singleton things,
and indeed that's the only multiplicity that makes sense for your use-case.

I should elaborate that the hidden iframe I was discussing that we use
for deuxdrop is actually an iframe that lives in the singleton
application hidden window. See nsIAppShellService.hiddenWindow:
https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsIAppShellService


> 2. I also implement XMPP in JS using nsISocket* . I don't think I have
> raw sockets in a webbish context. (And no, I don't want to depend BOSH
> and stuff.)

It's my understanding that Boot2Gecko is planning to prototype and seek
to standardize raw socket support. Since you are dealing with this
use-case, it would probably be helpful for everyone if you join the
WebAPI list if you aren't already on it so that you can be involved in
the process:
https://lists.mozilla.org/listinfo/dev-webapi


Andrew

Reply all
Reply to author
Forward
0 new messages