1package web
2
3import (
4 "log/slog"
5 "net/http"
6
7 "tug/internal/transport/web/text"
8)
9
10type Confirm struct {
11 Title text.Key
12 Body text.Key
13 Button text.Key
14 Subject Ident
15 Action string
16 Cancel string
17 Neutral bool
18 Once bool
19 Message text.Key
20 Also string
21 AlsoButton text.Key
22 Refused bool
23 Elsewhere string
24 ElsewhereText text.Key
25}
26
27type OneTime struct {
28 Title text.Key
29 Subject Ident
30 Secret Ident
31 Expires Ident
32 Message string
33 Groups []Ident
34 Label string
35 Back string
36 BackText text.Key
37}
38
39func (k *Kit) RenderConfirm(w http.ResponseWriter, r *http.Request, c Confirm) {
40 if !relativeSameOrigin(c.Action) || !relativeSameOrigin(c.Cancel) || (c.Also != "" && !relativeSameOrigin(c.Also)) || (c.Elsewhere != "" && k.origins.allows(c.Elsewhere) != nil) {
41 slog.Error("confirm page refused: action and cancel must be same-origin paths")
42 k.renderError(w, r, http.StatusInternalServerError, text.ErrorInternalTitle, text.ErrorInternal)
43 return
44 }
45 p := k.formPage(w, r, c)
46 if c.Once {
47 p.Once = k.formNonce(r)
48 }
49 k.render(w, r, http.StatusOK, "confirm", p)
50}
51
52func (k *Kit) RenderOneTime(w http.ResponseWriter, r *http.Request, o OneTime) {
53 k.render(w, r, http.StatusOK, "onetime", k.newPage(w, r, newOneTimeView(o)))
54}
55
56func (k *Kit) SeeOther(w http.ResponseWriter, r *http.Request, path string) {
57 if !relativeSameOrigin(path) {
58 slog.Error("redirect refused: target must be a same-origin path")
59 k.renderError(w, r, http.StatusInternalServerError, text.ErrorInternalTitle, text.ErrorInternal)
60 return
61 }
62 http.Redirect(w, r, path, http.StatusSeeOther)
63}