| 1 |
|
package web |
| 2 |
|
|
| 3 |
|
import ( |
| 4 |
|
"net/http" |
| 5 |
|
|
| 6 |
|
"sourcecraft.dev/bigbes/sr-ht-ecore/chrome" |
| 7 |
|
|
| 8 |
|
"sourcecraft.dev/bigbes/sr-ht-spec/authn" |
| 9 |
|
) |
| 10 |
|
|
| 11 |
|
// viewData is the root value every template is executed against. |
| 12 |
|
// |
| 13 |
|
// chrome.Page is embedded rather than copied field by field, so the shared |
| 14 |
|
// partials — "srht-nav", "srht-env-banner" — find the fields they read on the |
| 15 |
|
// dot they are handed, and a field ecore adds later arrives here without an |
| 16 |
|
// edit. The page's own payload lives under Data and is reached as |
| 17 |
|
// {{.Data.Something}}, which is what keeps a page from shadowing a chrome |
| 18 |
|
// field: a page wanting a "Username" of its own puts it in its payload, where |
| 19 |
|
// it cannot silently replace the one the login block reads. |
| 20 |
|
type viewData struct { |
| 21 |
|
chrome.Page |
| 22 |
|
|
| 23 |
|
// Data is the page's own payload. |
| 24 |
|
Data any |
| 25 |
|
} |
| 26 |
|
|
| 27 |
|
// view builds the frame for one request: the shared chrome plus a title. |
| 28 |
|
// |
| 29 |
|
// The username handed to the chrome is the *authoritative* identity, not |
| 30 |
|
// whatever the cookie said: on this instance a logged-in human who is not the |
| 31 |
|
// owner resolves to anonymous, so the nav offers them a login rather than |
| 32 |
|
// greeting them by a name that grants nothing. An agent's bearer token is not |
| 33 |
|
// an identity for the nav either — it never renders a page for itself. |
| 34 |
81 |
func (s *Server) view(r *http.Request, title string) viewData { |
| 35 |
81 |
username := "" |
| 36 |
81 |
if p := authn.PrincipalFromContext(r.Context()); p.IsOwner() { |
| 37 |
56 |
username = p.Owner |
| 38 |
56 |
} |
| 39 |
81 |
return viewData{Page: s.chromeSvc.Page(r, title, username)} |
| 40 |
|
} |
| 41 |
|
|
| 42 |
|
// loginRedirect sends a viewer with no read authority to meta.sr.ht's login, |
| 43 |
|
// with return_to pointing back at what they asked for. There is no login flow |
| 44 |
|
// of our own — identity is the shared unified-login cookie and nothing else. |
| 45 |
|
// |
| 46 |
|
// The URL comes from the chrome rather than from a second hand-rolled |
| 47 |
|
// concatenation of the meta origin and an escaped return_to: the link in the |
| 48 |
|
// nav and the redirect a gate issues must be the same URL, and the cheapest way |
| 49 |
|
// to guarantee that is to have exactly one place that builds it. LoginURLFor is |
| 50 |
|
// that place — a redirect wants the one field, not a whole page built to be |
| 51 |
|
// thrown away. |
| 52 |
6 |
func (s *Server) loginRedirect(w http.ResponseWriter, r *http.Request) { |
| 53 |
6 |
http.Redirect(w, r, s.chromeSvc.LoginURLFor(r), http.StatusFound) |
| 54 |
6 |
} |