Jsd3 #1386

Merged
merged 2 commits into from Feb 10, 2012

Projects

None yet

5 participants

@ellisonbg
Member

Adding handling of dynamic javascript output to the notebook. I take the JS string and simply call eval on it. The enclosing scope has the element so the JS code can insert things into the DOM at the right point on the page. The code is not eval'd when the notebook is loaded or cells are pasted - only when they are executed.

Here is an example:

from IPython.core.display import Javascript
Javascript("element.html('hi')")

Currently, the full jquery/jqueryui libs are available for use. The JS classes that we use in the client are also available, so users can muck with the notebook itself. This includes running code in the kernel. BUT, the kernel will need to be refactored to pull that off. Once that is done, we should be ready for manipulate/interact style things.

Do we want to ship d3 and load it in the notebook for people to use? It really needs to be loaded in advance by us.

I can't wait to see how people use this!

@fperez
Member
fperez commented Feb 7, 2012

Quick q: why do we need to load d3 ourselves? I'm not too happy about enshrining a particular JS library right away... I mean, from what I've seen d3 is awesome, but I'd prefer if we could take a more hands-off approach there, and let various users and projects figure out which JS tools they end up using.

@ellisonbg
Member

There are two aspects:

  1. It has to be hosted somewhere. I don't know of any place that is
    hosting d3 in a CDN like manner. This is why we need to include it in
    our source code.
  2. It has to be loaded using a script tag. Doing that dynamically is
    a bit of a pain.

Point 2 is an annoyance, point 1 has to be solved and the simplest way
of doing that is to include it ourselves. I will look around to see
if I can find a CDN version of it.

Cheers,

Brian

On Tue, Feb 7, 2012 at 9:33 AM, Fernando Perez
reply@reply.github.com
wrote:

Quick q: why do we need to load d3 ourselves?  I'm not too happy about enshrining a particular JS library right away... I mean, from what I've seen d3 is awesome, but I'd prefer if we could take a more hands-off approach there, and let various users and projects figure out which JS tools they end up using.


Reply to this email directly or view it on GitHub:
#1386 (comment)

Brian E. Granger
Cal Poly State University, San Luis Obispo
bgranger@calpoly.edu and ellisonbg@gmail.com

@cschin
cschin commented Feb 7, 2012

I think it will be great to make it more general to be used other than d3, but it might be a good idea to start with one framework before it gets to complicated. It will be nice that a codecell can run javascript, but there is a good chance that arbitrary can totally mess up the whole notebook DOM. My earlier hacking uses IFRAME or open a new window to avoid that (e.g. https://github.com/cschin/IPython-Notebook---d3.js-mashup). It seems to me we need some "namespace" to constrain about what and where the javascript can manipulate. I don't have a good solution except the IFRAME thing now.

@wilsaj
wilsaj commented Feb 7, 2012

I saw this on the list and got really excited about it.

jQuery has a getScript method for dynamically loading a file which seems to work regarding issue 2. With a sym link to an external d3 dir in frontend/html/notebook/static

from IPython.core.display import Javascript
Javascript("$.getScript('/static/d3/d3.js')")

works as expected. For security reasons, you can't load local resources via "file:///*" urls but if you add a mechanism to expose additional static directories via the webserver then that would let people load any code they want.

@ellisonbg
Member

I wasn't aware of the getScript function of jquery. That definitely
helps. On the CDN side of things there is this CDN:

http://www.cdnjs.com/

That allows the community to add new JS packages. Someone could add
d3. I think something like that is probably best.

On the security side of things: it is impossible to prevent the JS
from hacking/destroying/modifying/mucking with the DOM, kernel and
notebook server. An attacker could easily write code that lists all
of the users notebook and delete them all. They could launch a
million kernels and crash the server. They could access all of the
users private data in the notebook directories. There is simply no
way of preventing these things if we want to enable this feature.
Period. In my mind, the usual warning applies: don't run code you
don't completely trust!

On Tue, Feb 7, 2012 at 10:35 AM, Andy Wilson
reply@reply.github.com
wrote:

I saw this on the list and got really excited about it.

jQuery has a getScript method for dynamically loading a file which seems to work regarding issue 2.  With a sym link to an external d3 dir in frontend/html/notebook/static

   from IPython.core.display import Javascript
   Javascript("$.getScript('/static/d3/d3.js')")

works as expected. For security reasons, you can't load local resources via "file:///*" urls, but if you add a mechanism to expose additional static directories via the webserver, then that would let people load any code they want.


Reply to this email directly or view it on GitHub:
#1386 (comment)

Brian E. Granger
Cal Poly State University, San Luis Obispo
bgranger@calpoly.edu and ellisonbg@gmail.com

@ellisonbg
Member

This addresses issue #879

@fperez
Member
fperez commented Feb 7, 2012

On Tue, Feb 7, 2012 at 11:31 AM, Brian E. Granger
reply@reply.github.com
wrote:

On the security side of things: it is impossible to prevent the JS
from hacking/destroying/modifying/mucking with the DOM, kernel and
notebook server.  An attacker could easily write code that lists all
of the users notebook and delete them all.  They could launch a
million kernels and crash the server.  They could access all of the
users private data in the notebook directories.  There is simply no
way of preventing these things if we want to enable this feature.
Period.  In my mind, the usual warning applies: don't run code you
don't completely trust!

And that's OK: IPython is a full-blown, system-level shell with zero
sandboxing, so there's no point pretending. We can't keep ipython
being what it is, while making it 'secure' in any way. A user has
the ability to run os.system('rm -rf $HOME'), and they can do the
same in JS via IPython.kernel....execute("os.system...). That's
just reality, and there's no point in sugarcoating it or trying to
make it any different.

@Sharpie
Sharpie commented Feb 7, 2012
  1. It has to be loaded using a script tag. Doing that dynamically is a bit of a pain.

Perhaps require.js could help with this?

@wilsaj
wilsaj commented Feb 7, 2012

For the security reasons you've outlined, executing any externally-linked javascript within the notebook is a bit dangerous. If malicious code ended up at the other end of any external link (or was injected along the way) that would be a very bad thing.

Also external links require internet connectivity, which can sometimes be a frustrating dependency.

@ellisonbg
Member

On Tue, Feb 7, 2012 at 3:43 PM, Andy Wilson
reply@reply.github.com
wrote:

For the security reasons you've outlined, executing any externally-linked javascript within the notebook is a bit dangerous. If malicious code ended up at the other end of any external link (or was injected along the way) that would be a very bad thing.

We are only executing JS code that come from the user's python code.
They have to trust that Python code to not do bad things. We
definitely would not execute externally-linked JS code. Although if a
user wants, they can write python code, that write JS code that does
that.

But keep in mind: IPython is already like a big gun. With regular
IPython - not even the notebook - you can completely destroy your user
files and DOS your system. I could send you a simple Python script
right now and tell you to do:

In [1]: %run danger.py

and create this type of destruction. Bottom line: you have to trust
the Python code you run in IPython. This new feature in the IPython
notebook doesn't change that one bit. The only additional risk the
notebook has is that someone could use it to get remote access to your
system. But if they do that, they surely don't need to execute JS
code to create trouble.

Cheers,

Brian

Also external links require internet connectivity, which can sometimes be a frustrating dependency.


Reply to this email directly or view it on GitHub:
#1386 (comment)

Brian E. Granger
Cal Poly State University, San Luis Obispo
bgranger@calpoly.edu and ellisonbg@gmail.com

@wilsaj
wilsaj commented Feb 8, 2012

We are only executing JS code that come from the user's python code.

I'm thinking of CDN-hosted code. Maybe I'm misinterpreting the CDN thing, but in my mind that means a link to some .js files that are hosted on some server(s) somewhere.

I agree that something like <script src="/static/user/danger.js"> doesn't change the nature of the trust relationship we users have with IPython, since it is just executing code that lives somewhere on our machines and that's equivalent to executing arbitrary python code that lives somewhere on our machines.

But <script src="http://cdn.example.com/danger.js"> is different because we don't have complete control - and therefore we shouldn't completely trust - what will get returned by that HTTP request. We now also have to trust whoever controls "http://cdn.example.com/danger.js" and that's a much bigger leap.

@ellisonbg
Member

On Tue, Feb 7, 2012 at 4:46 PM, Andy Wilson
reply@reply.github.com
wrote:

We are only executing JS code that come from the user's python code.

I'm thinking of CDN-hosted code. Maybe I'm misinterpreting the CDN thing, but in my mind that means a link to some .js files that are hosted on some server(s) somewhere.

Yes, the CDN does introduce an extra indirection of trust.

I agree that something like <script src="/static/user/danger.js"> doesn't change the nature of the trust relationship we users have with IPython, since it is just executing code that lives somewhere on our machines and that's equivalent to executing arbitrary python code that lives somewhere on our machines.

But <script src="http://cdn.example.com/danger.js"> is different because we don't have complete control - and therefore we shouldn't completely trust - what will get returned by that HTTP request. We now also have to trust whoever controls "http://cdn.example.com/danger.js" and that's a much bigger leap.

But we (IPython) won't load code from the CDN. The only way to load
it is to put the calls inside some <script src="/static/user/danger.js"> and do it dynamically. Ultimately
you still have to trust the author of <script src="/static/user/danger.js"> to do his/her homework on the CDN.

I guess another way of saying it is this: the CDN example makes it
clear that the author of the scripts that we do load can do anything
including loading code from other sites. Their ability to do bad
things is not limited or sandboxed in any manner other than the OS
level permissions the IPython kernel is running under.


Reply to this email directly or view it on GitHub:
#1386 (comment)

Brian E. Granger
Cal Poly State University, San Luis Obispo
bgranger@calpoly.edu and ellisonbg@gmail.com

@wilsaj
wilsaj commented Feb 8, 2012

But we (IPython) won't load code from the CDN. The only way to load
it is to put the calls inside some <script src="/static/user/danger.js"> and do it dynamically. Ultimately
you still have to trust the author of <script src="/static/user/danger.js"> to do his/her homework on the CDN.

This makes sense. I was concerned about a CDN-hosted copy of d3.js being included in the notebook by default.

If there is a way for users to specify their own js files then does d3 need to be included at all? If someone wants d3, then he/she can just make that part of their user js files.

@ellisonbg
Member

A user can definitely put any JS code they want into the following dir:

IPython/frontend/html/notebook/static

And refer to it in the code as:

/static/...

The only thing that would change that is if they were using a
different base URL for the notebook.

On Tue, Feb 7, 2012 at 8:33 PM, Andy Wilson
reply@reply.github.com
wrote:

But we (IPython) won't load code from the CDN.  The only way to load
it is to put the calls inside some  <script src="/static/user/danger.js"> and do it dynamically.  Ultimately
you still have to trust the author of  <script src="/static/user/danger.js"> to do his/her homework on the CDN.

This makes sense. I was concerned about a CDN-hosted copy of d3.js being included in the notebook by default.

If there is a way for users to specify their own js files then does d3 need to be included at all? If someone wants d3, then he/she can just make that part of their user js files.


Reply to this email directly or view it on GitHub:
#1386 (comment)

Brian E. Granger
Cal Poly State University, San Luis Obispo
bgranger@calpoly.edu and ellisonbg@gmail.com

@ellisonbg
Member

Is this ready to merge. I don't think we should include d3.

On Tue, Feb 7, 2012 at 8:37 PM, Brian Granger ellisonbg@gmail.com wrote:

A user can definitely put any JS code they want into the following dir:

IPython/frontend/html/notebook/static

And refer to it in the code as:

/static/...

The only thing that would change that is if they were using a
different base URL for the notebook.

On Tue, Feb 7, 2012 at 8:33 PM, Andy Wilson
reply@reply.github.com
wrote:

But we (IPython) won't load code from the CDN.  The only way to load
it is to put the calls inside some  <script src="/static/user/danger.js"> and do it dynamically.  Ultimately
you still have to trust the author of  <script src="/static/user/danger.js"> to do his/her homework on the CDN.

This makes sense. I was concerned about a CDN-hosted copy of d3.js being included in the notebook by default.

If there is a way for users to specify their own js files then does d3 need to be included at all? If someone wants d3, then he/she can just make that part of their user js files.


Reply to this email directly or view it on GitHub:
#1386 (comment)

Brian E. Granger
Cal Poly State University, San Luis Obispo
bgranger@calpoly.edu and ellisonbg@gmail.com

Brian E. Granger
Cal Poly State University, San Luis Obispo
bgranger@calpoly.edu and ellisonbg@gmail.com

@cschin
cschin commented Feb 8, 2012

I think it would be fine if a user want to put any javascript lib, he/she can do himself/herself. d3.js is just one of a lot possibles interesting js libraries.

@cschin
cschin commented Feb 8, 2012

In the meantime, does it make sense to have a new window just for displaying dynamic content? I am looking into the handlers.py to see a potential way to do that within ipython.

@ellisonbg
Member

The dynamic content should definitely be inline as it is now - at the
same time, the JS code can put content elsewhere if it wants to.
But the usual browser constraints would prevent putting it in other
windows (no pop-ups allowed).

On Tue, Feb 7, 2012 at 8:50 PM, Jason Chin
reply@reply.github.com
wrote:

In the meantime, does it make sense to have a new window just for displaying dynamic content? I am looking into the handlers.py to see a potential way to do that within ipython.


Reply to this email directly or view it on GitHub:
#1386 (comment)

Brian E. Granger
Cal Poly State University, San Luis Obispo
bgranger@calpoly.edu and ellisonbg@gmail.com

@cschin
cschin commented Feb 8, 2012

good point. I forget we can use JS to put the element any place. My original though it more like to open a new notebook, but it has only output cell for dynamic content. This will allow developing some dynamic visualization easier.

@ellisonbg
Member

We really want the dynamic content on the same page - all of the
connections to the server - mainly the kernel are per page. We want
the dynamic content to be able to reuse all of that so things need to
be on page.

On Tue, Feb 7, 2012 at 9:34 PM, Jason Chin
reply@reply.github.com
wrote:

good point. I forget we can use JS to put the element any place.  My original though it more like to open a new notebook, but it has only output cell for dynamic content. This will allow developing some dynamic visualization easier.


Reply to this email directly or view it on GitHub:
#1386 (comment)

Brian E. Granger
Cal Poly State University, San Luis Obispo
bgranger@calpoly.edu and ellisonbg@gmail.com

@cschin
cschin commented Feb 8, 2012

Here is a screen shot using the "Javascript" function:

<img src="https://github.com/cschin/IPython-Notebook---d3.js-mashup/raw/master/images/example3_d3.jpg" /img>

from this notebook. I also have an experimental one:

<img src="https://github.com/cschin/IPython-Notebook---d3.js-mashup/raw/master/images/example2_d3.jpg" /img>

from this notebook where I move the zmq / websocket bridge that sends javascript to a iframe into the handler.py. No extra server is needed. One advantage of this setup is that one can control the animations by python code and it could be used to make two way communication too.)

@fperez
Member
fperez commented Feb 9, 2012

Thanks for those, @cschin, I just edited your post to inline the figs so the post would read better, left content unchanged.

@ellisonbg ellisonbg merged commit f77a23d into ipython:master Feb 10, 2012
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment