218 lines
6 KiB
Go
218 lines
6 KiB
Go
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\" }}<html><body><h1>ERROR {{ $params.ErrorCode }}</h1><p class='error'>{{ $params.ErrorMessage }}</p></body></html>")
|
|
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<id>\S+)/subscribe`, ProtectWithSubscriberKey(
|
|
apiAdapterSubscribe(renderer.JSON("data")),
|
|
self.subscribers,
|
|
))
|
|
|
|
rtr.Get(`/adapters/(?P<adapter_id>\S+)/fetch`, ProtectWithSubscriberKey(
|
|
apiAdapterFetch(renderer.JSON("data"), self.subscribers),
|
|
self.subscribers,
|
|
))
|
|
|
|
return http.HandlerFunc(rtr.ServeHTTP)
|
|
}
|