From 56c965bb566e61a280a85a5f9126679cfa915e8f Mon Sep 17 00:00:00 2001 From: jkoberg Date: Fri, 6 Dec 2024 15:17:15 +0100 Subject: [PATCH 1/7] feat(ocm): allow locking via ocm Signed-off-by: jkoberg --- changelog/unreleased/ocm-locking.md | 5 ++++ .../http/services/owncloud/ocdav/locks.go | 27 ++++++++++++------- pkg/ocm/storage/received/ocm.go | 16 +++++++++-- 3 files changed, 36 insertions(+), 12 deletions(-) create mode 100644 changelog/unreleased/ocm-locking.md diff --git a/changelog/unreleased/ocm-locking.md b/changelog/unreleased/ocm-locking.md new file mode 100644 index 0000000000..4e56bdc46e --- /dev/null +++ b/changelog/unreleased/ocm-locking.md @@ -0,0 +1,5 @@ +Enhancement: Allow locking via ocm + +Implement locking endpoints so files can be locked and unlocked via ocm. + +https://github.com/cs3org/reva/pull/4990 diff --git a/internal/http/services/owncloud/ocdav/locks.go b/internal/http/services/owncloud/ocdav/locks.go index 5458ec4e58..9f66a0f778 100644 --- a/internal/http/services/owncloud/ocdav/locks.go +++ b/internal/http/services/owncloud/ocdav/locks.go @@ -84,6 +84,7 @@ type lockInfo struct { Shared *struct{} `xml:"lockscope>shared"` Write *struct{} `xml:"locktype>write"` Owner owner `xml:"owner"` + LockID string `xml:"locktoken>href"` } // http://www.webdav.org/specs/rfc4918.html#ELEMENT_owner @@ -184,13 +185,6 @@ func (cls *cs3LS) Create(ctx context.Context, now time.Time, details LockDetails } */ - // Having a lock token provides no special access rights. Anyone can find out anyone - // else's lock token by performing lock discovery. Locks must be enforced based upon - // whatever authentication mechanism is used by the server, not based on the secrecy - // of the token values. - // see: http://www.webdav.org/specs/rfc2518.html#n-lock-tokens - token := uuid.New() - u := ctxpkg.ContextMustGetUser(ctx) // add metadata via opaque @@ -198,6 +192,17 @@ func (cls *cs3LS) Create(ctx context.Context, now time.Time, details LockDetails o := utils.AppendPlainToOpaque(nil, "lockownername", u.GetDisplayName()) o = utils.AppendPlainToOpaque(o, "locktime", now.Format(time.RFC3339)) + lockid := details.LockID + if lockid == "" { + // Having a lock token provides no special access rights. Anyone can find out anyone + // else's lock token by performing lock discovery. Locks must be enforced based upon + // whatever authentication mechanism is used by the server, not based on the secrecy + // of the token values. + // see: http://www.webdav.org/specs/rfc2518.html#n-lock-tokens + token := uuid.New() + + lockid = lockTokenPrefix + token.String() + } r := &provider.SetLockRequest{ Ref: details.Root, Lock: &provider.Lock{ @@ -205,7 +210,7 @@ func (cls *cs3LS) Create(ctx context.Context, now time.Time, details LockDetails Type: provider.LockType_LOCK_TYPE_EXCL, User: details.UserID, // no way to set an app lock? TODO maybe via the ownerxml //AppName: , // TODO use a urn scheme? - LockId: lockTokenPrefix + token.String(), // can be a token or a Coded-URL + LockId: lockid, }, } if details.Duration > 0 { @@ -227,7 +232,7 @@ func (cls *cs3LS) Create(ctx context.Context, now time.Time, details LockDetails } switch res.GetStatus().GetCode() { case rpc.Code_CODE_OK: - return lockTokenPrefix + token.String(), nil + return lockid, nil default: return "", ocdavErrors.NewErrFromStatus(res.GetStatus()) } @@ -287,6 +292,8 @@ type LockDetails struct { OwnerName string // Locktime is the time the lock was created Locktime time.Time + // LockID is the lock token + LockID string } func readLockInfo(r io.Reader) (li lockInfo, status int, err error) { @@ -450,7 +457,7 @@ func (s *svc) lockReference(ctx context.Context, w http.ResponseWriter, r *http. u := ctxpkg.ContextMustGetUser(ctx) token, now, created := "", time.Now(), false - ld := LockDetails{UserID: u.Id, Root: ref, Duration: duration, OwnerName: u.GetDisplayName(), Locktime: now} + ld := LockDetails{UserID: u.Id, Root: ref, Duration: duration, OwnerName: u.GetDisplayName(), Locktime: now, LockID: li.LockID} if li == (lockInfo{}) { // An empty lockInfo means to refresh the lock. ih, ok := parseIfHeader(r.Header.Get(net.HeaderIf)) diff --git a/pkg/ocm/storage/received/ocm.go b/pkg/ocm/storage/received/ocm.go index 1b595eb017..897c1cd916 100644 --- a/pkg/ocm/storage/received/ocm.go +++ b/pkg/ocm/storage/received/ocm.go @@ -474,8 +474,14 @@ func (d *driver) UnsetArbitraryMetadata(ctx context.Context, ref *provider.Refer return errtypes.NotSupported("operation not supported") } +// SetLock sets a lock on a file func (d *driver) SetLock(ctx context.Context, ref *provider.Reference, lock *provider.Lock) error { - return errtypes.NotSupported("operation not supported") + client, _, rel, err := d.webdavClient(ctx, nil, ref) + if err != nil { + return err + } + + return client.Lock(rel, lock.GetLockId()) } func (d *driver) GetLock(ctx context.Context, ref *provider.Reference) (*provider.Lock, error) { @@ -486,8 +492,14 @@ func (d *driver) RefreshLock(ctx context.Context, ref *provider.Reference, lock return errtypes.NotSupported("operation not supported") } +// Unlock removes a lock from a file func (d *driver) Unlock(ctx context.Context, ref *provider.Reference, lock *provider.Lock) error { - return errtypes.NotSupported("operation not supported") + client, _, rel, err := d.webdavClient(ctx, nil, ref) + if err != nil { + return err + } + + return client.Unlock(rel, lock.GetLockId()) } func (d *driver) ListStorageSpaces(ctx context.Context, filters []*provider.ListStorageSpacesRequest_Filter, _ bool) ([]*provider.StorageSpace, error) { From 012d520d3cf067880f1650819b365c4e8c225ea1 Mon Sep 17 00:00:00 2001 From: jkoberg Date: Thu, 12 Dec 2024 11:35:50 +0100 Subject: [PATCH 2/7] feat(ocm): send locktoken with PUT request Signed-off-by: jkoberg --- cmd/reva/upload.go | 2 +- .../services/publicstorageprovider/publicstorageprovider.go | 1 + pkg/ocm/storage/received/upload.go | 5 +++-- pkg/rhttp/datatx/manager/simple/simple.go | 5 +++++ 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/cmd/reva/upload.go b/cmd/reva/upload.go index f0161741de..3d3d8396b2 100644 --- a/cmd/reva/upload.go +++ b/cmd/reva/upload.go @@ -271,7 +271,7 @@ func checkUploadWebdavRef(protocols []*gateway.FileUploadProtocol, md os.FileInf c.SetHeader(ctxpkg.TokenHeader, token) c.SetHeader("Upload-Length", strconv.FormatInt(md.Size(), 10)) - if err = c.WriteStream(filePath, fd, 0700); err != nil { + if err = c.WriteStream(filePath, fd, 0700, ""); err != nil { return err } diff --git a/internal/grpc/services/publicstorageprovider/publicstorageprovider.go b/internal/grpc/services/publicstorageprovider/publicstorageprovider.go index c743372295..114c674c95 100644 --- a/internal/grpc/services/publicstorageprovider/publicstorageprovider.go +++ b/internal/grpc/services/publicstorageprovider/publicstorageprovider.go @@ -315,6 +315,7 @@ func (s *service) InitiateFileUpload(ctx context.Context, req *provider.Initiate uReq := &provider.InitiateFileUploadRequest{ Ref: cs3Ref, Opaque: req.Opaque, + LockId: req.LockId, } gatewayClient, err := s.gatewaySelector.Next() diff --git a/pkg/ocm/storage/received/upload.go b/pkg/ocm/storage/received/upload.go index 05556ede47..046a5fcc66 100644 --- a/pkg/ocm/storage/received/upload.go +++ b/pkg/ocm/storage/received/upload.go @@ -106,7 +106,8 @@ func (d *driver) Upload(ctx context.Context, req storage.UploadRequest, _ storag } }) - return &provider.ResourceInfo{}, client.WriteStream(rel, req.Body, 0) + locktoken, _ := ctxpkg.ContextGetLockID(ctx) + return &provider.ResourceInfo{}, client.WriteStream(rel, req.Body, 0, locktoken) } // UseIn tells the tus upload middleware which extensions it supports. @@ -356,7 +357,7 @@ func (u *upload) FinishUpload(ctx context.Context) error { return err } defer f.Close() - return client.WriteStream(rel, f, 0) + return client.WriteStream(rel, f, 0, "") } func (u *upload) Terminate(ctx context.Context) error { diff --git a/pkg/rhttp/datatx/manager/simple/simple.go b/pkg/rhttp/datatx/manager/simple/simple.go index 5074b3861d..5cfec2ca4e 100644 --- a/pkg/rhttp/datatx/manager/simple/simple.go +++ b/pkg/rhttp/datatx/manager/simple/simple.go @@ -24,6 +24,7 @@ import ( userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" + ctxpkg "github.com/cs3org/reva/v2/pkg/ctx" "github.com/mitchellh/mapstructure" "github.com/pkg/errors" "github.com/rs/zerolog" @@ -109,6 +110,10 @@ func (m *manager) Handler(fs storage.FS) (http.Handler, error) { ref := &provider.Reference{Path: fn} + if lockID := r.Header.Get("X-Lock-Id"); lockID != "" { + ctx = ctxpkg.ContextSetLockID(ctx, lockID) + } + info, err := fs.Upload(ctx, storage.UploadRequest{ Ref: ref, Body: r.Body, From 5b7b242bff0d3ad16d6a1a4229e15b2a3ee79de9 Mon Sep 17 00:00:00 2001 From: jkoberg Date: Fri, 6 Dec 2024 15:23:07 +0100 Subject: [PATCH 3/7] feat(gowebdav): use custom fork Signed-off-by: jkoberg --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 466071fd2d..41c83d6645 100644 --- a/go.mod +++ b/go.mod @@ -229,7 +229,7 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect ) -replace github.com/studio-b12/gowebdav => github.com/aduffeck/gowebdav v0.0.0-20241122070217-29b328c136b1 +replace github.com/studio-b12/gowebdav => github.com/kobergj/gowebdav v0.0.0-20241212102826-849dbbfbe392 // exclude the v2 line of go-sqlite3 which was released accidentally and prevents pulling in newer versions of go-sqlite3 // see https://github.com/mattn/go-sqlite3/issues/965 for more details diff --git a/go.sum b/go.sum index 796bc31aba..540220100a 100644 --- a/go.sum +++ b/go.sum @@ -65,8 +65,6 @@ github.com/ProtonMail/go-crypto v0.0.0-20220930113650-c6815a8c17ad h1:QeeqI2zxxg github.com/ProtonMail/go-crypto v0.0.0-20220930113650-c6815a8c17ad/go.mod h1:UBYPn8k0D56RtnR8RFQMjmh4KrZzWJ5o7Z9SYjossQ8= github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= -github.com/aduffeck/gowebdav v0.0.0-20241122070217-29b328c136b1 h1:FAoQBuRdMyGNkp5Mg7HLkaao10BEViEPJNg+5cnW7xk= -github.com/aduffeck/gowebdav v0.0.0-20241122070217-29b328c136b1/go.mod h1:bHA7t77X/QFExdeAnDzK6vKM34kEZAcE1OX4MfiwjkE= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -494,6 +492,8 @@ github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90 github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/kobergj/gowebdav v0.0.0-20241212102826-849dbbfbe392 h1:pdybugon6i4+YFQoF8m9vcBZBOczUksbjo4YgbSqc0E= +github.com/kobergj/gowebdav v0.0.0-20241212102826-849dbbfbe392/go.mod h1:bHA7t77X/QFExdeAnDzK6vKM34kEZAcE1OX4MfiwjkE= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= From c57d82be97b138a6d6f5ae6dee972a95bc802d49 Mon Sep 17 00:00:00 2001 From: jkoberg Date: Thu, 12 Dec 2024 17:42:10 +0100 Subject: [PATCH 4/7] fix(storagespace): use proto getters Signed-off-by: jkoberg --- pkg/storagespace/storagespace.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/storagespace/storagespace.go b/pkg/storagespace/storagespace.go index 78fa52df09..e6412f4ae5 100644 --- a/pkg/storagespace/storagespace.go +++ b/pkg/storagespace/storagespace.go @@ -75,8 +75,8 @@ func SplitStorageID(sid string) (storageID, spaceID string) { // The result format will look like: // $! func FormatResourceID(sid *provider.ResourceId) string { - if sid.OpaqueId == "" { - return FormatStorageID(sid.StorageId, sid.SpaceId) + if sid.GetOpaqueId() == "" { + return FormatStorageID(sid.GetStorageId(), sid.GetSpaceId()) } return strings.Join([]string{FormatStorageID(sid.StorageId, sid.SpaceId), sid.OpaqueId}, _idDelimiter) } From 04068462d461418c1e6a5b84964a4d7d663ff65f Mon Sep 17 00:00:00 2001 From: jkoberg Date: Mon, 23 Dec 2024 15:31:28 +0100 Subject: [PATCH 5/7] fest(ocm): implement RefreshLock and GetLock Signed-off-by: jkoberg --- pkg/ocm/storage/received/ocm.go | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/pkg/ocm/storage/received/ocm.go b/pkg/ocm/storage/received/ocm.go index 897c1cd916..0b069ccc34 100644 --- a/pkg/ocm/storage/received/ocm.go +++ b/pkg/ocm/storage/received/ocm.go @@ -485,11 +485,27 @@ func (d *driver) SetLock(ctx context.Context, ref *provider.Reference, lock *pro } func (d *driver) GetLock(ctx context.Context, ref *provider.Reference) (*provider.Lock, error) { - return nil, errtypes.NotSupported("operation not supported") + client, _, rel, err := d.webdavClient(ctx, nil, ref) + if err != nil { + return nil, err + } + + token, err := client.GetLock(rel) + if err != nil { + return nil, err + } + + return &provider.Lock{LockId: token, Type: provider.LockType_LOCK_TYPE_EXCL}, nil } func (d *driver) RefreshLock(ctx context.Context, ref *provider.Reference, lock *provider.Lock, existingLockID string) error { - return errtypes.NotSupported("operation not supported") + client, _, rel, err := d.webdavClient(ctx, nil, ref) + if err != nil { + return err + } + + err = client.RefreshLock(rel, lock.GetLockId()) + return err } // Unlock removes a lock from a file From 9143227556ef845424a28029d1b8f68b8863d0b4 Mon Sep 17 00:00:00 2001 From: jkoberg Date: Mon, 23 Dec 2024 15:55:30 +0100 Subject: [PATCH 6/7] feat(go.mod): bump gowebdav version Signed-off-by: jkoberg --- go.mod | 2 +- go.sum | 4 ++-- pkg/sdk/common/net/webdav.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 41c83d6645..bccbb892c5 100644 --- a/go.mod +++ b/go.mod @@ -229,7 +229,7 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect ) -replace github.com/studio-b12/gowebdav => github.com/kobergj/gowebdav v0.0.0-20241212102826-849dbbfbe392 +replace github.com/studio-b12/gowebdav => github.com/kobergj/gowebdav v0.0.0-20241223142249-060874be3bb2 // exclude the v2 line of go-sqlite3 which was released accidentally and prevents pulling in newer versions of go-sqlite3 // see https://github.com/mattn/go-sqlite3/issues/965 for more details diff --git a/go.sum b/go.sum index 540220100a..d167557444 100644 --- a/go.sum +++ b/go.sum @@ -492,8 +492,8 @@ github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90 github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/kobergj/gowebdav v0.0.0-20241212102826-849dbbfbe392 h1:pdybugon6i4+YFQoF8m9vcBZBOczUksbjo4YgbSqc0E= -github.com/kobergj/gowebdav v0.0.0-20241212102826-849dbbfbe392/go.mod h1:bHA7t77X/QFExdeAnDzK6vKM34kEZAcE1OX4MfiwjkE= +github.com/kobergj/gowebdav v0.0.0-20241223142249-060874be3bb2 h1:jtEsQsh9Wpo622GUZwMmcV3fR4nw1PZWhob4z530nz0= +github.com/kobergj/gowebdav v0.0.0-20241223142249-060874be3bb2/go.mod h1:bHA7t77X/QFExdeAnDzK6vKM34kEZAcE1OX4MfiwjkE= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= diff --git a/pkg/sdk/common/net/webdav.go b/pkg/sdk/common/net/webdav.go index 17776d3438..845fcc5c3e 100644 --- a/pkg/sdk/common/net/webdav.go +++ b/pkg/sdk/common/net/webdav.go @@ -71,7 +71,7 @@ func (webdav *WebDAVClient) Read(file string) ([]byte, error) { func (webdav *WebDAVClient) Write(file string, data io.Reader, size int64) error { webdav.client.SetHeader("Upload-Length", strconv.FormatInt(size, 10)) - if err := webdav.client.WriteStream(file, data, 0700); err != nil { + if err := webdav.client.WriteStream(file, data, 0700, ""); err != nil { return fmt.Errorf("unable to write the data: %v", err) } From d357f5d0f2d1fd2efe6ce3a7b01321b807067ca5 Mon Sep 17 00:00:00 2001 From: jkoberg Date: Mon, 23 Dec 2024 17:08:26 +0100 Subject: [PATCH 7/7] feat(ocdav): allow lock refreshing Signed-off-by: jkoberg --- go.mod | 2 +- go.sum | 4 +- .../http/services/owncloud/ocdav/locks.go | 47 +++++++++++++++++-- pkg/ocm/storage/received/ocm.go | 3 +- 4 files changed, 47 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index bccbb892c5..d6359f818b 100644 --- a/go.mod +++ b/go.mod @@ -229,7 +229,7 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect ) -replace github.com/studio-b12/gowebdav => github.com/kobergj/gowebdav v0.0.0-20241223142249-060874be3bb2 +replace github.com/studio-b12/gowebdav => github.com/kobergj/gowebdav v0.0.0-20250102091030-aa65266db202 // exclude the v2 line of go-sqlite3 which was released accidentally and prevents pulling in newer versions of go-sqlite3 // see https://github.com/mattn/go-sqlite3/issues/965 for more details diff --git a/go.sum b/go.sum index d167557444..1715082d73 100644 --- a/go.sum +++ b/go.sum @@ -492,8 +492,8 @@ github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90 github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/kobergj/gowebdav v0.0.0-20241223142249-060874be3bb2 h1:jtEsQsh9Wpo622GUZwMmcV3fR4nw1PZWhob4z530nz0= -github.com/kobergj/gowebdav v0.0.0-20241223142249-060874be3bb2/go.mod h1:bHA7t77X/QFExdeAnDzK6vKM34kEZAcE1OX4MfiwjkE= +github.com/kobergj/gowebdav v0.0.0-20250102091030-aa65266db202 h1:A1xJ2NKgiYFiaHiLl9B5yw/gUBACSs9crDykTS3GuQI= +github.com/kobergj/gowebdav v0.0.0-20250102091030-aa65266db202/go.mod h1:bHA7t77X/QFExdeAnDzK6vKM34kEZAcE1OX4MfiwjkE= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= diff --git a/internal/http/services/owncloud/ocdav/locks.go b/internal/http/services/owncloud/ocdav/locks.go index 9f66a0f778..da98699615 100644 --- a/internal/http/services/owncloud/ocdav/locks.go +++ b/internal/http/services/owncloud/ocdav/locks.go @@ -145,7 +145,7 @@ type LockSystem interface { // // See http://www.webdav.org/specs/rfc4918.html#rfc.section.9.10.6 for // when to use each error. - Refresh(ctx context.Context, now time.Time, token string, duration time.Duration) (LockDetails, error) + Refresh(ctx context.Context, now time.Time, ref *provider.Reference, token string) error // Unlock unlocks the lock with the given token. // @@ -239,8 +239,45 @@ func (cls *cs3LS) Create(ctx context.Context, now time.Time, details LockDetails } -func (cls *cs3LS) Refresh(ctx context.Context, now time.Time, token string, duration time.Duration) (LockDetails, error) { - return LockDetails{}, ocdavErrors.ErrNotImplemented +func (cls *cs3LS) Refresh(ctx context.Context, now time.Time, ref *provider.Reference, token string) error { + u := ctxpkg.ContextMustGetUser(ctx) + + // add metadata via opaque + // TODO: upate cs3api: https://github.com/cs3org/cs3apis/issues/213 + o := utils.AppendPlainToOpaque(nil, "lockownername", u.GetDisplayName()) + o = utils.AppendPlainToOpaque(o, "locktime", now.Format(time.RFC3339)) + + if token == "" { + return errors.New("token is empty") + } + + r := &provider.RefreshLockRequest{ + Ref: ref, + Lock: &provider.Lock{ + Opaque: o, + Type: provider.LockType_LOCK_TYPE_EXCL, + //AppName: , // TODO use a urn scheme? + LockId: token, + User: u.GetId(), + }, + } + + client, err := cls.selector.Next() + if err != nil { + return err + } + + res, err := client.RefreshLock(ctx, r) + if err != nil { + return err + } + switch res.GetStatus().GetCode() { + case rpc.Code_CODE_OK: + return nil + + default: + return ocdavErrors.NewErrFromStatus(res.GetStatus()) + } } func (cls *cs3LS) Unlock(ctx context.Context, now time.Time, ref *provider.Reference, token string) error { @@ -470,7 +507,7 @@ func (s *svc) lockReference(ctx context.Context, w http.ResponseWriter, r *http. if token == "" { return http.StatusBadRequest, ocdavErrors.ErrInvalidLockToken } - ld, err = s.LockSystem.Refresh(ctx, now, token, duration) + err = s.LockSystem.Refresh(ctx, now, ref, token) if err != nil { if err == ocdavErrors.ErrNoSuchLock { return http.StatusPreconditionFailed, err @@ -478,6 +515,8 @@ func (s *svc) lockReference(ctx context.Context, w http.ResponseWriter, r *http. return http.StatusInternalServerError, err } + ld.LockID = token + } else { // Section 9.10.3 says that "If no Depth header is submitted on a LOCK request, // then the request MUST act as if a "Depth:infinity" had been submitted." diff --git a/pkg/ocm/storage/received/ocm.go b/pkg/ocm/storage/received/ocm.go index 0b069ccc34..02b5d8235a 100644 --- a/pkg/ocm/storage/received/ocm.go +++ b/pkg/ocm/storage/received/ocm.go @@ -504,8 +504,7 @@ func (d *driver) RefreshLock(ctx context.Context, ref *provider.Reference, lock return err } - err = client.RefreshLock(rel, lock.GetLockId()) - return err + return client.RefreshLock(rel, lock.GetLockId()) } // Unlock removes a lock from a file