diff --git a/server/api.go b/server/api.go index 57284f5..fb51793 100644 --- a/server/api.go +++ b/server/api.go @@ -1,14 +1,101 @@ 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 apiConfigureAdapters(next http.Handler) http.Handler { +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) }) @@ -28,14 +115,23 @@ func apiAdapterSubscribe(next http.Handler) http.Handler { }) } -func ProtectWithSubscriberKey(next http.Handler) http.Handler { +func ProtectWithSubscriberKey(next http.Handler, subscribers map[*Subscriber][]adapter.Adapter) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - w.WriteHeader(201) - next.ServeHTTP(w, req) + 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 apiMux() http.Handler { +func (self *BBSServer) apiMux() http.Handler { errTemplate, err := template.New("err").Parse("{{ $params := (.Context).Value \"params\" }}
{{ $params.ErrorMessage }}
") if err != nil { panic("error template was malformed") @@ -45,10 +141,20 @@ func apiMux() http.Handler { } // adapters (POST & GET) - rtr.Post("/adapters", ProtectWithSubscriberKey(apiConfigureAdapters(renderer.JSON("data")))) - rtr.Get("/adapters", ProtectWithSubscriberKey(apiGetAdapters(renderer.JSON("data")))) + 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