Subject: [Wpack] Counter-proposal where bundles only contain a single origin

From: Jeffrey Yasskin <[email-masked]>
Date: Wed, 26 Aug 2020 11:00:34 -0700

I worked with Martin to flesh out his ideas for simplifying the bundle URL
and origin design, and we came up with the following. I still prefer the
proposal I presented a couple weeks ago
<https://github.com/WICG/webpackage/blob/master/explainers/bundle-urls-and-origins.md#proposal-a-package-scheme>,
based on the tradeoffs down at the bottom here, but it's quite possible
I've missed things. I'd appreciate this group's input on which way we
should go.

The basic idea here is that:

* Each bundle defines a single origin.
* Bundles identify their contents with paths, not full URLs.
* Metadata can provide a base URL to resolve those paths against.
* We allow a single file to contain multiple origins using nested bundles.
Use cases:
   * Users should be able to share subsets of the web that can link within
themselves, in a way that different sites within those subsets don't have
their storage collide.
   * One request for ads should be able to return the contents of multiple
iframes in a way that those contents can't modify each other.

# URLs for nested bundle resources

```
package://distributor.example/bundle.wbn$app/foo.wbn$bar.html
package:///c:/Users/name/Downloads/bundle.wbn$app/foo.wbn$bar.html
```

This fetches the outer bundle by removing everything after the first `$`
and:

* If the URL has an authority, replacing the `package:` with `https:`
* If the URL doesn't have an authority, replacing the `package:` with
`file:`.

To allow the outer bundle to be fetched using a third scheme, we would need
to add a matching new scheme for addressing inside it.

Subsequently, each segment separated by `$`s is the path to look up in a
nested bundle. Any `$`s inside a segment are percent-encoded.

# Origins for nested bundle resources

The origin of one of these holds the information from the URL up to the
last `$`. So for

```
package://distributor.example/bundle.wbn$app/foo.wbn$bar.html
```

* scheme: package:
* host: distributor.example/bundle.wbn$app/foo.wbn
* port: null
* domain: null

We could also hold the part after the first `/` in a new component, similar
to Gecko's OriginAttributes
<https://wiki.mozilla.org/Security/Contextual_Identity_Project/Containers#An_extended_origin>,
but OriginAttributes are mostly undocumented, and origins define "opaque
hosts <https://url.spec.whatwg.org/#opaque-host>" to encode this sort of
information into the existing field.

# Navigating across nested bundles

Within something like El Paquete Semanal or the Web Archive, it's
straightforward to store each origin in separate nested bundles, but we
want links from one origin to another to also work within the same
top-level bundle.

Addressing something in a sibling or parent bundle is reasonably
straightforward, with something similar to the following syntax:

```
<a href="package:..$/https/other.site.example.wbn$/path.html">
```

The downside is that if a user wants to take one site out of the big bundle
and use it on its own, and they want links outside that site to land on the
internet, they have to know the mapping from URLs to bundle names and undo
it in all the links. If they don't do this, the links are broken instead.

Similarly, if someone wants to compose a couple of pre-existing bundles,
they have to rewrite links to point to sibling bundles appropriately.

# Comparison

We need to compare "single-origin bundles", described above, with
"multi-origin bundles", described at
https://github.com/WICG/webpackage/blob/master/explainers/bundle-urls-and-origins.md#proposal-a-package-scheme
.

Both use a package:bundle-location$within-bundle format.

Because the single-origin proposal chooses not to encode the whole origin
to fit in the authority URL component, and implies rather than states the
bundle's scheme, I'll compare it to a variant of the multi-origin proposal
that does the same, yielding:

```
package://archive.example/2020-04-01.wbn$https://camera.example/edit.html
```

The difference becomes whether the origin computation includes an authority
component in the last $-delimited segment.

## Single-origin bundles are better:

* Implementers can use a simpler algorithm to compute the origin, ending at
the last $ instead of having to also parse a URL from the last component.

* Including just a single origin may avoid the need for signatures to
specify a subset of the bundle, which could simplify that section.

* Naming subresources with paths instead of URLs is more consistent with
other archiving formats.

## Multi-origin bundles are better:

* Users can expect simple tools to combine and split pre-existing bundles.

* When authors are composing a bundle, cross-origin resources can go
directly into the bundle, instead of needing to rewrite them to same-origin
or put them in a nested bundle.

* Implementations only need to spin up the bundle parser once, which could
affect performance.

* Implementers need to write and maintain tools to rewrite cross-origin
URLs when saving a bundle from a website

---

From: "Martin Thomson" <[email-masked]>
Date: Thu, 27 Aug 2020 15:44:36 +1000

On Thu, Aug 27, 2020, at 04:00, Jeffrey Yasskin wrote:
> last `$`. 

This is one option.  I tend to think that adding to the tuple is also reasonable (it doesn't have to be origin attributes).  Suborigins proposed a new origin tuple item, for instance.

> The difference becomes whether the origin computation includes an 
> authority component in the last $-delimited segment.

This is the bit that I want to draw on a little harder.  If the URI for a resource is its identity, and we are basing the fact that x$https://example.com/foo comes from example.com purely on an unsubstantiated assertion, why would we consider example.com to be a necessary part of the identity of the resource?  Or the identity of the origin for that matter?

> * Users can expect simple tools to combine and split pre-existing bundles.

I think that this is not correct, or at least founded on a poor assumption.  

I believe that your assumption is that a resource can refer to content by an https:// URL (or otherwise "canonical" URL) without identifying the bundle in which it appears.

It's a good assumption when content is properly attributed to an https:// (or otherwise "canonical") source through something like a signature.  But also completely unnecessary in that case (we no longer need the new scheme).  In that case saying "http://example.com/resource" is enough.  It perfectly matches with the treatment of the referenced content.  But I don't believe that you can safely identify content without also identifying the bundle in which it appears unless you have that guarantee.

The narrow cases in which this is interesting is when you have resources from multiple origins with multiple cross references.  If your CSS is in a different origin and it references content from yet another origin, then those links need to be adjusted based on the bundle structure.  (Which was your next point; but see below.)

> directly into the bundle, instead of needing to rewrite them to 
> same-origin or put them in a nested bundle.

There is another option, which is to adopt resources.  Many subresources are effectively adopted anyway (JS, CSS, CORS images).  Bundling removes confidentiality advantages conferred to others (non-CORS images).  A simple bundler gains nothing by retaining isolation for either; only a bundler that intends to have the content re-attributed to the "online" origin gains anything by isolating the latter.  

The main reasons I can think of to maintain any isolation are: reuse (a large bundle like El Paquete Semanal might want to avoid resource duplication), or sandboxing (for re-attribution to online origins, or isoation of mutually distrustful content like iframes).  Both of which are things I might argue are sufficiently advanced as to justify the non-trivial extra effort.

There are other options of course.  If you find that link writing is awkward, then a different authority form for the package: scheme might help.  Let's say we choose a non-reg-name form, maybe something that starts with a $ and reserve that.  Then we can name packages and reference content in them.  Then you might name a shared package of images as eps-images and refer to an image in it using <package://$eps-images/people/person.jpg>.

This is as meaningful as the pseudo-origin that appears after the $ in your examples, it just doesn't pretend to be something it isn't.

You could use the same methods for avoiding collisions (i.e., a domain name), but you can also use short mnemonics or UUIDs.   The phishing potential of this simple design leads me to wonder if it is the best strategy, but maybe we can just ensure that that string never appears in security-sensitive UX.

> * Implementations only need to spin up the bundle parser once, which 
> could affect performance.

Gee, I hope it doesn't cost that much.  A better baseline comparison is not zero overhead, but a new TLS connection.  And if we can't beat that, we'd have to try not to.

> URLs when saving a bundle from a website

See above.  It might be enough to avoid that at a granular level.