diff --git a/go.mod b/go.mod index 6eed43e3bc..1fd7c00051 100644 --- a/go.mod +++ b/go.mod @@ -64,7 +64,7 @@ require ( github.com/open-policy-agent/opa v1.17.1 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.4-0.20260615073558-209c2cd3b52b + github.com/opencloud-eu/reva/v2 v2.46.4-0.20260617101222-64667a51e1ee 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 diff --git a/go.sum b/go.sum index 81020cf62c..0417b9960d 100644 --- a/go.sum +++ b/go.sum @@ -949,8 +949,8 @@ 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.4-0.20260615073558-209c2cd3b52b h1:ejmGkLVlWauUkcnXYbSr7dY1a59dUdkKHOvzeGpwwgE= -github.com/opencloud-eu/reva/v2 v2.46.4-0.20260615073558-209c2cd3b52b/go.mod h1:RoFQt+u7edxwzHr1IZ2Y6VaDinMiRPQupAvMBy3WVmE= +github.com/opencloud-eu/reva/v2 v2.46.4-0.20260617101222-64667a51e1ee h1:9FxUPKO9Mowt24yr1vaG8OjhBNYcfeFoGdhJerKbpEU= +github.com/opencloud-eu/reva/v2 v2.46.4-0.20260617101222-64667a51e1ee/go.mod h1:z3cZwP9nHkvyyZgrG56MvxSUkqTF7DTlcGJzJfkyNlI= 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= diff --git a/services/graph/pkg/config/defaults/defaultconfig.go b/services/graph/pkg/config/defaults/defaultconfig.go index 21827d9850..f27bcce186 100644 --- a/services/graph/pkg/config/defaults/defaultconfig.go +++ b/services/graph/pkg/config/defaults/defaultconfig.go @@ -15,6 +15,7 @@ var ( // but can be enabled by the user. _disabledByDefaultUnifiedRoleRoleIDs = []string{ unifiedrole.UnifiedRoleSecureViewerID, + unifiedrole.UnifiedRoleSpaceViewerWithVersionsID, unifiedrole.UnifiedRoleSpaceEditorWithoutVersionsID, unifiedrole.UnifiedRoleViewerListGrantsID, unifiedrole.UnifiedRoleEditorListGrantsID, diff --git a/services/graph/pkg/unifiedrole/conversion.go b/services/graph/pkg/unifiedrole/conversion.go index 92dbcf5030..a554ff2b9a 100644 --- a/services/graph/pkg/unifiedrole/conversion.go +++ b/services/graph/pkg/unifiedrole/conversion.go @@ -5,6 +5,7 @@ import ( provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" libregraph "github.com/opencloud-eu/libre-graph-api-go" + "github.com/opencloud-eu/reva/v2/pkg/conversions" ) @@ -210,6 +211,8 @@ func cs3RoleToDisplayName(role *conversions.Role) string { return _viewerListGrantsUnifiedRoleDisplayName case conversions.RoleSpaceViewer: return _spaceViewerUnifiedRoleDisplayName + case conversions.RoleSpaceViewerWithVersions: + return _spaceViewerWithVersionsUnifiedRoleDisplayName case conversions.RoleEditor: return _editorUnifiedRoleDisplayName case conversions.RoleEditorWithVersions: diff --git a/services/graph/pkg/unifiedrole/export_test.go b/services/graph/pkg/unifiedrole/export_test.go index 0ef80b3be4..b8da3c53fa 100644 --- a/services/graph/pkg/unifiedrole/export_test.go +++ b/services/graph/pkg/unifiedrole/export_test.go @@ -5,6 +5,7 @@ var ( RoleViewerWithVersions = roleViewerWithVersions RoleViewerListGrants = roleViewerListGrants RoleSpaceViewer = roleSpaceViewer + RoleSpaceViewerWithVersions = roleSpaceViewerWithVersions RoleEditor = roleEditor RoleEditorWithVersions = roleEditorWithVersions RoleEditorListGrants = roleEditorListGrants diff --git a/services/graph/pkg/unifiedrole/roles.go b/services/graph/pkg/unifiedrole/roles.go index 2c75a86152..83667bd1c0 100644 --- a/services/graph/pkg/unifiedrole/roles.go +++ b/services/graph/pkg/unifiedrole/roles.go @@ -6,9 +6,10 @@ import ( "strings" libregraph "github.com/opencloud-eu/libre-graph-api-go" - "github.com/opencloud-eu/reva/v2/pkg/conversions" "google.golang.org/protobuf/proto" + "github.com/opencloud-eu/reva/v2/pkg/conversions" + "github.com/opencloud-eu/opencloud/pkg/l10n" graphl10n "github.com/opencloud-eu/opencloud/services/graph/pkg/l10n" ) @@ -22,6 +23,8 @@ const ( UnifiedRoleViewerListGrantsID = "d5041006-ebb3-4b4a-b6a4-7c180ecfb17d" // UnifiedRoleSpaceViewerID Unified role space viewer id. UnifiedRoleSpaceViewerID = "a8d5fe5e-96e3-418d-825b-534dbdf22b99" + // UnifiedRoleSpaceViewerWithVersionsID + UnifiedRoleSpaceViewerWithVersionsID = "3de465fc-6e17-4839-8b8a-a77cc497878b" // UnifiedRoleEditorID Unified role editor id. UnifiedRoleEditorID = "fb6c3e19-e378-47e5-b277-9732f9de6e21" // UnifiedRoleEditorWithVersionsID @@ -121,6 +124,12 @@ var ( // UnifiedRole SpaseViewer, Role DisplayName (resolves directly) _spaceViewerUnifiedRoleDisplayName = l10n.Template("Can view") + // UnifiedRole SpaceViewer, Role Description (resolves directly) + _spaceViewerWithVersionsUnifiedRoleDescription = l10n.Template("View and download including the history.") + + // UnifiedRole SpaseViewer, Role DisplayName (resolves directly) + _spaceViewerWithVersionsUnifiedRoleDisplayName = l10n.Template("Can view") + // UnifiedRole Editor, Role Description (resolves directly) _editorUnifiedRoleDescription = l10n.Template("View, download, upload, edit, add and delete.") @@ -214,6 +223,7 @@ var ( roleViewerWithVersions, roleViewerListGrants, roleSpaceViewer, + roleSpaceViewerWithVersions, roleEditor, roleEditorListGrants, roleEditorWithVersions, @@ -345,6 +355,23 @@ var ( } }() + // roleSpaceViewer creates a spaceviewer role + roleSpaceViewerWithVersions = func() *libregraph.UnifiedRoleDefinition { + r := conversions.NewSpaceViewerWithVersionsRole() + return &libregraph.UnifiedRoleDefinition{ + Id: proto.String(UnifiedRoleSpaceViewerWithVersionsID), + Description: proto.String(_spaceViewerWithVersionsUnifiedRoleDescription), + DisplayName: proto.String(cs3RoleToDisplayName(r)), + RolePermissions: []libregraph.UnifiedRolePermission{ + { + AllowedResourceActions: CS3ResourcePermissionsToLibregraphActions(r.CS3ResourcePermissions()), + Condition: proto.String(UnifiedRoleConditionDrive), + }, + }, + LibreGraphWeight: proto.Int32(40), + } + }() + // roleEditorLite creates an editor-lite role roleEditorLite = func() *libregraph.UnifiedRoleDefinition { r := conversions.NewEditorLiteRole() diff --git a/services/graph/pkg/unifiedrole/roles_test.go b/services/graph/pkg/unifiedrole/roles_test.go index 2bb5f80da3..746a9ccaec 100644 --- a/services/graph/pkg/unifiedrole/roles_test.go +++ b/services/graph/pkg/unifiedrole/roles_test.go @@ -38,6 +38,10 @@ func TestGetDefinition(t *testing.T) { ids: []string{unifiedrole.UnifiedRoleFileEditorWithVersionsID}, unifiedRoleDefinition: unifiedrole.RoleFileEditorWithVersions, }, + "pass space-viewer-with-versions": { + ids: []string{unifiedrole.UnifiedRoleSpaceViewerWithVersionsID}, + unifiedRoleDefinition: unifiedrole.RoleSpaceViewerWithVersions, + }, "fail unknown": { ids: []string{"unknown"}, expectError: unifiedrole.ErrUnknownRole, @@ -203,6 +207,7 @@ func TestGetRolesByPermissions(t *testing.T) { constraints: unifiedrole.UnifiedRoleConditionDrive, unifiedRoleDefinition: []*libregraph.UnifiedRoleDefinition{ unifiedrole.RoleSpaceViewer, + unifiedrole.RoleSpaceViewerWithVersions, unifiedrole.RoleSpaceEditorWithoutVersions, unifiedrole.RoleSpaceEditor, unifiedrole.RoleManager, diff --git a/services/web/pkg/theme/theme.go b/services/web/pkg/theme/theme.go index 099845fc0a..a6f05c62b8 100644 --- a/services/web/pkg/theme/theme.go +++ b/services/web/pkg/theme/theme.go @@ -33,6 +33,10 @@ var themeDefaults = KV{ "label": "UnifiedRoleSpaceViewer", "iconName": "eye", }, + unifiedrole.UnifiedRoleSpaceViewerWithVersionsID: KV{ + "label": "UnifiedRoleSpaceViewerWithVersions", + "iconName": "eye", + }, unifiedrole.UnifiedRoleFileEditorID: KV{ "label": "UnifiedRoleFileEditor", "iconName": "pencil", diff --git a/vendor/github.com/opencloud-eu/reva/v2/pkg/conversions/role.go b/vendor/github.com/opencloud-eu/reva/v2/pkg/conversions/role.go index 239387426d..92f49ea825 100644 --- a/vendor/github.com/opencloud-eu/reva/v2/pkg/conversions/role.go +++ b/vendor/github.com/opencloud-eu/reva/v2/pkg/conversions/role.go @@ -24,6 +24,7 @@ import ( "strings" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" + "github.com/opencloud-eu/reva/v2/pkg/storage/utils/grants" ) @@ -41,6 +42,8 @@ const ( RoleViewerWithVersions = "viewer-with-versions" // RoleViewerListGrants grants non-editor role on a resource. RoleViewerListGrants = "viewer-list-grants" + // RoleSpaceViewerWithVersions grants non-editor role on a space, including list/restore versions. + RoleSpaceViewerWithVersions = "spaceviewer-with-versions" // RoleSpaceViewer grants non-editor role on a space. RoleSpaceViewer = "spaceviewer" // RoleEditor grants editor permission on a resource, including folders. @@ -175,6 +178,8 @@ func RoleFromName(name string) *Role { return NewViewerListGrantsRole() case RoleSpaceViewer: return NewSpaceViewerRole() + case RoleSpaceViewerWithVersions: + return NewSpaceViewerWithVersionsRole() case RoleEditor: return NewEditorRole() case RoleEditorWithVersions: @@ -269,6 +274,14 @@ func NewSpaceViewerRole() *Role { } } +// NewSpaceViewerWithVersionsRole creates a spaceviewer role which enables listing of file versions +func NewSpaceViewerWithVersionsRole() *Role { + role := NewSpaceViewerRole() + role.Name = RoleSpaceViewerWithVersions + role.cS3ResourcePermissions.ListFileVersions = true + return role +} + // NewEditorRole creates an editor role. `sharing` indicates if sharing permission should be added func NewEditorRole() *Role { p := PermissionRead | PermissionCreate | PermissionWrite | PermissionDelete 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/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 b15cb1e871..0695f95636 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1364,7 +1364,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.4-0.20260615073558-209c2cd3b52b +# github.com/opencloud-eu/reva/v2 v2.46.4-0.20260617101222-64667a51e1ee ## explicit; go 1.25.0 github.com/opencloud-eu/reva/v2/cmd/revad/internal/grace github.com/opencloud-eu/reva/v2/cmd/revad/runtime