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}