fix(backend): CreateShare wrong common parent check

This commit is contained in:
2025-12-28 23:43:17 +00:00
parent 399b513e55
commit fdfad036f8
5 changed files with 40 additions and 32 deletions

View File

@@ -1 +1,3 @@
data/
bin/
.gocache/

View File

@@ -1368,7 +1368,7 @@
"BearerAuth": []
}
],
"description": "Create a new share link for one or more files or directories",
"description": "Create a new share link for one or more files or directories. All items must be in the same parent directory. Root directory cannot be shared.",
"tags": [
"shares"
],
@@ -1408,7 +1408,7 @@
}
},
"400": {
"description": "Invalid request or no items provided",
"description": "Invalid request, items not in same directory, or root directory cannot be shared",
"content": {
"application/json": {
"schema": {

View File

@@ -1102,7 +1102,7 @@
"BearerAuth": []
}
],
"description": "Create a new share link for one or more files or directories",
"description": "Create a new share link for one or more files or directories. All items must be in the same parent directory. Root directory cannot be shared.",
"consumes": [
"application/json"
],
@@ -1140,7 +1140,7 @@
}
},
"400": {
"description": "Invalid request or no items provided",
"description": "Invalid request, items not in same directory, or root directory cannot be shared",
"schema": {
"type": "object",
"additionalProperties": {

View File

@@ -90,25 +90,17 @@ func (h *HTTPHandler) shareMiddleware(c *fiber.Ctx) error {
})
}
u := reqctx.AuthenticatedUser(c).(*user.User)
if u != nil {
consumerAccount, err = h.accountService.AccountByID(c.Context(), h.db, u.ID, consumerAccountID)
if err != nil {
if errors.Is(err, account.ErrAccountNotFound) {
return c.SendStatus(fiber.StatusNotFound)
}
return httperr.Internal(err)
}
consumerAccount, err = h.accountService.AccountByID(c.Context(), h.db, u.ID, consumerAccountID)
if err != nil {
if errors.Is(err, account.ErrAccountNotFound) {
return c.SendStatus(fiber.StatusNotFound)
}
return httperr.Internal(err)
}
u, _ := reqctx.AuthenticatedUser(c).(*user.User)
if u == nil {
return c.SendStatus(fiber.StatusUnauthorized)
}
consumerAccount, err = h.accountService.AccountByID(c.Context(), h.db, u.ID, consumerAccountID)
if err != nil {
if errors.Is(err, account.ErrAccountNotFound) {
return c.SendStatus(fiber.StatusNotFound)
}
return httperr.Internal(err)
}
}
scope, err := h.sharingService.ResolveScopeForShare(c.Context(), h.db, consumerAccount, share)
@@ -155,14 +147,14 @@ func (h *HTTPHandler) getShare(c *fiber.Ctx) error {
// createShare creates a new share link for files or directories
// @Summary Create share
// @Description Create a new share link for one or more files or directories
// @Description Create a new share link for one or more files or directories. All items must be in the same parent directory. Root directory cannot be shared.
// @Tags shares
// @Accept json
// @Produce json
// @Param accountID path string true "Account ID" format(uuid)
// @Param request body createShareRequest true "Share details"
// @Success 200 {object} Share "Created share"
// @Failure 400 {object} map[string]string "Invalid request or no items provided"
// @Failure 400 {object} map[string]string "Invalid request, items not in same directory, or root directory cannot be shared"
// @Failure 401 {string} string "Not authenticated"
// @Failure 404 {object} map[string]string "One or more items not found"
// @Security BearerAuth
@@ -214,6 +206,12 @@ func (h *HTTPHandler) createShare(c *fiber.Ctx) error {
share, err := h.sharingService.CreateShare(c.Context(), tx, acc.ID, opts)
if err != nil {
if errors.Is(err, ErrNotSameParent) {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "items must be in the same directory"})
}
if errors.Is(err, ErrCannotShareRoot) {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "cannot share root directory"})
}
return httperr.Internal(err)
}

View File

@@ -46,6 +46,7 @@ var (
ErrShareNoItems = errors.New("share has no items")
ErrNoPermissions = errors.New("no permissions found")
ErrNotSameParent = errors.New("items to be shared must be in the same parent directory")
ErrCannotShareRoot = errors.New("cannot share root directory")
)
func NewService(vfs *virtualfs.VirtualFS) (*Service, error) {
@@ -56,8 +57,13 @@ func NewService(vfs *virtualfs.VirtualFS) (*Service, error) {
return &Service{vfs: vfs, sqid: sqid}, nil
}
// CreateShare creates a share record for a parent directory and its allowed items.
// CreateShare creates a share record for its allowed items.
// A share is a partial share of a directory: the share root is always the common parent directory of all items.
func (s *Service) CreateShare(ctx context.Context, db bun.IDB, accountID uuid.UUID, opts CreateShareOptions) (*Share, error) {
if len(opts.Items) == 0 {
return nil, ErrShareNoItems
}
id, err := generateInternalID()
if err != nil {
return nil, err
@@ -68,11 +74,13 @@ func (s *Service) CreateShare(ctx context.Context, db bun.IDB, accountID uuid.UU
return nil, err
}
var parentID *uuid.UUID
for _, item := range opts.Items {
if parentID == nil {
parentID = &item.ID
} else if item.ParentID != *parentID {
sharedDirectoryID := opts.Items[0].ParentID
if sharedDirectoryID == uuid.Nil {
// Root directories have no parent; they are never shareable.
return nil, ErrCannotShareRoot
}
for _, item := range opts.Items[1:] {
if item.ParentID != sharedDirectoryID {
return nil, ErrNotSameParent
}
}
@@ -82,7 +90,7 @@ func (s *Service) CreateShare(ctx context.Context, db bun.IDB, accountID uuid.UU
ID: id,
AccountID: accountID,
PublicID: pid,
SharedDirectoryID: opts.Items[0].ID,
SharedDirectoryID: sharedDirectoryID,
CreatedAt: now,
UpdatedAt: now,
}