diff --git a/server/api/image.go b/server/api/image.go index 3f11bf4..c5fc4d5 100644 --- a/server/api/image.go +++ b/server/api/image.go @@ -12,17 +12,14 @@ import ( func handleUploadImage(c fiber.Ctx) error { uid, ok := c.Locals("uid").(uint) if !ok { - return model.NewUnAuthorizedError("Unauthorized") - } - if err := service.HavePermissionToUpload(uid); err != nil { - return err + return model.NewUnAuthorizedError("You must be logged in to upload an image") } data := c.Body() contentType := http.DetectContentType(data) if !strings.HasPrefix(contentType, "image/") { return model.NewRequestError("Invalid image format") } - id, err := service.CreateImage(data) + id, err := service.CreateImage(uid, data) if err != nil { return err } @@ -64,10 +61,7 @@ func handleDeleteImage(c fiber.Ctx) error { if !ok { return model.NewUnAuthorizedError("Unauthorized") } - if err := service.HavePermissionToUpload(uid); err != nil { - return err - } - if err := service.DeleteImage(uint(id)); err != nil { + if err := service.DeleteImage(uid, uint(id)); err != nil { return err } return c.Status(fiber.StatusOK).JSON(model.Response[any]{ diff --git a/server/api/tag.go b/server/api/tag.go index 016d85c..30747c7 100644 --- a/server/api/tag.go +++ b/server/api/tag.go @@ -12,7 +12,11 @@ func handleCreateTag(c fiber.Ctx) error { if tag == "" { return model.NewRequestError("name is required") } - t, err := service.CreateTag(tag) + uid, ok := c.Locals("uid").(uint) + if !ok { + return model.NewUnAuthorizedError("You must be logged in to create a tag") + } + t, err := service.CreateTag(uid, tag) if err != nil { return err } diff --git a/server/api/user.go b/server/api/user.go index 61d398f..17044aa 100644 --- a/server/api/user.go +++ b/server/api/user.go @@ -16,12 +16,6 @@ func handleUserRegister(c fiber.Ctx) error { if username == "" || password == "" { return model.NewRequestError("Username and password are required") } - if len(password) < 6 { - return model.NewRequestError("Password must be at least 6 characters long") - } - if len(username) < 3 { - return model.NewRequestError("Username must be at least 3 characters long") - } user, err := service.CreateUser(username, password) if err != nil { return err diff --git a/server/model/user.go b/server/model/user.go index d1b1f1a..5c5068c 100644 --- a/server/model/user.go +++ b/server/model/user.go @@ -8,7 +8,7 @@ import ( type User struct { gorm.Model - Username string + Username string `gorm:"uniqueIndex;not null"` PasswordHash []byte IsAdmin bool CanUpload bool diff --git a/server/service/image.go b/server/service/image.go index 7c451ae..35d1511 100644 --- a/server/service/image.go +++ b/server/service/image.go @@ -34,7 +34,7 @@ func init() { } if len(images) > 0 { for _, i := range images { - err := DeleteImage(i.ID) + err := deleteImage(i.ID) if err != nil { log.Errorf("Failed to delete unused image %d: %v", i.ID, err) } @@ -45,7 +45,16 @@ func init() { }() } -func CreateImage(data []byte) (uint, error) { +func CreateImage(uid uint, data []byte) (uint, error) { + canUpload, err := checkUserCanUpload(uid) + if err != nil { + log.Error("Error checking user upload permission:", err) + return 0, model.NewInternalServerError("Error checking user upload permission") + } + if !canUpload { + return 0, model.NewUnAuthorizedError("User cannot upload images") + } + if len(data) == 0 { return 0, model.NewRequestError("Image data is empty") } else if len(data) > 1024*1024*5 { @@ -112,7 +121,24 @@ func GetImage(id uint) ([]byte, error) { return data, nil } -func DeleteImage(id uint) error { +func DeleteImage(uid, id uint) error { + canUpload, err := checkUserCanUpload(uid) + if err != nil { + log.Error("Error checking user upload permission:", err) + return model.NewInternalServerError("Error checking user upload permission") + } + if !canUpload { + return model.NewUnAuthorizedError("User cannot upload images") + } + err = deleteImage(id) + if err != nil { + log.Error("Error deleting image:", err) + return model.NewInternalServerError("Error deleting image") + } + return nil +} + +func deleteImage(id uint) error { i, err := dao.GetImageByID(id) if err != nil { return err diff --git a/server/service/tag.go b/server/service/tag.go index 9409c26..77c4ce0 100644 --- a/server/service/tag.go +++ b/server/service/tag.go @@ -1,11 +1,20 @@ package service import ( + "github.com/gofiber/fiber/v3/log" "nysoure/server/dao" "nysoure/server/model" ) -func CreateTag(name string) (*model.TagView, error) { +func CreateTag(uid uint, name string) (*model.TagView, error) { + canUpload, err := checkUserCanUpload(uid) + if err != nil { + log.Error("Error checking user permissions:", err) + return nil, model.NewInternalServerError("Error checking user permissions") + } + if !canUpload { + return nil, model.NewUnAuthorizedError("User cannot create tags") + } t, err := dao.CreateTag(name) if err != nil { return nil, err diff --git a/server/service/user.go b/server/service/user.go index 225f92f..c412c52 100644 --- a/server/service/user.go +++ b/server/service/user.go @@ -18,6 +18,12 @@ const ( ) func CreateUser(username, password string) (model.UserViewWithToken, error) { + if len(username) < 3 || len(username) > 20 { + return model.UserViewWithToken{}, model.NewRequestError("Username must be between 3 and 20 characters") + } + if len(password) < 6 || len(password) > 20 { + return model.UserViewWithToken{}, model.NewRequestError("Password must be between 6 and 20 characters") + } hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if err != nil { return model.UserViewWithToken{}, err @@ -57,7 +63,7 @@ func ChangePassword(id uint, oldPassword, newPassword string) (model.UserViewWit return model.UserViewWithToken{}, err } if err := bcrypt.CompareHashAndPassword(user.PasswordHash, []byte(oldPassword)); err != nil { - return model.UserViewWithToken{}, err + return model.UserViewWithToken{}, model.NewUnAuthorizedError("Invalid old password") } hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost) if err != nil { @@ -117,17 +123,6 @@ func getEmbedAvatar(id uint) ([]byte, error) { return static.Static.ReadFile(fileName) } -func HavePermissionToUpload(id uint) error { - user, err := dao.GetUserByID(id) - if err != nil { - return err - } - if !user.IsAdmin && !user.CanUpload { - return model.NewUnAuthorizedError("User does not have permission to upload") - } - return nil -} - func SetUserAdmin(adminID uint, targetUserID uint, isAdmin bool) (model.UserView, error) { if adminID == targetUserID { return model.UserView{}, model.NewRequestError("You cannot modify your own admin status")