Refactor and remove sqlite and replace with MySQL
This commit is contained in:
49
internal/http/middleware/auth.go
Normal file
49
internal/http/middleware/auth.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
httpHelpers "synlotto-website/helpers/http"
|
||||
|
||||
"synlotto-website/constants"
|
||||
)
|
||||
|
||||
func Auth(required bool) func(http.HandlerFunc) http.HandlerFunc {
|
||||
return func(next http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
session, _ := httpHelpers.GetSession(w, r)
|
||||
|
||||
_, ok := session.Values["user_id"].(int)
|
||||
|
||||
if required && !ok {
|
||||
http.Redirect(w, r, "/account/login", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
if ok {
|
||||
last, hasLast := session.Values["last_activity"].(time.Time)
|
||||
if hasLast && time.Since(last) > constants.SessionDuration {
|
||||
session.Options.MaxAge = -1
|
||||
session.Save(r, w)
|
||||
|
||||
newSession, _ := httpHelpers.GetSession(w, r)
|
||||
newSession.Values["flash"] = "Your session has timed out."
|
||||
newSession.Save(r, w)
|
||||
|
||||
http.Redirect(w, r, "/account/login", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
session.Values["last_activity"] = time.Now()
|
||||
session.Save(r, w)
|
||||
}
|
||||
|
||||
next(w, r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Protected(h http.HandlerFunc) http.HandlerFunc {
|
||||
return Auth(true)(SessionTimeout(h))
|
||||
}
|
||||
23
internal/http/middleware/headers.go
Normal file
23
internal/http/middleware/headers.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package middleware
|
||||
|
||||
import "net/http"
|
||||
|
||||
func EnforceHTTPS(next http.Handler, enabled bool) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if enabled && r.Header.Get("X-Forwarded-Proto") != "https" && r.TLS == nil {
|
||||
http.Redirect(w, r, "https://"+r.Host+r.RequestURI, http.StatusMovedPermanently)
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func SecureHeaders(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Security-Policy", "default-src 'self'; style-src 'self' https://cdn.jsdelivr.net; script-src 'self' https://cdn.jsdelivr.net; font-src 'self' https://cdn.jsdelivr.net")
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
w.Header().Set("X-Frame-Options", "DENY")
|
||||
w.Header().Set("X-XSS-Protection", "1; mode=block")
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
35
internal/http/middleware/ratelimit.go
Normal file
35
internal/http/middleware/ratelimit.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/time/rate"
|
||||
)
|
||||
|
||||
var visitors = make(map[string]*rate.Limiter)
|
||||
var mu sync.Mutex
|
||||
|
||||
func GetVisitorLimiter(ip string) *rate.Limiter {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
limiter, exists := visitors[ip]
|
||||
if !exists {
|
||||
limiter = rate.NewLimiter(3, 5)
|
||||
visitors[ip] = limiter
|
||||
}
|
||||
return limiter
|
||||
}
|
||||
|
||||
func RateLimit(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ip, _, _ := net.SplitHostPort(r.RemoteAddr)
|
||||
if !GetVisitorLimiter(ip).Allow() {
|
||||
http.Error(w, "Too many requests", http.StatusTooManyRequests)
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
22
internal/http/middleware/recover.go
Normal file
22
internal/http/middleware/recover.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"runtime/debug"
|
||||
|
||||
templateHelpers "synlotto-website/helpers/template"
|
||||
)
|
||||
|
||||
func Recover(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
defer func() {
|
||||
if rec := recover(); rec != nil {
|
||||
log.Printf("🔥 Recovered from panic: %v\n%s", rec, debug.Stack())
|
||||
|
||||
templateHelpers.RenderError(w, r, http.StatusInternalServerError)
|
||||
}
|
||||
}()
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
40
internal/http/middleware/sessiontimeout.go
Normal file
40
internal/http/middleware/sessiontimeout.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
session "synlotto-website/handlers/session"
|
||||
|
||||
"synlotto-website/constants"
|
||||
)
|
||||
|
||||
func SessionTimeout(next http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
sess, err := session.GetSession(w, r)
|
||||
if err != nil {
|
||||
http.Redirect(w, r, "/account/login", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
last, ok := sess.Values["last_activity"].(time.Time)
|
||||
if !ok || time.Since(last) > constants.SessionDuration {
|
||||
sess.Options.MaxAge = -1
|
||||
_ = sess.Save(r, w)
|
||||
|
||||
newSession, _ := session.GetSession(w, r)
|
||||
newSession.Values["flash"] = "Your session has timed out."
|
||||
_ = newSession.Save(r, w)
|
||||
|
||||
log.Printf("Session timeout triggered")
|
||||
http.Redirect(w, r, "/account/login", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
sess.Values["last_activity"] = time.Now().UTC()
|
||||
_ = sess.Save(r, w)
|
||||
|
||||
next(w, r)
|
||||
}
|
||||
}
|
||||
28
internal/http/routes/accountroutes.go
Normal file
28
internal/http/routes/accountroutes.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"net/http"
|
||||
|
||||
accountHandlers "synlotto-website/handlers/account"
|
||||
lotteryDrawHandlers "synlotto-website/handlers/lottery/tickets"
|
||||
|
||||
"synlotto-website/handlers"
|
||||
"synlotto-website/middleware"
|
||||
)
|
||||
|
||||
func SetupAccountRoutes(mux *http.ServeMux, db *sql.DB) {
|
||||
mux.HandleFunc("/account/login", accountHandlers.Login(db))
|
||||
mux.HandleFunc("/account/logout", middleware.Protected(accountHandlers.Logout))
|
||||
mux.HandleFunc("/account/signup", accountHandlers.Signup)
|
||||
mux.HandleFunc("/account/tickets/add_ticket", lotteryDrawHandlers.AddTicket(db))
|
||||
mux.HandleFunc("/account/tickets/my_tickets", lotteryDrawHandlers.GetMyTickets(db))
|
||||
mux.HandleFunc("/account/messages", middleware.Protected(handlers.MessagesInboxHandler(db)))
|
||||
mux.HandleFunc("/account/messages/read", middleware.Protected(handlers.ReadMessageHandler(db)))
|
||||
mux.HandleFunc("/account/messages/archive", middleware.Protected(handlers.ArchiveMessageHandler(db)))
|
||||
mux.HandleFunc("/account/messages/archived", middleware.Protected(handlers.ArchivedMessagesHandler(db)))
|
||||
mux.HandleFunc("/account/messages/restore", middleware.Protected(handlers.RestoreMessageHandler(db)))
|
||||
mux.HandleFunc("/account/messages/send", middleware.Protected(handlers.SendMessageHandler(db)))
|
||||
mux.HandleFunc("/account/notifications", middleware.Protected(handlers.NotificationsHandler(db)))
|
||||
mux.HandleFunc("/account/notifications/read", middleware.Protected(handlers.MarkNotificationReadHandler(db)))
|
||||
}
|
||||
27
internal/http/routes/adminroutes.go
Normal file
27
internal/http/routes/adminroutes.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"net/http"
|
||||
|
||||
admin "synlotto-website/handlers/admin"
|
||||
"synlotto-website/middleware"
|
||||
)
|
||||
|
||||
func SetupAdminRoutes(mux *http.ServeMux, db *sql.DB) {
|
||||
mux.HandleFunc("/admin/access", middleware.Protected(admin.AdminAccessLogHandler(db)))
|
||||
mux.HandleFunc("/admin/audit", middleware.Protected(admin.AuditLogHandler(db)))
|
||||
mux.HandleFunc("/admin/dashboard", middleware.Protected(admin.AdminDashboardHandler(db)))
|
||||
mux.HandleFunc("/admin/triggers", middleware.Protected(admin.AdminTriggersHandler(db)))
|
||||
|
||||
// Draw management
|
||||
mux.HandleFunc("/admin/draws", middleware.Protected(admin.ListDrawsHandler(db)))
|
||||
// mux.HandleFunc("/admin/draws/new", middleware.AdminOnly(db, admin.RenderNewDrawForm(db)))
|
||||
// mux.HandleFunc("/admin/draws/submit", middleware.AdminOnly(db, admin.CreateDrawHandler(db)))
|
||||
mux.HandleFunc("/admin/draws/modify", middleware.Protected(admin.ModifyDrawHandler(db)))
|
||||
mux.HandleFunc("/admin/draws/delete", middleware.Protected(admin.DeleteDrawHandler(db)))
|
||||
|
||||
// Prize management
|
||||
mux.HandleFunc("/admin/draws/prizes/add", middleware.Protected(admin.AddPrizesHandler(db)))
|
||||
mux.HandleFunc("/admin/draws/prizes/modify", middleware.Protected(admin.ModifyPrizesHandler(db)))
|
||||
}
|
||||
12
internal/http/routes/resultroutes.go
Normal file
12
internal/http/routes/resultroutes.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"net/http"
|
||||
|
||||
"synlotto-website/handlers"
|
||||
)
|
||||
|
||||
func SetupResultRoutes(mux *http.ServeMux, db *sql.DB) {
|
||||
mux.HandleFunc("/results/thunderball", handlers.ResultsThunderball(db))
|
||||
}
|
||||
13
internal/http/routes/statisticroutes.go
Normal file
13
internal/http/routes/statisticroutes.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"net/http"
|
||||
|
||||
handlers "synlotto-website/handlers/statistics"
|
||||
"synlotto-website/middleware"
|
||||
)
|
||||
|
||||
func SetupStatisticsRoutes(mux *http.ServeMux, db *sql.DB) {
|
||||
mux.HandleFunc("/statistics/thunderball", middleware.Auth(true)(handlers.StatisticsThunderball(db)))
|
||||
}
|
||||
25
internal/http/routes/syndicateroutes.go
Normal file
25
internal/http/routes/syndicateroutes.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"net/http"
|
||||
|
||||
lotterySyndicateHandlers "synlotto-website/handlers/lottery/syndicate"
|
||||
|
||||
"synlotto-website/middleware"
|
||||
)
|
||||
|
||||
func SetupSyndicateRoutes(mux *http.ServeMux, db *sql.DB) {
|
||||
mux.HandleFunc("/syndicate", middleware.Auth(true)(lotterySyndicateHandlers.ListSyndicatesHandler(db)))
|
||||
mux.HandleFunc("/syndicate/create", middleware.Auth(true)(lotterySyndicateHandlers.CreateSyndicateHandler(db)))
|
||||
mux.HandleFunc("/syndicate/view", middleware.Auth(true)(lotterySyndicateHandlers.ViewSyndicateHandler(db)))
|
||||
mux.HandleFunc("/syndicate/tickets", middleware.Auth(true)(lotterySyndicateHandlers.SyndicateTicketsHandler(db)))
|
||||
mux.HandleFunc("/syndicate/tickets/new", middleware.Auth(true)(lotterySyndicateHandlers.SyndicateLogTicketHandler(db)))
|
||||
mux.HandleFunc("/syndicate/invites", middleware.Auth(true)(lotterySyndicateHandlers.ViewInvitesHandler(db)))
|
||||
mux.HandleFunc("/syndicate/invites/accept", middleware.Auth(true)(lotterySyndicateHandlers.AcceptInviteHandler(db)))
|
||||
mux.HandleFunc("/syndicate/invites/decline", middleware.Auth(true)(lotterySyndicateHandlers.DeclineInviteHandler(db)))
|
||||
mux.HandleFunc("/syndicate/invite/token", middleware.Auth(true)(lotterySyndicateHandlers.GenerateInviteLinkHandler(db)))
|
||||
mux.HandleFunc("/syndicate/invite/tokens", middleware.Auth(true)(lotterySyndicateHandlers.ManageInviteTokensHandler(db)))
|
||||
mux.HandleFunc("/syndicate/join", middleware.Auth(true)(lotterySyndicateHandlers.JoinSyndicateWithTokenHandler(db)))
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user