Compare commits

...

2 Commits

Author SHA1 Message Date
Grendgi
f12487d036 fix: show shared folder contents consistently
All checks were successful
CI / hygiene (push) Successful in 2s
Build and Deploy / build-and-deploy (push) Successful in 29s
CI / test (push) Successful in 19s
2026-06-16 13:45:15 +03:00
Grendgi
facdba7f0b fix: validate parent folder access 2026-06-16 13:38:17 +03:00
2 changed files with 35 additions and 2 deletions

View File

@@ -61,6 +61,9 @@ func (h *NodeHandler) CreateFolder(w http.ResponseWriter, r *http.Request) {
return
}
userID := commonmw.GetUserID(r.Context())
if !h.requireWritableParent(w, r, userID, req.ParentID) {
return
}
node, err := h.repo.CreateFolder(r.Context(), req.Title, req.ParentID, userID)
if err != nil {
writeInternalError(w, r, err, "failed to create folder")
@@ -97,13 +100,16 @@ func (h *NodeHandler) UploadFile(w http.ResponseWriter, r *http.Request) {
title = strings.TrimSuffix(filename, filepath.Ext(filename))
}
userID := commonmw.GetUserID(r.Context())
parentID := emptyToNil(r.FormValue("parent_id"))
if !h.requireWritableParent(w, r, userID, parentID) {
return
}
key := storage.GenerateKey(userID, filename)
contentType := storage.GuessContentType(filename, header.Header.Get("Content-Type"))
if err := h.store.PutObject(r.Context(), key, file, header.Size, contentType); err != nil {
writeInternalError(w, r, err, "failed to upload file")
return
}
parentID := emptyToNil(r.FormValue("parent_id"))
node, err := h.repo.CreateFile(r.Context(), &model.Node{
ParentID: parentID,
Title: title,
@@ -271,6 +277,30 @@ func (h *NodeHandler) requireNode(w http.ResponseWriter, r *http.Request) (*mode
return node, true
}
func (h *NodeHandler) requireWritableParent(w http.ResponseWriter, r *http.Request, userID string, parentID *string) bool {
if parentID == nil || strings.TrimSpace(*parentID) == "" {
return true
}
parent, err := h.repo.GetForUser(r.Context(), *parentID, userID, subordinates(r))
if errors.Is(err, repository.ErrNotFound) {
writeError(w, http.StatusNotFound, "parent folder not found")
return false
}
if err != nil {
writeInternalError(w, r, err, "failed to check parent folder")
return false
}
if parent.NodeType != model.NodeTypeFolder {
writeError(w, http.StatusBadRequest, "parent_id must point to folder")
return false
}
if parent.EffectiveAccess != model.AccessEdit {
writeError(w, http.StatusForbidden, "edit access to parent folder required")
return false
}
return true
}
func (h *NodeHandler) publicNode(w http.ResponseWriter, r *http.Request) (*model.Node, bool) {
node, err := h.repo.GetByPublicToken(r.Context(), chi.URLParam(r, "token"))
if errors.Is(err, repository.ErrNotFound) {

View File

@@ -51,7 +51,10 @@ func (r *NodeRepository) List(ctx context.Context, userID string, subordinateIDs
switch scope {
case "shared":
where = append(where, `n.owner_user_id <> $1 AND (
if parentID == nil || *parentID == "" {
where = append(where, "n.owner_user_id <> $1")
}
where = append(where, `(
has_node_access(n.id, $1)
OR n.owner_user_id::text = ANY($2::text[])
)`)