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}