Merge branch 'dev-ars' into dev
All checks were successful
Build and Deploy Go App / build (push) Successful in 5m36s
Build and Deploy Go App / deploy (push) Successful in 37s

This commit is contained in:
Iron_Felix 2025-12-04 06:13:46 +03:00
commit 31e55c0539
12 changed files with 233 additions and 5 deletions

View file

@ -11,6 +11,7 @@ import (
oapi "nyanimedb/api"
handlers "nyanimedb/modules/backend/handlers"
middleware "nyanimedb/modules/backend/middlewares"
"nyanimedb/modules/backend/rmq"
"github.com/gin-contrib/cors"
@ -45,6 +46,8 @@ func main() {
r := gin.Default()
r.Use(middleware.CSRFMiddleware())
// jwt middle will be here
queries := sqlc.New(pool)
// === RabbitMQ setup ===
@ -63,7 +66,6 @@ func main() {
rpcClient := rmq.NewRPCClient(rmqConn, 30*time.Second)
server := handlers.NewServer(queries, publisher, rpcClient)
// r.LoadHTMLGlob("templates/*")
r.Use(cors.New(cors.Config{
AllowOrigins: []string{"*"}, // allow all origins, change to specific domains in production

View file

@ -0,0 +1,70 @@
package middleware
import (
"crypto/subtle"
"net/http"
"github.com/gin-gonic/gin"
)
// CSRFMiddleware для Gin
func CSRFMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// Пропускаем безопасные методы
if !isStateChangingMethod(c.Request.Method) {
c.Next()
return
}
// 1. Получаем токен из заголовка
headerToken := c.GetHeader("X-XSRF-TOKEN")
if headerToken == "" {
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{
"error": "missing X-XSRF-TOKEN header",
})
return
}
// 2. Получаем токен из cookie
cookie, err := c.Cookie("xsrf_token")
if err != nil {
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{
"error": "missing xsrf_token cookie",
})
return
}
// 3. Безопасное сравнение
if subtle.ConstantTimeCompare([]byte(headerToken), []byte(cookie)) != 1 {
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{
"error": "CSRF token mismatch",
})
return
}
// 4. Опционально: сохраняем токен в контексте
c.Set("csrf_token", headerToken)
c.Next()
}
}
func isStateChangingMethod(method string) bool {
switch method {
case http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete:
return true
default:
return false
}
}
// CSRFTokenFromGin извлекает токен из Gin context
func CSRFTokenFromGin(c *gin.Context) (string, bool) {
token, exists := c.Get("xsrf_token")
if !exists {
return "", false
}
if s, ok := token.(string); ok {
return s, true
}
return "", false
}