diff --git a/internal/api/api.go b/internal/api/api.go deleted file mode 100644 index a4294e7..0000000 --- a/internal/api/api.go +++ /dev/null @@ -1,34 +0,0 @@ -package api - -import ( - "database/sql" - "errors" - "os" - - "github.com/gofiber/fiber/v2" - "github.com/gofiber/fiber/v2/middleware/keyauth" -) - -func Setup(app *fiber.App, db *sql.DB) 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), - })) - - apiHandler := NewHandler(db) - - v1 := api.Group("/v1") - v1.Post("/users", apiHandler.createUser) - v1.Post("/users/:userID/feeds", apiHandler.createFeed) - - return nil -} diff --git a/internal/api/auth.go b/internal/api/auth.go deleted file mode 100644 index b8221f8..0000000 --- a/internal/api/auth.go +++ /dev/null @@ -1,56 +0,0 @@ -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/feed.go b/internal/api/feed.go deleted file mode 100644 index 4e11628..0000000 --- a/internal/api/feed.go +++ /dev/null @@ -1,58 +0,0 @@ -package api - -import ( - "fmt" - "freed/internal/model" - - "github.com/gofiber/fiber/v2" - "github.com/gofiber/fiber/v2/log" - "github.com/mattn/go-sqlite3" -) - -func (h *Handler) createFeed(c *fiber.Ctx) error { - userID := c.Params("userID") - feed := new(model.Feed) - - if parseErr := c.BodyParser(feed); parseErr != nil { - log.Warn(parseErr) - return defaultUserError - } - - validationErr := ValidateModel(feed) - - if validationErr != nil { - return fiber.NewError(fiber.ErrInternalServerError.Code, validationErr.Message) - } - - userExists := h.userExists(userID) - fmt.Printf("exists? %v", userExists) - - if h.userExists(userID) == false { - return fiber.NewError(fiber.ErrInternalServerError.Code, "No existing user found, check user id path param.") - } - - // TODO: Get name from feed - // TODO: Get type from feed - // TODO: Either schedule or request items from feed immediately - - sqlResult, insertErr := h.db.Exec("INSERT INTO feed (userId, name, url) VALUES (?, ?, ?)", userID, feed.Url, feed.Url) - - if sqliteErr, ok := insertErr.(sqlite3.Error); ok { - log.Warn(insertErr) - - if sqliteErr.ExtendedCode == sqlite3.ErrConstraintUnique { - return fiber.NewError(fiber.StatusBadRequest, "Feed with url already exists") - } - - return fiber.NewError(fiber.ErrInternalServerError.Code, "Could not create feed") - } - - feedID, idErr := sqlResult.LastInsertId() - - if idErr != nil { - return fiber.NewError(fiber.ErrInternalServerError.Code, "Created feed, but could not retrieve its ID, check database.") - } - - c.SendStatus(201) - return c.JSON(&fiber.Map{"id": feedID}) -} diff --git a/internal/api/handler.go b/internal/api/handler.go deleted file mode 100644 index 2b75080..0000000 --- a/internal/api/handler.go +++ /dev/null @@ -1,13 +0,0 @@ -package api - -import ( - "database/sql" -) - -type Handler struct { - db *sql.DB -} - -func NewHandler(db *sql.DB) *Handler { - return &Handler{db: db} -} diff --git a/internal/api/user.go b/internal/api/user.go deleted file mode 100644 index d8dfd5d..0000000 --- a/internal/api/user.go +++ /dev/null @@ -1,80 +0,0 @@ -package api - -import ( - "database/sql" - "errors" - "fmt" - "freed/internal/model" - - "github.com/gofiber/fiber/v2" - "github.com/gofiber/fiber/v2/log" - "github.com/google/uuid" - "github.com/mattn/go-sqlite3" -) - -var defaultUserError = fiber.NewError(fiber.ErrInternalServerError.Code, "Could not create user") - -func (h *Handler) createUser(c *fiber.Ctx) error { - user := new(model.User) - - userId, idErr := uuid.NewRandom() - - if idErr != nil { - log.Warn(idErr) - return defaultUserError - } - - user.ID = userId.String() - - if parseErr := c.BodyParser(user); parseErr != nil { - log.Warn(parseErr) - return defaultUserError - } - - validationErr := ValidateModel(user) - - if validationErr != nil { - return fiber.NewError(fiber.ErrInternalServerError.Code, validationErr.Message) - } - - _, insertErr := h.db.Exec("INSERT INTO user (id, first_name, email) VALUES (?, ?, ?)", user.ID, user.FirstName, user.Email) - - if sqliteErr, ok := insertErr.(sqlite3.Error); ok { - log.Warn(insertErr) - - if sqliteErr.ExtendedCode == sqlite3.ErrConstraintUnique { - return fiber.NewError(fiber.StatusBadRequest, "User with email already exists") - } - - return defaultUserError - } - - c.SendStatus(201) - return c.JSON(&fiber.Map{"userId": userId}) -} - -func (h *Handler) getUserByID(id string) (*model.User, error) { - var user *model.User - - if err := h.db.QueryRow("SELECT * FROM user WHERE id = ?", id).Scan(&user); err != nil { - if err == sql.ErrNoRows { - notFoundErrMessage := fmt.Sprintf("No user found with ID: %s", id) - return nil, errors.New(notFoundErrMessage) - } - - unexpectedErrMessage := fmt.Sprintf("Unexpected error occured, could not get user with ID: %s", id) - return nil, errors.New(unexpectedErrMessage) - } - - return user, nil -} - -func (h *Handler) userExists(id string) bool { - var userID string - - if err := h.db.QueryRow("SELECT id FROM user WHERE id = ?", id).Scan(&userID); err != nil { - return false - } - - return true -} diff --git a/internal/api/validator.go b/internal/api/validator.go deleted file mode 100644 index 283fefc..0000000 --- a/internal/api/validator.go +++ /dev/null @@ -1,40 +0,0 @@ -package api - -import ( - "fmt" - "freed/internal/model" - "strings" - - "github.com/go-playground/validator/v10" - "github.com/gofiber/fiber/v2" -) - -type ModelConstraint interface { - *model.User | *model.Feed -} - -type ValidationError struct { - FailedField string - Tag string - Value string -} - -func ValidateModel[T ModelConstraint](s T) *fiber.Error { - var errorMessages []string - validate := validator.New() - err := validate.Struct(s) - - fmt.Printf("%#v", err) - - if err == nil { - return nil - } - - for _, err := range err.(validator.ValidationErrors) { - err := fmt.Sprintf("Field %s is invalid, reason: %s", err.StructNamespace(), err.Tag()) - - errorMessages = append(errorMessages, err) - } - - return fiber.NewError(fiber.StatusBadRequest, strings.Join(errorMessages, ". ")) -}