66 lines
1.8 KiB
Go
66 lines
1.8 KiB
Go
package middleware
|
|
|
|
import (
|
|
"git.itzana.me/strafesnet/go-grpc/dev"
|
|
"github.com/gin-gonic/gin"
|
|
log "github.com/sirupsen/logrus"
|
|
"google.golang.org/grpc"
|
|
"net/http"
|
|
"strconv"
|
|
)
|
|
|
|
const (
|
|
HeaderAPIKey = "X-API-Key"
|
|
HeaderRateLimitBurst = "X-Rate-Limit-Burst"
|
|
HeaderRateLimitDaily = "X-Rate-Limit-Daily"
|
|
HeaderRateLimitMonthly = "X-Rate-Limit-Monthly"
|
|
|
|
// Error messages
|
|
ErrMsgAPIKeyRequired = "API key is required"
|
|
ErrMsgInternalServer = "Internal server error"
|
|
)
|
|
|
|
// ValidateRequest returns a middleware that validates API requests against the dev service
|
|
func ValidateRequest(service, permission string, conn *grpc.ClientConn) gin.HandlerFunc {
|
|
return func(ctx *gin.Context) {
|
|
// Get API key from the request header
|
|
apiKey := ctx.GetHeader(HeaderAPIKey)
|
|
if apiKey == "" {
|
|
ctx.JSON(http.StatusUnauthorized, gin.H{"error": ErrMsgAPIKeyRequired})
|
|
ctx.Abort()
|
|
return
|
|
}
|
|
|
|
// Create client and validate the API key
|
|
resp, err := dev.NewDevServiceClient(conn).Validate(ctx, &dev.APIValidationRequest{
|
|
Service: service,
|
|
Permission: permission,
|
|
Key: apiKey,
|
|
IP: ctx.ClientIP(),
|
|
Resource: ctx.Request.URL.String(),
|
|
})
|
|
|
|
if err != nil {
|
|
ctx.JSON(http.StatusInternalServerError, gin.H{"error": ErrMsgInternalServer})
|
|
ctx.Abort()
|
|
log.WithError(err).Error(
|
|
"failed to validate API key",
|
|
)
|
|
return
|
|
}
|
|
|
|
// Set the remaining rate limits in the response headers
|
|
ctx.Header(HeaderRateLimitBurst, strconv.FormatUint(resp.RemainingBurst, 10))
|
|
ctx.Header(HeaderRateLimitDaily, strconv.FormatUint(resp.RemainingDaily, 10))
|
|
ctx.Header(HeaderRateLimitMonthly, strconv.FormatUint(resp.RemainingMonthly, 10))
|
|
|
|
if !resp.Valid {
|
|
ctx.JSON(int(resp.StatusCode), gin.H{"error": resp.ErrorMessage})
|
|
ctx.Abort()
|
|
return
|
|
}
|
|
|
|
ctx.Next()
|
|
}
|
|
}
|