package server import ( "encoding/json" "errors" "fmt" "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 fmt.Print("looking for subscriber in map..") for s, _ := range subscribers { fmt.Print(".") if s.key == key { ptr = s } } fmt.Println() if ptr != nil { fmt.Println("setting adaters for the found subscriber: " + ptr.key) 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{} case "mastodon": a = &adapter.MastoAdapter{} case "misskey": a = &adapter.MisskeyAdapter{} default: break } err := a.Init(s, subscriber.data) if err != nil { util.AddContextValue(req, "data", err.Error()) w.WriteHeader(500) next.ServeHTTP(w, req) return } fmt.Println("adapter initialized - subscribing with default filter") errs := a.Subscribe(a.DefaultSubscriptionFilter()) if errs != nil { errMsg := "" for _, e := range errs { fmt.Println("processing an error") errMsg += fmt.Sprintf("- %s\n", e.Error()) } util.AddContextValue(req, "data", errMsg) w.WriteHeader(500) next.ServeHTTP(w, req) return } fmt.Println("adapter ready for use; adding to array") adapters = append(adapters, a) fmt.Println("adapter added to array") } // 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] if getSubscriberByKey(subscriberKey, subscribers) != nil { next.ServeHTTP(w, req) return } } w.WriteHeader(http.StatusUnauthorized) }) } func apiAdapterFetch(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] s := getSubscriberByKey(subscriberKey, subscribers) if s != nil { apiParams := req.Context().Value("params").(map[string]string) queryParams := req.URL.Query() for _, a := range subscribers[s] { if a.Name() == apiParams["adapter_id"] { err := a.Fetch(queryParams["entity_type"][0], queryParams["entity_id"][0]) if err != nil { fmt.Println(err.Error()) w.WriteHeader(http.StatusInternalServerError) } else { w.WriteHeader(http.StatusAccepted) } 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, )) rtr.Get(`/adapters/(?P\S+)/fetch`, ProtectWithSubscriberKey( apiAdapterFetch(renderer.JSON("data"), self.subscribers), self.subscribers, )) return http.HandlerFunc(rtr.ServeHTTP) }