Monorepo for Tangled tangled.org
5

Configure Feed

Select the types of activity you want to include in your feed.

1package serviceauth 2 3import ( 4 "context" 5 "encoding/json" 6 "log/slog" 7 "net/http" 8 "path" 9 "strings" 10 11 "github.com/bluesky-social/indigo/atproto/auth" 12 "github.com/bluesky-social/indigo/atproto/identity" 13 "github.com/bluesky-social/indigo/atproto/syntax" 14 "tangled.org/core/log" 15 xrpcerr "tangled.org/core/xrpc/errors" 16) 17 18type contextKey string 19 20const ActorDid contextKey = "ActorDid" 21 22func DidWeb(hostname string) syntax.DID { 23 return syntax.DID("did:web:" + strings.ReplaceAll(hostname, ":", "%3A")) 24} 25 26type ServiceAuth struct { 27 logger *slog.Logger 28 dir identity.Directory 29 audienceDid string 30} 31 32func NewServiceAuth(logger *slog.Logger, dir identity.Directory, audienceDid string) *ServiceAuth { 33 return &ServiceAuth{ 34 logger: log.SubLogger(logger, "serviceauth"), 35 dir: dir, 36 audienceDid: audienceDid, 37 } 38} 39 40func (sa *ServiceAuth) VerifyServiceAuth(next http.Handler) http.Handler { 41 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 42 token := r.Header.Get("Authorization") 43 token = strings.TrimPrefix(token, "Bearer ") 44 45 lxm, err := syntax.ParseNSID(path.Base(r.URL.Path)) 46 if err != nil { 47 sa.logger.Error("could not derive lexicon method from request path", "path", r.URL.Path, "err", err) 48 writeError(w, xrpcerr.AuthError(err), http.StatusForbidden) 49 return 50 } 51 52 s := auth.ServiceAuthValidator{ 53 Audience: sa.audienceDid, 54 Dir: sa.dir, 55 } 56 57 did, err := s.Validate(r.Context(), token, &lxm) 58 if err != nil { 59 sa.logger.Error("signature verification failed", "err", err) 60 writeError(w, xrpcerr.AuthError(err), http.StatusForbidden) 61 return 62 } 63 64 sa.logger.Debug("valid signature", "did", did) 65 66 r = r.WithContext( 67 context.WithValue(r.Context(), ActorDid, did), 68 ) 69 70 next.ServeHTTP(w, r) 71 }) 72} 73 74// this is slightly different from http_util::write_error to follow the spec: 75// 76// the json object returned must include an "error" and a "message" 77func writeError(w http.ResponseWriter, e xrpcerr.XrpcError, status int) { 78 w.Header().Set("Content-Type", "application/json") 79 w.WriteHeader(status) 80 json.NewEncoder(w).Encode(e) 81}