From c47a48a50b2d9a11165bfe4082c8938e4339fafd Mon Sep 17 00:00:00 2001 From: jkoberg Date: Wed, 4 Oct 2023 14:43:10 +0200 Subject: [PATCH 1/2] delete outdated userlog events Signed-off-by: jkoberg --- changelog/unreleased/bump-reva.md | 1 + .../unreleased/delete-outdated-userlog-events.md | 5 +++++ services/userlog/pkg/service/http.go | 15 +++++++++++++++ 3 files changed, 21 insertions(+) create mode 100644 changelog/unreleased/delete-outdated-userlog-events.md diff --git a/changelog/unreleased/bump-reva.md b/changelog/unreleased/bump-reva.md index 5052a056b6..5751ff4e10 100644 --- a/changelog/unreleased/bump-reva.md +++ b/changelog/unreleased/bump-reva.md @@ -6,3 +6,4 @@ https://github.com/owncloud/ocis/pull/7138 https://github.com/owncloud/ocis/pull/6427 https://github.com/owncloud/ocis/pull/7178 https://github.com/owncloud/ocis/pull/7217 +https://github.com/owncloud/ocis/pull/7410 diff --git a/changelog/unreleased/delete-outdated-userlog-events.md b/changelog/unreleased/delete-outdated-userlog-events.md new file mode 100644 index 0000000000..df0ea8e9c2 --- /dev/null +++ b/changelog/unreleased/delete-outdated-userlog-events.md @@ -0,0 +1,5 @@ +Bugfix: Delete outdated userlog events + +Userlog will now delete events when the user has no longer access to the underlying resource + +https://github.com/owncloud/ocis/pull/7410 diff --git a/services/userlog/pkg/service/http.go b/services/userlog/pkg/service/http.go index 0d13f1c810..b869d3e154 100644 --- a/services/userlog/pkg/service/http.go +++ b/services/userlog/pkg/service/http.go @@ -61,6 +61,7 @@ func (ul *UserlogService) HandleGetEvents(w http.ResponseWriter, r *http.Request conv := NewConverter(ctx, r.Header.Get(HeaderAcceptLanguage), gwc, ul.cfg.Service.Name, ul.cfg.TranslationPath) + var outdatedEvents []string resp := GetEventResponseOC10{} for _, e := range evs { etype, ok := ul.registeredEvents[e.Type] @@ -77,6 +78,10 @@ func (ul *UserlogService) HandleGetEvents(w http.ResponseWriter, r *http.Request noti, err := conv.ConvertEvent(e.Id, einterface) if err != nil { + if utils.IsErrNotFound(err) || utils.IsErrPermissionDenied(err) { + outdatedEvents = append(outdatedEvents, e.Id) + continue + } ul.log.Error().Err(err).Str("eventid", e.Id).Str("eventtype", e.Type).Msg("failed to convert event") continue } @@ -84,6 +89,16 @@ func (ul *UserlogService) HandleGetEvents(w http.ResponseWriter, r *http.Request resp.OCS.Data = append(resp.OCS.Data, noti) } + // delete outdated events asynchronously + if len(outdatedEvents) > 0 { + go func() { + err := ul.DeleteEvents(u.GetId().GetOpaqueId(), outdatedEvents) + if err != nil { + ul.log.Error().Err(err).Msg("failed to delete events") + } + }() + } + glevs, err := ul.GetGlobalEvents(ctx) if err != nil { ul.log.Error().Err(err).Int("returned statuscode", http.StatusInternalServerError).Msg("get global events failed") From 3b08e24581bb55f8ab62c219a8487143bdef202d Mon Sep 17 00:00:00 2001 From: jkoberg Date: Wed, 4 Oct 2023 14:35:06 +0200 Subject: [PATCH 2/2] bump reva Signed-off-by: jkoberg --- go.mod | 2 +- go.sum | 4 +- .../http/services/owncloud/ocdav/copy.go | 11 +++- .../http/services/owncloud/ocdav/move.go | 25 ++++---- .../http/services/owncloud/ocdav/ocdav.go | 6 ++ .../cs3org/reva/v2/pkg/utils/grpc.go | 60 +++++++++++++++---- vendor/modules.txt | 2 +- 7 files changed, 79 insertions(+), 31 deletions(-) diff --git a/go.mod b/go.mod index 8e9a196a54..c060287f58 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.16.1-0.20230926132524-45fce234f21b + github.com/cs3org/reva/v2 v2.16.1-0.20231004143709-c089e31b8175 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 8f4e3ff121..418f7c09e4 100644 --- a/go.sum +++ b/go.sum @@ -1011,8 +1011,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.16.1-0.20230926132524-45fce234f21b h1:G5lYtoDjMLPvPJk9hXEVJoVTHJZEuCWZ2Wr+n0rpJAA= -github.com/cs3org/reva/v2 v2.16.1-0.20230926132524-45fce234f21b/go.mod h1:WFSfkOQNmUggMed4lUQTF2vd9hg0acvsHI6awGwnwxQ= +github.com/cs3org/reva/v2 v2.16.1-0.20231004143709-c089e31b8175 h1:3rWU0bw0q2SlaScyTKX5Xb5usVdznz4ygV2DnHKtlzM= +github.com/cs3org/reva/v2 v2.16.1-0.20231004143709-c089e31b8175/go.mod h1:WFSfkOQNmUggMed4lUQTF2vd9hg0acvsHI6awGwnwxQ= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= diff --git a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/copy.go b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/copy.go index 7b4bce24ee..7415b9cd0f 100644 --- a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/copy.go +++ b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/copy.go @@ -608,6 +608,11 @@ func (s *svc) prepareCopy(ctx context.Context, w http.ResponseWriter, r *http.Re errors.HandleErrorStatus(log, w, srcStatRes.Status) return nil } + if isSpaceRoot(srcStatRes.GetInfo()) { + log.Error().Msg("the source is disallowed") + w.WriteHeader(http.StatusBadRequest) + return nil + } dstStatReq := &provider.StatRequest{Ref: dstRef} dstStatRes, err := client.Stat(ctx, dstStatReq) @@ -625,6 +630,11 @@ func (s *svc) prepareCopy(ctx context.Context, w http.ResponseWriter, r *http.Re if dstStatRes.Status.Code == rpc.Code_CODE_OK { successCode = http.StatusNoContent // 204 if target already existed, see https://tools.ietf.org/html/rfc4918#section-9.8.5 + if isSpaceRoot(dstStatRes.GetInfo()) { + log.Error().Msg("overwriting is not allowed") + w.WriteHeader(http.StatusBadRequest) + return nil + } if !overwrite { log.Warn().Bool("overwrite", overwrite).Msg("dst already exists") w.WriteHeader(http.StatusPreconditionFailed) @@ -633,7 +643,6 @@ func (s *svc) prepareCopy(ctx context.Context, w http.ResponseWriter, r *http.Re errors.HandleWebdavError(log, w, b, err) // 412, see https://tools.ietf.org/html/rfc4918#section-9.8.5 return nil } - // delete existing tree when overwriting a directory or replacing a file with a directory if dstStatRes.Info.Type == provider.ResourceType_RESOURCE_TYPE_CONTAINER || (dstStatRes.Info.Type == provider.ResourceType_RESOURCE_TYPE_FILE && diff --git a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/move.go b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/move.go index 65d298c244..d0550ae624 100644 --- a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/move.go +++ b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/move.go @@ -141,12 +141,6 @@ func (s *svc) handleSpacesMove(w http.ResponseWriter, r *http.Request, srcSpaceI } func (s *svc) handleMove(ctx context.Context, w http.ResponseWriter, r *http.Request, src, dst *provider.Reference, log zerolog.Logger) { - // do not allow overwriting spaces - if err := s.validateDestination(dst); err != nil { - log.Error().Err(err) - w.WriteHeader(http.StatusPreconditionFailed) // 412, see https://tools.ietf.org/html/rfc4918#section-9.9.4 - return - } isChild, err := s.referenceIsChildOf(ctx, s.gatewaySelector, dst, src) if err != nil { switch err.(type) { @@ -200,6 +194,11 @@ func (s *svc) handleMove(ctx context.Context, w http.ResponseWriter, r *http.Req errors.HandleErrorStatus(&log, w, srcStatRes.Status) return } + if isSpaceRoot(srcStatRes.GetInfo()) { + log.Error().Msg("the source is disallowed") + w.WriteHeader(http.StatusBadRequest) + return + } // check dst exists dstStatReq := &provider.StatRequest{Ref: dst} @@ -218,12 +217,16 @@ func (s *svc) handleMove(ctx context.Context, w http.ResponseWriter, r *http.Req if dstStatRes.Status.Code == rpc.Code_CODE_OK { successCode = http.StatusNoContent // 204 if target already existed, see https://tools.ietf.org/html/rfc4918#section-9.9.4 + if isSpaceRoot(dstStatRes.GetInfo()) { + log.Error().Msg("overwriting is not allowed") + w.WriteHeader(http.StatusBadRequest) + return + } if !overwrite { log.Warn().Bool("overwrite", overwrite).Msg("dst already exists") w.WriteHeader(http.StatusPreconditionFailed) // 412, see https://tools.ietf.org/html/rfc4918#section-9.9.4 return } - // delete existing tree delReq := &provider.DeleteRequest{Ref: dst} delRes, err := client.Delete(ctx, delReq) @@ -311,11 +314,3 @@ func (s *svc) handleMove(ctx context.Context, w http.ResponseWriter, r *http.Req w.Header().Set(net.HeaderOCETag, info.Etag) w.WriteHeader(successCode) } - -func (s *svc) validateDestination(dstStatRes *provider.Reference) error { - // do not allow overwriting spaces - if dstStatRes.GetPath() == "." && dstStatRes.GetResourceId().GetOpaqueId() == dstStatRes.GetResourceId().GetSpaceId() { - return fmt.Errorf("overwriting is not allowed") - } - return nil -} diff --git a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/ocdav.go b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/ocdav.go index a96d11ebf4..840f6fe3e3 100644 --- a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/ocdav.go +++ b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/ocdav.go @@ -413,3 +413,9 @@ func (s *svc) referenceIsChildOf(ctx context.Context, selector pool.Selectable[g pp := path.Join(parentPathRes.Path, parent.Path) + "/" return strings.HasPrefix(cp, pp), nil } + +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/pkg/utils/grpc.go b/vendor/github.com/cs3org/reva/v2/pkg/utils/grpc.go index 662a0b32f9..0be65a67db 100644 --- a/vendor/github.com/cs3org/reva/v2/pkg/utils/grpc.go +++ b/vendor/github.com/cs3org/reva/v2/pkg/utils/grpc.go @@ -27,6 +27,14 @@ var ( ManagerRole SpaceRole = func(perms *storageprovider.ResourcePermissions) bool { return perms.DenyGrant } ) +var _errStatusCodeTmpl = "unexpected status code while %s: %v" + +// Package error checkers +var ( + IsErrNotFound = func(err error) bool { return IsStatusCodeError(err, rpc.Code_CODE_NOT_FOUND) } + IsErrPermissionDenied = func(err error) bool { return IsStatusCodeError(err, rpc.Code_CODE_PERMISSION_DENIED) } +) + // GetServiceUserContext returns an authenticated context of the given service user func GetServiceUserContext(serviceUserID string, gwc gateway.GatewayAPIClient, serviceUserSecret string) (context.Context, error) { ctx := context.Background() @@ -38,8 +46,9 @@ func GetServiceUserContext(serviceUserID string, gwc gateway.GatewayAPIClient, s if err != nil { return nil, err } - if authRes.GetStatus().GetCode() != rpc.Code_CODE_OK { - return nil, fmt.Errorf("error authenticating service user: %s", authRes.Status.Message) + + if err := checkStatusCode("authenticating service user", authRes.GetStatus().GetCode()); err != nil { + return nil, err } return metadata.AppendToOutgoingContext(ctx, revactx.TokenHeader, authRes.Token), nil @@ -51,8 +60,9 @@ func GetUser(userID *user.UserId, gwc gateway.GatewayAPIClient) (*user.User, err if err != nil { return nil, err } - if getUserResponse.Status.Code != rpc.Code_CODE_OK { - return nil, fmt.Errorf("error getting user: %s", getUserResponse.Status.Message) + + if err := checkStatusCode("getting user", getUserResponse.GetStatus().GetCode()); err != nil { + return nil, err } return getUserResponse.GetUser(), nil @@ -65,12 +75,12 @@ func GetSpace(ctx context.Context, spaceID string, gwc gateway.GatewayAPIClient) return nil, err } - if res.GetStatus().GetCode() != rpc.Code_CODE_OK { - return nil, fmt.Errorf("error while getting space: (%v) %s", res.GetStatus().GetCode(), res.GetStatus().GetMessage()) + if err := checkStatusCode("getting space", res.GetStatus().GetCode()); err != nil { + return nil, err } if len(res.StorageSpaces) == 0 { - return nil, fmt.Errorf("error getting storage space %s: no space returned", spaceID) + return nil, statusCodeError{"getting space", rpc.Code_CODE_NOT_FOUND} } return res.StorageSpaces[0], nil @@ -83,8 +93,8 @@ func GetGroupMembers(ctx context.Context, groupID string, gwc gateway.GatewayAPI return nil, err } - if r.GetStatus().GetCode() != rpc.Code_CODE_OK { - return nil, fmt.Errorf("unexpected status code from gateway client: %d", r.GetStatus().GetCode()) + if err := checkStatusCode("getting group", r.GetStatus().GetCode()); err != nil { + return nil, err } users := make([]string, 0, len(r.GetGroup().GetMembers())) @@ -147,13 +157,30 @@ func GetResource(ctx context.Context, ref *storageprovider.Reference, gwc gatewa return nil, err } - if res.GetStatus().GetCode() != rpc.Code_CODE_OK { - return nil, fmt.Errorf("unexpected status code while getting space: %v", res.GetStatus().GetCode()) + if err := checkStatusCode("getting resource", res.GetStatus().GetCode()); err != nil { + return nil, err } return res.GetInfo(), nil } +// IsStatusCodeError returns true if `err` was caused because of status code `code` +func IsStatusCodeError(err error, code rpc.Code) bool { + sce, ok := err.(statusCodeError) + if !ok { + return false + } + + return sce.code == code +} + +func checkStatusCode(reason string, code rpc.Code) error { + if code == rpc.Code_CODE_OK { + return nil + } + return statusCodeError{reason, code} +} + func gatherProjectSpaceMembers(ctx context.Context, space *storageprovider.StorageSpace, gwc gateway.GatewayAPIClient, role SpaceRole) ([]string, error) { var permissionsMap map[string]*storageprovider.ResourcePermissions if err := ReadJSONFromOpaque(space.GetOpaque(), "grants", &permissionsMap); err != nil { @@ -215,3 +242,14 @@ func listStorageSpaceRequest(spaceID string) *storageprovider.ListStorageSpacesR }, } } + +// statusCodeError is a helper struct to return errors +type statusCodeError struct { + reason string + code rpc.Code +} + +// Error implements error interface +func (sce statusCodeError) Error() string { + return fmt.Sprintf(_errStatusCodeTmpl, sce.reason, sce.code) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 813d8e3384..68cbcae76f 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -357,7 +357,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.16.1-0.20230926132524-45fce234f21b +# github.com/cs3org/reva/v2 v2.16.1-0.20231004143709-c089e31b8175 ## explicit; go 1.20 github.com/cs3org/reva/v2/cmd/revad/internal/grace github.com/cs3org/reva/v2/cmd/revad/runtime