diff --git a/changelog/unreleased/bump-reva.md b/changelog/unreleased/bump-reva.md index c24d3eb11..a1391e763 100644 --- a/changelog/unreleased/bump-reva.md +++ b/changelog/unreleased/bump-reva.md @@ -27,3 +27,4 @@ Update reva to latest edge https://github.com/owncloud/ocis/pull/6529 https://github.com/owncloud/ocis/pull/6544 https://github.com/owncloud/ocis/pull/6507 +https://github.com/owncloud/ocis/pull/6572 diff --git a/go.mod b/go.mod index ef15ebb94..8170284f5 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/coreos/go-oidc v2.2.1+incompatible github.com/coreos/go-oidc/v3 v3.6.0 github.com/cs3org/go-cs3apis v0.0.0-20230516150832-730ac860c71d - github.com/cs3org/reva/v2 v2.14.1-0.20230619124027-9bd3d7359257 + github.com/cs3org/reva/v2 v2.14.1-0.20230621095551-a4c97189e11a github.com/disintegration/imaging v1.6.2 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 86c73d4fc..f034a738e 100644 --- a/go.sum +++ b/go.sum @@ -625,8 +625,8 @@ github.com/crewjam/httperr v0.2.0 h1:b2BfXR8U3AlIHwNeFFvZ+BV1LFvKLlzMjzaTnZMybNo github.com/crewjam/httperr v0.2.0/go.mod h1:Jlz+Sg/XqBQhyMjdDiC+GNNRzZTD7x39Gu3pglZ5oH4= github.com/crewjam/saml v0.4.13 h1:TYHggH/hwP7eArqiXSJUvtOPNzQDyQ7vwmwEqlFWhMc= github.com/crewjam/saml v0.4.13/go.mod h1:igEejV+fihTIlHXYP8zOec3V5A8y3lws5bQBFsTm4gA= -github.com/cs3org/reva/v2 v2.14.1-0.20230619124027-9bd3d7359257 h1:Z+iEDQlIEjnOd/GQa1AJN5gPVCSPJ2aKFVCM2xj8Q+g= -github.com/cs3org/reva/v2 v2.14.1-0.20230619124027-9bd3d7359257/go.mod h1:E32krZG159YflDSjDWfx/QGIC2529PS5LiPnGNHu3d0= +github.com/cs3org/reva/v2 v2.14.1-0.20230621095551-a4c97189e11a h1:MKQ3H+hxw7geL2ih7wdhIF/YGFY2F1Bl8HBt6WTTkwk= +github.com/cs3org/reva/v2 v2.14.1-0.20230621095551-a4c97189e11a/go.mod h1:E32krZG159YflDSjDWfx/QGIC2529PS5LiPnGNHu3d0= github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8 h1:Z9lwXumT5ACSmJ7WGnFl+OMLLjpz5uR2fyz7dC255FI= github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8/go.mod h1:4abs/jPXcmJzYoYGF91JF9Uq9s/KL5n1jvFDix8KcqY= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= diff --git a/vendor/github.com/cs3org/reva/v2/internal/http/services/archiver/manager/archiver.go b/vendor/github.com/cs3org/reva/v2/internal/http/services/archiver/manager/archiver.go index 341505861..7fdfd84c6 100644 --- a/vendor/github.com/cs3org/reva/v2/internal/http/services/archiver/manager/archiver.go +++ b/vendor/github.com/cs3org/reva/v2/internal/http/services/archiver/manager/archiver.go @@ -73,6 +73,11 @@ func (a *Archiver) CreateTar(ctx context.Context, dst io.Writer) error { return err } + // when archiving a space we can omit the spaceroot + if isSpaceRoot(info) { + return nil + } + isDir := info.Type == provider.ResourceType_RESOURCE_TYPE_CONTAINER filesCount++ @@ -140,6 +145,11 @@ func (a *Archiver) CreateZip(ctx context.Context, dst io.Writer) error { return err } + // when archiving a space we can omit the spaceroot + if isSpaceRoot(info) { + return nil + } + isDir := info.Type == provider.ResourceType_RESOURCE_TYPE_CONTAINER filesCount++ @@ -189,3 +199,9 @@ func (a *Archiver) CreateZip(ctx context.Context, dst io.Writer) error { } return w.Close() } + +func isSpaceRoot(info *provider.ResourceInfo) bool { + f := info.GetId() + s := info.GetSpace().GetRoot() + return f.GetOpaqueId() == s.GetOpaqueId() && f.GetSpaceId() == s.GetSpaceId() +} diff --git a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/public.go b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/public.go index 9e2cd9398..574cc6f66 100644 --- a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/public.go +++ b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/public.go @@ -23,12 +23,14 @@ import ( "fmt" "net/http" "strconv" + "strings" permissionsv1beta1 "github.com/cs3org/go-cs3apis/cs3/permissions/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" types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" + "github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool" "github.com/rs/zerolog/log" "github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/conversions" @@ -36,7 +38,6 @@ import ( "github.com/cs3org/reva/v2/pkg/appctx" ctxpkg "github.com/cs3org/reva/v2/pkg/ctx" "github.com/cs3org/reva/v2/pkg/publicshare" - "github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool" "github.com/pkg/errors" ) @@ -127,7 +128,12 @@ func (h *Handler) createPublicLinkShare(w http.ResponseWriter, r *http.Request, } } - permissions, err := ocPublicPermToCs3(permKey, h) + // default perms: read-only + // TODO: the default might change depending on allowed permissions and configs + if permKey == nil { + permKey = &_defaultPublicLinkPermission + } + permissions, err := ocPublicPermToCs3(permKey) if err != nil { return nil, &ocsError{ Code: response.MetaBadRequest.StatusCode, @@ -135,16 +141,13 @@ func (h *Handler) createPublicLinkShare(w http.ResponseWriter, r *http.Request, Error: err, } } - if permissions == nil { - // default perms: read-only - // TODO: the default might change depending on allowed permissions and configs - permissions, err = ocPublicPermToCs3(&_defaultPublicLinkPermission, h) - if err != nil { - return nil, &ocsError{ - Code: response.MetaServerError.StatusCode, - Message: "Could not convert default permissions", - Error: err, - } + + password := strings.TrimSpace(r.FormValue("password")) + if h.enforcePassword(permKey) && len(password) == 0 { + return nil, &ocsError{ + Code: response.MetaBadRequest.StatusCode, + Message: "missing required password", + Error: errors.New("missing required password"), } } @@ -172,7 +175,7 @@ func (h *Handler) createPublicLinkShare(w http.ResponseWriter, r *http.Request, Permissions: &link.PublicSharePermissions{ Permissions: permissions, }, - Password: r.FormValue("password"), + Password: password, }, } @@ -198,7 +201,6 @@ func (h *Handler) createPublicLinkShare(w http.ResponseWriter, r *http.Request, Metadata: map[string]string{ "name": r.FormValue("name"), "quicklink": r.FormValue("quicklink"), - // "password": r.FormValue("password"), }, } @@ -275,9 +277,10 @@ func (h *Handler) listPublicShares(r *http.Request, filters []*link.ListPublicSh func (h *Handler) isPublicShare(r *http.Request, oid string) (*link.PublicShare, bool) { logger := appctx.GetLogger(r.Context()) - client, err := pool.GetGatewayServiceClient(h.gatewayAddr) + client, err := h.getClient() if err != nil { logger.Err(err) + return nil, false } psRes, err := client.GetPublicShare(r.Context(), &link.GetPublicShareRequest{ @@ -301,7 +304,7 @@ func (h *Handler) updatePublicShare(w http.ResponseWriter, r *http.Request, shar updates := []*link.UpdatePublicShareRequest_Update{} logger := appctx.GetLogger(r.Context()) - gwC, err := pool.GetGatewayServiceClient(h.gatewayAddr) + gwC, err := h.getClient() if err != nil { log.Err(err).Str("shareID", share.GetId().GetOpaqueId()).Msg("updatePublicShare") response.WriteOCSError(w, r, response.MetaBadRequest.StatusCode, "error getting a connection to the gateway service", nil) @@ -377,7 +380,7 @@ func (h *Handler) updatePublicShare(w http.ResponseWriter, r *http.Request, shar } // Permissions - newPermissions, err := ocPublicPermToCs3(permKey, h) + newPermissions, err := ocPublicPermToCs3(permKey) logger.Debug().Interface("newPermissions", newPermissions).Msg("Parsed permissions") if err != nil { response.WriteOCSError(w, r, response.MetaBadRequest.StatusCode, "invalid permissions", err) @@ -447,6 +450,14 @@ func (h *Handler) updatePublicShare(w http.ResponseWriter, r *http.Request, shar // Password newPassword, ok := r.Form["password"] + // enforcePassword + if h.enforcePassword(permKey) { + if (!ok && !share.PasswordProtected) || (ok && len(strings.TrimSpace(newPassword[0])) == 0) { + response.WriteOCSError(w, r, response.MetaBadRequest.StatusCode, "missing required password", err) + return + } + } + // update or clear password if ok { updatesFound = true @@ -500,7 +511,7 @@ func (h *Handler) updatePublicShare(w http.ResponseWriter, r *http.Request, shar func (h *Handler) removePublicShare(w http.ResponseWriter, r *http.Request, share *link.PublicShare) { ctx := r.Context() - c, err := pool.GetGatewayServiceClient(h.gatewayAddr) + c, err := h.getClient() if err != nil { response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error getting grpc gateway client", err) return @@ -548,6 +559,39 @@ func (h *Handler) removePublicShare(w http.ResponseWriter, r *http.Request, shar response.WriteOCSSuccess(w, r, nil) } +// enforcePassword validate Password enforce based on configuration +// read_only: 1 +// read_write: 3 or 5 +// read_write_delete: 15 +// upload_only: 4 +func (h *Handler) enforcePassword(pk *int) bool { + if pk == nil { + return false + } + p, err := conversions.NewPermissions(decreasePermissionsIfNecessary(*pk)) + if err != nil { + return false + } + if h.publicPasswordEnforced.EnforcedForReadOnly && + p == conversions.PermissionRead { + return true + } + if h.publicPasswordEnforced.EnforcedForReadWrite && + (p == conversions.PermissionRead|conversions.PermissionWrite || + p == conversions.PermissionRead|conversions.PermissionCreate) { + return true + } + if h.publicPasswordEnforced.EnforcedForReadWriteDelete && + p == conversions.PermissionRead|conversions.PermissionWrite|conversions.PermissionCreate|conversions.PermissionDelete { + return true + } + if h.publicPasswordEnforced.EnforcedForUploadOnly && + p == conversions.PermissionCreate { + return true + } + return false +} + // for public links oc10 api decreases all permissions to read: stay compatible! func decreasePermissionsIfNecessary(perm int) int { if perm == int(conversions.PermissionAll) { @@ -556,7 +600,7 @@ func decreasePermissionsIfNecessary(perm int) int { return perm } -func ocPublicPermToCs3(pk *int, h *Handler) (*provider.ResourcePermissions, error) { +func ocPublicPermToCs3(pk *int) (*provider.ResourcePermissions, error) { if pk == nil { return nil, nil } diff --git a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go index 97a55a9b8..7c675f9bd 100644 --- a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go +++ b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go @@ -86,6 +86,7 @@ type Handler struct { statCache cache.StatCache deniable bool resharing bool + publicPasswordEnforced passwordEnforced getClient GatewayClientGetter } @@ -103,6 +104,13 @@ type ocsError struct { Message string } +type passwordEnforced struct { + EnforcedForReadOnly bool + EnforcedForReadWrite bool + EnforcedForReadWriteDelete bool + EnforcedForUploadOnly bool +} + func getCacheWarmupManager(c *config.Config) (sharecache.Warmup, error) { if f, ok := warmupreg.NewFuncs[c.CacheWarmupDriver]; ok { return f(c.CacheWarmupDrivers[c.CacheWarmupDriver]) @@ -129,6 +137,7 @@ func (h *Handler) Init(c *config.Config) { _ = h.userIdentifierCache.SetTTL(time.Second * time.Duration(c.UserIdentifierCacheTTL)) h.deniable = c.EnableDenials h.resharing = resharing(c) + h.publicPasswordEnforced = publicPwdEnforced(c) h.statCache = cache.GetStatCache(c.StatCacheStore, c.StatCacheNodes, c.StatCacheDatabase, "stat", time.Duration(c.StatCacheTTL)*time.Second, c.StatCacheSize) if c.CacheWarmupDriver != "" { @@ -503,7 +512,7 @@ func (h *Handler) GetShare(w http.ResponseWriter, r *http.Request) { ctx := r.Context() sublog := appctx.GetLogger(ctx).With().Str("shareID", shareID).Logger() - client, err := pool.GetGatewayServiceClient(h.gatewayAddr) + client, err := h.getClient() if err != nil { response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error getting grpc gateway client", err) return @@ -695,7 +704,7 @@ func (h *Handler) updateShare(w http.ResponseWriter, r *http.Request, share *col ctx := r.Context() sublog := appctx.GetLogger(ctx).With().Str("shareID", share.GetId().GetOpaqueId()).Logger() - client, err := pool.GetGatewayServiceClient(h.gatewayAddr) + client, err := h.getClient() if err != nil { response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error getting grpc gateway client", err) return @@ -1110,7 +1119,7 @@ func (h *Handler) addFilters(w http.ResponseWriter, r *http.Request, ref *provid ctx := r.Context() // first check if the file exists - client, err := pool.GetGatewayServiceClient(h.gatewayAddr) + client, err := h.getClient() if err != nil { response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error getting grpc gateway client", err) return nil, nil, err @@ -1159,7 +1168,7 @@ func (h *Handler) addFileInfo(ctx context.Context, s *conversions.ShareData, inf switch { case h.sharePrefix == "/": s.FileTarget = info.Path - client, err := pool.GetGatewayServiceClient(h.gatewayAddr) + client, err := h.getClient() if err == nil { gpRes, err := client.GetPath(ctx, &provider.GetPathRequest{ ResourceId: info.Id, @@ -1538,6 +1547,23 @@ func (h *Handler) granteeExists(ctx context.Context, g *provider.Grantee, rid *p return false, nil } +func publicPwdEnforced(c *config.Config) passwordEnforced { + enf := passwordEnforced{} + if c == nil || + c.Capabilities.Capabilities == nil || + c.Capabilities.Capabilities.FilesSharing == nil || + c.Capabilities.Capabilities.FilesSharing.Public == nil || + c.Capabilities.Capabilities.FilesSharing.Public.Password == nil || + c.Capabilities.Capabilities.FilesSharing.Public.Password.EnforcedFor == nil { + return enf + } + enf.EnforcedForReadOnly = bool(c.Capabilities.Capabilities.FilesSharing.Public.Password.EnforcedFor.ReadOnly) + enf.EnforcedForReadWrite = bool(c.Capabilities.Capabilities.FilesSharing.Public.Password.EnforcedFor.ReadWrite) + enf.EnforcedForReadWriteDelete = bool(c.Capabilities.Capabilities.FilesSharing.Public.Password.EnforcedFor.ReadWriteDelete) + enf.EnforcedForUploadOnly = bool(c.Capabilities.Capabilities.FilesSharing.Public.Password.EnforcedFor.UploadOnly) + return enf +} + // sufficientPermissions returns true if the `existing` permissions contain the `requested` permissions func sufficientPermissions(existing, requested *provider.ResourcePermissions, islink bool) bool { ep := conversions.RoleFromResourcePermissions(existing, islink).OCSPermissions() diff --git a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/spaces.go b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/spaces.go index 90d34f561..7956918ff 100644 --- a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/spaces.go +++ b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/spaces.go @@ -44,7 +44,7 @@ import ( func (h *Handler) getGrantee(ctx context.Context, name string) (provider.Grantee, error) { log := appctx.GetLogger(ctx) - client, err := pool.GetGatewayServiceClient(h.gatewayAddr) + client, err := h.getClient() if err != nil { return provider.Grantee{}, err } @@ -96,7 +96,7 @@ func (h *Handler) addSpaceMember(w http.ResponseWriter, r *http.Request, info *p return } - client, err := pool.GetGatewayServiceClient(h.gatewayAddr) + client, err := h.getClient() if err != nil { response.WriteOCSError(w, r, response.MetaNotFound.StatusCode, "error getting gateway client", err) return @@ -226,7 +226,7 @@ func (h *Handler) removeSpaceMember(w http.ResponseWriter, r *http.Request, spac return } - gatewayClient, err := pool.GetGatewayServiceClient(h.gatewayAddr) + gatewayClient, err := h.getClient() if err != nil { response.WriteOCSError(w, r, response.MetaNotFound.StatusCode, "error getting gateway client", err) return diff --git a/vendor/github.com/cs3org/reva/v2/pkg/share/manager/jsoncs3/jsoncs3.go b/vendor/github.com/cs3org/reva/v2/pkg/share/manager/jsoncs3/jsoncs3.go index c5587e761..9bd39f3dc 100644 --- a/vendor/github.com/cs3org/reva/v2/pkg/share/manager/jsoncs3/jsoncs3.go +++ b/vendor/github.com/cs3org/reva/v2/pkg/share/manager/jsoncs3/jsoncs3.go @@ -29,6 +29,12 @@ import ( "sync" "time" + gatewayv1beta1 "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" + userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" + rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" + collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1" + provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" + "github.com/go-micro/plugins/v4/events/natsjs" "github.com/google/uuid" "github.com/mitchellh/mapstructure" "github.com/pkg/errors" @@ -37,11 +43,6 @@ import ( "golang.org/x/sync/errgroup" "google.golang.org/genproto/protobuf/field_mask" - gatewayv1beta1 "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" - userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" - rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" - collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1" - provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" "github.com/cs3org/reva/v2/pkg/appctx" ctxpkg "github.com/cs3org/reva/v2/pkg/ctx" "github.com/cs3org/reva/v2/pkg/errtypes" @@ -57,7 +58,6 @@ import ( "github.com/cs3org/reva/v2/pkg/storage/utils/metadata" // nolint:staticcheck // we need the legacy package to convert V1 to V2 messages "github.com/cs3org/reva/v2/pkg/storagespace" "github.com/cs3org/reva/v2/pkg/utils" - "github.com/go-micro/plugins/v4/events/natsjs" ) /* @@ -333,83 +333,112 @@ func (m *Manager) Share(ctx context.Context, md *provider.ResourceInfo, g *colla Mtime: ts, } - err = m.Cache.Add(ctx, md.Id.StorageId, md.Id.SpaceId, shareID, s) - if _, ok := err.(errtypes.IsPreconditionFailed); ok { - if err := m.Cache.Sync(ctx, md.Id.StorageId, md.Id.SpaceId); err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, err.Error()) - return nil, err - } - err = m.Cache.Add(ctx, md.Id.StorageId, md.Id.SpaceId, shareID, s) - // TODO try more often? - } - if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, err.Error()) - return nil, err - } + eg, ctx := errgroup.WithContext(ctx) - err = m.CreatedCache.Add(ctx, s.GetCreator().GetOpaqueId(), shareID) - if _, ok := err.(errtypes.IsPreconditionFailed); ok { - if err := m.CreatedCache.Sync(ctx, s.GetCreator().GetOpaqueId()); err != nil { + eg.Go(func() error { + err := m.Cache.Add(ctx, md.Id.StorageId, md.Id.SpaceId, shareID, s) + if _, ok := err.(errtypes.IsPreconditionFailed); ok { + if err := m.Cache.Sync(ctx, md.Id.StorageId, md.Id.SpaceId); err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, err.Error()) + + return err + } + + err = m.Cache.Add(ctx, md.Id.StorageId, md.Id.SpaceId, shareID, s) + // TODO try more often? + } + + if err != nil { span.RecordError(err) span.SetStatus(codes.Error, err.Error()) - return nil, err } - err = m.CreatedCache.Add(ctx, s.GetCreator().GetOpaqueId(), shareID) - // TODO try more often? - } - if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, err.Error()) - return nil, err - } + + return err + }) + + eg.Go(func() error { + err := m.CreatedCache.Add(ctx, s.GetCreator().GetOpaqueId(), shareID) + if _, ok := err.(errtypes.IsPreconditionFailed); ok { + if err := m.CreatedCache.Sync(ctx, s.GetCreator().GetOpaqueId()); err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, err.Error()) + + return err + } + + err = m.CreatedCache.Add(ctx, s.GetCreator().GetOpaqueId(), shareID) + // TODO try more often? + } + + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, err.Error()) + } + + return err + }) spaceID := md.Id.StorageId + shareid.IDDelimiter + md.Id.SpaceId // set flag for grantee to have access to share switch g.Grantee.Type { case provider.GranteeType_GRANTEE_TYPE_USER: - userid := g.Grantee.GetUserId().GetOpaqueId() + eg.Go(func() error { + userid := g.Grantee.GetUserId().GetOpaqueId() - rs := &collaboration.ReceivedShare{ - Share: s, - State: collaboration.ShareState_SHARE_STATE_PENDING, - } - err = m.UserReceivedStates.Add(ctx, userid, spaceID, rs) - if _, ok := err.(errtypes.IsPreconditionFailed); ok { - if err := m.UserReceivedStates.Sync(ctx, s.GetCreator().GetOpaqueId()); err != nil { + rs := &collaboration.ReceivedShare{ + Share: s, + State: collaboration.ShareState_SHARE_STATE_PENDING, + } + err := m.UserReceivedStates.Add(ctx, userid, spaceID, rs) + if _, ok := err.(errtypes.IsPreconditionFailed); ok { + if err := m.UserReceivedStates.Sync(ctx, s.GetCreator().GetOpaqueId()); err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, err.Error()) + return err + } + + err = m.UserReceivedStates.Add(ctx, userid, spaceID, rs) + // TODO try more often? + } + + if err != nil { span.RecordError(err) span.SetStatus(codes.Error, err.Error()) - return nil, err } - err = m.UserReceivedStates.Add(ctx, userid, spaceID, rs) - // TODO try more often? - } - if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, err.Error()) - return nil, err - } + + return err + }) case provider.GranteeType_GRANTEE_TYPE_GROUP: - groupid := g.Grantee.GetGroupId().GetOpaqueId() - err := m.GroupReceivedCache.Add(ctx, groupid, shareID) - if _, ok := err.(errtypes.IsPreconditionFailed); ok { - if err := m.GroupReceivedCache.Sync(ctx, groupid); err != nil { + eg.Go(func() error { + groupid := g.Grantee.GetGroupId().GetOpaqueId() + err := m.GroupReceivedCache.Add(ctx, groupid, shareID) + if _, ok := err.(errtypes.IsPreconditionFailed); ok { + if err := m.GroupReceivedCache.Sync(ctx, groupid); err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, err.Error()) + return err + } + + err = m.GroupReceivedCache.Add(ctx, groupid, shareID) + // TODO try more often? + } + + if err != nil { span.RecordError(err) span.SetStatus(codes.Error, err.Error()) - return nil, err } - err = m.GroupReceivedCache.Add(ctx, groupid, shareID) - // TODO try more often? - } - if err != nil { - span.RecordError(err) - span.SetStatus(codes.Error, err.Error()) - return nil, err - } + + return err + }) + } + + if err = eg.Wait(); err != nil { + return nil, err } span.SetStatus(codes.Ok, "") + return s, nil } @@ -1087,33 +1116,36 @@ func (m *Manager) removeShare(ctx context.Context, s *collaboration.Share) error ctx, span := appctx.GetTracerProvider(ctx).Tracer(tracerName).Start(ctx, "removeShare") defer span.End() - storageID, spaceID, _ := shareid.Decode(s.Id.OpaqueId) - err := m.Cache.Remove(ctx, storageID, spaceID, s.Id.OpaqueId) - if _, ok := err.(errtypes.IsPreconditionFailed); ok { - if err := m.Cache.Sync(ctx, storageID, spaceID); err != nil { - return err + eg, ctx := errgroup.WithContext(ctx) + eg.Go(func() error { + storageID, spaceID, _ := shareid.Decode(s.Id.OpaqueId) + err := m.Cache.Remove(ctx, storageID, spaceID, s.Id.OpaqueId) + if _, ok := err.(errtypes.IsPreconditionFailed); ok { + if err := m.Cache.Sync(ctx, storageID, spaceID); err != nil { + return err + } + err = m.Cache.Remove(ctx, storageID, spaceID, s.Id.OpaqueId) + // TODO try more often? } - err = m.Cache.Remove(ctx, storageID, spaceID, s.Id.OpaqueId) - // TODO try more often? - } - if err != nil { - return err - } - // remove from created cache - err = m.CreatedCache.Remove(ctx, s.GetCreator().GetOpaqueId(), s.Id.OpaqueId) - if _, ok := err.(errtypes.IsPreconditionFailed); ok { - if err := m.CreatedCache.Sync(ctx, s.GetCreator().GetOpaqueId()); err != nil { - return err - } - err = m.CreatedCache.Remove(ctx, s.GetCreator().GetOpaqueId(), s.Id.OpaqueId) - // TODO try more often? - } - if err != nil { return err - } + }) + + eg.Go(func() error { + // remove from created cache + err := m.CreatedCache.Remove(ctx, s.GetCreator().GetOpaqueId(), s.Id.OpaqueId) + if _, ok := err.(errtypes.IsPreconditionFailed); ok { + if err := m.CreatedCache.Sync(ctx, s.GetCreator().GetOpaqueId()); err != nil { + return err + } + err = m.CreatedCache.Remove(ctx, s.GetCreator().GetOpaqueId(), s.Id.OpaqueId) + // TODO try more often? + } + + return err + }) // TODO remove from grantee cache - return nil + return eg.Wait() } diff --git a/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/spaces.go b/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/spaces.go index 0ddd32f33..96285f784 100644 --- a/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/spaces.go +++ b/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/spaces.go @@ -27,6 +27,7 @@ import ( "path/filepath" "strconv" "strings" + "sync/atomic" "time" userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" @@ -49,6 +50,7 @@ import ( "github.com/cs3org/reva/v2/pkg/utils" "github.com/google/uuid" "github.com/pkg/errors" + "golang.org/x/sync/errgroup" ) const ( @@ -429,66 +431,106 @@ func (fs *Decomposedfs) ListStorageSpaces(ctx context.Context, filter []*provide // But what about sharding nodes by space? // an efficient lookup would be possible if we received a spaceid&opaqueid in the request // the personal spaces must also use the nodeid and not the name + numShares := atomic.Int64{} + errg, ctx := errgroup.WithContext(ctx) + work := make(chan string, len(matches)) + results := make(chan *provider.StorageSpace, len(matches)) - numShares := 0 - - for match := range matches { - var err error - // TODO introduce metadata.IsLockFile(path) - // do not investigate flock files any further. They indicate file locks but are not relevant here. - if strings.HasSuffix(match, filelocks.LockFileSuffix) { - continue - } - // skip metadata files - if fs.lu.MetadataBackend().IsMetaFile(match) { - continue - } - // always read link in case storage space id != node id - spaceID, nodeID, err = ReadSpaceAndNodeFromIndexLink(match) - if err != nil { - appctx.GetLogger(ctx).Error().Err(err).Str("match", match).Msg("could not read link, skipping") - continue - } - - n, err := node.ReadNode(ctx, fs.lu, spaceID, nodeID, true, nil, true) - if err != nil { - appctx.GetLogger(ctx).Error().Err(err).Str("id", nodeID).Msg("could not read node, skipping") - continue - } - - if !n.Exists { - continue - } - - space, err := fs.storageSpaceFromNode(ctx, n, checkNodePermissions) - if err != nil { - switch err.(type) { - case errtypes.IsPermissionDenied: - // ok - case errtypes.NotFound: - // ok - default: - appctx.GetLogger(ctx).Error().Err(err).Str("id", nodeID).Msg("could not convert to storage space") + // Distribute work + errg.Go(func() error { + defer close(work) + for match := range matches { + select { + case work <- match: + case <-ctx.Done(): + return ctx.Err() } - continue } + return nil + }) - // FIXME type share evolved to grant on the edge branch ... make it configurable if the driver should support them or not for now ... ignore type share - if space.SpaceType == spaceTypeShare { - numShares++ - // do not list shares as spaces for the owner - continue - } - - // TODO apply more filters - _, ok1 := spaceTypes[spaceTypeAny] - _, ok2 := spaceTypes[space.SpaceType] - if ok1 || ok2 { - spaces = append(spaces, space) - } + // Spawn workers that'll concurrently work the queue + numWorkers := 20 + if len(matches) < numWorkers { + numWorkers = len(matches) } + for i := 0; i < numWorkers; i++ { + errg.Go(func() error { + for match := range work { + var err error + // TODO introduce metadata.IsLockFile(path) + // do not investigate flock files any further. They indicate file locks but are not relevant here. + if strings.HasSuffix(match, filelocks.LockFileSuffix) { + continue + } + // skip metadata files + if fs.lu.MetadataBackend().IsMetaFile(match) { + continue + } + // always read link in case storage space id != node id + spaceID, nodeID, err = ReadSpaceAndNodeFromIndexLink(match) + if err != nil { + appctx.GetLogger(ctx).Error().Err(err).Str("match", match).Msg("could not read link, skipping") + continue + } + + n, err := node.ReadNode(ctx, fs.lu, spaceID, nodeID, true, nil, true) + if err != nil { + appctx.GetLogger(ctx).Error().Err(err).Str("id", nodeID).Msg("could not read node, skipping") + continue + } + + if !n.Exists { + continue + } + + space, err := fs.storageSpaceFromNode(ctx, n, checkNodePermissions) + if err != nil { + switch err.(type) { + case errtypes.IsPermissionDenied: + // ok + case errtypes.NotFound: + // ok + default: + appctx.GetLogger(ctx).Error().Err(err).Str("id", nodeID).Msg("could not convert to storage space") + } + continue + } + + // FIXME type share evolved to grant on the edge branch ... make it configurable if the driver should support them or not for now ... ignore type share + if space.SpaceType == spaceTypeShare { + numShares.Add(1) + // do not list shares as spaces for the owner + continue + } + + // TODO apply more filters + _, ok1 := spaceTypes[spaceTypeAny] + _, ok2 := spaceTypes[space.SpaceType] + if ok1 || ok2 { + select { + case results <- space: + case <-ctx.Done(): + return ctx.Err() + } + } + } + return nil + }) + } + + // Wait for things to settle down, then close results chan + go func() { + _ = errg.Wait() // error is checked later + close(results) + }() + + for r := range results { + spaces = append(spaces, r) + } + // if there are no matches (or they happened to be spaces for the owner) and the node is a child return a space - if len(matches) <= numShares && nodeID != spaceID { + if int64(len(matches)) <= numShares.Load() && nodeID != spaceID { // try node id n, err := node.ReadNode(ctx, fs.lu, spaceID, nodeID, true, nil, false) // permission to read disabled space is checked in storageSpaceFromNode if err != nil { diff --git a/vendor/github.com/cs3org/reva/v2/pkg/utils/ldap/reconnect.go b/vendor/github.com/cs3org/reva/v2/pkg/utils/ldap/reconnect.go index 13a913652..684d6d60d 100644 --- a/vendor/github.com/cs3org/reva/v2/pkg/utils/ldap/reconnect.go +++ b/vendor/github.com/cs3org/reva/v2/pkg/utils/ldap/reconnect.go @@ -163,10 +163,10 @@ func (c *ConnWithReconnect) getConnection() (*ldap.Conn, error) { } func (c *ConnWithReconnect) ldapAutoConnect(config Config) { - l, err := c.ldapConnect(config) - if err != nil { - c.logger.Debug().Err(err).Msg("autoconnect could not get ldap Connection") - } + var ( + l *ldap.Conn + err error + ) for { select { @@ -203,7 +203,7 @@ func (c *ConnWithReconnect) ldapConnect(config Config) (*ldap.Conn, error) { } if err != nil { - c.logger.Debug().Err(err).Msg("could not get ldap Connection") + c.logger.Error().Err(err).Msg("could not get ldap Connection") return nil, err } c.logger.Debug().Msg("LDAP Connected") diff --git a/vendor/modules.txt b/vendor/modules.txt index f6baa8bb8..c1534c019 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -352,7 +352,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.14.1-0.20230619124027-9bd3d7359257 +# github.com/cs3org/reva/v2 v2.14.1-0.20230621095551-a4c97189e11a ## explicit; go 1.20 github.com/cs3org/reva/v2/cmd/revad/internal/grace github.com/cs3org/reva/v2/cmd/revad/runtime