diff --git a/internal/api/api.go b/internal/api/api.go new file mode 100644 index 0000000..df85c97 --- /dev/null +++ b/internal/api/api.go @@ -0,0 +1,31 @@ +package api + +import ( + "errors" + "os" + + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/keyauth" +) + +func Setup(app *fiber.App) error { + apiKey := os.Getenv("API_KEY") + + if apiKey == "" { + return errors.New("Could not read API_KEY from ENV file.") + } + + api := app.Group("/api", keyauth.New(keyauth.Config{ + SuccessHandler: successHandler, + ErrorHandler: errHandler, + KeyLookup: "header:x-api-key", + ContextKey: "apiKey", + Validator: apiKeyValidator(apiKey), + })) + + v1 := api.Group("/v1") + + v1.Get("/users", FetchAllUsersHandler) + + return nil +} diff --git a/internal/api/auth.go b/internal/api/auth.go new file mode 100644 index 0000000..b8221f8 --- /dev/null +++ b/internal/api/auth.go @@ -0,0 +1,56 @@ +package api + +import ( + "crypto/sha256" + "crypto/subtle" + "regexp" + "strings" + + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/keyauth" +) + +var ( + apiKey = "willbechanged" + protectedURLs = []*regexp.Regexp{ + regexp.MustCompile("^/api$"), + } + errForbidden = &fiber.Error{ + Code: 403, + Message: "API Key is missing or invalid", + } +) + +func apiKeyValidator(apiKey string) func(*fiber.Ctx, string) (bool, error) { + return func(_ *fiber.Ctx, key string) (bool, error) { + hashedAPIKey := sha256.Sum256([]byte(apiKey)) + hashedKey := sha256.Sum256([]byte(key)) + + if subtle.ConstantTimeCompare(hashedAPIKey[:], hashedKey[:]) == 1 { + return true, nil + } + + return false, keyauth.ErrMissingOrMalformedAPIKey + } +} + +func protectedRoutesFilter(ctx *fiber.Ctx) bool { + originalURL := strings.ToLower(ctx.OriginalURL()) + + for _, pattern := range protectedURLs { + if pattern.MatchString(originalURL) { + return false + } + } + return true +} + +func successHandler(ctx *fiber.Ctx) error { + return ctx.Next() +} + +func errHandler(ctx *fiber.Ctx, err error) error { + ctx.Status(fiber.StatusForbidden) + + return ctx.JSON(errForbidden) +} diff --git a/internal/api/users.go b/internal/api/users.go new file mode 100644 index 0000000..cc3e4df --- /dev/null +++ b/internal/api/users.go @@ -0,0 +1,9 @@ +package api + +import ( + "github.com/gofiber/fiber/v2" +) + +func FetchAllUsersHandler(ctx *fiber.Ctx) error { + return ctx.JSON(&fiber.Map{"users": "none"}) +}