oficina / home Public

Clone
git clone https://amadan.net/oficina/home

Plain git — no account needed to clone.

Download

Download this file

1package connect
2
3import (
4 "errors"
5 "net/http"
6
7 "amadan.net/oficina/home/connect/linkstore"
8 "amadan.net/oficina/home/handoff"
9)
10
11// Link routes belong behind the app's CSRF, session, identity and admission
12// middleware. They recheck the actual cookie at each sensitive transition.
13func (b *Bridge) LinkPage(w http.ResponseWriter, r *http.Request) {
14 if !b.guard(w, r, http.MethodGet, "/account/home") {
15 return
16 }
17 session, err := b.actualSession(r)
18 if err != nil || session == nil {
19 b.fail(w, r, http.StatusForbidden)
20 return
21 }
22 person, err := b.existingPerson(r, *session)
23 if err != nil {
24 b.fail(w, r, http.StatusForbidden)
25 return
26 }
27 b.render(w, r, "start", person.Label, http.StatusOK)
28}
29func (b *Bridge) LinkStart(w http.ResponseWriter, r *http.Request) {
30 if !b.guard(w, r, http.MethodPost, "/account/home") {
31 return
32 }
33 for _, name := range []string{homeInitCookie, homeProofCookie} {
34 if _, _, ok := homeCookie(r, name); !ok {
35 b.fail(w, r, http.StatusBadRequest)
36 return
37 }
38 }
39 local, _, err := b.localBinding(r)
40 // The reviewed local reauthentication continuation is wired separately.
41 // Stale local authentication cannot begin or reuse a linking initiation.
42 if err != nil {
43 b.fail(w, r, http.StatusForbidden)
44 return
45 }
46 path := "/"
47 if b.returnPath != nil {
48 if candidate := b.returnPath(r); handoff.SafePath(candidate) {
49 path = candidate
50 }
51 }
52 secret, err := b.links.Start(r.Context(), local, path, b.now())
53 if err != nil {
54 b.linkFailure(w, r, err)
55 return
56 }
57 setHomeCookie(w, homeInitCookie, secret, 300)
58 setHomeCookie(w, homeProofCookie, "", -1)
59 http.Redirect(w, r, "/auth/start?return_to=%2Faccount%2Fhome%2Fconfirm", http.StatusSeeOther)
60}
61func (b *Bridge) ConfirmPage(w http.ResponseWriter, r *http.Request) {
62 if !b.guard(w, r, http.MethodGet, "/account/home/confirm") {
63 return
64 }
65 secret, present, ok := homeCookie(r, homeProofCookie)
66 if !ok || !present {
67 b.fail(w, r, http.StatusBadRequest)
68 return
69 }
70 local, person, err := b.localBinding(r)
71 if err != nil {
72 b.fail(w, r, http.StatusForbidden)
73 return
74 }
75 if _, err := b.links.Pending(r.Context(), secret, local, b.now()); err != nil {
76 if errors.Is(err, linkstore.ErrRefused) {
77 setHomeCookie(w, homeProofCookie, "", -1)
78 }
79 b.linkFailure(w, r, err)
80 return
81 }
82 b.render(w, r, "confirm", person.Label, http.StatusOK)
83}
84func (b *Bridge) ConfirmPost(w http.ResponseWriter, r *http.Request) {
85 if !b.guard(w, r, http.MethodPost, "/account/home/confirm") {
86 return
87 }
88 secret, present, ok := homeCookie(r, homeProofCookie)
89 if !ok || !present {
90 b.fail(w, r, http.StatusBadRequest)
91 return
92 }
93 local, _, err := b.localBinding(r)
94 if err != nil {
95 b.fail(w, r, http.StatusForbidden)
96 return
97 }
98 pending, err := b.links.Confirm(r.Context(), secret, local, b.now())
99 if err == nil || errors.Is(err, linkstore.ErrRefused) {
100 setHomeCookie(w, homeProofCookie, "", -1)
101 }
102 if err != nil {
103 b.linkFailure(w, r, err)
104 return
105 }
106 http.Redirect(w, r, pending.ReturnPath, http.StatusSeeOther)
107}
108func (b *Bridge) linkFailure(w http.ResponseWriter, r *http.Request, err error) {
109 status := http.StatusServiceUnavailable
110 if errors.Is(err, linkstore.ErrRefused) {
111 status = http.StatusForbidden
112 }
113 b.fail(w, r, status)
114}
115