Discover books, shows, and movies at your level. Track your progress by filling your Shelf with what you find, and share with other language learners. *No dusting required.
shlf.space
1package middleware
2
3import (
4 "context"
5 "log/slog"
6 "net/http"
7 "slices"
8 "strings"
9
10 "github.com/go-chi/chi/v5"
11 "shlf.space/internal/atproto"
12 "shlf.space/internal/server/oauth"
13 notfound "shlf.space/internal/views/not-found"
14)
15
16type CtxKey string
17
18const UnreadNotificationCountCtxKey CtxKey = "unreadNotificationCount"
19
20type Middleware struct {
21 oauth *oauth.OAuth
22 idResolver *atproto.Resolver
23}
24
25func New(oauth *oauth.OAuth, idResolver *atproto.Resolver) Middleware {
26 return Middleware{
27 oauth: oauth,
28 idResolver: idResolver,
29 }
30}
31
32type middlewareFunc func(http.Handler) http.Handler
33
34func (mw Middleware) ResolveIdent() middlewareFunc {
35 excluded := []string{"favicon.ico", "favicon.svg"}
36
37 return func(next http.Handler) http.Handler {
38 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
39 didOrHandle := chi.URLParam(r, "user")
40 didOrHandle = strings.TrimPrefix(didOrHandle, "@")
41
42 if slices.Contains(excluded, didOrHandle) {
43 next.ServeHTTP(w, r)
44 return
45 }
46
47 id, err := mw.idResolver.ResolveIdent(r.Context(), didOrHandle)
48 if err != nil {
49 slog.Error("failed to resolve did/handle", "err", err)
50 w.WriteHeader(http.StatusNotFound)
51 notfound.NotFoundPage(notfound.NotFoundParams{}).Render(r.Context(), w)
52 return
53 }
54
55 ctx := context.WithValue(r.Context(), "resolvedId", *id)
56
57 next.ServeHTTP(w, r.WithContext(ctx))
58 })
59 }
60}