mirror of
https://github.com/wgh136/nysoure.git
synced 2025-09-27 04:17:23 +00:00
Improve request validation.
This commit is contained in:
@@ -12,17 +12,14 @@ import (
|
|||||||
func handleUploadImage(c fiber.Ctx) error {
|
func handleUploadImage(c fiber.Ctx) error {
|
||||||
uid, ok := c.Locals("uid").(uint)
|
uid, ok := c.Locals("uid").(uint)
|
||||||
if !ok {
|
if !ok {
|
||||||
return model.NewUnAuthorizedError("Unauthorized")
|
return model.NewUnAuthorizedError("You must be logged in to upload an image")
|
||||||
}
|
|
||||||
if err := service.HavePermissionToUpload(uid); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
data := c.Body()
|
data := c.Body()
|
||||||
contentType := http.DetectContentType(data)
|
contentType := http.DetectContentType(data)
|
||||||
if !strings.HasPrefix(contentType, "image/") {
|
if !strings.HasPrefix(contentType, "image/") {
|
||||||
return model.NewRequestError("Invalid image format")
|
return model.NewRequestError("Invalid image format")
|
||||||
}
|
}
|
||||||
id, err := service.CreateImage(data)
|
id, err := service.CreateImage(uid, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -64,10 +61,7 @@ func handleDeleteImage(c fiber.Ctx) error {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return model.NewUnAuthorizedError("Unauthorized")
|
return model.NewUnAuthorizedError("Unauthorized")
|
||||||
}
|
}
|
||||||
if err := service.HavePermissionToUpload(uid); err != nil {
|
if err := service.DeleteImage(uid, uint(id)); err != nil {
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := service.DeleteImage(uint(id)); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return c.Status(fiber.StatusOK).JSON(model.Response[any]{
|
return c.Status(fiber.StatusOK).JSON(model.Response[any]{
|
||||||
|
@@ -12,7 +12,11 @@ func handleCreateTag(c fiber.Ctx) error {
|
|||||||
if tag == "" {
|
if tag == "" {
|
||||||
return model.NewRequestError("name is required")
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@@ -16,12 +16,6 @@ func handleUserRegister(c fiber.Ctx) error {
|
|||||||
if username == "" || password == "" {
|
if username == "" || password == "" {
|
||||||
return model.NewRequestError("Username and password are required")
|
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)
|
user, err := service.CreateUser(username, password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@@ -8,7 +8,7 @@ import (
|
|||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
gorm.Model
|
gorm.Model
|
||||||
Username string
|
Username string `gorm:"uniqueIndex;not null"`
|
||||||
PasswordHash []byte
|
PasswordHash []byte
|
||||||
IsAdmin bool
|
IsAdmin bool
|
||||||
CanUpload bool
|
CanUpload bool
|
||||||
|
@@ -34,7 +34,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
if len(images) > 0 {
|
if len(images) > 0 {
|
||||||
for _, i := range images {
|
for _, i := range images {
|
||||||
err := DeleteImage(i.ID)
|
err := deleteImage(i.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Failed to delete unused image %d: %v", i.ID, err)
|
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 {
|
if len(data) == 0 {
|
||||||
return 0, model.NewRequestError("Image data is empty")
|
return 0, model.NewRequestError("Image data is empty")
|
||||||
} else if len(data) > 1024*1024*5 {
|
} else if len(data) > 1024*1024*5 {
|
||||||
@@ -112,7 +121,24 @@ func GetImage(id uint) ([]byte, error) {
|
|||||||
return data, nil
|
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)
|
i, err := dao.GetImageByID(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@@ -1,11 +1,20 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/gofiber/fiber/v3/log"
|
||||||
"nysoure/server/dao"
|
"nysoure/server/dao"
|
||||||
"nysoure/server/model"
|
"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)
|
t, err := dao.CreateTag(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@@ -18,6 +18,12 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func CreateUser(username, password string) (model.UserViewWithToken, error) {
|
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)
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return model.UserViewWithToken{}, err
|
return model.UserViewWithToken{}, err
|
||||||
@@ -57,7 +63,7 @@ func ChangePassword(id uint, oldPassword, newPassword string) (model.UserViewWit
|
|||||||
return model.UserViewWithToken{}, err
|
return model.UserViewWithToken{}, err
|
||||||
}
|
}
|
||||||
if err := bcrypt.CompareHashAndPassword(user.PasswordHash, []byte(oldPassword)); err != nil {
|
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)
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -117,17 +123,6 @@ func getEmbedAvatar(id uint) ([]byte, error) {
|
|||||||
return static.Static.ReadFile(fileName)
|
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) {
|
func SetUserAdmin(adminID uint, targetUserID uint, isAdmin bool) (model.UserView, error) {
|
||||||
if adminID == targetUserID {
|
if adminID == targetUserID {
|
||||||
return model.UserView{}, model.NewRequestError("You cannot modify your own admin status")
|
return model.UserView{}, model.NewRequestError("You cannot modify your own admin status")
|
||||||
|
Reference in New Issue
Block a user