Stack of changes to get gin, scs, nosurf running.

This commit is contained in:
2025-10-28 11:56:42 +00:00
parent 07117ba35e
commit 86be6479f1
65 changed files with 1890 additions and 1503 deletions

View File

@@ -1,57 +1,84 @@
package storage
import (
"context"
"database/sql"
"log"
"net/http"
"time"
securityHelpers "synlotto-website/internal/helpers/security"
templateHelpers "synlotto-website/internal/helpers/template"
"synlotto-website/internal/logging"
"synlotto-website/internal/http/middleware"
"synlotto-website/internal/logging"
"synlotto-website/internal/platform/bootstrap"
"github.com/gin-gonic/gin"
)
func AdminOnly(db *sql.DB, next http.HandlerFunc) http.HandlerFunc {
return middleware.Auth(true)(func(w http.ResponseWriter, r *http.Request) {
userID, ok := securityHelpers.GetCurrentUserID(r)
if !ok || !securityHelpers.IsAdmin(db, userID) {
log.Printf("⛔️ Unauthorized admin attempt: user_id=%v, IP=%s, Path=%s", userID, r.RemoteAddr, r.URL.Path)
templateHelpers.RenderError(w, r, http.StatusForbidden)
const insertRegistrationSQL = `
INSERT INTO audit_registration
(user_id, username, email, ip, user_agent, timestamp)
VALUES (?, ?, ?, ?, ?, ?)
`
func AdminOnly() gin.HandlerFunc {
return func(c *gin.Context) {
app := c.MustGet("app").(*bootstrap.App)
sm := app.SessionManager
ctx := c.Request.Context()
// Require logged in (assumes RequireAuth already ran; this is a safety net)
v := sm.Get(ctx, "user_id")
var uid int64
switch t := v.(type) {
case int64:
uid = t
case int:
uid = int64(t)
default:
c.Redirect(http.StatusSeeOther, "/account/login")
c.Abort()
return
}
ip := r.RemoteAddr
ua := r.UserAgent()
path := r.URL.Path
_, err := db.Exec(`
INSERT INTO admin_access_log (user_id, path, ip, user_agent)
VALUES (?, ?, ?, ?)`,
userID, path, ip, ua,
)
if err != nil {
log.Printf("⚠️ Failed to log admin access: %v", err)
// Check admin
if !securityHelpers.IsAdmin(app.DB, int(uid)) {
// Optional: log access attempt here or in a helper
c.String(http.StatusForbidden, "Forbidden")
c.Abort()
return
}
log.Printf("🛡️ Admin access: user_id=%d IP=%s Path=%s", userID, ip, path)
// Optionally record access (moved here from storage)
_, _ = app.DB.Exec(`
INSERT INTO admin_access_log (user_id, path, ip, user_agent, accessed_at)
VALUES ($1, $2, $3, $4, $5)
`, uid, c.Request.URL.Path, c.ClientIP(), c.Request.UserAgent(), time.Now().UTC())
next(w, r)
})
c.Next()
}
}
// Todo has to add in - db *sql.DB to make this work should this not be an import as all functions use it, more importantly no functions in storage just sql?
func LogLoginAttempt(db *sql.DB, r *http.Request, username string, success bool) {
ip := r.RemoteAddr
userAgent := r.UserAgent()
// Handler Call - auditlogStorage.LogLoginAttempt(db, r.RemoteAddr, r.UserAgent(), username, ok)
func LogLoginAttempt(db *sql.DB, rIP, rUA, username string, success bool) {
_, err := db.Exec(
`INSERT INTO audit_login (username, success, ip, user_agent, timestamp)
VALUES (?, ?, ?, ?, ?)`,
username, success, ip, userAgent, time.Now().UTC(),
VALUES ($1, $2, $3, $4, $5)`,
username, success, rIP, rUA, time.Now().UTC(),
)
if err != nil {
logging.Info("❌ Failed to log login:", err)
}
}
func LogSignup(db *sql.DB, userID int64, username, email, ip, userAgent string) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
_, err := db.ExecContext(ctx, insertRegistrationSQL,
userID, username, email, ip, userAgent, time.Now().UTC(),
)
if err != nil {
logging.Info("❌ Failed to log registration: %v", err)
}
}