Documentation
¶
Overview ¶
Package realorigin serves untrusted remote content at a genuine, isolated browser origin whose network layer is a service worker, while the credentials that fetch it stay on a separate origin behind a capability.
The problem it solves is a certificate problem before it is a network one. Rendering content at a real origin over HTTPS needs a certificate for that origin's hostname, and issuing one per site exhausts CA rate limits, so one wildcard has to cover every site. But a wildcard certificate matches exactly one label and only the left-most one (RFC 6125 section 6.4.3, and the CA/Browser Forum Baseline Requirements): *.*.example is not a certificate any CA issues or any browser accepts. So the target cannot be encoded into the hostname — a subdomain, or a name long enough to crowd the 63-character label limit, has nowhere to go.
The way out is to stop naming the target at all. A browse origin is a short, stable hash of it:
id = base32(sha256(canonical))[:20] B = https://<id>.<suffix>
One wildcard then covers every site whatever the target looks like; the hash is deterministic, so a site keeps its cookies and storage across sessions; and because the frame knows only its own id, it supplies a path and never a host, which is what stops one browse origin asking for another's content.
Index ¶
Constants ¶
const IDLen = 20
IDLen is the number of base32 characters in a browse-origin label: 20 characters, so 100 bits of the digest, truncated to leave room under the 63-character DNS label limit.
Variables ¶
var ( // ErrNoSuffix is returned when Config.Suffix is empty. ErrNoSuffix = errors.New("realorigin: Suffix is required") // ErrNoAppOrigin is returned when Config.AppOrigin is empty. ErrNoAppOrigin = errors.New("realorigin: AppOrigin is required") )
Functions ¶
func BootstrapHTML ¶
func BootstrapHTML() []byte
BootstrapHTML returns the built-in shell, as a starting point for a Config.Shell that wants a richer interstitial without reimplementing the bridge.
func Handler ¶
Handler returns the browse-origin handler.
Every path except the worker's serves the same shell, which is what makes navigation work: the worker deliberately does not intercept navigations, so each one lands here and the shell fetches that path and writes it into the origin. Serving the shell only at "/" would break every link on every page.
func Host ¶
Host returns the full browse-origin hostname for a canonical target under suffix, e.g. "k3f9….mesh.localhost". A missing leading dot on the suffix is supplied.
func ID ¶
ID returns the browse-origin label for a canonical target string.
The caller decides what canonical means for its own address space and is responsible for making equivalent addresses produce the same string — two spellings of one target that canonicalize differently get two origins, and so two separate cookie jars. The JavaScript half computes this identically.
func IDFromHost ¶
IDFromHost recovers the label from a browse-origin hostname, and reports whether host was in fact a browse origin under suffix. A port is not accepted here: strip it first.
func ResponderJS ¶
func ResponderJS() []byte
ResponderJS returns the script to serve from the APP origin, first-party.
It has to be first-party there. Put it in a cross-origin helper iframe and Storage Partitioning lands the helper in a different partition from the app's own workers, where it cannot reach the client it exists to call.
func ServiceWorkerJS ¶ added in v0.1.1
func ServiceWorkerJS() []byte
ServiceWorkerJS returns the transport worker, for an embedder that serves the browse origin itself rather than through Handler — a host-routed setup where B and the app share one listener, say. Serve it at Config.SWPath.
Types ¶
type Config ¶
type Config struct {
// Addr is the listen address for ListenAndServe. Ignored by Handler.
Addr string
// Suffix is the browse-origin domain suffix, with or without a leading dot
// (".mesh.localhost" locally, or a registrable domain you hold). Required.
//
// Hosted, this must be a DIFFERENT registrable domain from the app's, not a
// subdomain of it: different hosts make the two cross-origin, but only
// different registrable domains make untrusted content fully cross-site from
// the app.
Suffix string
// AppOrigin is the origin of the app that holds the credentials and answers
// the handshake, e.g. "https://app.example". Required.
AppOrigin string
// SWPath is where the service worker is served. Defaults to "/sw.js". It must
// stay at the root of the origin, since the worker claims the whole scope.
SWPath string
// Shell replaces the bootstrap shell served for navigations. Empty uses the
// built-in one, which is deliberately plain: it says what is happening and
// prints whatever progress the transport reports, and no more.
//
// Override it when the wait is worth dressing — a slow transport that sets up
// a route before it can fetch anything has a real story to tell, and a bare
// spinner wastes it. A replacement must speak the same bridge protocol:
// handshake to window.parent with {type:'realorigin-hello', shortid}, register
// the worker, relay 'realorigin-fetch' between the worker and the app, and
// write the response into the document. Start from web/bootstrap.html.
//
// __APP_ORIGIN__ and __SUFFIX__ are substituted here exactly as they are in
// the built-in shell.
Shell []byte
// Worker replaces the transport service worker served at SWPath. Empty uses
// the built-in one.
//
// The built-in worker is deliberately small and names no transport, which is
// what makes it auditable on the untrusted origin. A replacement inherits that
// responsibility: it runs on B, so whatever it can reach, untrusted content can
// reach through it. It must speak the same bridge protocol — relay each
// non-navigation fetch to a controlling client as {type:realorigin-fetch}
// over a MessagePort and answer with the returned {status, headers, body}.
//
// A worker that needs companion files (a wasm module and its loader, say)
// serves them through Assets.
Worker []byte
// Assets are extra paths served verbatim on the browse origin, e.g.
// {"/sw.wasm": mod, "/wasm_exec.js": loader}. Keys are absolute paths and win
// over the shell; SWPath still wins over both.
//
// Every byte here is served to the UNTRUSTED origin, so put nothing in it that
// the browsed content should not have.
Assets map[string][]byte
}
Config describes the browse-origin server: the static half of the substrate.
It never proxies content. It serves the service worker at one path and the bootstrap shell at every other, and that is all. Every fetch the rendered page makes is relayed to the visitor's own app tab and satisfied by the transport there — so a public deployment of this carries, sees and stores none of the traffic, and nothing about it scales with how much anyone browses.
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
realorigin-demo
command
Command realorigin-demo is a working example of the substrate with an ordinary HTTP transport.
|
Command realorigin-demo is a working example of the substrate with an ordinary HTTP transport. |