lens @ 1ae70dbd9124675d4a510954619b01edd5f1f6c3

  1package ext
  2
  3import (
  4	"encoding/base64"
  5	"time"
  6
  7	"github.com/sirupsen/logrus"
  8	"github.com/valyala/fasthttp"
  9
 10	"git.sr.ht/~gabrielgio/img/pkg/database/repository"
 11)
 12
 13func HTML(next fasthttp.RequestHandler) fasthttp.RequestHandler {
 14	return func(ctx *fasthttp.RequestCtx) {
 15		ctx.Response.Header.SetContentType("text/html")
 16		next(ctx)
 17	}
 18}
 19
 20type LogMiddleware struct {
 21	entry *logrus.Entry
 22}
 23
 24func NewLogMiddleare(log *logrus.Entry) *LogMiddleware {
 25	return &LogMiddleware{
 26		entry: log,
 27	}
 28}
 29
 30func (l *LogMiddleware) HTTP(next fasthttp.RequestHandler) fasthttp.RequestHandler {
 31	return func(ctx *fasthttp.RequestCtx) {
 32		start := time.Now()
 33		next(ctx)
 34		elapsed := time.Since(start)
 35		l.entry.
 36			WithField("time", elapsed).
 37			WithField("code", ctx.Response.StatusCode()).
 38			WithField("path", string(ctx.Path())).
 39			WithField("bytes", len(ctx.Response.Body())).
 40			Info(string(ctx.Request.Header.Method()))
 41	}
 42}
 43
 44type AuthMiddleware struct {
 45	key   []byte
 46	entry *logrus.Entry
 47}
 48
 49func NewAuthMiddleware(key []byte, log *logrus.Entry) *AuthMiddleware {
 50	return &AuthMiddleware{
 51		key:   key,
 52		entry: log.WithField("context", "auth"),
 53	}
 54}
 55
 56func (a *AuthMiddleware) LoggedIn(next fasthttp.RequestHandler) fasthttp.RequestHandler {
 57	return func(ctx *fasthttp.RequestCtx) {
 58		path := string(ctx.Path())
 59		if path == "/login" || path == "/initial" {
 60			next(ctx)
 61			return
 62		}
 63
 64		redirectLogin := "/login?redirect=" + path
 65		authBase64 := ctx.Request.Header.Cookie("auth")
 66		if authBase64 == nil {
 67			a.entry.Info("No auth provided")
 68			ctx.Redirect(redirectLogin, 307)
 69			return
 70		}
 71
 72		auth, err := base64.StdEncoding.DecodeString(string(authBase64))
 73		if err != nil {
 74			a.entry.Error(err)
 75			return
 76		}
 77
 78		token, err := ReadToken(auth, a.key)
 79		if err != nil {
 80			a.entry.Error(err)
 81			ctx.Redirect(redirectLogin, 307)
 82			return
 83		}
 84		ctx.SetUserValue("token", token)
 85		a.entry.
 86			WithField("userID", token.UserID).
 87			WithField("username", token.Username).
 88			Info("user recognized")
 89		next(ctx)
 90	}
 91}
 92
 93type InitialSetupMiddleware struct {
 94	userRepository repository.UserRepository
 95}
 96
 97func NewInitialSetupMiddleware(userRepository repository.UserRepository) *InitialSetupMiddleware {
 98	return &InitialSetupMiddleware{
 99		userRepository: userRepository,
100	}
101}
102
103func (i *InitialSetupMiddleware) Check(next fasthttp.RequestHandler) fasthttp.RequestHandler {
104	return func(ctx *fasthttp.RequestCtx) {
105		// if user has been set to context it is logged in already
106		_, ok := ctx.UserValue("token").(*Token)
107		if ok {
108			next(ctx)
109			return
110		}
111
112		path := string(ctx.Path())
113		if path == "/initial" {
114			next(ctx)
115			return
116		}
117
118		exists, err := i.userRepository.Any(ctx)
119		if err != nil {
120			InternalServerError(ctx, err)
121			return
122		}
123
124		if exists {
125			next(ctx)
126			return
127		}
128		ctx.Redirect("/initial", 307)
129	}
130}