(This is a placeholder issue, will be updated in future)
The goal: window.ipfs v2 ships and is production ready
(tl;dr: injected on-demand, expose only requested APIs)
Future-proof way of using window.ipfs is:
if (window.ipfs) {
try {
const ipfs = await window.ipfs.enable({commands: ['add','cat']})
const [{ hash }] = await ipfs.add(Buffer.from('=^.^='))
const data = await ipfs.cat(hash)
console.log(data.toString()) // =^.^=
} catch (err) {
// find more code samples at https://git.io/fjAu8
...
https://github.com/ipfs-shipyard/ipfs-companion/pull/619:
window.ipfs.enable.enable() (no params) and keep no-dialog for things like ipfs.cat or display no initial dialog but prompt every api insteadwindow.ipfs.enable (https://github.com/ipfs-shipyard/ipfs-companion/pull/619)window.ipfs.enable({commands: ['id','version'] }) experimentsawait window.ipfs.enable({ experiments: { ipfsx: true } }) will return ipfsx version of the APIwindow.ipfswindow.ipfsProxy.enable? (to avoid breaking websites that manually detect window.ipfs and execute window.ipfs.<command>) or is it enough to deprecate old use for 3 months and then remove support for old ways?window.ipfs.enable should we require permission from user for all commands? (remove acl-whitelist for things like dag.get ?)window.ipfs injection via manifest in Chromiumwindow.ipfs.enable we should revisit window.ipfswindow.ipfswindow.ipfs.enable()window objectwindow.ethereum attributewindow.ethereum.enable() triggers permission dialogwindow.ethereumwindow.postMessage API injection schemewindow.postMessage + window.addEventListener)window object (assumption: there are no other fingerprinting vectors)window.ipfs attribute. Given this reality, there is no value in over-complicating the detection. window.ipfs that has only a .enable() methodwindow solves the problem of signaling ipfs capability to dappwindow.ipfs becomes a thin entry pointwindow.ipfs.enable() method, user accepts/denies, actual API object is returned with only those namespaces, permission is cached and user is not prompted next timeawait window.ipfs.enable(<capabilities>) should return a complete IPFS API instance <capabilities> should trigger ad-hoc permission prompt for that single capability (and update ACLs for the scope)window.ipfs.enable(<capabilities>) multiple times should be possible as well as an alternative, UX-friendly way to extend preexisting permissions with additional oneswindow but there is only one additional bit of info malicious parties can use for fingerprinting.window.ipfs.* later.enable(arg) and then target method on a cached API object + printing warning in logs.enable() call window.ipfs in Chromewindow.ipfs in synchronous fashion needs to be deprecated as it won't be fixed in Chrome.config) should trigger more prominent visual warning (within the same, single dialog)window before page loads)window.ethereumnavigator.permissions.* can't be usedwindow.postMessage can't respond with a full API providerSounds like B is a good candidate for moving forwards.
actual API object is returned with only those namespaces, permission is cached and user is not prompted next time
Should we consider the case where an app would like basic permissions (low barrier to entry, less chance of hitting no)? 99% of the time the app only needs those permissions but very occasionally might want to do something more sensitive that requires additional permissions.
With the proposal above there's no way to "get more", or could you call .enable() multiple times - I guess so. Maybe something to note down! (sorry just brain dumping...)
It would be _nicer_ to just be able to use the API and get a prompt when you try to use restricted API calls you haven't already requested access to. It means you don't have to code around missing properties and calling enable again and secondly, if you add some new feature and forget to request a permission you don't break your app.
Also, when I say "nicer" I think it might be necessary! The issue is if we have a provider library we don't know what type of ipfs we're getting given - we should just be able to use it like a regular IPFS instance.
I think we discussed a request permissions API once apon a time, what if we had window.ipfs.permissions.request() for requesting multiple permissions in one shot and just exposed the full API as we do now? The API is public knowledge, what additional attack surface area are we exposing by this being present? Is the only reason to not do this the performance impact of injecting the whole API?
Very good feedback!
I think we could do all of that without adding additional APIs:
just allowing multiple calls to .enable() and returning a "full" IPFS API instance should do the trick.
Added notes:
await window.ipfs.enable(<capabilities>) should return a complete IPFS API instance<capabilities> should trigger ad-hoc permission prompt for that single capability (and update ACLs for the scope)window.ipfs.enable(<capabilities>) multiple times should be possible as wellHaving that, a dapp first asks for basic dag get/put APIs (that triggers a calm user prompt,) and in rare case when dapp wants access to ipfs.config API a separate call can be issued to trigger a more prominent user prompt.
The API is public knowledge, what additional attack surface area are we exposing by this being present? Is the only reason to not do this the performance impact of injecting the whole API?
Yes, we don't want to load ipfs-postmsg-proxy nor initialize messaging port with background extension until window.ipfs.enable() is executed.
PR with await window.ipfs.enable(opts) aka Bulk Permission Prompt is ready for review at https://github.com/ipfs-shipyard/ipfs-companion/pull/619.
I also updated https://github.com/ipfs-shipyard/ipfs-companion/issues/589#issue-362096499 to include remaining work plan.
window.ipfs.enable landed in Beta: v2.6.3.12520
tl;dr
await window.ipfs.enable({ commands: ['id','peers'] }) triggers the Bulk Permission Prompt:
- deprecation warning is shown for
window.ipfs.<cmd>():
Calling commands directly on window.ipfs is deprecated and will be removed on 2019-04-01. Use API instance returned bywindow.ipfs.enable()instead. More: /docs/window.ipfs.md
- Tip: where possible, use window.ipfs-fallback library that takes care of fallback ceremony.
It will ensure your app follows API changes and does not break in the future.
- support opt-in ipfsx experiment (b633eb4)
ifexperiments:{ipfsx:true}is passed towindow.ipfs.enableit will return IPFS API instance wrapped in ipfsx prototype from ipfs-shipyard/ipfsxlet ipfsx = await window.ipfs.enable({ commands: ['add','files.addPullStream'], experiments: { ipfsx: true } })
- remove ACL whitelist for window.ipfs (756b177)
no command can be run without explicit approval from the user
I've been looking at ways we can optimize thin window.ipfs.enable and no matter how thin we make it, it still feels wasteful to inject content script on every website and iframe.
We could make things much more efficient if we.. did not inject any script payload at all. What if websites could explicitly ask for window.ipfs, and ipfs-companion would inject it only when "invited"?
Are there any downsides to this approach?
Quick idea dump: such hint needs to happend before entire HTML is loaded, so it could be:
X-Ipfs-Path as a hint, or add an explicit X-Ipfs-Api-Enable: trueX-Ipfs-Path is already sent by public gateways so it could be used as equal to X-Ipfs-Api-Enable: true (if explicit X-Ipfs-Api-Enable is not specified). This way pages loaded from public gateway would automatically get window.ipfs, but website owner would still have a way to opt-out via X-Ipfs-Api-Enable: false <meta> tag in HTML payload#x-ipfs-companion-enable-api or ?x-ipfs-companion-enable-apiAre there any downsides to this approach?
IMO headers are too strict. There might be cases where a user/developer is not able to control headers returned by hosting provider.
Another example might be userscripts (I know it is quite dev focused) but I think there are cases where someone might want to write a userscript using window.ipfs on third-party website.
Another idea:
What if we introduce a simple handshake does not require any changes on the server?
Something along these lines:
fetch (HTTP HEAD request) for some predefined path, eg. /.well-known/ipfs/companion/window.ipfs window.ipfs on the page that sent it via blocking executeScript call/.well-known/ipfs/companion/window.ipfs/ready to provide a confirmation everything is readyconst handshake = await fetch('/.well-known/ipfs/companion/window.ipfs')
if (handshake.url.endsWith('window.ipfs/ready') && window.ipfs) {
// companion with window.ipfs
const ipfs = await window.ipfs.enable({commands: ['add','cat']})
} else {
// no companion / window.ipfs
}
This comes with some interesting characteristics:
window.ipfs.enable is called)window.ipfs-fallback and everything continues to work fetch removes surface for synchronous code, solving issue of early injection in Chrome (https://github.com/ipfs-shipyard/ipfs-companion/issues/362#issuecomment-362231167)Downsides:
HEAD request (but we could make it to localhost to remove network overhead)PSA: to remove overhead introduced by IPFS Companion the plan for the end of Q4 is to expose window.ipfs only when any of below hints is true:
X-Ipfs-Path header is present (indicating response comes from IPFS Gateway)/ipfs/ or /ipns/ or CID in subdomain)This will not introduce any new overhead (reusing checks we already do for other things) and will decrease resource usage on non-IPFS websites.
It will also act as a small incentive to enable DNSLink and/or self-host gateway.
The window.ipfs experiment was disabled since last year (see #777 for rationale why).
It did help us understand challenges and risks, and identified the need for more robust API for the web. We are officially putting window.ipfs experiment (in the form that was disabled in #777) in the Icebox and will be looking at other ways for node sharing and deduplication on the web in https://github.com/ipfs/in-web-browsers/issues/158.
If we revisit this approach, it will be a more robust API tailored for use on the web,
and most likely happen after migration to Manifest V3 (#666).
Bonjour à Vous je recherche une installation Mà j et traducteur en français s'il vous plaît