package calls import ( "net/http" "strings" "amadan.net/rastrillo/rastrillo" ) // ServeOptions completes opts with what Calls serves: its mux, its error // page and its scheduled-wake function. main passes the result to // rastrillo.Serve, and the tests that need the production stack (the CSP // tests, the browser gate) pass it to rastrillo.Handler, so the headers // they check are the ones production sends. // // opts.CSP is deliberately left empty: Calls serves rastrillo's default // policy unchanged, the strict one since fb806a2 (style-src 'self' plus // pow's honeypot hash, no 'unsafe-inline'). Nothing Calls draws needs // more. Its templates, and the estilo and ui partials they call, carry // no style attribute; its scripts set geometry and the speaking rim // through CSSOM (element.style.setProperty, .translate, .display), which // CSP does not govern; and the web client's network is all same-origin // (fetch, the SSE stream), with media from getUserMedia on srcObject and // TURN/STUN reached by RTCPeerConnection, neither of which connect-src // or media-src covers. With Home configured, connect's middleware // replaces the policy on every page in the group; homeFormPolicy keeps // that one rastrillo's default too, with only the issuer added to // form-action. TestProductionServesRastrillosDefaultCSP, // TestHomeCSPPreservesPinnedFrameworkDirectives and the browser gate's // CSP check hold this. func ServeOptions(opts rastrillo.Options, mux *http.ServeMux, rt *Runtime) rastrillo.Options { opts.Mux = mux if rt != nil { // NextDue answers the platform's scheduled-wake poll: a magic // link or pending-join row can outlive an instance's // hibernation, and without this the platform has no way to know // it should wake the app to clear one (review C2-2). opts.NextDue = rt.NextDue // A panic outside the router gets the app's own error page, not // rastrillo's plain "Something went wrong." (shared chrome ยง3.3). opts.ErrorPage = rt.ErrorPage } return opts } // Runtime is the parts of Runtime a test harness can have: everything // but Close, which belongs to whoever built the app with App. Tests // only. func (h *TestHandle) Runtime() *Runtime { return &Runtime{NextDue: h.a.nextDue, ErrorPage: h.a.ErrorPage} } // frameworkCSP is rastrillo's default Content-Security-Policy at the // pinned version (serve.go's defaultCSP, unexported), spelled out // because homeFormPolicy must start from it. // TestProductionServesRastrillosDefaultCSP fails the day a bump changes // the default, so this cannot quietly keep an older policy. const frameworkCSP = "default-src 'self'; " + "style-src 'self' 'unsafe-hashes' 'sha256-yJxAE4rjdcckohdlnvecSporPcqS9xOaA4hJxi87LMc='; " + "img-src 'self' data:; frame-ancestors 'none'; base-uri 'self'; form-action 'self'" // homeFormPolicy is the policy connect's middleware sends in Home mode: // rastrillo's default with the issuer added to form-action, because the // Home exchange posts a form there. connect's own FormPolicy predates // rastrillo fb806a2 and still allows inline styles; Calls has none to // allow. The one style attribute connect's pages carry (home_link.html's // overflow-wrap on the linked address) is in calls-shell.css instead. func homeFormPolicy(issuer string) string { return strings.Replace(frameworkCSP, "form-action 'self'", "form-action 'self' "+issuer, 1) }