lens @ 1d9d5f40fe4092657f529bdba18f6f52511eea00

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