ipfs / in-web-browsers

Tracking the endeavor towards getting web browsers to natively support IPFS and content-addressing
https://docs.ipfs.tech/how-to/address-ipfs-on-web/
MIT License
345 stars 29 forks source link

Epic: WebExtension with pluggable IPFS nodes #39

Open flyingzumwalt opened 7 years ago

flyingzumwalt commented 7 years ago

Break up the functionality that #12 is aiming for.

flyingzumwalt commented 7 years ago

How we're going to break it up (will make issues):

General notes:

Stories:

If A is completely done, B and C can be activated with a toggle -- Redirect-URLs can be true or false

flyingzumwalt commented 7 years ago

See #43 for a discussion of the security implications of this web extension.

victorb commented 7 years ago

I've did some quick research after thinking that probably we can't expose anything on window from an web extension to a web page. And yeah, we can't just add whatever we want to a page's window object.

What we can do is to setup some message passing and provide a library for websites to use that.

But, we won't be able to have an extension that people can simply install and now window.ipfs exists everywhere as a full node... There will have to be things that the website authors needs to do.

Kubuxu commented 7 years ago

We for sure can add an element that could load a script and then use some sort of RPC (or ipfs api) to pass the messages.

Just an idea.

victorb commented 7 years ago

@Kubuxu you won't be able to load arbitrary scripts into the same context of a web page. CSP will deny that and it would be a security threat otherwise.

This RPC/ipfs-api you're talking about, is a possibility, but the website authors needs themselves to include this in their webpage. That's not what we're aiming for, but rather be able to provide everything so a user could simply do window.ipfs.swarm.peers(cb) without any further fuzz.

Kubuxu commented 7 years ago

Can't you modify the webpage as it is loaded to include inline script block that would contain the script necessary to expose the bindings?

Kubuxu commented 7 years ago

Also I have found this: https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Content_scripts

victorb commented 7 years ago

@Kubuxu as far as my testing went, no. The browser rejects to execute any code that has been injected into the page. I can successfully run a js-ipfs node in the background page, and communicate with it via a content script, but can't expose a API for the communication...

Kubuxu commented 7 years ago

I can successfully run a js-ipfs node in the background page, and communicate with it via a content script, but can't expose a API for the communication...

I don't understand the "but can't expose a API for the communication..." part.

victorb commented 7 years ago

Yeah, what I did was setting up a background page that has the daemon running and exposes a couple of methods via message passing.

In the content script, I can successfully add properties to the window object of a page. I can also talk with the background ipfs daemon without troubles.

Problems arise when I wanted to write a thin-layer of API methods that the users can use directly from their page. I'm adding functions to a IPFS object that acts kind of like js-ipfs-api, but the browser won't execute those functions, since they were added from the outside.

I've made the code public here: https://github.com/VictorBjelkholm/js-ipfs-in-the-browser

Content-Script: https://github.com/VictorBjelkholm/js-ipfs-in-the-browser/blob/master/page-script.js Background-Script: https://github.com/VictorBjelkholm/js-ipfs-in-the-browser/blob/master/start-daemon.js

I don't understand the "but can't expose a API for the communication..." part.

We can't have window.ipfs that just works. Users are required to include something for the communication to the daemon...

Kubuxu commented 7 years ago

I think we need to use cloneInto as it is shown here: https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Content_scripts#cloneInto

flyingzumwalt commented 7 years ago

Maybe it's a bad idea for the extension to initialize window.ipfs anyway. Wouldn't it be better if we allow web pages to initialize that with a very small amount of code -- so the browser extension provides the whole ipfs stack and a web developer just has to initialize the connection wherever they see fit?

Either way, any page that wants to use ipfs is going to have to run a script to check if the extension is installed, so we will need to provide an easy way to do the following (and should provide an npm module that does it for you):

  1. Check if the ipfs web extension is installed
  2. Initialize ipfs 2a. If the web extension is installed, just initialize the connection 2b. If the web extension is not installed, download ipfs and then initialize

Given that, is it really necessary for the web extension to initialize window.ipfs?

victorb commented 7 years ago

We wanted to simulate an environment which would be as similar as possible to when we actually have ipfs supported natively in the browsers. We could do bunch of guesses how that would look, but probably there would be an node of some sort exposed at window.ipfs. It's straight-forward to check if it exists.

if (window.ipfs === undefined) {
 // ipfs is not here, we need to have a polyfill
} else {
 // ipfs was on the page already!
}

This is also how new features are being detected in browsers, and polyfill if necessary...

I think something that is missed, is the performance gain of having an already initialized node as well. Currently, js-ipfs when starting up in the browser, locks my browser for half a second and takes a while to find peers.

If we could run the node always, and allow pages to directly connect to it, we'll have no startup time + already connected peers when the page first loads.

flyingzumwalt commented 7 years ago

Those are all good points. Thanks for clarifying.

jmc265 commented 7 years ago

Potential solution for the issue around content scripts not being able to affect the page script's window object:

From the content script, inject a script ('js-ipfs-bridge.js') into the page (using the method detailed here: https://gist.github.com/nok/a98c7c5ce0d0803b42da50c4b901ef84).

'js-ipfs-bridge.js' can then define a window.ipfs shim which just uses window.postMessage to communicate back and forth between the page scripts and the content scripts.

This means that developers can just go ahead and use window.ipfs unaware that the extension has re-mapped that object to the extension's content and background scripts via postMessage.

daviddias commented 7 years ago

All the extension work is happening here https://github.com/ipfs/ipfs-companion