Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

As a user, there is no mechanism to control the IPFS networking of a webapp I use #197

Open
pimterry opened this issue Jan 7, 2022 · 5 comments
Labels
dif/expert Extensive knowledge (implications, ramifications) required env:browser kind/discussion Topical discussion; usually not changes to codebase need/analysis Needs further analysis before proceeding need/community-input Needs input from the wider community topic/http-api

Comments

@pimterry
Copy link

pimterry commented Jan 7, 2022

As a user of a 3rd party web application using js-ipfs in the browser, there's no way for me to indicate the configuration I would like the application to use.

This is somewhat related to ipfs/js-ipfs#3042, but it's a much simpler case: rather than auto-detecting the appropriate configuration for an arbitrary system/network, I'd like to be able to explicitly set configuration that should be used.

Right now, individual IPFS applications in the browser each have full control of network configuration. This doesn't fit well into the traditional browser model, where the browser manages network config (proxy settings, trusted CAs, etc) and exposes network interactions in dev tools, while pages use the environment's config to request content. These differences take control of networking away from users, developers and system administrators, and put it entirely in the hands of the applications, which isn't great.

I'm looking for a mechanism so that a) js-ipfs nodes obey my personal config by default and b) applications that need to override default config can easily merge my personal config into their custom settings to do so. I understand it's not practical to force all IPFS webapps to use a given configuration, but I think setting defaults plus having a standard approach will be enough to cover most cases.

There's a few use cases for this:

  • To encourage IPFS applications in a browser to connect to a local node on my machine, to boost performance and share data between local applications easily. Detecting this reliably may be complicated, but manually configuring it is very easy.
  • Similarly I could run an IPFS node on my network, e.g. in enterprise environments, so everybody in the office could share a common local node for a performance boost, or even to use apps on a fully private intranet-only IPFS network.
  • In other environments, IPFS might be blocked (by blocking the default delegates & bootstrap addresses) making js-ipfs on the web unusuable. Being able to configure addresses as a user would allow me to work around this.
  • To control IPFS trust, so I can see who an application is talking to and what they're saying. Right now if I want to debug what an IPFS web application is actually sharing about me, I can't - the default config hardcodes addresses & keys for remote peers, so now my browser is sending data to an address I can't control that it's completely impossible for me to see. It would be useful to be able to make apps use a local node to answer questions about data sharing and for app debugging.

Fortunately, this is super simple to implement for this basic case: this could be done by just making config.browser.js default to the value of window.IPFS_USER_CONFIG if set.

If that worked, browsers or browser extensions that want to configure IPFS could inject this global into pages before they load. Well-behaved IPFS applications could then be encouraged to check for this too, to take user configuration into account whilst adding their own settings where necessary. I don't think there's any security concerns here - anybody who can write to arbitrary global properties into a JS process before the application loads can do anything they want to in that process already.

This is notably similar to how Ethereum and others manage user config for web apps: extensions like metamask inject a window.ethereum property, which apps can use to connect to Ethereum via the user's preferred wallet, or they can fall back to connecting to a local/hosted node URL elsewhere when that's not available.

In future auto-detection mechanisms as in ipfs/js-ipfs#3042 could improve on this further, but an explicit config option will still probably be useful anyway, and it's a very easy first step.

Thoughts? I'm happy to open a PR for this of course, but the debate around the concept is the important part so I'd like to check there's interest first.

@pimterry pimterry added the need/triage Needs initial labeling and prioritization label Jan 7, 2022
@welcome
Copy link

welcome bot commented Jan 7, 2022

Thank you for submitting your first issue to this repository! A maintainer will be here shortly to triage and review.
In the meantime, please double-check that you have provided all the necessary information to make this process easy! Any information that can help save additional round trips is useful! We currently aim to give initial feedback within two business days. If this does not happen, feel free to leave a comment.
Please keep an eye on how this issue will be labeled, as labels give an overview of priorities, assignments and additional actions requested by the maintainers:

  • "Priority" labels will show how urgent this is for the team.
  • "Status" labels will show if this is ready to be worked on, blocked, or in progress.
  • "Need" labels will indicate if additional input or analysis is required.

Finally, remember to use https://discuss.ipfs.io if you just need general support.

@pimterry
Copy link
Author

Just to add to this: I am aware that there was previously a window.ipfs injection that was removed. This is a different approach, which I think still makes sense, and follows Ethereum world's very similar challenges and new in-browser configuration approach too.

Once upon a time, Metamask etc used to inject web3.js, providing a fixed version of the full client library, and that caused them similar compatibility and upgrade problems to what IPFS saw (i.e. ipfs/ipfs-companion#777). This was removed in early 2021.

Nowdays, their window.ethereum injection only provides a basic raw connection configured with the user's settings, not a full client. Web applications provide a full web3.js library of their choice which uses that internally, which allows the browser to inject a base environment without having compatibility issues at the library level.

There would still be compatibility issues if there was ever a breaking change in the base config format, but:

  • AFAICT there have been no breaking changes between the original config file from March 2016 and the latest version, only additions of new fields, all of which are optional, so it seems likely that we can avoid this fairly easily.
  • If there was a need for breaking changes in future, that could be handled at that time by adding a version number to to config (and converting config without a version number to the latest format automatically) with no effort required in advance - i.e. we can ignore this until that actually becomes a concern, if ever.

Meanwhile, not doing this means web applications deployed with IPFS effectively rot as their unchangeable config becomes invalid. This is especially problematic since they're often deployed immutably to IPFS itself.

As an example, for any applications deployed with js-ipfs versions 0.24.1 to 0.31.0, none of the hardcoded bootstrap addresses (e.g. strawberry.i.ipfs.io or later nyc-1.bootstrap.libp2p.io) resolve nowadays. You may be able to load those deployed apps' code from IPFS, but the apps themselves will no longer be able to bootstrap, and there's no practical mechanism to reconfigure them without locally downloading and manually editing the whole (generally webpacked & minified) codebase. There's good odds this will happen again in future.

If there was a way to externally inject default config into those web applications, such as window.IPFS_USER_CONFIG, it would still be possible to use them today.

@pimterry
Copy link
Author

Any thoughts on this @achingbrain? I'm happy to put together the PR, if this might be accepted. As a user I'd find this really useful, and the sooner it's implemented the more long-term benefit it provides.

Pointers to somewhere else that I should suggest this instead are also welcome 😄.

@lidel
Copy link
Member

lidel commented Aug 13, 2022

Thank you for writing this up @pimterry.

Unfortunately, proposed mechanism for providing js-ipfs config (with up-to-date bootstrappers etc) is not enough for future-proofing. Applications deployed with very old versions of js-ipfs won't be able to connect, even if you provide them with compatible config that includes new bootstrappers because over time, insecure protocols could be replaced with new ones, but the old js-ipfs remains the same.

For example, SECIO was removed in js-ipfs 0.50: https://blog.ipfs.io/2020-10-29-js-ipfs-0-50/#secio-removal

Instead, smaller, implementation-agnostic convention for exposing basic hints may be worth discussing. Not saying the below musing is right or wrong, just some food for thought to understand how generic this need to be:

  • window.IPFS_GATEWAY could reuse some ideas from IPIP-280: App Conventions for HTTP Gateway Detection specs#280. In many cases IPFS is used only for trustless retrieval, and that is possible with gateway endpoint + ipfs-car for verifying hashes, no need for full node, and no need to worry about freezing js-ipfs in time and not being able to connect over legacy transports in the future. js-ipfs itself could use this hint and attempt gateway retrieval instead/in parallel to bitswap.
  • window.IPFS_BOOTSTRAP / PEERING could be a randomized list of multiaddrs of libp2p peers, provided in addition to gateway endpoint(s), for websites which are kept up-to-date that want to run full p2p stack. This could serve as bootstrappers, or be a permanent peering agreement.
  • window.IPFS_ROUTING could be a list of reframe endpoints with user-prefered routing systems IPFS node can utilize for finding content and providers (removing the need for node running on page to run full DHT client).

If you are interested in pursuing this, I suggest either engaging on the PR I linked in ipfs/specs repo and suggest extending it with browser-related section, or working on this independently, and extending mentioned integration specs at a later time.

ps. would it be ok if I move this to issue to https://github.com/ipfs/in-web-browsers? It does not feel limited to js-ipfs, more like something ipfs-companion or vendors like Brave could expose.

@lidel lidel added kind/discussion Topical discussion; usually not changes to codebase need/analysis Needs further analysis before proceeding env:browser and removed need/triage Needs initial labeling and prioritization labels Aug 13, 2022
@pimterry
Copy link
Author

ps. would it be ok if I move this to issue to https://github.com/ipfs/in-web-browsers? It does not feel limited to js-ipfs, more like something ipfs-companion or vendors like Brave could expose.

Absolutely! Happy to discuss this wherever's best, and it's certainly something where integrator opinions would be necessary.

In many cases IPFS is used only for trustless retrieval, and that is possible with gateway endpoint + ipfs-car for verifying hashes, no need for full node, and no need to worry about freezing js-ipfs in time and not being able to connect over legacy transports in the future.

100% agree that retrieval via gateway is enough for many cases. That said, I think there are other real cases that aren't well supported by using the gateway API only (and can't be, unless the goal is for the gateway API to subsume at least the entire js-ipfs HTTP API).

Those cases are some of the most interesting in the long term imo: web applications that build on the full power of IPFS, rather than just using IPFS as another CDN.

For the majority gateway case though, yes I think window.IPFS_GATEWAY would be a great move, and matches intuitively with the proposed IPFS_GATEWAY env var in ipfs/specs#280, to make the user's preferred gateway consistently discoverable in all environments. I'll start a discussion around this on that PR.

window.IPFS_BOOTSTRAP / PEERING could be a randomized list of multiaddrs of libp2p peers, provided in addition to gateway endpoint(s), for websites which are kept up-to-date that want to run full p2p stack. This could serve as bootstrappers, or be a permanent peering agreement.

I think this would work very well. The bootstrappers are definitely the most important part of the config to solve this problem imo, and the part where it's most likely an application might receive useful external configuration from the environment.

Imo it's OK (and inevitable) that out-of-date applications may not be able to use the provided bootstrappers in some configurations due to protocol changes. If anything though, this proposal improves that situation.

Currently those applications would be permanently disconnected and doomed, since their hardcoded bootstrappers would have become unusable, but if the bootstrap peers were configurable it would become possible for app users to provide their own backward compatibility/translation (e.g. you could run a local bridge peer that continues to support SECIO), or you could even continue running an app indefinitely on an private IPFS network using your own nodes.

Neither is a great plan for normal day to day usage, and its certainly better for apps to be upgraded instead, but both are far better results than "this otherwise working application is now unusable forever".

@lidel lidel transferred this issue from ipfs/js-ipfs Aug 17, 2022
@ipfs ipfs deleted a comment from welcome bot Aug 17, 2022
@lidel lidel added dif/expert Extensive knowledge (implications, ramifications) required need/community-input Needs input from the wider community topic/http-api labels Aug 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dif/expert Extensive knowledge (implications, ramifications) required env:browser kind/discussion Topical discussion; usually not changes to codebase need/analysis Needs further analysis before proceeding need/community-input Needs input from the wider community topic/http-api
Projects
None yet
Development

No branches or pull requests

2 participants