this repo has no description
1package state
2
3import (
4 "log"
5 "net/http"
6 "time"
7
8 comatproto "github.com/bluesky-social/indigo/api/atproto"
9 "github.com/bluesky-social/indigo/xrpc"
10 "github.com/go-chi/chi/v5"
11 "github.com/sotangled/tangled/appview"
12 "github.com/sotangled/tangled/appview/auth"
13)
14
15type Middleware func(http.Handler) http.Handler
16
17func AuthMiddleware(s *State) Middleware {
18 return func(next http.Handler) http.Handler {
19 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
20 session, _ := s.auth.Store.Get(r, appview.SessionName)
21 authorized, ok := session.Values[appview.SessionAuthenticated].(bool)
22 if !ok || !authorized {
23 log.Printf("not logged in, redirecting")
24 http.Redirect(w, r, "/login", http.StatusTemporaryRedirect)
25 return
26 }
27
28 // refresh if nearing expiry
29 // TODO: dedup with /login
30 expiryStr := session.Values[appview.SessionExpiry].(string)
31 expiry, err := time.Parse(appview.TimeLayout, expiryStr)
32 if err != nil {
33 log.Println("invalid expiry time", err)
34 return
35 }
36 pdsUrl := session.Values[appview.SessionPds].(string)
37 did := session.Values[appview.SessionDid].(string)
38 refreshJwt := session.Values[appview.SessionRefreshJwt].(string)
39
40 if time.Now().After(expiry) {
41 log.Println("token expired, refreshing ...")
42
43 client := xrpc.Client{
44 Host: pdsUrl,
45 Auth: &xrpc.AuthInfo{
46 Did: did,
47 AccessJwt: refreshJwt,
48 RefreshJwt: refreshJwt,
49 },
50 }
51 atSession, err := comatproto.ServerRefreshSession(r.Context(), &client)
52 if err != nil {
53 log.Println(err)
54 return
55 }
56
57 sessionish := auth.RefreshSessionWrapper{atSession}
58
59 err = s.auth.StoreSession(r, w, &sessionish, pdsUrl)
60 if err != nil {
61 log.Printf("failed to store session for did: %s\n: %s", atSession.Did, err)
62 return
63 }
64
65 log.Println("successfully refreshed token")
66 }
67
68 next.ServeHTTP(w, r)
69 })
70 }
71}
72
73func RoleMiddleware(s *State, group string) Middleware {
74 return func(next http.Handler) http.Handler {
75 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
76 // requires auth also
77 actor := s.auth.GetUser(r)
78 if actor == nil {
79 // we need a logged in user
80 log.Printf("not logged in, redirecting")
81 http.Error(w, "Forbiden", http.StatusUnauthorized)
82 return
83 }
84 domain := chi.URLParam(r, "domain")
85 if domain == "" {
86 http.Error(w, "malformed url", http.StatusBadRequest)
87 return
88 }
89
90 ok, err := s.enforcer.E.HasGroupingPolicy(actor.Did, group, domain)
91 if err != nil || !ok {
92 // we need a logged in user
93 log.Printf("%s does not have perms of a %s in domain %s", actor.Did, group, domain)
94 http.Error(w, "Forbiden", http.StatusUnauthorized)
95 return
96 }
97
98 next.ServeHTTP(w, r)
99 })
100 }
101}