85 lines
2.6 KiB
Go
85 lines
2.6 KiB
Go
package middleware
|
|
|
|
import (
|
|
"github.com/gofiber/fiber/v2"
|
|
|
|
"wucher/internal/service"
|
|
sharedconst "wucher/internal/shared/const"
|
|
"wucher/internal/shared/pkg/apperrorsx"
|
|
)
|
|
|
|
const permissionPinVerificationHeader = "X-PIN-Verification-Token"
|
|
|
|
func PermissionRequired(svc *service.AuthService, permissionKey string) fiber.Handler {
|
|
return permissionRequired(svc, permissionKey, true)
|
|
}
|
|
|
|
func PermissionRequiredReusable(svc *service.AuthService, permissionKey string) fiber.Handler {
|
|
return permissionRequired(svc, permissionKey, false)
|
|
}
|
|
|
|
func permissionRequired(svc *service.AuthService, permissionKey string, consume bool) fiber.Handler {
|
|
return func(c *fiber.Ctx) error {
|
|
if svc == nil {
|
|
e := apperrorsx.New(apperrorsx.ErrUserUnauthorized)
|
|
e.Message = "auth service not configured"
|
|
return apperrorsx.Write(c, e)
|
|
}
|
|
|
|
raw := c.Locals("user_id")
|
|
userID, ok := raw.([]byte)
|
|
if !ok || len(userID) == 0 {
|
|
e := apperrorsx.New(apperrorsx.ErrUserUnauthorized)
|
|
e.Message = "missing auth context"
|
|
return apperrorsx.Write(c, e)
|
|
}
|
|
|
|
allowed, err := svc.HasPermission(c.UserContext(), userID, permissionKey)
|
|
if err != nil {
|
|
e := apperrorsx.New(apperrorsx.ErrForbiddenAccess)
|
|
e.Message = "failed to verify permission"
|
|
return apperrorsx.Write(c, e)
|
|
}
|
|
if !allowed {
|
|
e := apperrorsx.New(apperrorsx.ErrForbiddenAccess)
|
|
e.Message = "insufficient permission"
|
|
return apperrorsx.Write(c, e)
|
|
}
|
|
|
|
required, err := svc.PermissionRequiresPIN(c.UserContext(), permissionKey)
|
|
if err != nil {
|
|
e := apperrorsx.New(apperrorsx.ErrForbiddenAccess)
|
|
e.Message = "failed to verify PIN requirement"
|
|
return apperrorsx.Write(c, e)
|
|
}
|
|
if required {
|
|
action := sharedconst.PinActionForPermissionKey(permissionKey)
|
|
if action == "" {
|
|
action = permissionKey
|
|
}
|
|
token := c.Get(permissionPinVerificationHeader)
|
|
sessionID := ""
|
|
for _, accessToken := range service.CookieValues(c.Get(fiber.HeaderCookie), svc.AccessCookieName()) {
|
|
sid, err := svc.ParseAccessTokenSessionID(c.UserContext(), accessToken)
|
|
if err == nil {
|
|
sessionID = sid
|
|
break
|
|
}
|
|
}
|
|
if sessionID == "" {
|
|
return apperrorsx.Write(c, apperrorsx.New(apperrorsx.ErrTokenInvalid))
|
|
}
|
|
var verifyErr error
|
|
if consume {
|
|
verifyErr = svc.ConsumeSecurityPINActionTokenInSession(c.UserContext(), userID, action, token, sessionID)
|
|
} else {
|
|
verifyErr = svc.ValidateSecurityPINActionTokenInSession(c.UserContext(), userID, action, token, sessionID)
|
|
}
|
|
if verifyErr != nil {
|
|
return apperrorsx.Write(c, apperrorsx.New(apperrorsx.ErrPINVerificationRequired202))
|
|
}
|
|
}
|
|
return c.Next()
|
|
}
|
|
}
|