wtf auth??

This commit is contained in:
41666 2025-03-26 21:08:15 -07:00
parent 607d7e121c
commit a3a1654030
14 changed files with 337 additions and 1 deletions

View file

@ -0,0 +1,130 @@
package authmiddleware
import (
"errors"
"fmt"
"time"
"slices"
"git.sapphic.engineer/roleypoly/v4/discord"
"git.sapphic.engineer/roleypoly/v4/types"
"github.com/gofiber/fiber/v3"
"github.com/gofiber/fiber/v3/middleware/session"
)
type AuthMiddleware struct {
Client discord.IDiscordClient
supportIDs []string
superuserIDs []string
}
type Session struct {
Permissions Permission
User *types.DiscordUser
AccessToken string
LastRefresh time.Time
}
var SessionKey uint8
func New(discordClient discord.IDiscordClient, supportIDs []string, superuserIDs []string) func(fiber.Ctx) error {
am := AuthMiddleware{
Client: discordClient,
supportIDs: supportIDs,
superuserIDs: superuserIDs,
}
return am.Handle
}
var DefaultSession *Session = &Session{Permissions: PermAnonymous}
func (am *AuthMiddleware) Handle(c fiber.Ctx) error {
sc := session.FromContext(c)
sess := am.Init(sc)
am.validateAccessToken(sess) // this will remove AccessToken if its no good
am.setPermissions(sess) // this captures this
am.Commit(sc, sess) // and save our first bits?
return c.Next()
}
func (am *AuthMiddleware) Init(sess *session.Middleware) *Session {
session, ok := sess.Get(SessionKey).(*Session)
if !ok {
am.Commit(sess, DefaultSession)
return DefaultSession
}
return session
}
func (am *AuthMiddleware) Commit(sc *session.Middleware, sess *Session) {
sc.Set(SessionKey, sess)
}
func SessionFrom(c fiber.Ctx) (s *Session) {
sess := session.FromContext(c)
s, _ = sess.Get(SessionKey).(*Session)
return s
}
func (am *AuthMiddleware) isSupport(userID string) bool {
return slices.Contains(am.supportIDs, userID)
}
func (am *AuthMiddleware) isSuperuser(userID string) bool {
return slices.Contains(am.superuserIDs, userID)
}
func (am *AuthMiddleware) setPermissions(sess *Session) {
sess.Permissions = PermAnonymous
if sess.AccessToken != "" {
sess.Permissions = PermUser
}
if am.isSupport(sess.User.ID) {
sess.Permissions = PermSupport
}
if am.isSuperuser(sess.User.ID) {
sess.Permissions = PermSuperuser
}
}
func (am *AuthMiddleware) validateAccessToken(sess *Session) {
if sess.AccessToken == "" {
return
}
if sess.LastRefresh.Add(time.Hour).Before(time.Now()) {
user, err := am.GetCurrentUser(sess.AccessToken)
if err != nil {
if errors.Is(err, discord.ErrUnauthorized) {
sess.AccessToken = ""
return
}
}
sess.User = user
}
}
func (am *AuthMiddleware) GetCurrentUser(accessToken string) (*types.DiscordUser, error) {
req := discord.NewRequest("GET", "/users/@me")
am.Client.ClientAuth(req, accessToken)
resp, err := am.Client.Do(req)
if err != nil {
return nil, fmt.Errorf("authmiddleware.GetCurrentUser: request failed: %w", err)
}
var user types.DiscordUser
err = discord.OutputResponse(resp, &user)
return &user, err
}

View file

@ -0,0 +1,80 @@
package authmiddleware_test
import (
"bytes"
"net/http"
"testing"
"git.sapphic.engineer/roleypoly/v4/authmiddleware"
"git.sapphic.engineer/roleypoly/v4/discord"
"git.sapphic.engineer/roleypoly/v4/discord/clientmock"
"github.com/goccy/go-json"
"github.com/gofiber/fiber/v3"
"github.com/gofiber/fiber/v3/middleware/session"
)
func TestAnonymous(t *testing.T) {
dc := clientmock.NewDiscordClientMock()
app := getApp(dc)
setSession(app, dc, authmiddleware.Session{
Permissions: authmiddleware.PermAnonymous,
})
}
func getApp(dc discord.IDiscordClient) *fiber.App {
app := fiber.New(fiber.Config{})
sessionMiddleware, sessionStore := session.NewWithStore()
sessionStore.RegisterType(authmiddleware.Session{})
app.Use(sessionMiddleware, authmiddleware.New(dc, []string{}, []string{}))
app.Get("/", authState)
app.Post("/updateSession", updateSession)
return app
}
func setSession(app *fiber.App, dc *clientmock.DiscordClientMock, sess authmiddleware.Session) error {
body := bytes.Buffer{}
json.NewEncoder(&body).Encode(sess)
// do mocks here
req, _ := http.NewRequest("POST", "/updateSession", &body)
_, err := app.Test(req)
return err
}
func authState(c fiber.Ctx) error {
s := authmiddleware.SessionFrom(c)
permList := []string{}
if s.Permissions >= authmiddleware.PermAnonymous {
permList = append(permList, "anonymous")
}
if s.Permissions >= authmiddleware.PermUser {
permList = append(permList, "user")
}
if s.Permissions >= authmiddleware.PermSupport {
permList = append(permList, "support")
}
if s.Permissions >= authmiddleware.PermSuperuser {
permList = append(permList, "superuser")
}
return c.JSON(permList)
}
func updateSession(c fiber.Ctx) error {
var newSession *authmiddleware.Session
c.Bind().JSON(&newSession)
sc := session.FromContext(c)
sc.Set(authmiddleware.SessionKey, newSession)
return c.SendString("ok")
}

10
authmiddleware/const.go Normal file
View file

@ -0,0 +1,10 @@
package authmiddleware
type Permission uint8
const (
PermAnonymous Permission = 1 << iota
PermUser
PermSupport
PermSuperuser
)