[full-ci] [reva bump] fix an error when lock/unlock a file

(cherry picked from commit 6fb545b3c1)
This commit is contained in:
Roman Perekhod
2024-03-12 16:49:33 +01:00
committed by Ralf Haferkamp
parent ab43efd3c4
commit 267ed92cab
10 changed files with 154 additions and 68 deletions
@@ -0,0 +1,6 @@
Bugfix: Fix an error when lock/unlock a public shared file
We fixed a bug when anonymous user with viewer role in public link of a folder can lock/unlock a file inside it
https://github.com/owncloud/ocis/pull/8472
https://github.com/owncloud/ocis/issues/7785
+1 -1
View File
@@ -13,7 +13,7 @@ require (
github.com/cenkalti/backoff v2.2.1+incompatible github.com/cenkalti/backoff v2.2.1+incompatible
github.com/coreos/go-oidc/v3 v3.9.0 github.com/coreos/go-oidc/v3 v3.9.0
github.com/cs3org/go-cs3apis v0.0.0-20231023073225-7748710e0781 github.com/cs3org/go-cs3apis v0.0.0-20231023073225-7748710e0781
github.com/cs3org/reva/v2 v2.19.2-0.20240307063856-698d86209c3d github.com/cs3org/reva/v2 v2.19.2-0.20240307091744-fa2caba1f4e4
github.com/dhowden/tag v0.0.0-20230630033851-978a0926ee25 github.com/dhowden/tag v0.0.0-20230630033851-978a0926ee25
github.com/disintegration/imaging v1.6.2 github.com/disintegration/imaging v1.6.2
github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e
+2 -2
View File
@@ -1019,8 +1019,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/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 h1:BUdwkIlf8IS2FasrrPg8gGPHQPOrQ18MS1Oew2tmGtY=
github.com/cs3org/go-cs3apis v0.0.0-20231023073225-7748710e0781/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY= 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.20240307063856-698d86209c3d h1:ru/ebNMHDU0SJ9CyzYY9uHMpFXGXT4cDaAh6zib4xPg= github.com/cs3org/reva/v2 v2.19.2-0.20240307091744-fa2caba1f4e4 h1:dOApLUv2cYnWU1Z8pqEBk8a9BEGe6VRl/f0sFmwzLw4=
github.com/cs3org/reva/v2 v2.19.2-0.20240307063856-698d86209c3d/go.mod h1:GRUrOp5HbFVwZTgR9bVrMZ/MvVy+Jhxw1PdMmhhKP9E= github.com/cs3org/reva/v2 v2.19.2-0.20240307091744-fa2caba1f4e4/go.mod h1:GRUrOp5HbFVwZTgR9bVrMZ/MvVy+Jhxw1PdMmhhKP9E=
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= 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 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
@@ -238,15 +238,6 @@ The expected failures in this file are from features in the owncloud/ocis repo.
- [apiLocks/lockFiles.feature:500](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiLocks/lockFiles.feature#L500) - [apiLocks/lockFiles.feature:500](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiLocks/lockFiles.feature#L500)
- [apiLocks/lockFiles.feature:501](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiLocks/lockFiles.feature#L501) - [apiLocks/lockFiles.feature:501](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiLocks/lockFiles.feature#L501)
### [anonymous user with viewer role in public link of a folder can lock a file inside it](https://github.com/owncloud/ocis/issues/7785)
- [apiLocks/lockFiles.feature:452](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiLocks/lockFiles.feature#L452)
- [apiLocks/lockFiles.feature:453](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiLocks/lockFiles.feature#L453)
- [apiLocks/lockFiles.feature:454](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiLocks/lockFiles.feature#L454)
- [apiLocks/lockFiles.feature:455](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiLocks/lockFiles.feature#L455)
- [apiLocks/lockFiles.feature:456](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiLocks/lockFiles.feature#L456)
- [apiLocks/lockFiles.feature:457](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiLocks/lockFiles.feature#L457)
### [blocksDownload link type is not implemented yet (sharing-ng)](https://github.com/owncloud/ocis/issues/7879) ### [blocksDownload link type is not implemented yet (sharing-ng)](https://github.com/owncloud/ocis/issues/7879)
- [apiSharingNg/linkShare.feature:78](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiSharingNg/linkShare.feature#L78) - [apiSharingNg/linkShare.feature:78](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiSharingNg/linkShare.feature#L78)
@@ -1057,11 +1057,11 @@ func (s *service) resolveAcceptedShare(ctx context.Context, ref *provider.Refere
return lsRes.Share, lsRes.Status, nil return lsRes.Share, lsRes.Status, nil
} }
// we currently need to list all shares and match the path if the request is relative to the share jail root // we currently need to list all accepted shares and match the path if the
// request is relative to the share jail root. Also we need to Stat() the
// shared resource's id to check whether that still exist. There might be
// old shares using the same path but for an already vanished resource id.
if ref.ResourceId.OpaqueId == utils.ShareStorageProviderID && ref.Path != "." { if ref.ResourceId.OpaqueId == utils.ShareStorageProviderID && ref.Path != "." {
// we need to list accepted shares and match the path
// look up share for this resourceid
lsRes, err := sharingCollaborationClient.ListReceivedShares(ctx, &collaboration.ListReceivedSharesRequest{ lsRes, err := sharingCollaborationClient.ListReceivedShares(ctx, &collaboration.ListReceivedSharesRequest{
Filters: []*collaboration.Filter{ Filters: []*collaboration.Filter{
{ {
@@ -1080,15 +1080,32 @@ func (s *service) resolveAcceptedShare(ctx context.Context, ref *provider.Refere
return nil, lsRes.Status, nil return nil, lsRes.Status, nil
} }
for _, receivedShare := range lsRes.Shares { for _, receivedShare := range lsRes.Shares {
// make sure to skip unaccepted shares
if receivedShare.State != collaboration.ShareState_SHARE_STATE_ACCEPTED {
continue
}
if isMountPointForPath(receivedShare.MountPoint.Path, ref.Path) { if isMountPointForPath(receivedShare.MountPoint.Path, ref.Path) {
// Only return this share if the resource still exists.
gatewayClient, err := s.gatewaySelector.Next()
if err != nil {
return nil, nil, err
}
sRes, err := gatewayClient.Stat(ctx, &provider.StatRequest{
Ref: &provider.Reference{ResourceId: receivedShare.GetShare().GetResourceId()},
})
if err != nil {
appctx.GetLogger(ctx).Debug().
Err(err).
Interface("resourceID", receivedShare.GetShare().GetResourceId()).
Msg("resolveAcceptedShare: failed to stat shared resource")
continue
}
if sRes.Status.Code != rpc.Code_CODE_OK {
appctx.GetLogger(ctx).Debug().
Interface("resourceID", receivedShare.GetShare().GetResourceId()).
Interface("status", sRes.Status).
Msg("resolveAcceptedShare: failed to stat shared resource")
continue
}
return receivedShare, lsRes.Status, nil return receivedShare, lsRes.Status, nil
} }
} }
} }
return nil, status.NewNotFound(ctx, "sharesstorageprovider: not found "+ref.String()), nil return nil, status.NewNotFound(ctx, "sharesstorageprovider: not found "+ref.String()), nil
@@ -33,6 +33,7 @@ import (
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/v2/pkg/appctx" "github.com/cs3org/reva/v2/pkg/appctx"
"github.com/cs3org/reva/v2/pkg/conversions"
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx" ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
"github.com/cs3org/reva/v2/pkg/errtypes" "github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/events" "github.com/cs3org/reva/v2/pkg/events"
@@ -230,6 +231,11 @@ func (s *service) UnsetArbitraryMetadata(ctx context.Context, req *provider.Unse
// SetLock puts a lock on the given reference // SetLock puts a lock on the given reference
func (s *service) SetLock(ctx context.Context, req *provider.SetLockRequest) (*provider.SetLockResponse, error) { func (s *service) SetLock(ctx context.Context, req *provider.SetLockRequest) (*provider.SetLockResponse, error) {
if !canLockPublicShare(ctx) {
return &provider.SetLockResponse{
Status: status.NewPermissionDenied(ctx, nil, "no permission to lock the share"),
}, nil
}
err := s.storage.SetLock(ctx, req.Ref, req.Lock) err := s.storage.SetLock(ctx, req.Ref, req.Lock)
return &provider.SetLockResponse{ return &provider.SetLockResponse{
@@ -249,6 +255,12 @@ func (s *service) GetLock(ctx context.Context, req *provider.GetLockRequest) (*p
// RefreshLock refreshes an existing lock on the given reference // RefreshLock refreshes an existing lock on the given reference
func (s *service) RefreshLock(ctx context.Context, req *provider.RefreshLockRequest) (*provider.RefreshLockResponse, error) { func (s *service) RefreshLock(ctx context.Context, req *provider.RefreshLockRequest) (*provider.RefreshLockResponse, error) {
if !canLockPublicShare(ctx) {
return &provider.RefreshLockResponse{
Status: status.NewPermissionDenied(ctx, nil, "no permission to refresh the share lock"),
}, nil
}
err := s.storage.RefreshLock(ctx, req.Ref, req.Lock, req.ExistingLockId) err := s.storage.RefreshLock(ctx, req.Ref, req.Lock, req.ExistingLockId)
return &provider.RefreshLockResponse{ return &provider.RefreshLockResponse{
@@ -258,6 +270,12 @@ func (s *service) RefreshLock(ctx context.Context, req *provider.RefreshLockRequ
// Unlock removes an existing lock from the given reference // Unlock removes an existing lock from the given reference
func (s *service) Unlock(ctx context.Context, req *provider.UnlockRequest) (*provider.UnlockResponse, error) { func (s *service) Unlock(ctx context.Context, req *provider.UnlockRequest) (*provider.UnlockResponse, error) {
if !canLockPublicShare(ctx) {
return &provider.UnlockResponse{
Status: status.NewPermissionDenied(ctx, nil, "no permission to unlock the share"),
}, nil
}
err := s.storage.Unlock(ctx, req.Ref, req.Lock) err := s.storage.Unlock(ctx, req.Ref, req.Lock)
return &provider.UnlockResponse{ return &provider.UnlockResponse{
@@ -1285,3 +1303,9 @@ func estreamFromConfig(c eventconfig) (events.Stream, error) {
return stream.NatsFromConfig("storageprovider", false, stream.NatsConfig(c)) return stream.NatsFromConfig("storageprovider", false, stream.NatsConfig(c))
} }
func canLockPublicShare(ctx context.Context) bool {
u := ctxpkg.ContextMustGetUser(ctx)
psr := utils.ReadPlainFromOpaque(u.Opaque, "public-share-role")
return psr == "" || psr == conversions.RoleEditor
}
@@ -21,6 +21,7 @@ package errors
import ( import (
"bytes" "bytes"
"encoding/xml" "encoding/xml"
"fmt"
"net/http" "net/http"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
@@ -193,3 +194,20 @@ func HandleWebdavError(log *zerolog.Logger, w http.ResponseWriter, b []byte, err
log.Err(err).Msg("error writing response") log.Err(err).Msg("error writing response")
} }
} }
func NewErrFromStatus(s *rpc.Status) error {
switch s.GetCode() {
case rpc.Code_CODE_OK:
return nil
case rpc.Code_CODE_DEADLINE_EXCEEDED:
return ErrInvalidTimeout
case rpc.Code_CODE_PERMISSION_DENIED:
return ErrForbidden
case rpc.Code_CODE_LOCKED, rpc.Code_CODE_FAILED_PRECONDITION:
return ErrLocked
case rpc.Code_CODE_UNIMPLEMENTED:
return ErrNotImplemented
default:
return fmt.Errorf(s.GetMessage())
}
}
@@ -21,6 +21,7 @@ package ocdav
import ( import (
"context" "context"
"encoding/xml" "encoding/xml"
"errors"
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
@@ -34,13 +35,12 @@ import (
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/errors" ocdavErrors "github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/errors"
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/net" "github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/net"
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/prop" "github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/prop"
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/spacelookup" "github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/spacelookup"
"github.com/cs3org/reva/v2/pkg/appctx" "github.com/cs3org/reva/v2/pkg/appctx"
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx" ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool" "github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/v2/pkg/utils" "github.com/cs3org/reva/v2/pkg/utils"
"github.com/google/uuid" "github.com/google/uuid"
@@ -172,7 +172,7 @@ type cs3LS struct {
} }
func (cls *cs3LS) Confirm(ctx context.Context, now time.Time, name0, name1 string, conditions ...Condition) (func(), error) { func (cls *cs3LS) Confirm(ctx context.Context, now time.Time, name0, name1 string, conditions ...Condition) (func(), error) {
return nil, errors.ErrNotImplemented return nil, ocdavErrors.ErrNotImplemented
} }
func (cls *cs3LS) Create(ctx context.Context, now time.Time, details LockDetails) (string, error) { func (cls *cs3LS) Create(ctx context.Context, now time.Time, details LockDetails) (string, error) {
@@ -180,7 +180,7 @@ func (cls *cs3LS) Create(ctx context.Context, now time.Time, details LockDetails
/* /*
if !details.ZeroDepth { if !details.ZeroDepth {
The CS3 Lock api currently has no depth property, it only locks single resources The CS3 Lock api currently has no depth property, it only locks single resources
return "", errors.ErrUnsupportedLockInfo return "", ocdavErrors.ErrUnsupportedLockInfo
} }
*/ */
@@ -225,20 +225,19 @@ func (cls *cs3LS) Create(ctx context.Context, now time.Time, details LockDetails
if err != nil { if err != nil {
return "", err return "", err
} }
switch res.Status.Code { switch res.GetStatus().GetCode() {
case rpc.Code_CODE_OK: case rpc.Code_CODE_OK:
return lockTokenPrefix + token.String(), nil return lockTokenPrefix + token.String(), nil
case rpc.Code_CODE_FAILED_PRECONDITION:
return "", errtypes.Aborted("file is already locked")
default: default:
return "", errtypes.NewErrtypeFromStatus(res.Status) return "", ocdavErrors.NewErrFromStatus(res.GetStatus())
} }
} }
func (cls *cs3LS) Refresh(ctx context.Context, now time.Time, token string, duration time.Duration) (LockDetails, error) { func (cls *cs3LS) Refresh(ctx context.Context, now time.Time, token string, duration time.Duration) (LockDetails, error) {
return LockDetails{}, errors.ErrNotImplemented return LockDetails{}, ocdavErrors.ErrNotImplemented
} }
func (cls *cs3LS) Unlock(ctx context.Context, now time.Time, ref *provider.Reference, token string) error { func (cls *cs3LS) Unlock(ctx context.Context, now time.Time, ref *provider.Reference, token string) error {
u := ctxpkg.ContextMustGetUser(ctx) u := ctxpkg.ContextMustGetUser(ctx)
@@ -260,14 +259,11 @@ func (cls *cs3LS) Unlock(ctx context.Context, now time.Time, ref *provider.Refer
return err return err
} }
switch res.Status.Code { newErr := ocdavErrors.NewErrFromStatus(res.GetStatus())
case rpc.Code_CODE_OK: if newErr != nil {
return nil appctx.GetLogger(ctx).Error().Str("token", token).Interface("unlock", ref).Msg("could not unlock " + res.GetStatus().GetMessage())
case rpc.Code_CODE_FAILED_PRECONDITION:
return errtypes.Aborted("file is not locked")
default:
return errtypes.NewErrtypeFromStatus(res.Status)
} }
return newErr
} }
// LockDetails are a lock's metadata. // LockDetails are a lock's metadata.
@@ -302,7 +298,7 @@ func readLockInfo(r io.Reader) (li lockInfo, status int, err error) {
// http://www.webdav.org/specs/rfc4918.html#refreshing-locks // http://www.webdav.org/specs/rfc4918.html#refreshing-locks
return lockInfo{}, 0, nil return lockInfo{}, 0, nil
} }
err = errors.ErrInvalidLockInfo err = ocdavErrors.ErrInvalidLockInfo
} }
return lockInfo{}, http.StatusBadRequest, err return lockInfo{}, http.StatusBadRequest, err
} }
@@ -349,15 +345,15 @@ func parseTimeout(s string) (time.Duration, error) {
} }
const pre = "Second-" const pre = "Second-"
if !strings.HasPrefix(s, pre) { if !strings.HasPrefix(s, pre) {
return 0, errors.ErrInvalidTimeout return 0, ocdavErrors.ErrInvalidTimeout
} }
s = s[len(pre):] s = s[len(pre):]
if s == "" || s[0] < '0' || '9' < s[0] { if s == "" || s[0] < '0' || '9' < s[0] {
return 0, errors.ErrInvalidTimeout return 0, ocdavErrors.ErrInvalidTimeout
} }
n, err := strconv.ParseInt(s, 10, 64) n, err := strconv.ParseInt(s, 10, 64)
if err != nil || 1<<32-1 < n { if err != nil || 1<<32-1 < n {
return 0, errors.ErrInvalidTimeout return 0, ocdavErrors.ErrInvalidTimeout
} }
return time.Duration(n) * time.Second, nil return time.Duration(n) * time.Second, nil
} }
@@ -420,7 +416,7 @@ func (s *svc) handleLock(w http.ResponseWriter, r *http.Request, ns string) (ret
return http.StatusInternalServerError, err return http.StatusInternalServerError, err
} }
if cs3Status.Code != rpc.Code_CODE_OK { if cs3Status.Code != rpc.Code_CODE_OK {
return http.StatusInternalServerError, errtypes.NewErrtypeFromStatus(cs3Status) return http.StatusInternalServerError, ocdavErrors.NewErrFromStatus(cs3Status)
} }
return s.lockReference(ctx, w, r, ref) return s.lockReference(ctx, w, r, ref)
@@ -444,12 +440,12 @@ func (s *svc) lockReference(ctx context.Context, w http.ResponseWriter, r *http.
sublog := appctx.GetLogger(ctx).With().Interface("ref", ref).Logger() sublog := appctx.GetLogger(ctx).With().Interface("ref", ref).Logger()
duration, err := parseTimeout(r.Header.Get(net.HeaderTimeout)) duration, err := parseTimeout(r.Header.Get(net.HeaderTimeout))
if err != nil { if err != nil {
return http.StatusBadRequest, errors.ErrInvalidTimeout return http.StatusBadRequest, ocdavErrors.ErrInvalidTimeout
} }
li, status, err := readLockInfo(r.Body) li, status, err := readLockInfo(r.Body)
if err != nil { if err != nil {
return status, errors.ErrInvalidLockInfo return status, ocdavErrors.ErrInvalidLockInfo
} }
u := ctxpkg.ContextMustGetUser(ctx) u := ctxpkg.ContextMustGetUser(ctx)
@@ -459,17 +455,17 @@ func (s *svc) lockReference(ctx context.Context, w http.ResponseWriter, r *http.
// An empty lockInfo means to refresh the lock. // An empty lockInfo means to refresh the lock.
ih, ok := parseIfHeader(r.Header.Get(net.HeaderIf)) ih, ok := parseIfHeader(r.Header.Get(net.HeaderIf))
if !ok { if !ok {
return http.StatusBadRequest, errors.ErrInvalidIfHeader return http.StatusBadRequest, ocdavErrors.ErrInvalidIfHeader
} }
if len(ih.lists) == 1 && len(ih.lists[0].conditions) == 1 { if len(ih.lists) == 1 && len(ih.lists[0].conditions) == 1 {
token = ih.lists[0].conditions[0].Token token = ih.lists[0].conditions[0].Token
} }
if token == "" { if token == "" {
return http.StatusBadRequest, errors.ErrInvalidLockToken return http.StatusBadRequest, ocdavErrors.ErrInvalidLockToken
} }
ld, err = s.LockSystem.Refresh(ctx, now, token, duration) ld, err = s.LockSystem.Refresh(ctx, now, token, duration)
if err != nil { if err != nil {
if err == errors.ErrNoSuchLock { if err == ocdavErrors.ErrNoSuchLock {
return http.StatusPreconditionFailed, err return http.StatusPreconditionFailed, err
} }
return http.StatusInternalServerError, err return http.StatusInternalServerError, err
@@ -484,7 +480,7 @@ func (s *svc) lockReference(ctx context.Context, w http.ResponseWriter, r *http.
if depth != 0 && depth != infiniteDepth { if depth != 0 && depth != infiniteDepth {
// Section 9.10.3 says that "Values other than 0 or infinity must not be // Section 9.10.3 says that "Values other than 0 or infinity must not be
// used with the Depth header on a LOCK method". // used with the Depth header on a LOCK method".
return http.StatusBadRequest, errors.ErrInvalidDepth return http.StatusBadRequest, ocdavErrors.ErrInvalidDepth
} }
} }
/* our url path has been shifted, so we don't need to do this? /* our url path has been shifted, so we don't need to do this?
@@ -505,15 +501,16 @@ func (s *svc) lockReference(ctx context.Context, w http.ResponseWriter, r *http.
// should we do that in the decomposedfs as well? the node does not exist // should we do that in the decomposedfs as well? the node does not exist
// this actually is a name based lock ... ugh // this actually is a name based lock ... ugh
token, err = s.LockSystem.Create(ctx, now, ld) token, err = s.LockSystem.Create(ctx, now, ld)
//
if err != nil { if err != nil {
switch err.(type) { switch {
case errtypes.Aborted: case errors.Is(err, ocdavErrors.ErrLocked):
return http.StatusLocked, err return http.StatusLocked, err
case errtypes.PermissionDenied: case errors.Is(err, ocdavErrors.ErrForbidden):
return http.StatusForbidden, err return http.StatusForbidden, err
default: default:
return http.StatusInternalServerError, err return http.StatusInternalServerError, err
} }
} }
@@ -611,7 +608,7 @@ func (s *svc) handleUnlock(w http.ResponseWriter, r *http.Request, ns string) (s
return http.StatusInternalServerError, err return http.StatusInternalServerError, err
} }
if cs3Status.Code != rpc.Code_CODE_OK { if cs3Status.Code != rpc.Code_CODE_OK {
return http.StatusInternalServerError, errtypes.NewErrtypeFromStatus(cs3Status) return http.StatusInternalServerError, ocdavErrors.NewErrFromStatus(cs3Status)
} }
return s.unlockReference(ctx, w, r, ref) return s.unlockReference(ctx, w, r, ref)
@@ -639,16 +636,14 @@ func (s *svc) unlockReference(ctx context.Context, _ http.ResponseWriter, r *htt
t = t[1 : len(t)-1] t = t[1 : len(t)-1]
} }
switch err := s.LockSystem.Unlock(ctx, time.Now(), ref, t); err { err := s.LockSystem.Unlock(ctx, time.Now(), ref, t)
case nil: switch {
return http.StatusNoContent, err case err == nil:
case errors.ErrForbidden: return http.StatusNoContent, nil
return http.StatusForbidden, err case errors.Is(err, ocdavErrors.ErrLocked):
case errors.ErrLocked:
return http.StatusLocked, err return http.StatusLocked, err
case errors.ErrNoSuchLock: case errors.Is(err, ocdavErrors.ErrForbidden):
return http.StatusConflict, err return http.StatusForbidden, err
default:
return http.StatusInternalServerError, err
} }
return http.StatusInternalServerError, err
} }
+39 -4
View File
@@ -295,12 +295,13 @@ func NewErrtypeFromStatus(status *rpc.Status) error {
case rpc.Code_CODE_UNIMPLEMENTED: case rpc.Code_CODE_UNIMPLEMENTED:
return NotSupported(status.Message) return NotSupported(status.Message)
case rpc.Code_CODE_PERMISSION_DENIED: case rpc.Code_CODE_PERMISSION_DENIED:
// FIXME add locked status!
if strings.HasPrefix(status.Message, "set lock: error: locked by ") {
return Locked(strings.TrimPrefix(status.Message, "set lock: error: locked by "))
}
return PermissionDenied(status.Message) return PermissionDenied(status.Message)
case rpc.Code_CODE_LOCKED: case rpc.Code_CODE_LOCKED:
// FIXME make something better for that
msg := strings.Split(status.Message, "error: locked by ")
if len(msg) > 1 {
return Locked(msg[len(msg)-1])
}
return Locked(status.Message) return Locked(status.Message)
// case rpc.Code_CODE_DATA_LOSS: ? // case rpc.Code_CODE_DATA_LOSS: ?
// IsPartialContent // IsPartialContent
@@ -350,3 +351,37 @@ func NewErrtypeFromHTTPStatusCode(code int, message string) error {
return InternalError(message) return InternalError(message)
} }
} }
// NewHTTPStatusCodeFromErrtype maps an errtype to an http status
func NewHTTPStatusCodeFromErrtype(err error) int {
switch err.(type) {
case NotFound:
return http.StatusNotFound
case AlreadyExists:
return http.StatusConflict
case NotSupported:
return http.StatusNotImplemented
case NotModified:
return http.StatusNotModified
case InvalidCredentials:
return http.StatusUnauthorized
case PermissionDenied:
return http.StatusForbidden
case Locked:
return http.StatusLocked
case Aborted:
return http.StatusPreconditionFailed
case PreconditionFailed:
return http.StatusMethodNotAllowed
case InsufficientStorage:
return http.StatusInsufficientStorage
case BadRequest:
return http.StatusBadRequest
case PartialContent:
return http.StatusPartialContent
case ChecksumMismatch:
return StatusChecksumMismatch
default:
return http.StatusInternalServerError
}
}
+1 -1
View File
@@ -359,7 +359,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/storage/registry/v1beta1
github.com/cs3org/go-cs3apis/cs3/tx/v1beta1 github.com/cs3org/go-cs3apis/cs3/tx/v1beta1
github.com/cs3org/go-cs3apis/cs3/types/v1beta1 github.com/cs3org/go-cs3apis/cs3/types/v1beta1
# github.com/cs3org/reva/v2 v2.19.2-0.20240307063856-698d86209c3d # github.com/cs3org/reva/v2 v2.19.2-0.20240307091744-fa2caba1f4e4
## explicit; go 1.21 ## explicit; go 1.21
github.com/cs3org/reva/v2/cmd/revad/internal/grace github.com/cs3org/reva/v2/cmd/revad/internal/grace
github.com/cs3org/reva/v2/cmd/revad/runtime github.com/cs3org/reva/v2/cmd/revad/runtime