feat(file): conceal file resource existence from other users

- feat: cross-user file access returns not-found instead of
  permission-denied
- fix: repository delete now only affects active rows and returns
  ErrNotFound when no row changes; repeated deletes yield not-found
- feat: parent directory operations (list, upload, create-dir, move)
  conceal ownership of other user's directories
- test: update handler, service, repository, and integration tests to
  assert not-found behavior for cross-user and missing file operations
This commit is contained in:
2026-07-16 00:06:31 +08:00
parent bb86950632
commit 6604ecb026
8 changed files with 292 additions and 42 deletions
+5 -6
View File
@@ -304,10 +304,6 @@ func (s *FileService) Update(ctx context.Context, userID, fileID string, newName
func (s *FileService) Delete(ctx context.Context, userID, fileID string) error {
file, err := s.getOwnedFile(ctx, userID, fileID)
if err != nil {
var ae *model.AppError
if errors.As(err, &ae) && errors.Is(ae.Err, model.ErrNotFound) {
return nil // idempotent: already deleted
}
return err
}
@@ -323,6 +319,9 @@ func (s *FileService) Delete(ctx context.Context, userID, fileID string) error {
}
if err := s.fileRepo.Delete(ctx, fileID); err != nil {
if errors.Is(err, model.ErrNotFound) {
return model.NewNotFoundError("file not found", model.ErrNotFound)
}
return model.NewInternalError("delete file record", err)
}
@@ -378,7 +377,7 @@ func (s *FileService) getOwnedFile(ctx context.Context, userID, fileID string) (
}
if file.UserID != userID {
return nil, model.NewForbiddenError("access denied", model.ErrForbidden)
return nil, model.NewNotFoundError("file not found", model.ErrNotFound)
}
return file, nil
@@ -395,7 +394,7 @@ func (s *FileService) verifyParent(ctx context.Context, userID, parentID string)
}
if parent.UserID != userID {
return model.NewForbiddenError("access denied", model.ErrForbidden)
return model.NewNotFoundError("parent directory not found", model.ErrNotFound)
}
if !parent.IsDir {