Get AI to fix vunerabilities in site
Some checks failed
Deploy with Docker Compose / deploy (push) Has been cancelled

This commit is contained in:
2026-03-09 14:12:29 +00:00
parent 85a2325683
commit 8e50537333
9 changed files with 136 additions and 41 deletions

View File

@@ -1,7 +1,6 @@
package handlers
import (
"fmt"
"net/http"
"adam-french.co.uk/backend/models"
@@ -68,10 +67,9 @@ func (store *Store) RefreshToken(ctx *gin.Context) {
claims, err := store.Auth.VerifyJWT(refreshToken)
if err != nil {
ctx.JSON(http.StatusUnauthorized, err.Error())
return
}
fmt.Printf("claims: %v\n", claims)
userIDF, ok := (*claims)["id"].(float64)
if !ok {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "invalid token claims"})
@@ -93,6 +91,7 @@ func (store *Store) RefreshToken(ctx *gin.Context) {
return
}
ctx.SetSameSite(http.SameSiteLaxMode)
ctx.SetCookie(
"access_token",
tokens.AccessToken,
@@ -122,12 +121,12 @@ func (store *Store) Login(ctx *gin.Context) {
user := models.User{}
if err := store.DB.Where("username = ?", input.Username).First(&user).Error; err != nil {
ctx.JSON(http.StatusNotFound, err.Error())
ctx.JSON(http.StatusUnauthorized, gin.H{"error": "invalid credentials"})
return
}
if err := bcrypt.CompareHashAndPassword(user.Password, []byte(input.Password)); err != nil {
ctx.JSON(http.StatusUnauthorized, err.Error())
ctx.JSON(http.StatusUnauthorized, gin.H{"error": "invalid credentials"})
return
}
@@ -137,6 +136,7 @@ func (store *Store) Login(ctx *gin.Context) {
return
}
ctx.SetSameSite(http.SameSiteLaxMode)
ctx.SetCookie(
"access_token",
tokens.AccessToken,
@@ -164,6 +164,7 @@ func (store *Store) Logout(ctx *gin.Context) {
}
func removeCookies(ctx *gin.Context) {
ctx.SetSameSite(http.SameSiteLaxMode)
ctx.SetCookie(
"access_token",
"",

View File

@@ -17,6 +17,12 @@ var allowedExtensions = map[string]bool{
".pdf": true, ".txt": true,
}
var extensionToMIMEPrefix = map[string]string{
".jpg": "image/", ".jpeg": "image/", ".png": "image/png", ".gif": "image/gif", ".webp": "image/webp",
".mp4": "video/", ".webm": "video/webm", ".mp3": "audio/", ".ogg": "audio/",
".pdf": "application/pdf", ".txt": "text/",
}
func (store *Store) UploadMessageFile(ctx *gin.Context) {
file, err := ctx.FormFile("file")
if err != nil {
@@ -36,6 +42,23 @@ func (store *Store) UploadMessageFile(ctx *gin.Context) {
return
}
// Validate actual content type matches extension
f, err := file.Open()
if err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "failed to read file"})
return
}
buf := make([]byte, 512)
n, _ := f.Read(buf)
f.Close()
detectedType := http.DetectContentType(buf[:n])
expectedPrefix, ok := extensionToMIMEPrefix[ext]
if ok && !strings.HasPrefix(detectedType, expectedPrefix) {
ctx.JSON(http.StatusBadRequest, gin.H{"error": "file content does not match extension"})
return
}
b := make([]byte, 16)
if _, err := rand.Read(b); err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "failed to generate filename"})

View File

@@ -15,6 +15,21 @@ type UserCredentials struct {
}
func (store *Store) CreateUser(ctx *gin.Context) {
claimsVal, ok := ctx.Get("userClaims")
if !ok {
ctx.JSON(http.StatusUnauthorized, gin.H{"error": "user claims could not be found"})
return
}
claims, ok := claimsVal.(*jwt.MapClaims)
if !ok {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "invalid claims"})
return
}
if !(*claims)["admin"].(bool) {
ctx.JSON(http.StatusForbidden, gin.H{"error": "admin access required"})
return
}
var input UserCredentials
if err := ctx.ShouldBindBodyWithJSON(&input); err != nil {
ctx.JSON(http.StatusBadRequest, err.Error())
@@ -31,32 +46,9 @@ func (store *Store) CreateUser(ctx *gin.Context) {
tx := store.DB.Create(&user)
if tx.Error != nil {
ctx.JSON(http.StatusInternalServerError, tx.Error.Error())
}
// Generate JWT token
tokens, err := store.Auth.GenerateJWT(&user)
if err != nil {
ctx.JSON(http.StatusInternalServerError, err.Error())
return
}
ctx.SetCookie(
"access_token",
tokens.AccessToken,
int(store.Auth.Config.AccessTokenLifetime.Seconds()),
store.Auth.Config.Endpoint,
store.Auth.Config.Domain,
true, true,
)
ctx.SetCookie(
"refresh_token",
tokens.RefreshToken,
int(store.Auth.Config.RefreshTokenLifetime.Seconds()),
store.Auth.Config.Endpoint,
store.Auth.Config.Domain,
true, true,
)
ctx.JSON(http.StatusOK, user)
}
@@ -141,6 +133,7 @@ func (store *Store) DeleteUser(ctx *gin.Context) {
return
}
ctx.SetSameSite(http.SameSiteLaxMode)
ctx.SetCookie(
"access_token",
"",