package server import ( "encoding/json" "errors" "forge.lightcrystal.systems/lightcrystal/underbbs/adapter" "forge.lightcrystal.systems/lightcrystal/underbbs/models" "hacklab.nilfm.cc/quartzgun/renderer" "hacklab.nilfm.cc/quartzgun/router" "hacklab.nilfm.cc/quartzgun/util" "html/template" "net/http" "strings" ) func getSubscriberKey(req *http.Request) (string, error) { authHeader := req.Header.Get("Authorization") if strings.HasPrefix(authHeader, "Bearer ") { return strings.Split(authHeader, "Bearer ")[1], nil } return "", errors.New("No subscriber key") } func getSubscriberByKey(key string, subscribers map[*Subscriber][]adapter.Adapter) *Subscriber { for s, _ := range subscribers { if s.key == key { return s } } return nil } func setAdaptersForSubscriber(key string, adapters []adapter.Adapter, subscribers map[*Subscriber][]adapter.Adapter) error { var ptr *Subscriber = nil for s, _ := range subscribers { if s.key == key { ptr = s } } if ptr != nil { subscribers[ptr] = adapters return nil } return errors.New("subscriber not present in map") } func apiConfigureAdapters(next http.Handler, subscribers map[*Subscriber][]adapter.Adapter) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { // get subscriber key skey, err := getSubscriberKey(req) if err != nil { w.WriteHeader(500) return } subscriber := getSubscriberByKey(skey, subscribers) if subscriber == nil { w.WriteHeader(404) return } // decode adapter config from request body settings := make([]models.Settings, 0) err = json.NewDecoder(req.Body).Decode(&settings) if err != nil { w.WriteHeader(400) next.ServeHTTP(w, req) return } // iterate through settings and create adapters adapters := make([]adapter.Adapter, 0) for _, s := range settings { var a adapter.Adapter switch s.Protocol { case "nostr": a = &adapter.NostrAdapter{} break default: break } err := a.Init(s, subscriber.data) if err != nil { util.AddContextValue(req, "data", err.Error()) w.WriteHeader(500) next.ServeHTTP(w, req) } adapters = append(adapters, a) } // TODO: cancel subscriptions on any existing adapters // store the adapters in the subscriber map err = setAdaptersForSubscriber(skey, adapters, subscribers) if err != nil { util.AddContextValue(req, "data", err.Error()) w.WriteHeader(500) next.ServeHTTP(w, req) } w.WriteHeader(201) next.ServeHTTP(w, req) }) } func apiGetAdapters(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { w.WriteHeader(201) next.ServeHTTP(w, req) }) } func apiAdapterSubscribe(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { w.WriteHeader(201) next.ServeHTTP(w, req) }) } func ProtectWithSubscriberKey(next http.Handler, subscribers map[*Subscriber][]adapter.Adapter) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { authHeader := req.Header.Get("Authorization") if strings.HasPrefix(authHeader, "Bearer ") { subscriberKey := strings.Split(authHeader, "Bearer ")[1] for s, _ := range subscribers { if s.key == subscriberKey { next.ServeHTTP(w, req) return } } } w.WriteHeader(http.StatusUnauthorized) }) } func (self *BBSServer) apiMux() http.Handler { errTemplate, err := template.New("err").Parse("{{ $params := (.Context).Value \"params\" }}

ERROR {{ $params.ErrorCode }}

{{ $params.ErrorMessage }}

") if err != nil { panic("error template was malformed") } rtr := &router.Router{ Fallback: *errTemplate, } // adapters (POST & GET) rtr.Post("/adapters", ProtectWithSubscriberKey( apiConfigureAdapters(renderer.JSON("data"), self.subscribers), self.subscribers, )) rtr.Get("/adapters", ProtectWithSubscriberKey( apiGetAdapters(renderer.JSON("data")), self.subscribers, )) // adapters/:name/subscribe rtr.Post(`/adapters/(?P\S+)/subscribe`, ProtectWithSubscriberKey( apiAdapterSubscribe(renderer.JSON("data")), self.subscribers, )) return http.HandlerFunc(rtr.ServeHTTP) }