lens @ 4d930c0c8cb585979798fac2bb254f991faa62fb

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