diff --git a/changelog/unreleased/bump-reva.md b/changelog/unreleased/bump-reva.md index 06804b3d2d7..17ce51bc027 100644 --- a/changelog/unreleased/bump-reva.md +++ b/changelog/unreleased/bump-reva.md @@ -2,6 +2,7 @@ Enhancement: Bump Reva bumps reva version +https://github.com/owncloud/ocis/pull/9188 https://github.com/owncloud/ocis/pull/9132 https://github.com/owncloud/ocis/pull/9041 https://github.com/owncloud/ocis/pull/9002 diff --git a/go.mod b/go.mod index de86a71db21..9f56fef0552 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/cenkalti/backoff v2.2.1+incompatible github.com/coreos/go-oidc/v3 v3.10.0 github.com/cs3org/go-cs3apis v0.0.0-20231023073225-7748710e0781 - github.com/cs3org/reva/v2 v2.19.2-0.20240510133919-1732d68a5591 + github.com/cs3org/reva/v2 v2.19.2-0.20240521134642-8fb71adbe500 github.com/dhowden/tag v0.0.0-20230630033851-978a0926ee25 github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e github.com/egirna/icap-client v0.1.1 diff --git a/go.sum b/go.sum index a0796a46955..50bad9abb2a 100644 --- a/go.sum +++ b/go.sum @@ -1025,8 +1025,8 @@ github.com/crewjam/saml v0.4.14 h1:g9FBNx62osKusnFzs3QTN5L9CVA/Egfgm+stJShzw/c= github.com/crewjam/saml v0.4.14/go.mod h1:UVSZCf18jJkk6GpWNVqcyQJMD5HsRugBPf4I1nl2mME= github.com/cs3org/go-cs3apis v0.0.0-20231023073225-7748710e0781 h1:BUdwkIlf8IS2FasrrPg8gGPHQPOrQ18MS1Oew2tmGtY= github.com/cs3org/go-cs3apis v0.0.0-20231023073225-7748710e0781/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY= -github.com/cs3org/reva/v2 v2.19.2-0.20240510133919-1732d68a5591 h1:6rfzawhTzz96p8ifzcjNiMknAfAdVpfqdyzmpp3+6w8= -github.com/cs3org/reva/v2 v2.19.2-0.20240510133919-1732d68a5591/go.mod h1:BOlJApKFrWRiaOoBCRxCTG5bghTTMlYaEZrRxOzKaS8= +github.com/cs3org/reva/v2 v2.19.2-0.20240521134642-8fb71adbe500 h1:BsbDsBAnEJlCN8PU6XhDgQNX9/aSrVcyDocrBR6GI5g= +github.com/cs3org/reva/v2 v2.19.2-0.20240521134642-8fb71adbe500/go.mod h1:BOlJApKFrWRiaOoBCRxCTG5bghTTMlYaEZrRxOzKaS8= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= diff --git a/services/graph/pkg/unifiedrole/unifiedrole.go b/services/graph/pkg/unifiedrole/unifiedrole.go index cd20a93ec96..75037fe5416 100644 --- a/services/graph/pkg/unifiedrole/unifiedrole.go +++ b/services/graph/pkg/unifiedrole/unifiedrole.go @@ -23,8 +23,8 @@ const ( UnifiedRoleSpaceEditorID = "58c63c02-1d89-4572-916a-870abc5a1b7d" // UnifiedRoleFileEditorID Unified role file editor id. UnifiedRoleFileEditorID = "2d00ce52-1fc2-4dbc-8b95-a73b73395f5a" - // UnifiedRoleUploaderID Unified role uploader id. - UnifiedRoleUploaderID = "1c996275-f1c9-4e71-abdf-a42f6495e960" + // UnifiedRoleEditorLiteID Unified role editor-lite id. + UnifiedRoleEditorLiteID = "1c996275-f1c9-4e71-abdf-a42f6495e960" // UnifiedRoleManagerID Unified role manager id. UnifiedRoleManagerID = "312c0871-5ef7-4b3a-85b6-0e4074c64049" // UnifiedRoleSecureViewerID Unified role secure viewer id. @@ -66,7 +66,7 @@ var legacyNames map[string]string = map[string]string{ UnifiedRoleSpaceEditorID: "editor", UnifiedRoleEditorID: conversions.RoleEditor, UnifiedRoleFileEditorID: conversions.RoleFileEditor, - UnifiedRoleUploaderID: conversions.RoleUploader, + UnifiedRoleEditorLiteID: conversions.RoleEditorLite, UnifiedRoleManagerID: conversions.RoleManager, UnifiedRoleSecureViewerID: conversions.RoleSecureViewer, } @@ -160,11 +160,11 @@ func NewFileEditorUnifiedRole() *libregraph.UnifiedRoleDefinition { } } -// NewUploaderUnifiedRole creates an uploader role -func NewUploaderUnifiedRole() *libregraph.UnifiedRoleDefinition { - r := conversions.NewUploaderRole() +// NewEditorLiteUnifiedRole creates an editor-lite role +func NewEditorLiteUnifiedRole() *libregraph.UnifiedRoleDefinition { + r := conversions.NewEditorLiteRole() return &libregraph.UnifiedRoleDefinition{ - Id: proto.String(UnifiedRoleUploaderID), + Id: proto.String(UnifiedRoleEditorLiteID), Description: proto.String("View, download and upload."), DisplayName: displayName(r), RolePermissions: []libregraph.UnifiedRolePermission{ @@ -239,7 +239,7 @@ func GetBuiltinRoleDefinitionList() []*libregraph.UnifiedRoleDefinition { NewEditorUnifiedRole(), NewSpaceEditorUnifiedRole(), NewFileEditorUnifiedRole(), - NewUploaderUnifiedRole(), + NewEditorLiteUnifiedRole(), NewManagerUnifiedRole(), NewSecureViewerUnifiedRole(), } @@ -501,7 +501,7 @@ func displayName(role *conversions.Role) *string { displayName = canEdit case conversions.RoleFileEditor: displayName = canEdit - case conversions.RoleUploader: + case conversions.RoleEditorLite: displayName = "Can upload" case conversions.RoleManager: displayName = "Can manage" diff --git a/services/graph/pkg/unifiedrole/unifiedrole_test.go b/services/graph/pkg/unifiedrole/unifiedrole_test.go index b8d95e3ae75..4dff7a68f96 100644 --- a/services/graph/pkg/unifiedrole/unifiedrole_test.go +++ b/services/graph/pkg/unifiedrole/unifiedrole_test.go @@ -171,8 +171,8 @@ var _ = Describe("unifiedroles", func() { unifiedrole.UnifiedRoleConditionFolder, []*libregraph.UnifiedRoleDefinition{ unifiedrole.NewSecureViewerUnifiedRole(), - unifiedrole.NewUploaderUnifiedRole(), unifiedrole.NewViewerUnifiedRole(), + unifiedrole.NewEditorLiteUnifiedRole(), unifiedrole.NewEditorUnifiedRole(), }, ), @@ -194,8 +194,8 @@ var _ = Describe("unifiedroles", func() { unifiedrole.UnifiedRoleConditionFolder, []*libregraph.UnifiedRoleDefinition{ unifiedrole.NewSecureViewerUnifiedRole(), - unifiedrole.NewUploaderUnifiedRole(), unifiedrole.NewViewerUnifiedRole(), + unifiedrole.NewEditorLiteUnifiedRole(), unifiedrole.NewEditorUnifiedRole(), }, ), @@ -221,10 +221,11 @@ var _ = Describe("unifiedroles", func() { Entry( "mixed", - append(rolesToAction(unifiedrole.NewUploaderUnifiedRole()), unifiedrole.DriveItemQuotaRead), + append(rolesToAction(unifiedrole.NewEditorLiteUnifiedRole()), unifiedrole.DriveItemQuotaRead), unifiedrole.UnifiedRoleConditionFolder, []*libregraph.UnifiedRoleDefinition{ - unifiedrole.NewUploaderUnifiedRole(), + unifiedrole.NewSecureViewerUnifiedRole(), + unifiedrole.NewEditorLiteUnifiedRole(), }, ), ) diff --git a/tests/acceptance/features/apiSharingNg/listPermissions.feature b/tests/acceptance/features/apiSharingNg/listPermissions.feature index e1c1e662b8a..ee598dfc2eb 100644 --- a/tests/acceptance/features/apiSharingNg/listPermissions.feature +++ b/tests/acceptance/features/apiSharingNg/listPermissions.feature @@ -106,19 +106,19 @@ Feature: List a sharing permissions "description": { "type": "string", "enum": [ - "View, download and upload." + "View and download." ] }, "displayName": { "type": "string", "enum": [ - "Can upload" + "Can view" ] }, "id": { "type": "string", "enum": [ - "1c996275-f1c9-4e71-abdf-a42f6495e960" + "b1e2218d-eef8-4d4c-b82d-0f1a1b48f3b5" ] } } @@ -141,19 +141,19 @@ Feature: List a sharing permissions "description": { "type": "string", "enum": [ - "View and download." + "View, download and upload." ] }, "displayName": { "type": "string", "enum": [ - "Can view" + "Can upload" ] }, "id": { "type": "string", "enum": [ - "b1e2218d-eef8-4d4c-b82d-0f1a1b48f3b5" + "1c996275-f1c9-4e71-abdf-a42f6495e960" ] } } @@ -855,13 +855,13 @@ Feature: List a sharing permissions "const": 2 }, "description": { - "const": "View, download and upload." + "const": "View and download." }, "displayName": { - "const": "Can upload" + "const": "Can view" }, "id": { - "const": "1c996275-f1c9-4e71-abdf-a42f6495e960" + "const": "b1e2218d-eef8-4d4c-b82d-0f1a1b48f3b5" } } }, @@ -878,13 +878,13 @@ Feature: List a sharing permissions "const": 3 }, "description": { - "const": "View and download." + "const": "View, download and upload." }, "displayName": { - "const": "Can view" + "const": "Can upload" }, "id": { - "const": "b1e2218d-eef8-4d4c-b82d-0f1a1b48f3b5" + "const": "1c996275-f1c9-4e71-abdf-a42f6495e960" } } }, diff --git a/vendor/github.com/cs3org/reva/v2/internal/grpc/services/gateway/appprovider.go b/vendor/github.com/cs3org/reva/v2/internal/grpc/services/gateway/appprovider.go index 3a91e12a0d3..be55590f753 100644 --- a/vendor/github.com/cs3org/reva/v2/internal/grpc/services/gateway/appprovider.go +++ b/vendor/github.com/cs3org/reva/v2/internal/grpc/services/gateway/appprovider.go @@ -27,16 +27,21 @@ import ( providerpb "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1" registry "github.com/cs3org/go-cs3apis/cs3/app/registry/v1beta1" + providerv1beta1 "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1" gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" + userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1" rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" typespb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" "github.com/cs3org/reva/v2/pkg/appctx" + "github.com/cs3org/reva/v2/pkg/auth/scope" ctxpkg "github.com/cs3org/reva/v2/pkg/ctx" "github.com/cs3org/reva/v2/pkg/errtypes" "github.com/cs3org/reva/v2/pkg/rgrpc/status" "github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool" + "github.com/cs3org/reva/v2/pkg/token" + "github.com/cs3org/reva/v2/pkg/utils" "github.com/pkg/errors" "google.golang.org/grpc" "google.golang.org/grpc/credentials" @@ -169,11 +174,9 @@ func (s *svc) openLocalResources(ctx context.Context, ri *storageprovider.Resour return nil, errors.Wrap(err, "gateway: error calling GetAppProviderClient") } - appProviderReq := &providerpb.OpenInAppRequest{ - ResourceInfo: ri, - ViewMode: providerpb.ViewMode(vm), - AccessToken: accessToken, - Opaque: opaque, + appProviderReq, err := buildOpenInAppRequest(ctx, ri, vm, s.tokenmgr, accessToken, opaque) + if err != nil { + return nil, errors.Wrap(err, "gateway: error building OpenInApp request") } res, err := appProviderClient.OpenInApp(ctx, appProviderReq) @@ -184,6 +187,41 @@ func (s *svc) openLocalResources(ctx context.Context, ri *storageprovider.Resour return res, nil } +func buildOpenInAppRequest(ctx context.Context, ri *storageprovider.ResourceInfo, vm gateway.OpenInAppRequest_ViewMode, tokenmgr token.Manager, accessToken string, opaque *typespb.Opaque) (*providerpb.OpenInAppRequest, error) { + // in case of a view only mode and a stat permission we need to create a view only token + if vm == gateway.OpenInAppRequest_VIEW_MODE_VIEW_ONLY && ri.GetPermissionSet().GetStat() { + // Limit scope to the resource + scope, err := scope.AddResourceInfoScope(ri, providerv1beta1.Role_ROLE_VIEWER, nil) + if err != nil { + return nil, err + } + + // build a fake user object for the token + currentuser := ctxpkg.ContextMustGetUser(ctx) + scopedUser := &userpb.User{ + Id: ri.GetOwner(), // the owner of the resource is always set, right? + DisplayName: "View Only user for " + currentuser.GetUsername(), + } + + // mint a view only token + viewOnlyToken, err := tokenmgr.MintToken(ctx, scopedUser, scope) + if err != nil { + return nil, err + } + + // TODO we should not append the token to the opaque, we should have a dedicated field in the request + opaque = utils.AppendPlainToOpaque(opaque, "viewOnlyToken", viewOnlyToken) + } + + return &providerpb.OpenInAppRequest{ + ResourceInfo: ri, + ViewMode: providerpb.ViewMode(vm), + AccessToken: accessToken, + // ViewOnlyToken: viewOnlyToken // scoped to the shared resource if the stat response hase a ViewOnly permission + Opaque: opaque, + }, nil +} + func (s *svc) findAppProvider(ctx context.Context, ri *storageprovider.ResourceInfo, app string) (*registry.ProviderInfo, error) { c, err := pool.GetAppRegistryClient(s.c.AppRegistryEndpoint) if err != nil { diff --git a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/dav.go b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/dav.go index 5c5b6e258b7..d6234f1508d 100644 --- a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/dav.go +++ b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/dav.go @@ -20,6 +20,7 @@ package ocdav import ( "context" + "fmt" "net/http" "path" "path/filepath" @@ -28,6 +29,7 @@ import ( gatewayv1beta1 "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" + link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" "github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/config" "github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/errors" @@ -36,12 +38,18 @@ import ( ctxpkg "github.com/cs3org/reva/v2/pkg/ctx" "github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool" "github.com/cs3org/reva/v2/pkg/rhttp/router" + "github.com/cs3org/reva/v2/pkg/storage/utils/grants" + "github.com/cs3org/reva/v2/pkg/storagespace" "github.com/cs3org/reva/v2/pkg/utils" + "go.opentelemetry.io/otel/trace" "google.golang.org/grpc/metadata" ) const ( _trashbinPath = "trash-bin" + + // WwwAuthenticate captures the Www-Authenticate header string. + WwwAuthenticate = "Www-Authenticate" ) // DavHandler routes to the different sub handlers @@ -248,6 +256,39 @@ func (h *DavHandler) Handler(s *svc) http.Handler { var hasValidBasicAuthHeader bool var pass string var err error + // If user is authenticated + _, userExists := ctxpkg.ContextGetUser(ctx) + if userExists { + client, err := s.gatewaySelector.Next() + if err != nil { + log.Error().Err(err).Msg("error sending grpc stat request") + w.WriteHeader(http.StatusInternalServerError) + return + } + psRes, err := client.GetPublicShare(ctx, &link.GetPublicShareRequest{ + Ref: &link.PublicShareReference{ + Spec: &link.PublicShareReference_Token{ + Token: token, + }, + }}) + if err != nil && !strings.Contains(err.Error(), "core access token not found") { + log.Error().Err(err).Msg("error sending grpc stat request") + w.WriteHeader(http.StatusInternalServerError) + return + } + // If the link is internal then 307 redirect + if psRes.Status.Code == rpc.Code_CODE_OK && grants.PermissionsEqual(psRes.Share.Permissions.GetPermissions(), &provider.ResourcePermissions{}) { + if psRes.GetShare().GetResourceId() != nil { + rUrl := path.Join("/dav/spaces", storagespace.FormatResourceID(*psRes.GetShare().GetResourceId())) + http.Redirect(w, r, rUrl, http.StatusTemporaryRedirect) + return + } + log.Debug().Str("token", token).Interface("status", res.Status).Msg("resource id not found") + w.WriteHeader(http.StatusNotFound) + return + } + } + if _, pass, hasValidBasicAuthHeader = r.BasicAuth(); hasValidBasicAuthHeader { res, err = handleBasicAuth(r.Context(), s.gatewaySelector, token, pass) } else { @@ -286,6 +327,17 @@ func (h *DavHandler) Handler(s *svc) http.Handler { return } + if userExists { + // Build new context without an authenticated user. + // the public link should be resolved by the 'publicshares' authenticated user + baseURI := ctx.Value(net.CtxKeyBaseURI).(string) + logger := appctx.GetLogger(ctx) + span := trace.SpanFromContext(ctx) + span.End() + ctx = trace.ContextWithSpan(context.Background(), span) + ctx = appctx.WithLogger(ctx, logger) + ctx = context.WithValue(ctx, net.CtxKeyBaseURI, baseURI) + } ctx = ctxpkg.ContextSetToken(ctx, res.Token) ctx = ctxpkg.ContextSetUser(ctx, res.User) ctx = metadata.AppendToOutgoingContext(ctx, ctxpkg.TokenHeader, res.Token) @@ -301,6 +353,16 @@ func (h *DavHandler) Handler(s *svc) http.Handler { return case sRes.Status.Code == rpc.Code_CODE_PERMISSION_DENIED: fallthrough + case sRes.Status.Code == rpc.Code_CODE_OK && grants.PermissionsEqual(sRes.GetInfo().GetPermissionSet(), &provider.ResourcePermissions{}): + // If the link is internal + if !userExists { + w.Header().Add(WwwAuthenticate, fmt.Sprintf("Bearer realm=\"%s\", charset=\"UTF-8\"", r.Host)) + w.WriteHeader(http.StatusUnauthorized) + b, err := errors.Marshal(http.StatusUnauthorized, "No 'Authorization: Bearer' header found", "") + errors.HandleWebdavError(log, w, b, err) + return + } + fallthrough case sRes.Status.Code == rpc.Code_CODE_NOT_FOUND: log.Debug().Str("token", token).Interface("status", res.Status).Msg("resource not found") w.WriteHeader(http.StatusNotFound) // log the difference diff --git a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/propfind/propfind.go b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/propfind/propfind.go index 027f8c73b16..521ff85ac6d 100644 --- a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/propfind/propfind.go +++ b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/propfind/propfind.go @@ -89,6 +89,21 @@ var ( "latitude", "longitude", } + imageKeys = []string{ + "width", + "height", + } + photoKeys = []string{ + "cameraMake", + "cameraModel", + "exposureDenominator", + "exposureNumerator", + "fNumber", + "focalLength", + "iso", + "orientation", + "takenDateTime", + } ) type countingReader struct { @@ -853,6 +868,10 @@ func metadataKeys(pf XML) ([]string, []string) { metadataKeys = append(metadataKeys, metadataKeysWithPrefix("libre.graph.audio", audioKeys)...) case "http://owncloud.org/ns/location": metadataKeys = append(metadataKeys, metadataKeysWithPrefix("libre.graph.location", locationKeys)...) + case "http://owncloud.org/ns/image": + metadataKeys = append(metadataKeys, metadataKeysWithPrefix("libre.graph.image", imageKeys)...) + case "http://owncloud.org/ns/photo": + metadataKeys = append(metadataKeys, metadataKeysWithPrefix("libre.graph.photo", photoKeys)...) default: metadataKeys = append(metadataKeys, key) } @@ -910,7 +929,7 @@ func requiresExplicitFetching(n *xml.Name) bool { } case net.NsOwncloud: switch n.Local { - case "favorite", "share-types", "checksums", "size", "tags", "audio", "location": + case "favorite", "share-types", "checksums", "size", "tags", "audio", "location", "image", "photo": return true default: return false @@ -1253,6 +1272,8 @@ func mdToPropResponse(ctx context.Context, pf *XML, md *provider.ResourceInfo, p propstatOK.Prop = append(propstatOK.Prop, prop.Raw("oc:tags", k["tags"])) appendMetadataProp(k, "oc", "audio", "libre.graph.audio", audioKeys) appendMetadataProp(k, "oc", "location", "libre.graph.location", locationKeys) + appendMetadataProp(k, "oc", "image", "libre.graph.image", imageKeys) + appendMetadataProp(k, "oc", "photo", "libre.graph.photo", photoKeys) } // ls do not report any properties as missing by default @@ -1534,6 +1555,14 @@ func mdToPropResponse(ctx context.Context, pf *XML, md *provider.ResourceInfo, p if k := md.GetArbitraryMetadata().GetMetadata(); k != nil { appendMetadataProp(k, "oc", "location", "libre.graph.location", locationKeys) } + case "image": + if k := md.GetArbitraryMetadata().GetMetadata(); k != nil { + appendMetadataProp(k, "oc", "image", "libre.graph.image", imageKeys) + } + case "photo": + if k := md.GetArbitraryMetadata().GetMetadata(); k != nil { + appendMetadataProp(k, "oc", "photo", "libre.graph.photo", photoKeys) + } case "name": appendToOK(prop.Escaped("oc:name", md.Name)) case "shareid": diff --git a/vendor/github.com/cs3org/reva/v2/pkg/conversions/role.go b/vendor/github.com/cs3org/reva/v2/pkg/conversions/role.go index 52a860bd1a3..f4dd614dac1 100644 --- a/vendor/github.com/cs3org/reva/v2/pkg/conversions/role.go +++ b/vendor/github.com/cs3org/reva/v2/pkg/conversions/role.go @@ -48,7 +48,9 @@ const ( RoleFileEditor = "file-editor" // RoleCoowner grants co-owner permissions on a resource. RoleCoowner = "coowner" - // RoleUploader grants uploader permission to upload onto a resource. + // RoleEditorLite grants permission to upload and download to a resource. + RoleEditorLite = "editor-lite" + // RoleUploader grants uploader permission to upload onto a resource (no download). RoleUploader = "uploader" // RoleManager grants manager permissions on a resource. Semantically equivalent to co-owner. RoleManager = "manager" @@ -313,7 +315,24 @@ func NewCoownerRole() *Role { } } -// NewUploaderRole creates an uploader role +// NewEditorLiteRole creates an editor-lite role +func NewEditorLiteRole() *Role { + return &Role{ + Name: RoleEditorLite, + cS3ResourcePermissions: &provider.ResourcePermissions{ + Stat: true, + GetPath: true, + CreateContainer: true, + InitiateFileUpload: true, + InitiateFileDownload: true, + ListContainer: true, + Move: true, + }, + ocsPermissions: PermissionCreate, + } +} + +// NewUploaderRole creates an uploader role with no download permissions func NewUploaderRole() *Role { return &Role{ Name: RoleUploader, @@ -524,6 +543,10 @@ func RoleFromResourcePermissions(rp *provider.ResourcePermissions, islink bool) } } if r.ocsPermissions == PermissionCreate { + if rp.GetPath && rp.InitiateFileDownload && rp.ListContainer && rp.Move { + r.Name = RoleEditorLite + return r + } r.Name = RoleUploader return r } diff --git a/vendor/github.com/cs3org/reva/v2/pkg/mime/mime.go b/vendor/github.com/cs3org/reva/v2/pkg/mime/mime.go index ed94566a9b9..a6feda944fd 100644 --- a/vendor/github.com/cs3org/reva/v2/pkg/mime/mime.go +++ b/vendor/github.com/cs3org/reva/v2/pkg/mime/mime.go @@ -794,6 +794,7 @@ var mimeTypes = map[string]string{ "s3m": "audio/s3m", "saf": "application/vnd.yamaha.smaf-audio", "sass": "text/x-sass", + "sb3": "application/x.scratch.sb3", "sbml": "application/sbml+xml", "sc": "application/vnd.ibm.secure-container", "scd": "application/x-msschedule", diff --git a/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/nextcloud/nextcloud_server_mock.go b/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/nextcloud/nextcloud_server_mock.go index a23b5533f2e..4998c5a5b73 100644 --- a/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/nextcloud/nextcloud_server_mock.go +++ b/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/nextcloud/nextcloud_server_mock.go @@ -53,7 +53,7 @@ const serverStateMetadata = "METADATA" var serverState = serverStateEmpty var responses = map[string]Response{ - `POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/AddGrant {"ref":{"path":"/subdir"},"g":{"grantee":{"type":1,"Id":{"UserId":{"opaque_id":"4c510ada-c86b-4815-8820-42cdf82c3d51"}}},"permissions":{"move":true,"stat":true}}} EMPTY`: {200, ``, serverStateGrantAdded}, + `POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/AddGrant {"ref":{"path":"/subdir"},"g":{"grantee":{"type":1,"Id":{"UserId":{"opaque_id":"4c510ada-c86b-4815-8820-42cdf82c3d51"}}},"permissions":{"initiate_file_download":true,"move":true,"stat":true}}} EMPTY`: {200, ``, serverStateGrantAdded}, `POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/CreateDir {"path":"/subdir"} EMPTY`: {200, ``, serverStateSubdir}, `POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/CreateDir {"path":"/subdir"} HOME`: {200, ``, serverStateSubdir}, @@ -149,7 +149,7 @@ var responses = map[string]Response{ `POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/UnsetArbitraryMetadata {"ref":{"path":"/subdir"},"keys":["foo"]}`: {200, ``, serverStateSubdir}, - `POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/UpdateGrant {"ref":{"path":"/subdir"},"g":{"grantee":{"type":1,"Id":{"UserId":{"opaque_id":"4c510ada-c86b-4815-8820-42cdf82c3d51"}}},"permissions":{"delete":true,"move":true,"stat":true}}}`: {200, ``, serverStateGrantUpdated}, + `POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/UpdateGrant {"ref":{"path":"/subdir"},"g":{"grantee":{"type":1,"Id":{"UserId":{"opaque_id":"4c510ada-c86b-4815-8820-42cdf82c3d51"}}},"permissions":{"delete":true,"initiate_file_download":true,"move":true,"stat":true}}}`: {200, ``, serverStateGrantUpdated}, `POST /apps/sciencemesh/~tester/api/storage/GetHome `: {200, `yes we are`, serverStateHome}, `POST /apps/sciencemesh/~tester/api/storage/CreateHome `: {201, ``, serverStateEmpty}, diff --git a/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/ace/ace.go b/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/ace/ace.go index da891255408..e88a98f7f5f 100644 --- a/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/ace/ace.go +++ b/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/ace/ace.go @@ -316,10 +316,15 @@ func (e *ACE) granteeType() provider.GranteeType { // grantPermissionSet returns the set of CS3 resource permissions representing the ACE func (e *ACE) grantPermissionSet() *provider.ResourcePermissions { p := &provider.ResourcePermissions{} - // r - if strings.Contains(e.permissions, "r") { + // t + if strings.Contains(e.permissions, "t") { p.Stat = true p.GetPath = true + } + // r + if strings.Contains(e.permissions, "r") { + p.Stat = true // currently assumed + p.GetPath = true // currently assumed p.InitiateFileDownload = true p.ListContainer = true } @@ -336,10 +341,9 @@ func (e *ACE) grantPermissionSet() *provider.ResourcePermissions { p.CreateContainer = true } // x - // if strings.Contains(e.Permissions, "x") { - // TODO execute file permission? - // TODO change directory permission? - // } + if strings.Contains(e.permissions, "x") { + p.ListContainer = true + } // d if strings.Contains(e.permissions, "d") { p.Delete = true @@ -436,10 +440,17 @@ func unmarshalKV(s string) (*ACE, error) { return e, nil } +// getACEPerm produces an NFSv4.x inspired permission string from a CS3 resource permissions set func getACEPerm(set *provider.ResourcePermissions) string { var b strings.Builder - if set.Stat || set.InitiateFileDownload || set.ListContainer || set.GetPath { + if set.Stat || set.GetPath { + b.WriteString("t") + } + if set.ListContainer { // we have no dedicated traversal permission, but to listing a container allows traversing it + b.WriteString("x") + } + if set.InitiateFileDownload { b.WriteString("r") } if set.InitiateFileUpload || set.Move { diff --git a/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node/permissions.go b/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node/permissions.go index c8367ef8593..444156e7f51 100644 --- a/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node/permissions.go +++ b/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node/permissions.go @@ -100,6 +100,7 @@ func ServiceAccountPermissions() provider.ResourcePermissions { RestoreRecycleItem: true, // for cli restore command Delete: true, // for cli restore command with replace option CreateContainer: true, // for space provisioning + AddGrant: true, // for initial project space member assignment } } diff --git a/vendor/modules.txt b/vendor/modules.txt index 70a674daf91..19e88bd978d 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -366,7 +366,7 @@ github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1 github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1 github.com/cs3org/go-cs3apis/cs3/tx/v1beta1 github.com/cs3org/go-cs3apis/cs3/types/v1beta1 -# github.com/cs3org/reva/v2 v2.19.2-0.20240510133919-1732d68a5591 +# github.com/cs3org/reva/v2 v2.19.2-0.20240521134642-8fb71adbe500 ## explicit; go 1.21 github.com/cs3org/reva/v2/cmd/revad/internal/grace github.com/cs3org/reva/v2/cmd/revad/runtime