diff --git a/go.mod b/go.mod index b2f7540fa4..5d0faeb3d3 100644 --- a/go.mod +++ b/go.mod @@ -64,7 +64,7 @@ require ( github.com/open-policy-agent/opa v1.15.2 github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89 github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20260310090739-853d972b282d - github.com/opencloud-eu/reva/v2 v2.46.3-0.20260610093751-a33d8108dd91 + github.com/opencloud-eu/reva/v2 v2.46.4 github.com/opensearch-project/opensearch-go/v4 v4.6.0 github.com/orcaman/concurrent-map v1.0.0 github.com/pkg/errors v0.9.1 @@ -411,3 +411,5 @@ replace go-micro.dev/v4 => github.com/butonic/go-micro/v4 v4.11.1-0.202411151126 exclude github.com/mattn/go-sqlite3 v2.0.3+incompatible replace github.com/go-micro/plugins/v4/store/nats-js-kv => github.com/opencloud-eu/go-micro-plugins/v4/store/nats-js-kv v0.0.0-20250512152754-23325793059a + +replace github.com/opencloud-eu/reva/v2 => github.com/rhafer/reva/v2 v2.0.0-20260618152110-b6e25ced4a03 diff --git a/go.sum b/go.sum index 9d30b7b4cc..f518f20282 100644 --- a/go.sum +++ b/go.sum @@ -948,8 +948,6 @@ github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89 h1:W1ms+l github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89/go.mod h1:vigJkNss1N2QEceCuNw/ullDehncuJNFB6mEnzfq9UI= github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20260310090739-853d972b282d h1:JcqGDiyrcaQwVyV861TUyQgO7uEmsjkhfm7aQd84dOw= github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20260310090739-853d972b282d/go.mod h1:pzatilMEHZFT3qV7C/X3MqOa3NlRQuYhlRhZTL+hN6Q= -github.com/opencloud-eu/reva/v2 v2.46.3-0.20260610093751-a33d8108dd91 h1:A/a0d9UNclpNBWGp2NUDWF+qO+U/u38EBH4CIk2dqIE= -github.com/opencloud-eu/reva/v2 v2.46.3-0.20260610093751-a33d8108dd91/go.mod h1:RoFQt+u7edxwzHr1IZ2Y6VaDinMiRPQupAvMBy3WVmE= github.com/opencloud-eu/secure v0.0.0-20260312082735-b6f5cb2244e4 h1:l2oB/RctH+t8r7QBj5p8thfEHCM/jF35aAY3WQ3hADI= github.com/opencloud-eu/secure v0.0.0-20260312082735-b6f5cb2244e4/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= @@ -1063,6 +1061,8 @@ github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2/go.mod h1:7tZKc github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 h1:bsUq1dX0N8AOIL7EB/X911+m4EHsnWEHeJ0c+3TTBrg= github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rhafer/reva/v2 v2.0.0-20260618152110-b6e25ced4a03 h1:DofePRc6/JK2s0K5atEPZB+8apT5N+Us/RbzrHWh7tg= +github.com/rhafer/reva/v2 v2.0.0-20260618152110-b6e25ced4a03/go.mod h1:RoFQt+u7edxwzHr1IZ2Y6VaDinMiRPQupAvMBy3WVmE= github.com/riandyrn/otelchi v0.12.3 h1:KW9gA+97d6mExk8vbh0FRwb2biUvpyYlc8YuxP1Oap0= github.com/riandyrn/otelchi v0.12.3/go.mod h1:weZZeUJURvtCcbWsdb7Y6F8KFZGedJlSrgUjq9VirV8= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= diff --git a/services/graph/pkg/service/v0/drives.go b/services/graph/pkg/service/v0/drives.go index e8914098aa..7134297d1b 100644 --- a/services/graph/pkg/service/v0/drives.go +++ b/services/graph/pkg/service/v0/drives.go @@ -1119,7 +1119,7 @@ func (g Graph) DeleteDrive(w http.ResponseWriter, r *http.Request) { return case cs3rpc.Code_CODE_PERMISSION_DENIED: logger.Debug().Interface("id", rid).Msg("could not delete drive: permission denied") - errorcode.ItemNotFound.Render(w, r, http.StatusNotFound, "drive not found") + errorcode.AccessDenied.Render(w, r, http.StatusForbidden, "permission denied") return case cs3rpc.Code_CODE_NOT_FOUND: logger.Debug().Interface("id", rid).Msg("could not delete drive: drive not found") diff --git a/tests/acceptance/features/apiSpaces/disableAndDeleteSpaces.feature b/tests/acceptance/features/apiSpaces/disableAndDeleteSpaces.feature index 3fef82ab94..577cc8f643 100644 --- a/tests/acceptance/features/apiSpaces/disableAndDeleteSpaces.feature +++ b/tests/acceptance/features/apiSpaces/disableAndDeleteSpaces.feature @@ -63,28 +63,28 @@ Feature: Disabling and deleting space Scenario Outline: user cannot delete their own space without first disabling it Given the administrator has assigned the role "" to user "Alice" using the Graph API When user "Alice" deletes a space "Project Moon" - Then the HTTP status code should be "400" + Then the HTTP status code should be "" And the user "Alice" should have a space called "Project Moon" Examples: - | user-role | - | Admin | - | Space Admin | - | User | - | User Light | + | user-role | code | + | Admin | 400 | + | Space Admin | 400 | + | User | 403 | + | User Light | 403 | - Scenario Outline: user can delete their own disabled space via the Graph API + Scenario Outline: user cannot delete their own disabled space via the Graph API Given the administrator has assigned the role "" to user "Alice" using the Graph API And user "Alice" has disabled a space "Project Moon" When user "Alice" deletes a space "Project Moon" - Then the HTTP status code should be "204" - And the user "Alice" should not have a space called "Project Moon" + Then the HTTP status code should be "" + And the user "Alice" have a space called "Project Moon" Examples: - | user-role | - | Admin | - | Space Admin | - | User | - | User Light | + | user-role | code | shouldOrNot | + | Admin | 204 | should not | + | Space Admin | 204 | should not | + | User | 403 | should | + | User Light | 403 | should | Scenario Outline: an admin and space manager can disable other space via the Graph API @@ -134,7 +134,7 @@ Feature: Disabling and deleting space Scenario Outline: viewer and space editor cannot disable space When user "" tries to disable a space "Project Moon" owned by user "Alice" - Then the HTTP status code should be "404" + Then the HTTP status code should be "403" And the user "" should have a space called "Project Moon" Examples: | user | diff --git a/vendor/github.com/opencloud-eu/reva/v2/internal/grpc/services/storageprovider/storageprovider.go b/vendor/github.com/opencloud-eu/reva/v2/internal/grpc/services/storageprovider/storageprovider.go index 4458ce90a5..c873cbcf33 100644 --- a/vendor/github.com/opencloud-eu/reva/v2/internal/grpc/services/storageprovider/storageprovider.go +++ b/vendor/github.com/opencloud-eu/reva/v2/internal/grpc/services/storageprovider/storageprovider.go @@ -631,7 +631,10 @@ func (s *Service) DeleteStorageSpace(ctx context.Context, req *provider.DeleteSt case errtypes.IsNotFound: st = status.NewNotFound(ctx, "space not found") case errtypes.PermissionDenied: - st = status.NewPermissionDenied(ctx, err, "permission denied") + // The requesting user, while being a member of the space, is currently + // not allowed to list that space. E.g. because it is disabled. Return + // a "NotFound" status here. + st = status.NewNotFound(ctx, "space not found") case errtypes.BadRequest: st = status.NewInvalid(ctx, err.Error()) default: diff --git a/vendor/github.com/opencloud-eu/reva/v2/internal/http/services/owncloud/ocdav/tus.go b/vendor/github.com/opencloud-eu/reva/v2/internal/http/services/owncloud/ocdav/tus.go index f88dc2192d..25455cffec 100644 --- a/vendor/github.com/opencloud-eu/reva/v2/internal/http/services/owncloud/ocdav/tus.go +++ b/vendor/github.com/opencloud-eu/reva/v2/internal/http/services/owncloud/ocdav/tus.go @@ -119,11 +119,18 @@ func (s *svc) handleTusPost(ctx context.Context, w http.ResponseWriter, r *http. isSecretFileDrop = true } - // r.Header.Get(net.HeaderOCChecksum) - // TODO must be SHA1, ADLER32 or MD5 ... in capital letters???? - // curl -X PUT https://demo.example.org/remote.php/webdav/testcs.bin -u demo:demo -d '123' -v -H 'OC-Checksum: SHA1:40bd001563085fc35165329ea1ff5c5ecbdbbeef' - - // TODO check Expect: 100-continue + checksum := "" + if cs, ok := meta["checksum"]; ok { + cparts := strings.SplitN(cs, " ", 2) + if len(cparts) != 2 { + log.Debug().Str("upload-checksum", cs).Msg("invalid Upload-Checksum format, expected '[algorithm] [checksum]'") + w.WriteHeader(http.StatusBadRequest) + return + } else { + // we do not check the algorithm here, because it might depend on the storage + checksum = strings.ToLower(cparts[0]) + " " + cparts[1] + } + } client, err := s.gatewaySelector.Next() if err != nil { @@ -216,6 +223,12 @@ func (s *svc) handleTusPost(ctx context.Context, w http.ResponseWriter, r *http. }, } + if checksum != "" { + opaqueMap[net.HeaderUploadChecksum] = &typespb.OpaqueEntry{ + Decoder: "plain", + Value: []byte(checksum), + } + } mtime := meta["mtime"] if mtime != "" { opaqueMap[net.HeaderOCMtime] = &typespb.OpaqueEntry{ diff --git a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/ignore/ignore.go b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/ignore/ignore.go index 5b3ee51c8c..9322df781d 100644 --- a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/ignore/ignore.go +++ b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/ignore/ignore.go @@ -7,10 +7,21 @@ import ( "github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/blobstore" "github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/lookup" "github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/options" + "github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/tree/propagator" "github.com/opencloud-eu/reva/v2/pkg/storage/utils/templates" "github.com/rs/zerolog" ) +const ( + // The needles include the separator at the beginning to avoid matching internal dir names in substrings + // The end segment boundary is checked in isInternalDir + trashNeedle = needle(string(filepath.Separator) + lookup.TrashDir) + metadataNeedle = needle(string(filepath.Separator) + lookup.MetadataDir) + tmpNeedle = needle(string(filepath.Separator) + blobstore.TMPDir) +) + +type needle string + // Ignorer handles checking if paths should be ignored in posix operations type Ignorer struct { options *options.Options @@ -31,37 +42,27 @@ func NewIgnorer(options *options.Options, log *zerolog.Logger) *Ignorer { // IsIgnored checking if paths should be ignored in posix operations func (i *Ignorer) IsIgnored(path string) bool { - return IsLockFile(path) || IsTrash(path) || i.IsUpload(path) || i.IsInternal(path) || i.IsRootPath(path) || i.IsSpaceRoot(path) + return i.IsChanges(path) || + i.IsIndex(path) || + IsLockFile(path) || + i.IsTrash(path) || + i.IsMetadata(path) || + i.IsTemporary(path) || + i.IsUpload(path) || + i.IsRootPath(path) || + i.IsSpaceRoot(path) } -func (i *Ignorer) IsUpload(path string) bool { - return strings.HasPrefix(path, i.options.UploadDirectory) +func (i *Ignorer) IsChanges(path string) bool { + return strings.HasPrefix(path, filepath.Join(i.options.Root, propagator.ChangesDir)) } func (i *Ignorer) IsIndex(path string) bool { - return strings.HasPrefix(path, filepath.Join(i.options.Root, "indexes")) -} - -func (i *Ignorer) IsChanges(path string) bool { - return strings.HasPrefix(path, filepath.Join(i.options.Root, "changes")) + return strings.HasPrefix(path, filepath.Join(i.options.Root, lookup.IndexesDir)) } -func (i *Ignorer) IsTemporary(path string) bool { - if filepath.IsAbs(path) { - tmpDirPattern := filepath.Join(i.options.Root, "*", "*", blobstore.TMPDir) - isTempDir, err := filepath.Match(tmpDirPattern, path) - if err != nil { - i.log.Error().Err(err).Str("pattern", tmpDirPattern).Str("path", path).Msg("error matching temporary path") - return false - } - isTempParentDir, err := filepath.Match(tmpDirPattern, filepath.Dir(path)) - if err != nil { - i.log.Error().Err(err).Str("pattern", tmpDirPattern).Str("path", filepath.Dir(path)).Msg("error matching temporary path") - return false - } - return isTempDir || isTempParentDir - } - return path == blobstore.TMPDir || filepath.Dir(path) == blobstore.TMPDir +func (i *Ignorer) IsUpload(path string) bool { + return strings.HasPrefix(path, i.options.UploadDirectory) } func (i *Ignorer) IsRootPath(path string) bool { @@ -75,14 +76,39 @@ func (i *Ignorer) IsSpaceRoot(path string) bool { return parent == i.personalSpacesRoot || parent == i.projectSpacesRoot } -func (i *Ignorer) IsInternal(path string) bool { - return i.IsIndex(path) || strings.Contains(path, lookup.MetadataDir) || i.IsTemporary(path) || i.IsChanges(path) -} - func IsLockFile(path string) bool { return strings.HasSuffix(path, ".flock") || strings.HasSuffix(path, ".mlock") } -func IsTrash(path string) bool { - return strings.HasSuffix(path, ".trashinfo") || strings.HasSuffix(path, ".trashitem") || strings.Contains(path, ".Trash") +func (i *Ignorer) IsMetadata(path string) bool { + return i.isInternalDir(path, metadataNeedle) +} + +func (i *Ignorer) IsTemporary(path string) bool { + return i.isInternalDir(path, tmpNeedle) +} + +func (i *Ignorer) IsTrash(path string) bool { + return i.isInternalDir(path, trashNeedle) +} + +// isInternalDir checks if the path contains the match dir and that the match lives +// in the space root, e.g. "/storage/users/user1/.metadata/file" -> match is ".metadata", +// parent dir is "/storage/users/user1" which is a space root, so this would return true +func (i *Ignorer) isInternalDir(path string, match needle) bool { + idx := strings.Index(path, string(match)) + if idx <= 0 { + return false + } + + // must end at a segment boundary (end of path or separator) + if length := idx + len(match); length != len(path) && path[length] != filepath.Separator { + return false + } + + // get the path of the parent dir, e.g. "/a/match" -> index of "match" is 3 + // so parentPath is path[:2] -> "/a" + parentPath := path[:idx-1] + + return len(parentPath) > 0 && i.IsSpaceRoot(parentPath) } diff --git a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/lookup/lookup.go b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/lookup/lookup.go index ea508407e4..2289e24e22 100644 --- a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/lookup/lookup.go +++ b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/lookup/lookup.go @@ -34,6 +34,7 @@ import ( "github.com/opencloud-eu/reva/v2/pkg/errtypes" "github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/idcache" "github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/options" + dfslookup "github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/lookup" "github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/metadata" "github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/metadata/prefixes" "github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/node" @@ -48,7 +49,11 @@ import ( var tracer trace.Tracer -const MetadataDir = ".oc-nodes" +const ( + IndexesDir = dfslookup.IndexesDir + MetadataDir = ".oc-nodes" + TrashDir = ".Trash" +) var _spaceTypePersonal = "personal" var _spaceTypeProject = "project" diff --git a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/trashbin/trashbin.go b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/trashbin/trashbin.go index a4b78d7020..9c54909dc0 100644 --- a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/trashbin/trashbin.go +++ b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/trashbin/trashbin.go @@ -145,7 +145,7 @@ func (tb *Trashbin) Setup(fs storage.FS) error { } func trashRootForNode(n *node.Node) string { - return filepath.Join(n.SpaceRoot.InternalPath(), ".Trash") + return filepath.Join(n.SpaceRoot.InternalPath(), lookup.TrashDir) } func (tb *Trashbin) MoveToTrash(ctx context.Context, n *node.Node, path string) error { @@ -192,7 +192,7 @@ func (tb *Trashbin) ListRecycle(ctx context.Context, spaceID string, key, relati _, span := tracer.Start(ctx, "ListRecycle") defer span.End() - trashRoot := filepath.Join(tb.lu.InternalPath(spaceID, spaceID), ".Trash") + trashRoot := filepath.Join(tb.lu.InternalPath(spaceID, spaceID), lookup.TrashDir) base := filepath.Join(trashRoot, "files") var originalPath string @@ -304,7 +304,7 @@ func (tb *Trashbin) RestoreRecycleItem(ctx context.Context, spaceID string, key, _, span := tracer.Start(ctx, "RestoreRecycleItem") defer span.End() - trashRoot := filepath.Join(tb.lu.InternalPath(spaceID, spaceID), ".Trash") + trashRoot := filepath.Join(tb.lu.InternalPath(spaceID, spaceID), lookup.TrashDir) trashPath := filepath.Clean(filepath.Join(trashRoot, "files", key+".trashitem", relativePath)) restorePath := "" @@ -377,7 +377,7 @@ func (tb *Trashbin) PurgeRecycleItem(ctx context.Context, spaceID, key, relative _, span := tracer.Start(ctx, "PurgeRecycleItem") defer span.End() - trashRoot := filepath.Join(tb.lu.InternalPath(spaceID, spaceID), ".Trash") + trashRoot := filepath.Join(tb.lu.InternalPath(spaceID, spaceID), lookup.TrashDir) trashPath := filepath.Clean(filepath.Join(trashRoot, "files", key+".trashitem", relativePath)) type item struct { @@ -522,7 +522,7 @@ func (tb *Trashbin) EmptyRecycle(ctx context.Context, spaceID string) error { _, span := tracer.Start(ctx, "EmptyRecycle") defer span.End() - trashRoot := filepath.Join(tb.lu.InternalPath(spaceID, spaceID), ".Trash") + trashRoot := filepath.Join(tb.lu.InternalPath(spaceID, spaceID), lookup.TrashDir) filesRoot := filepath.Join(trashRoot, "files") entries, err := os.ReadDir(filesRoot) @@ -582,7 +582,7 @@ func (tb *Trashbin) EmptyRecycle(ctx context.Context, spaceID string) error { func (tb *Trashbin) IsEmpty(ctx context.Context, spaceID string) bool { _, span := tracer.Start(ctx, "HasTrashedItems") defer span.End() - trashRoot := filepath.Join(tb.lu.InternalPath(spaceID, spaceID), ".Trash", "info") + trashRoot := filepath.Join(tb.lu.InternalPath(spaceID, spaceID), lookup.TrashDir, "info") trash, err := os.Open(filepath.Clean(trashRoot)) if err != nil { // there is no trash for this space, so no trashed items diff --git a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/assimilation.go b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/assimilation.go index 0162ca1dcc..7628f4b722 100644 --- a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/assimilation.go +++ b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/assimilation.go @@ -41,7 +41,6 @@ import ( "github.com/opencloud-eu/reva/v2/pkg/errtypes" "github.com/opencloud-eu/reva/v2/pkg/events" - "github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/ignore" "github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/watcher" "github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/metadata" "github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/metadata/prefixes" @@ -898,10 +897,7 @@ func (t *Tree) WarmupIDCache(root string, assimilate, onlyDirty bool) error { } // skip irrelevant files - if t.Ignorer.IsInternal(path) || - ignore.IsLockFile(path) || - ignore.IsTrash(path) || - t.Ignorer.IsUpload(path) { + if !t.Ignorer.IsSpaceRoot(path) && t.Ignorer.IsIgnored(path) { if info.IsDir() { return filepath.SkipDir } diff --git a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/tree.go b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/tree.go index 8d9a55c813..a788c18d3e 100644 --- a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/tree.go +++ b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/tree.go @@ -326,6 +326,10 @@ func (t *Tree) GetMD(_ context.Context, n *node.Node) (os.FileInfo, error) { // TouchFile creates a new empty file func (t *Tree) TouchFile(ctx context.Context, n *node.Node, markprocessing bool, mtime string) error { + if t.Ignorer.IsIgnored(filepath.Join(n.ParentPath(), n.Name)) { + return errtypes.PermissionDenied(n.ID) + } + if n.Exists { if markprocessing { return n.SetXattr(ctx, prefixes.StatusPrefix, []byte(node.ProcessingStatus)) @@ -566,7 +570,7 @@ func (t *Tree) ListFolder(ctx context.Context, n *node.Node) ([]*node.Node, erro g.Go(func() error { defer close(work) for _, name := range names { - if t.Ignorer.IsInternal(name) || ignore.IsLockFile(name) || ignore.IsTrash(name) { + if t.Ignorer.IsIgnored(filepath.Join(dir, name)) { continue } @@ -758,6 +762,10 @@ func (t *Tree) ResolveSpaceIDIndexEntry(spaceID string) (string, error) { // InitNewNode initializes a new node func (t *Tree) InitNewNode(ctx context.Context, n *node.Node, fsize uint64) (metadata.UnlockFunc, error) { + if t.Ignorer.IsIgnored(filepath.Join(n.ParentPath(), n.Name)) { + return nil, errtypes.PermissionDenied(n.ID) + } + _, span := tracer.Start(ctx, "InitNewNode") defer span.End() // create folder structure (if needed) @@ -804,6 +812,10 @@ func (t *Tree) InitNewNode(ctx context.Context, n *node.Node, fsize uint64) (met // TODO check if node exists? func (t *Tree) createDirNode(ctx context.Context, n *node.Node) (err error) { + if t.Ignorer.IsIgnored(filepath.Join(n.ParentPath(), n.Name)) { + return errtypes.PermissionDenied(n.ID) + } + ctx, span := tracer.Start(ctx, "createDirNode") defer span.End() @@ -850,6 +862,7 @@ func (t *Tree) createDirNode(ctx context.Context, n *node.Node) (err error) { attributes := n.NodeMetadata(ctx) attributes[prefixes.MTimeAttr] = []byte(mtime.UTC().Format(time.RFC3339Nano)) attributes[prefixes.IDAttr] = []byte(n.ID) + attributes[prefixes.SpaceIDAttr] = []byte(n.SpaceID) attributes[prefixes.TreesizeAttr] = []byte("0") // initialize as empty, TODO why bother? if it is not set we could treat it as 0? if t.options.TreeTimeAccounting || t.options.TreeSizeAccounting { diff --git a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/watcher_darwin.go b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/watcher_darwin.go index 9fc424d724..3aca2fae95 100644 --- a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/watcher_darwin.go +++ b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/watcher_darwin.go @@ -12,7 +12,6 @@ import ( "github.com/fsnotify/fsnotify" "github.com/rs/zerolog" - "github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/ignore" "github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/options" "github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/watcher" ) @@ -43,7 +42,7 @@ func NewWatcher(tree *Tree, o *options.Options, log *zerolog.Logger) (*FSnotifyW // add takes care of adding watches for root and its subpaths. func (w *FSnotifyWatcher) add(fsWatcher *fsnotify.Watcher, root string) error { // Check if the root is ignored before walking the tree - if isPathIgnored(w.tree, root) { + if w.tree.Ignorer.IsIgnored(root) { return nil } @@ -53,7 +52,7 @@ func (w *FSnotifyWatcher) add(fsWatcher *fsnotify.Watcher, root string) error { } // skip ignored paths or files - if isPathIgnored(w.tree, p) || !d.IsDir() { + if w.tree.Ignorer.IsIgnored(p) || !d.IsDir() { return nil } @@ -99,7 +98,7 @@ func (w *FSnotifyWatcher) handleEvent(fsWatcher *fsnotify.Watcher, event fsnotif isWrite := event.Op&fsnotify.Write != 0 isKnownEvent := isCreate || isRemove || isRename || isWrite - isIgnored := isPathIgnored(w.tree, event.Name) + isIgnored := w.tree.Ignorer.IsIgnored(event.Name) // filter out unwanted events if isIgnored || !isKnownEvent { @@ -209,19 +208,3 @@ func isSubpath(root, p string) bool { return rel != "." && !strings.HasPrefix(rel, "..") } - -// isIgnored checks if the path is ignored by its tree. -func isPathIgnored(tree *Tree, path string) bool { - - isLockFile := ignore.IsLockFile(path) - isTrash := ignore.IsTrash(path) - isUpload := tree.isUpload(path) - isInternal := tree.isInternal(path) - - // ask the tree if the path is internal or ignored - return path == "" || - isLockFile || - isTrash || - isUpload || - isInternal -} diff --git a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/decomposedfs.go b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/decomposedfs.go index 22e3021a6c..9ed963dc26 100644 --- a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/decomposedfs.go +++ b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/decomposedfs.go @@ -206,17 +206,17 @@ func New(o *options.Options, aspects aspects.Aspects, log *zerolog.Logger) (stor if o.LockCycleDurationFactor != 0 { filelocks.SetLockCycleDurationFactor(o.LockCycleDurationFactor) } - userSpaceIndex := spaceidindex.New(filepath.Join(o.Root, "indexes"), "by-user-id") + userSpaceIndex := spaceidindex.New(filepath.Join(o.Root, lookup.IndexesDir), "by-user-id") err = userSpaceIndex.Init() if err != nil { return nil, err } - groupSpaceIndex := spaceidindex.New(filepath.Join(o.Root, "indexes"), "by-group-id") + groupSpaceIndex := spaceidindex.New(filepath.Join(o.Root, lookup.IndexesDir), "by-group-id") err = groupSpaceIndex.Init() if err != nil { return nil, err } - spaceTypeIndex := spaceidindex.New(filepath.Join(o.Root, "indexes"), "by-type") + spaceTypeIndex := spaceidindex.New(filepath.Join(o.Root, lookup.IndexesDir), "by-type") err = spaceTypeIndex.Init() if err != nil { return nil, err diff --git a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/lookup/lookup.go b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/lookup/lookup.go index b24ac8e037..bafc23fdae 100644 --- a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/lookup/lookup.go +++ b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/lookup/lookup.go @@ -45,6 +45,8 @@ var tracer trace.Tracer const ( _spaceTypePersonal = "personal" + + IndexesDir = "indexes" ) func init() { diff --git a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/spaces.go b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/spaces.go index 0942cc3ee2..d18093bfc6 100644 --- a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/spaces.go +++ b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/spaces.go @@ -1147,8 +1147,8 @@ func canDeleteSpace(ctx context.Context, spaceID string, typ string, purge bool, return errtypes.PermissionDenied("user is not allowed to delete a personal space") } - // space managers are allowed to disable and delete their project spaces - if rp, err := p.AssemblePermissions(ctx, n); err == nil && permissions.IsManager(rp) { + // space managers are allowed to disable their project spaces + if rp, err := p.AssemblePermissions(ctx, n); err == nil && !purge && permissions.IsManager(rp) { return nil } diff --git a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/tree/propagator/async.go b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/tree/propagator/async.go index 19f97c42cc..dfa57a7b44 100644 --- a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/tree/propagator/async.go +++ b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/tree/propagator/async.go @@ -37,6 +37,10 @@ import ( "github.com/vmihailenco/msgpack/v5" ) +const ( + ChangesDir = "changes" +) + var _propagationGracePeriod = 3 * time.Minute type PropagationNode interface { @@ -80,7 +84,7 @@ func NewAsyncPropagator(treeSizeAccounting, treeTimeAccounting bool, o options.A return } - changesDirPath := filepath.Join(p.lookup.InternalRoot(), "changes") + changesDirPath := filepath.Join(p.lookup.InternalRoot(), ChangesDir) doSleep := false // switch to not sleep on the first iteration for { if doSleep { @@ -426,5 +430,5 @@ func (p AsyncPropagator) propagate(ctx context.Context, pn PropagationNode, reca } func (p AsyncPropagator) changesPath(spaceID, nodeID, filename string) string { - return filepath.Join(p.lookup.InternalRoot(), "changes", spaceID[0:2], spaceID+":"+nodeID, filename) + return filepath.Join(p.lookup.InternalRoot(), ChangesDir, spaceID[0:2], spaceID+":"+nodeID, filename) } diff --git a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/tree/tree.go b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/tree/tree.go index c718b3f163..8f5daa41df 100644 --- a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/tree/tree.go +++ b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/tree/tree.go @@ -845,6 +845,7 @@ func (t *Tree) createDirNode(ctx context.Context, n *node.Node) (err error) { } attributes := n.NodeMetadata(ctx) + attributes[prefixes.SpaceIDAttr] = []byte(n.SpaceID) attributes[prefixes.TreesizeAttr] = []byte("0") // initialize as empty, TODO why bother? if it is not set we could treat it as 0? if t.options.TreeTimeAccounting || t.options.TreeSizeAccounting { attributes[prefixes.PropagationAttr] = []byte("1") // mark the node for propagation diff --git a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/upload/upload.go b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/upload/upload.go index 7dff40c588..20bb21dcca 100644 --- a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/upload/upload.go +++ b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/upload/upload.go @@ -135,6 +135,7 @@ func (session *DecomposedFsSession) FinishUploadDecomposed(ctx context.Context) ctx = ctxpkg.ContextSetInitiator(ctx, session.InitiatorID()) + ctx = context.WithoutCancel(ctx) // Do not cancel the finish process, we unconditionally want to complete the upload. sha1h, md5h, adler32h, err := node.CalculateChecksums(ctx, session.binPath()) if err != nil { return err diff --git a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/utils/decomposedfs/tree/tree.go b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/utils/decomposedfs/tree/tree.go index 6fdf2df3c5..7b08a7b97c 100644 --- a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/utils/decomposedfs/tree/tree.go +++ b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/utils/decomposedfs/tree/tree.go @@ -867,6 +867,7 @@ func (t *Tree) createDirNode(ctx context.Context, n *node.Node) (err error) { } attributes := n.NodeMetadata(ctx) + attributes[prefixes.SpaceIDAttr] = []byte(n.SpaceID) attributes[prefixes.TreesizeAttr] = []byte("0") // initialize as empty, TODO why bother? if it is not set we could treat it as 0? if t.options.TreeTimeAccounting || t.options.TreeSizeAccounting { attributes[prefixes.PropagationAttr] = []byte("1") // mark the node for propagation diff --git a/vendor/modules.txt b/vendor/modules.txt index ab6c6a5a87..e9811ff69a 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1360,7 +1360,7 @@ github.com/opencloud-eu/icap-client # github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20260310090739-853d972b282d ## explicit; go 1.18 github.com/opencloud-eu/libre-graph-api-go -# github.com/opencloud-eu/reva/v2 v2.46.3-0.20260610093751-a33d8108dd91 +# github.com/opencloud-eu/reva/v2 v2.46.4 => github.com/rhafer/reva/v2 v2.0.0-20260618152110-b6e25ced4a03 ## explicit; go 1.25.0 github.com/opencloud-eu/reva/v2/cmd/revad/internal/grace github.com/opencloud-eu/reva/v2/cmd/revad/runtime @@ -2735,3 +2735,4 @@ stash.kopano.io/kgol/rndm # github.com/unrolled/secure => github.com/opencloud-eu/secure v0.0.0-20260312082735-b6f5cb2244e4 # go-micro.dev/v4 => github.com/butonic/go-micro/v4 v4.11.1-0.20241115112658-b5d4de5ed9b3 # github.com/go-micro/plugins/v4/store/nats-js-kv => github.com/opencloud-eu/go-micro-plugins/v4/store/nats-js-kv v0.0.0-20250512152754-23325793059a +# github.com/opencloud-eu/reva/v2 => github.com/rhafer/reva/v2 v2.0.0-20260618152110-b6e25ced4a03