add loger, access log and bans/whitelist

This commit is contained in:
nahakubuilde
2025-08-26 07:46:01 +01:00
parent e21a0b5b10
commit 4cafd9848f
10 changed files with 1163 additions and 60 deletions

View File

@@ -2,8 +2,10 @@ package server
import (
"crypto/rand"
"database/sql"
"encoding/base64"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
@@ -105,3 +107,84 @@ func (s *Server) RequireAdmin() gin.HandlerFunc {
c.Next()
}
}
// AccessLogger logs all requests to the access_logs table after handling.
func (s *Server) AccessLogger() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
c.Next()
duration := time.Since(start)
status := c.Writer.Status()
ip := c.ClientIP()
method := c.Request.Method
path := c.FullPath()
if path == "" {
path = c.Request.URL.Path
}
ua := c.Request.UserAgent()
var userID interface{}
if uidAny, ok := c.Get("user_id"); ok {
if v, ok := uidAny.(int64); ok {
userID = v
}
}
_, _ = s.auth.DB.Exec(
`INSERT INTO access_logs (user_id, ip, method, path, status, duration_ms, user_agent) VALUES (?,?,?,?,?,?,?)`,
userID, ip, method, path, status, duration.Milliseconds(), ua,
)
}
}
// IPBanEnforce blocks banned IPs (unless whitelisted).
func (s *Server) IPBanEnforce() gin.HandlerFunc {
return func(c *gin.Context) {
ip := c.ClientIP()
var whitelisted, permanent int
var until sql.NullTime
err := s.auth.DB.QueryRow(`SELECT whitelisted, permanent, until FROM ip_bans WHERE ip = ?`, ip).Scan(&whitelisted, &permanent, &until)
if err != nil {
if err == sql.ErrNoRows {
c.Next()
return
}
s.logError(c, "ip_ban_lookup_failed: "+err.Error(), "")
c.Next()
return
}
if whitelisted == 1 {
c.Next()
return
}
banned := false
if permanent == 1 {
banned = true
} else if until.Valid && until.Time.After(time.Now()) {
banned = true
}
if banned {
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "access denied"})
return
}
c.Next()
}
}
// logError stores error logs (best-effort).
func (s *Server) logError(c *gin.Context, message, stack string) {
var userID interface{}
if uidAny, ok := c.Get("user_id"); ok {
if v, ok := uidAny.(int64); ok {
userID = v
}
}
ip := c.ClientIP()
path := c.Request.URL.Path
_, _ = s.auth.DB.Exec(`INSERT INTO error_logs (user_id, ip, path, message, stack) VALUES (?,?,?,?,?)`, userID, ip, path, message, stack)
}