chore: fix some validation issues

This commit is contained in:
2026-04-29 15:23:13 +02:00
parent 6669fda371
commit da3dee9ae7
5 changed files with 47 additions and 27 deletions
+1 -1
View File
@@ -26,7 +26,7 @@ func Kickoff(logger *slog.Logger, env bootstrap.Environment, db *gorm.DB) {
if env.Authentication { if env.Authentication {
slog.Debug("injecting authentication middleware") // only log when actually doign the thing it logs to do slog.Debug("injecting authentication middleware") // only log when actually doign the thing it logs to do
r.Use(middleware.AuthMiddleware()) r.Use(middleware.AuthMiddleware(db))
} }
api := r.Group("/api") api := r.Group("/api")
+5 -21
View File
@@ -1,7 +1,6 @@
package assets package assets
import ( import (
"fmt"
"net/http" "net/http"
"time" "time"
@@ -50,27 +49,12 @@ func FileDownloadResponse(c *gin.Context, fp string) {
c.File(fp) c.File(fp)
} }
func BasicResponse(c *gin.Context, data ...any) { func BasicResponse(c *gin.Context, data any) {
fmt.Println(len(data))
switch len(data) {
case 0:
// empty slice so just an ok message
c.JSON(http.StatusOK, ResponseObject{
Msg: OkMes,
})
// single object in our slice (even if the object itself is a slice) // single object in our slice (even if the object itself is a slice)
case 1: c.JSON(http.StatusOK, ResponseObject{
c.JSON(http.StatusOK, ResponseObject{ Msg: OkMes,
Msg: OkMes, Data: data,
Data: data[0], })
})
// multiple objects inside our slice
default:
c.JSON(http.StatusOK, ResponseObject{
Msg: OkMes,
Data: data,
})
}
} }
func CreationResponse(c *gin.Context, data any) { func CreationResponse(c *gin.Context, data any) {
+23 -2
View File
@@ -4,10 +4,13 @@ import (
"log/slog" "log/slog"
"net/http" "net/http"
"orbits-server/internal/server/api/assets" "orbits-server/internal/server/api/assets"
"orbits-server/internal/server/service"
"orbits-server/internal/shared/security"
"strings" "strings"
"time" "time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"gorm.io/gorm"
) )
func SlogMiddleware(logger *slog.Logger) gin.HandlerFunc { func SlogMiddleware(logger *slog.Logger) gin.HandlerFunc {
@@ -38,7 +41,9 @@ func SlogMiddleware(logger *slog.Logger) gin.HandlerFunc {
} }
} }
func AuthMiddleware() gin.HandlerFunc { func AuthMiddleware(db *gorm.DB) gin.HandlerFunc {
keyService := service.NewKeyService(db)
return func(c *gin.Context) { return func(c *gin.Context) {
authorizationHeader := c.GetHeader("Authorization") authorizationHeader := c.GetHeader("Authorization")
if len(authorizationHeader) == 0 { if len(authorizationHeader) == 0 {
@@ -58,6 +63,22 @@ func AuthMiddleware() gin.HandlerFunc {
return return
} }
//givenKey := headerParts[1] candidateKey := headerParts[1]
storedKeys, err := keyService.ListValidKeyHashes()
if err != nil {
slog.Error("failed to retrieve key hashes", "error", err)
assets.InternalErrorResponse(c)
}
for _, key := range storedKeys {
if match := security.CompareKey(key, candidateKey); match {
c.Next()
return
}
}
c.AbortWithStatusJSON(http.StatusUnauthorized, assets.ResponseObject{
Msg: "invalid key",
})
} }
} }
+14
View File
@@ -23,6 +23,20 @@ func NewKeyService(db *gorm.DB) *KeyService {
} }
} }
func (s *KeyService) ListValidKeyHashes() ([]string, error) {
keyRecords, err := database.ListKeys(s.db)
if err != nil {
return nil, err
}
hashList := make([]string, 0, len(keyRecords))
for _, k := range keyRecords {
hashList = append(hashList, k.KeyHash)
}
return hashList, nil
}
func (s *KeyService) Create(name string, expiresAt time.Time) (assets.KeyResponse, error) { func (s *KeyService) Create(name string, expiresAt time.Time) (assets.KeyResponse, error) {
keyContent := security.GenerateChars(accessKeyLen) keyContent := security.GenerateChars(accessKeyLen)
+4 -3
View File
@@ -30,6 +30,7 @@ func HashFileReader(r io.Reader) (string, error) {
return base64.StdEncoding.EncodeToString(h.Sum(nil)), nil return base64.StdEncoding.EncodeToString(h.Sum(nil)), nil
} }
// we use argon2 for key hashing - since it won the key encryption "war"
func HashKey(key string) (string, error) { func HashKey(key string) (string, error) {
salt := make([]byte, argonSaltLen) salt := make([]byte, argonSaltLen)
rand.Read(salt) rand.Read(salt)
@@ -46,8 +47,8 @@ func HashKey(key string) (string, error) {
return encoded, nil return encoded, nil
} }
func CompareKey(key, candidate string) bool { func CompareKey(storedKey, candidate string) bool {
parts := strings.Split(candidate, ":") parts := strings.Split(storedKey, ":")
if len(parts) != 3 { if len(parts) != 3 {
return false return false
} }
@@ -65,7 +66,7 @@ func CompareKey(key, candidate string) bool {
return false return false
} }
actual := argon2.IDKey([]byte(key), salt, argonTime, argonMemory, argonThreads, argonKeyLen) actual := argon2.IDKey([]byte(candidate), salt, argonTime, argonMemory, argonThreads, argonKeyLen)
return subtle.ConstantTimeCompare(actual, expected) == 1 return subtle.ConstantTimeCompare(actual, expected) == 1
} }