1package middleware
2
3import (
4 "fmt"
5 "log"
6 "net/http"
7 "time"
8
9 "github.com/bnema/gordon/internal/db/queries"
10 "github.com/bnema/gordon/internal/server"
11
12 "github.com/labstack/echo-contrib/session"
13 "github.com/labstack/echo/v4"
14)
15
16func RequireLogin(a *server.App) echo.MiddlewareFunc {
17 return func(next echo.HandlerFunc) echo.HandlerFunc {
18 return func(c echo.Context) error {
19 if err := validateSessionAndUser(c, a); err != nil {
20 log.Println("Session validation failed:", err)
21 return redirectToLogin(c, a)
22 }
23 return next(c)
24 }
25 }
26}
27
28func validateSessionAndUser(c echo.Context, a *server.App) error {
29 sess, err := session.Get("session", c)
30 if err != nil {
31 return err
32 }
33
34 // Retrieve accountID and sessionID from session values
35 accountID, ok := sess.Values["accountID"].(string)
36 if !ok {
37 return fmt.Errorf("invalid account ID type")
38 }
39
40 sessionID, ok := sess.Values["sessionID"].(string)
41 if !ok {
42 return fmt.Errorf("invalid session ID type")
43 }
44
45 // Retrieve expires from session values and parse it to time.Time
46 expiresStr, ok := sess.Values["expires"].(string)
47 if !ok {
48 return fmt.Errorf("invalid expires type")
49 }
50 expires, err := time.Parse(time.RFC3339, expiresStr)
51 if err != nil {
52 return fmt.Errorf("could not parse expires: %v", err)
53 }
54
55 if accountCheck, err := isAccountIDInDB(a, accountID); err != nil || !accountCheck {
56 fmt.Println("accountCheck:", accountCheck)
57 return err
58 }
59
60 if sessionExpired, err := isSessionExpiredInDB(a, accountID, sessionID); err != nil || sessionExpired {
61 fmt.Println("sessionExpired:", sessionExpired)
62 return err
63 }
64
65 if cookieExpired, err := isCookieExpired(c); err != nil || cookieExpired {
66 fmt.Println("cookieExpired:", cookieExpired)
67 return err
68 }
69
70 if time.Now().After(expires) {
71 fmt.Println("session expired")
72 queries.SessionCleaner(a, time.Now().Format(time.RFC3339))
73 return fmt.Errorf("session expired")
74
75 }
76
77 return nil
78}
79
80func redirectToLogin(c echo.Context, a *server.App) error {
81 return c.Redirect(http.StatusSeeOther, a.Config.Admin.Path+"/login")
82}
83
84func isCookieExpired(c echo.Context) (bool, error) {
85 cookie, err := c.Cookie("session")
86 if err != nil {
87 return false, err
88 }
89
90 currentTime := time.Now()
91 expirationTime := cookie.Expires
92 return currentTime.After(expirationTime), nil
93}
94
95func isSessionExpiredInDB(a *server.App, userID string, sessionID string) (bool, error) {
96 currentTime := time.Now()
97 expirationTime, err := queries.GetSessionExpiration(a, userID, sessionID, currentTime)
98 if err != nil {
99 return false, err
100 }
101
102 return currentTime.After(expirationTime), nil
103}
104
105func isAccountIDInDB(a *server.App, accountID string) (bool, error) {
106 accountExists, err := queries.CheckDBAccountExists(a, accountID)
107 if err != nil {
108 return false, err
109 }
110
111 return accountExists, nil
112}
113
114func DeleteAndRedirectToLogin(c echo.Context, a *server.App) error {
115 sess, err := session.Get("session", c)
116 if err != nil {
117 return err
118 }
119
120 // Retrieve accountID and sessionID from session values
121 accountID, ok := sess.Values["accountID"].(string)
122 if !ok {
123 return fmt.Errorf("invalid account ID type")
124 }
125
126 sessionID, ok := sess.Values["sessionID"].(string)
127 if !ok {
128 return fmt.Errorf("invalid session ID type")
129 }
130
131 // Delete session from DB
132 if err := queries.DeleteDBSession(a, accountID, sessionID); err != nil {
133 return err
134 }
135
136 // Delete session cookie
137 cookie := new(http.Cookie)
138 cookie.Name = "session"
139 cookie.Value = ""
140 cookie.Expires = time.Now().Add(-1 * time.Hour)
141 c.SetCookie(cookie)
142
143 return redirectToLogin(c, a)
144}