diff --git a/changelog/unreleased/fix-remove-update-share.md b/changelog/unreleased/fix-remove-update-share.md new file mode 100644 index 00000000000..9740a060126 --- /dev/null +++ b/changelog/unreleased/fix-remove-update-share.md @@ -0,0 +1,8 @@ +Bugfix: Fix remove/update share permissions + +This is a workaround that should prevent removing or changing the share permissions when the file is locked. +These limitations have to be removed after the wopi server will be able to unlock the file properly. +These limitations are not spread on the files inside the shared folder. + +https://github.com/cs3org/reva/pull/4534 +https://github.com/owncloud/ocis/issues/8273 diff --git a/internal/grpc/services/gateway/usershareprovider.go b/internal/grpc/services/gateway/usershareprovider.go index d9677866f4f..553f2bdb033 100644 --- a/internal/grpc/services/gateway/usershareprovider.go +++ b/internal/grpc/services/gateway/usershareprovider.go @@ -106,6 +106,15 @@ func (s *svc) ListShares(ctx context.Context, req *collaboration.ListSharesReque } func (s *svc) updateShare(ctx context.Context, req *collaboration.UpdateShareRequest) (*collaboration.UpdateShareResponse, error) { + // TODO: update wopi server + // FIXME This is a workaround that should prevent removing or changing the share permissions when the file is locked. + // https://github.com/owncloud/ocis/issues/8474 + if status, err := s.checkLock(ctx, req.GetShare().GetId()); err != nil { + return &collaboration.UpdateShareResponse{ + Status: status, + }, nil + } + c, err := pool.GetUserShareProviderClient(s.c.UserShareProviderEndpoint) if err != nil { appctx.GetLogger(ctx). @@ -657,6 +666,15 @@ func (s *svc) removeShare(ctx context.Context, req *collaboration.RemoveShareReq share = getShareRes.Share } + // TODO: update wopi server + // FIXME This is a workaround that should prevent removing or changing the share permissions when the file is locked. + // https://github.com/owncloud/ocis/issues/8474 + if status, err := s.checkShareLock(ctx, share); err != nil { + return &collaboration.RemoveShareResponse{ + Status: status, + }, nil + } + res, err := c.RemoveShare(ctx, req) if err != nil { return nil, errors.Wrap(err, "gateway: error calling RemoveShare") @@ -712,6 +730,55 @@ func (s *svc) removeSpaceShare(ctx context.Context, ref *provider.ResourceId, gr return &collaboration.RemoveShareResponse{Status: status.NewOK(ctx)}, nil } +func (s *svc) checkLock(ctx context.Context, shareId *collaboration.ShareId) (*rpc.Status, error) { + logger := appctx.GetLogger(ctx) + getShareRes, err := s.GetShare(ctx, &collaboration.GetShareRequest{ + Ref: &collaboration.ShareReference{ + Spec: &collaboration.ShareReference_Id{Id: shareId}, + }, + }) + if err != nil { + msg := "gateway: error calling GetShare" + logger.Err(err).Interface("share_id", shareId).Msg(msg) + return status.NewInternal(ctx, msg), errors.Wrap(err, msg) + } + if getShareRes.GetStatus().GetCode() != rpc.Code_CODE_OK { + msg := "can not get share stat " + getShareRes.GetStatus().GetMessage() + logger.Debug().Interface("share", shareId).Msg(msg) + if getShareRes.GetStatus().GetCode() != rpc.Code_CODE_NOT_FOUND { + return status.NewNotFound(ctx, msg), errors.New(msg) + } + return status.NewInternal(ctx, msg), errors.New(msg) + } + return s.checkShareLock(ctx, getShareRes.Share) +} + +func (s *svc) checkShareLock(ctx context.Context, share *collaboration.Share) (*rpc.Status, error) { + logger := appctx.GetLogger(ctx) + sRes, err := s.Stat(ctx, &provider.StatRequest{Ref: &provider.Reference{ResourceId: share.GetResourceId()}, + ArbitraryMetadataKeys: []string{"lockdiscovery"}}) + if err != nil { + msg := "failed to stat shared resource" + logger.Err(err).Interface("resource_id", share.GetResourceId()).Msg(msg) + return status.NewInternal(ctx, msg), errors.Wrap(err, msg) + } + if sRes.GetStatus().GetCode() != rpc.Code_CODE_OK { + msg := "can not get share stat " + sRes.GetStatus().GetMessage() + logger.Debug().Interface("lock", sRes.GetInfo().GetLock()).Msg(msg) + if sRes.GetStatus().GetCode() != rpc.Code_CODE_NOT_FOUND { + return status.NewNotFound(ctx, msg), errors.New(msg) + } + return status.NewInternal(ctx, msg), errors.New(msg) + } + + if sRes.GetInfo().GetLock() != nil { + msg := "can not chane grants, the shared resource is locked" + logger.Debug().Interface("lock", sRes.GetInfo().GetLock()).Msg(msg) + return status.NewLocked(ctx, msg), errors.New(msg) + } + return nil, nil +} + func refIsSpaceRoot(ref *provider.ResourceId) bool { if ref == nil { return false diff --git a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go index 6ebcaf37f7a..694273866e7 100644 --- a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go +++ b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go @@ -850,9 +850,13 @@ func (h *Handler) updateShare(w http.ResponseWriter, r *http.Request, share *col } if uRes.Status.Code != rpc.Code_CODE_OK { - if uRes.Status.Code == rpc.Code_CODE_NOT_FOUND { + switch uRes.Status.Code { + case rpc.Code_CODE_NOT_FOUND: response.WriteOCSError(w, r, response.MetaNotFound.StatusCode, "not found", nil) return + case rpc.Code_CODE_LOCKED: + response.WriteOCSError(w, r, response.MetaLocked.StatusCode, uRes.GetStatus().GetMessage(), nil) + return } response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "grpc update share request failed", err) return diff --git a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/user.go b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/user.go index dd940741b2f..65247a94430 100644 --- a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/user.go +++ b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/user.go @@ -293,9 +293,13 @@ func (h *Handler) removeUserShare(w http.ResponseWriter, r *http.Request, share } if uRes.Status.Code != rpc.Code_CODE_OK { - if uRes.Status.Code == rpc.Code_CODE_NOT_FOUND { + switch uRes.Status.Code { + case rpc.Code_CODE_NOT_FOUND: response.WriteOCSError(w, r, response.MetaNotFound.StatusCode, "not found", nil) return + case rpc.Code_CODE_LOCKED: + response.WriteOCSError(w, r, response.MetaLocked.StatusCode, uRes.GetStatus().GetMessage(), nil) + return } response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "grpc delete share request failed", err) return diff --git a/pkg/storage/utils/decomposedfs/node/locks.go b/pkg/storage/utils/decomposedfs/node/locks.go index b968ef3aa41..3e0d3656dfb 100644 --- a/pkg/storage/utils/decomposedfs/node/locks.go +++ b/pkg/storage/utils/decomposedfs/node/locks.go @@ -296,6 +296,7 @@ func readLocksIntoOpaque(ctx context.Context, n *Node, ri *provider.ResourceInfo Decoder: "json", Value: b, } + ri.Lock = lock return err }