package main // Small generic oauth authentication server to retrieve oauth tokens // from mastodon instances. import ( "encoding/json" "fmt" "net/http" "os" "github.com/gorilla/websocket" "github.com/labstack/echo" "github.com/labstack/echo/middleware" "github.com/labstack/gommon/log" "go.etcd.io/bbolt" ) var ( upgrader = websocket.Upgrader{} ) type Instance struct { Secret string `json:"client_secret"` ID string `json:"client_id"` } type App struct { AuthMap *AuthenticationMap Logger *echo.Logger DB *bbolt.DB } func (a *App) authRequestWebSocket(c echo.Context) error { ws, err := upgrader.Upgrade(c.Response(), c.Request(), nil) if err != nil { return err } client := &AuthRequestClient{ conn: ws, app: a, } req, err := client.ReceiveRequest() if err != nil { return err } (*a.Logger).Info("Queueing AuthRequest") a.AuthMap.QueueRequest(req) return nil } func (a *App) authRequestRedirect(c echo.Context) error { requestId := c.Param("request_id") authRequest := a.AuthMap.GetRequestByID(requestId) if authRequest == nil { return c.String(http.StatusNotFound, "No authentication request found by this ID") } var instance *Instance a.DB.View(func(t *bbolt.Tx) error { instanceJson := t.Bucket([]byte("instances")).Get([]byte(authRequest.Instance)) if instanceJson == nil { instance = nil return nil } instance = &Instance{} err := json.Unmarshal(instanceJson, instance) return err }) return c.String(http.StatusOK, "BLAAT") //return c.Redirect(http.StatusTemporaryRedirect, ) } func main() { arguments := os.Args[1:] if len(arguments) != 2 { fmt.Fprintln(os.Stderr, "Expected 2 command line argumens, but got : ", len(arguments)) fmt.Fprintln(os.Stderr, "Usage: generic-mastodon-authenticator APP_NAME DB_PATH") os.Exit(1) } database := arguments[1] db, err := bbolt.Open(database, 0600, nil) if err != nil { log.Fatal(err) } db.Update(func(t *bbolt.Tx) error { _, err := t.CreateBucketIfNotExists([]byte("instances")) return err }) e := echo.New() e.Use(middleware.Logger()) e.Use(middleware.Recover()) e.Static("/", "../public") e.Logger.SetLevel(log.INFO) a := &App{ Logger: &e.Logger, DB: db, } m := &AuthenticationMap{ app: a, } m.Init() a.AuthMap = m e.GET("/ws", a.authRequestWebSocket) e.GET("/auth/:request_id", a.authRequestRedirect) e.Logger.Fatal(e.Start(":1323")) }