mirror of
https://github.com/cs3org/reva.git
synced 2025-04-18 13:44:12 +03:00
Merge branch 'upsmaster' into spaces
This commit is contained in:
commit
25493f52a7
3
changelog/unreleased/app-agent-log.md
Normal file
3
changelog/unreleased/app-agent-log.md
Normal file
@ -0,0 +1,3 @@
|
||||
Enhancement: log simplified user agent in apps
|
||||
|
||||
https://github.com/cs3org/reva/pull/5113
|
3
changelog/unreleased/app-filetype-log.md
Normal file
3
changelog/unreleased/app-filetype-log.md
Normal file
@ -0,0 +1,3 @@
|
||||
Enhancement: add file extension in the returning app URL log message
|
||||
|
||||
https://github.com/cs3org/reva/pull/5107
|
6
changelog/unreleased/broken-remove-favs
Normal file
6
changelog/unreleased/broken-remove-favs
Normal file
@ -0,0 +1,6 @@
|
||||
Bugfix: allow folders to be un-favorited
|
||||
|
||||
Currently, removing a folder from your favorites is broken, if you are the only one who has favorited it.
|
||||
This is because the UnsetAttr call to EOS over gRPC is failing. As a temporary workaround, we now always set it to empty.
|
||||
|
||||
https://github.com/cs3org/reva/pull/5120
|
3
changelog/unreleased/eos-acl-log.md
Normal file
3
changelog/unreleased/eos-acl-log.md
Normal file
@ -0,0 +1,3 @@
|
||||
Enhancement: log acl payload on AddACL on EOS over gRPC
|
||||
|
||||
https://github.com/cs3org/reva/pull/5110
|
9
changelog/unreleased/eos-bc-for-attrs
Normal file
9
changelog/unreleased/eos-bc-for-attrs
Normal file
@ -0,0 +1,9 @@
|
||||
Bugfix: Use binary client for Attrs
|
||||
|
||||
EOS < 5.3 has a couple of bugs related to attributes:
|
||||
* Attributes can only be removed as root or the owner, but over gRPC we cannot become root
|
||||
* The recursive property is ignored on set attributes
|
||||
|
||||
For these two issues, we circumvent them by calling the binary client until we have deployed EOS 5.3
|
||||
|
||||
https://github.com/cs3org/reva/pull/5123
|
13
changelog/unreleased/eos-nonutf8.md
Normal file
13
changelog/unreleased/eos-nonutf8.md
Normal file
@ -0,0 +1,13 @@
|
||||
Bugfix: stop sending non-UTF8 strings over gRPC
|
||||
|
||||
EOS supports having non-UTF8 attributes, which get returned in a Stat. This is problematic for us, as we pass these attributes in the ArbitraryMetadata, which gets sent over gRPC. However, the protobuf language specification states:
|
||||
|
||||
> A string must always contain UTF-8 encoded or 7-bit ASCII text, and cannot be longer than 2^32.
|
||||
|
||||
An example of such an attribute is:
|
||||
|
||||
user.$KERNEL.PURGE.SEC.FILEHASH="S<><53>ϫ]<5D><><EFBFBD>z<EFBFBD><7A>#1}<7D><>uU<75>v<EFBFBD><76>8<EFBFBD>L0R<30>9j<39>j<EFBFBD><6A>e?<3F>2K<32>T<sJ<EFBFBD>*<2A>l<EFBFBD><EFBFBD><EFBFBD>Dǭ<EFBFBD><EFBFBD>_[<5B>>η<EFBFBD>...<2E><>w<EFBFBD>w[<5B><>Yg"
|
||||
|
||||
We fix this by stripping non-UTF8 metadata entries before sending the ResourceInfo over gRPC
|
||||
|
||||
https://github.com/cs3org/reva/pull/5119
|
3
changelog/unreleased/fix-app-agent-log.md
Normal file
3
changelog/unreleased/fix-app-agent-log.md
Normal file
@ -0,0 +1,3 @@
|
||||
Bugfix: apps: fixed UserAgent matching
|
||||
|
||||
https://github.com/cs3org/reva/pull/5124
|
3
changelog/unreleased/fix-eos-app-header.md
Normal file
3
changelog/unreleased/fix-eos-app-header.md
Normal file
@ -0,0 +1,3 @@
|
||||
Bugfix: use the correct eos app header
|
||||
|
||||
https://github.com/cs3org/reva/pull/5122
|
5
changelog/unreleased/move-publicshare.md
Normal file
5
changelog/unreleased/move-publicshare.md
Normal file
@ -0,0 +1,5 @@
|
||||
Change: move publicshare sql driver
|
||||
|
||||
The publicshare sql driver has been moved to reva-plugins, to be consistent with the usershare sql driver.
|
||||
|
||||
https://github.com/cs3org/reva/pull/5105
|
11
changelog/unreleased/ocm1.2.md
Normal file
11
changelog/unreleased/ocm1.2.md
Normal file
@ -0,0 +1,11 @@
|
||||
Enhancement: implement OCM 1.2
|
||||
|
||||
This PR brings in the implementation of parts of OpenCloudMesh 1.2, including:
|
||||
* Adopting the new properties of the OCM 1.2 payloads, without implementing any new functionality for now. In particular, any non-empty `requirement` in a share will be rejected (a test was added for that).
|
||||
* Extending the OCM discovery endpoint.
|
||||
* Using the remote OCM discovery endpoint to establish the full URL of an incoming remote share, regardless if provided or not. When sending a share, though, we still send a full URL.
|
||||
* Caching the webdav client used to connect to remote endpoints, with added compatibility to OCM 1.0 remote servers.
|
||||
* Some refactoring and consolidation of duplicated code.
|
||||
* Improved logging.
|
||||
|
||||
https://github.com/cs3org/reva/pull/5076
|
5
changelog/unreleased/publicshares-logging.md
Normal file
5
changelog/unreleased/publicshares-logging.md
Normal file
@ -0,0 +1,5 @@
|
||||
Enhancement: extra logging in publicshares
|
||||
|
||||
Some extra log lines in the public-files DAV handler have been added
|
||||
|
||||
https://github.com/cs3org/reva/pull/5109
|
@ -197,7 +197,7 @@ func getAccessMethods(webdav, webapp, datatx bool, rol string) ([]*ocm.AccessMet
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m = append(m, ocmshare.NewWebDavAccessMethod(perm))
|
||||
m = append(m, ocmshare.NewWebDavAccessMethod(perm, []string{}))
|
||||
}
|
||||
if webapp {
|
||||
v, err := getOCMViewMode(rol)
|
||||
|
@ -75,7 +75,8 @@ func ocmShareUpdateCommand() *command {
|
||||
AccessMethods: &ocm.AccessMethod{
|
||||
Term: &ocm.AccessMethod_WebdavOptions{
|
||||
WebdavOptions: &ocm.WebDAVAccessMethod{
|
||||
Permissions: perm,
|
||||
Permissions: perm,
|
||||
Requirements: []string{},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -9,7 +9,7 @@ description: >
|
||||
# _struct: config_
|
||||
|
||||
{{% dir name="mount_path" type="string" default="/" %}}
|
||||
The path where the file system would be mounted. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L61)
|
||||
The path where the file system would be mounted. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L62)
|
||||
{{< highlight toml >}}
|
||||
[grpc.services.storageprovider]
|
||||
mount_path = "/"
|
||||
@ -17,7 +17,7 @@ mount_path = "/"
|
||||
{{% /dir %}}
|
||||
|
||||
{{% dir name="mount_id" type="string" default="-" %}}
|
||||
The ID of the mounted file system. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L62)
|
||||
The ID of the mounted file system. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L63)
|
||||
{{< highlight toml >}}
|
||||
[grpc.services.storageprovider]
|
||||
mount_id = "-"
|
||||
@ -25,7 +25,7 @@ mount_id = "-"
|
||||
{{% /dir %}}
|
||||
|
||||
{{% dir name="driver" type="string" default="localhome" %}}
|
||||
The storage driver to be used. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L63)
|
||||
The storage driver to be used. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L64)
|
||||
{{< highlight toml >}}
|
||||
[grpc.services.storageprovider]
|
||||
driver = "localhome"
|
||||
@ -33,7 +33,7 @@ driver = "localhome"
|
||||
{{% /dir %}}
|
||||
|
||||
{{% dir name="drivers" type="map[string]map[string]interface{}" default="localhome" %}}
|
||||
[[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L64)
|
||||
[[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L65)
|
||||
{{< highlight toml >}}
|
||||
[grpc.services.storageprovider.drivers.localhome]
|
||||
root = "/var/tmp/reva/"
|
||||
@ -44,7 +44,7 @@ user_layout = "{{.Username}}"
|
||||
{{% /dir %}}
|
||||
|
||||
{{% dir name="data_server_url" type="string" default="http://localhost/data" %}}
|
||||
The URL for the data server. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L65)
|
||||
The URL for the data server. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L66)
|
||||
{{< highlight toml >}}
|
||||
[grpc.services.storageprovider]
|
||||
data_server_url = "http://localhost/data"
|
||||
@ -52,7 +52,7 @@ data_server_url = "http://localhost/data"
|
||||
{{% /dir %}}
|
||||
|
||||
{{% dir name="expose_data_server" type="bool" default=false %}}
|
||||
Whether to expose data server. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L66)
|
||||
Whether to expose data server. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L67)
|
||||
{{< highlight toml >}}
|
||||
[grpc.services.storageprovider]
|
||||
expose_data_server = false
|
||||
@ -60,7 +60,7 @@ expose_data_server = false
|
||||
{{% /dir %}}
|
||||
|
||||
{{% dir name="available_checksums" type="map[string]uint32" default=nil %}}
|
||||
List of available checksums. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L67)
|
||||
List of available checksums. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L68)
|
||||
{{< highlight toml >}}
|
||||
[grpc.services.storageprovider]
|
||||
available_checksums = nil
|
||||
@ -68,7 +68,7 @@ available_checksums = nil
|
||||
{{% /dir %}}
|
||||
|
||||
{{% dir name="custom_mime_types_json" type="string" default="nil" %}}
|
||||
An optional mapping file with the list of supported custom file extensions and corresponding mime types. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L68)
|
||||
An optional mapping file with the list of supported custom file extensions and corresponding mime types. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/storageprovider/storageprovider.go#L69)
|
||||
{{< highlight toml >}}
|
||||
[grpc.services.storageprovider]
|
||||
custom_mime_types_json = "nil"
|
||||
|
@ -9,7 +9,7 @@ description: >
|
||||
# _struct: Config_
|
||||
|
||||
{{% dir name="insecure" type="bool" default=false %}}
|
||||
Whether to skip certificate checks when sending requests. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/http/services/appprovider/appprovider.go#L57)
|
||||
Whether to skip certificate checks when sending requests. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/http/services/appprovider/appprovider.go#L59)
|
||||
{{< highlight toml >}}
|
||||
[http.services.appprovider]
|
||||
insecure = false
|
||||
|
@ -48,8 +48,16 @@ webapp_root = "/external/sciencemesh"
|
||||
{{< /highlight >}}
|
||||
{{% /dir %}}
|
||||
|
||||
{{% dir name="invite_accept_dialog" type="string" default="/sciencemesh-app/invitations" %}}
|
||||
The frontend URL where to land when receiving an invitation [[Ref]](https://github.com/cs3org/reva/tree/master/internal/http/services/wellknown/ocm.go#L38)
|
||||
{{< highlight toml >}}
|
||||
[http.services.wellknown]
|
||||
invite_accept_dialog = "/sciencemesh-app/invitations"
|
||||
{{< /highlight >}}
|
||||
{{% /dir %}}
|
||||
|
||||
{{% dir name="enable_webapp" type="bool" default=false %}}
|
||||
Whether web apps are enabled in OCM shares. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/http/services/wellknown/ocm.go#L38)
|
||||
Whether web apps are enabled in OCM shares. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/http/services/wellknown/ocm.go#L39)
|
||||
{{< highlight toml >}}
|
||||
[http.services.wellknown]
|
||||
enable_webapp = false
|
||||
@ -57,7 +65,7 @@ enable_webapp = false
|
||||
{{% /dir %}}
|
||||
|
||||
{{% dir name="enable_datatx" type="bool" default=false %}}
|
||||
Whether data transfers are enabled in OCM shares. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/http/services/wellknown/ocm.go#L39)
|
||||
Whether data transfers are enabled in OCM shares. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/http/services/wellknown/ocm.go#L40)
|
||||
{{< highlight toml >}}
|
||||
[http.services.wellknown]
|
||||
enable_datatx = false
|
||||
|
@ -146,6 +146,8 @@ enable_home_creation = true
|
||||
|
||||
[grpc.services.storageprovider.drivers.localhome]
|
||||
user_layout = "{{.Username}}"
|
||||
root = "/revalocalstorage"
|
||||
share_folder = "/revashares"
|
||||
|
||||
[[grpc.services.storageprovider]]
|
||||
driver = "ocmoutcoming"
|
||||
@ -257,6 +259,7 @@ driver = "localhome"
|
||||
|
||||
[http.services.dataprovider.drivers.localhome]
|
||||
user_layout = "{{.Username}}"
|
||||
root = "/revalocalstorage"
|
||||
|
||||
[[http.services.dataprovider]]
|
||||
address = ":443"
|
||||
@ -406,3 +409,7 @@ debug = true
|
||||
exposed_headers = []
|
||||
|
||||
[http.middlewares.log]
|
||||
level = "debug"
|
||||
|
||||
[http.interceptors.log]
|
||||
level = "debug"
|
||||
|
@ -115,6 +115,11 @@ http {
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
|
||||
location ^~ /.well-known/ {
|
||||
proxy_pass https://revad;
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
|
||||
location ^~ /ocm/ {
|
||||
proxy_pass https://revad;
|
||||
proxy_set_header Host $host;
|
||||
|
20
go.mod
20
go.mod
@ -5,7 +5,7 @@ require (
|
||||
github.com/CiscoM31/godata v1.0.8
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible
|
||||
github.com/ReneKroon/ttlcache/v2 v2.11.0
|
||||
github.com/beevik/etree v1.4.1
|
||||
github.com/beevik/etree v1.5.0
|
||||
github.com/bluele/gcache v0.0.2
|
||||
github.com/c-bata/go-prompt v0.2.6
|
||||
github.com/ceph/go-ceph v0.32.0
|
||||
@ -14,12 +14,12 @@ require (
|
||||
github.com/coreos/go-oidc/v3 v3.12.0
|
||||
github.com/creasty/defaults v1.8.0
|
||||
github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e
|
||||
github.com/cs3org/go-cs3apis v0.0.0-20241105092511-3ad35d174fc1
|
||||
github.com/cs3org/go-cs3apis v0.0.0-20250218144737-544dd3919658
|
||||
github.com/dgraph-io/ristretto v0.2.0
|
||||
github.com/dolthub/go-mysql-server v0.14.0
|
||||
github.com/gdexlab/go-render v1.0.1
|
||||
github.com/glpatcern/go-mime v0.0.0-20221026162842-2a8d71ad17a9
|
||||
github.com/go-chi/chi/v5 v5.2.0
|
||||
github.com/go-chi/chi/v5 v5.2.1
|
||||
github.com/go-ldap/ldap/v3 v3.4.10
|
||||
github.com/go-playground/locales v0.14.1
|
||||
github.com/go-playground/universal-translator v0.18.1
|
||||
@ -44,7 +44,7 @@ require (
|
||||
github.com/onsi/gomega v1.36.2
|
||||
github.com/owncloud/libre-graph-api-go v1.0.5-0.20240425090020-dba6d1507c38
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.20.5
|
||||
github.com/prometheus/client_golang v1.21.1
|
||||
github.com/rs/cors v1.11.1
|
||||
github.com/rs/zerolog v1.33.0
|
||||
github.com/sethvargo/go-password v0.3.1
|
||||
@ -61,8 +61,8 @@ require (
|
||||
golang.org/x/sys v0.29.0
|
||||
golang.org/x/term v0.28.0
|
||||
google.golang.org/genproto v0.0.0-20241209162323-e6fa225c2576
|
||||
google.golang.org/grpc v1.69.4
|
||||
google.golang.org/protobuf v1.36.4
|
||||
google.golang.org/grpc v1.71.0
|
||||
google.golang.org/protobuf v1.36.5
|
||||
gorm.io/driver/mysql v1.5.7
|
||||
gorm.io/driver/sqlite v1.5.7
|
||||
gorm.io/gorm v1.25.12
|
||||
@ -123,20 +123,20 @@ require (
|
||||
github.com/pkg/term v1.2.0-beta.2 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.61.0 // indirect
|
||||
github.com/prometheus/common v0.62.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/shopspring/decimal v1.4.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/stretchr/objx v0.5.2 // indirect
|
||||
go.mongodb.org/mongo-driver v1.17.1 // indirect
|
||||
go.opentelemetry.io/otel v1.31.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.31.0 // indirect
|
||||
go.opentelemetry.io/otel v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.34.0 // indirect
|
||||
golang.org/x/mod v0.22.0 // indirect
|
||||
golang.org/x/net v0.34.0 // indirect
|
||||
golang.org/x/text v0.22.0 // indirect
|
||||
golang.org/x/tools v0.28.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect
|
||||
gopkg.in/src-d/go-errors.v1 v1.0.0 // indirect
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
54
go.sum
54
go.sum
@ -824,8 +824,8 @@ github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQ
|
||||
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.45.1/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
|
||||
github.com/beevik/etree v1.4.1 h1:PmQJDDYahBGNKDcpdX8uPy1xRCwoCGVUiW669MEirVI=
|
||||
github.com/beevik/etree v1.4.1/go.mod h1:gPNJNaBGVZ9AwsidazFZyygnd+0pAU38N4D+WemwKNs=
|
||||
github.com/beevik/etree v1.5.0 h1:iaQZFSDS+3kYZiGoc9uKeOkUY3nYMXOKLl6KIJxiJWs=
|
||||
github.com/beevik/etree v1.5.0/go.mod h1:gPNJNaBGVZ9AwsidazFZyygnd+0pAU38N4D+WemwKNs=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
@ -895,8 +895,8 @@ github.com/creasty/defaults v1.8.0 h1:z27FJxCAa0JKt3utc0sCImAEb+spPucmKoOdLHvHYK
|
||||
github.com/creasty/defaults v1.8.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM=
|
||||
github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e h1:tqSPWQeueWTKnJVMJffz4pz0o1WuQxJ28+5x5JgaHD8=
|
||||
github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e/go.mod h1:XJEZ3/EQuI3BXTp/6DUzFr850vlxq11I6satRtz0YQ4=
|
||||
github.com/cs3org/go-cs3apis v0.0.0-20241105092511-3ad35d174fc1 h1:RU6LT6mkD16xZs011+8foU7T3LrPvTTSWeTQ9OgfhkA=
|
||||
github.com/cs3org/go-cs3apis v0.0.0-20241105092511-3ad35d174fc1/go.mod h1:DedpcqXl193qF/08Y04IO0PpxyyMu8+GrkD6kWK2MEQ=
|
||||
github.com/cs3org/go-cs3apis v0.0.0-20250218144737-544dd3919658 h1:CmH7twDuNUrHQXChZMafWjsEp1V47KutJlOAt6FjzGA=
|
||||
github.com/cs3org/go-cs3apis v0.0.0-20250218144737-544dd3919658/go.mod h1:DedpcqXl193qF/08Y04IO0PpxyyMu8+GrkD6kWK2MEQ=
|
||||
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=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@ -959,8 +959,8 @@ github.com/glpatcern/go-mime v0.0.0-20221026162842-2a8d71ad17a9 h1:3um08ooi0/lyR
|
||||
github.com/glpatcern/go-mime v0.0.0-20221026162842-2a8d71ad17a9/go.mod h1:EJaddanP+JfU3UkVvn0rYYF3b/gD7eZRejbTHqiQExA=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.7 h1:DTX+lbVTWaTw1hQ+PbZPlnDZPEIs0SS/GCZAl535dDk=
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.7/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||
github.com/go-chi/chi/v5 v5.2.0 h1:Aj1EtB0qR2Rdo2dG4O94RIU35w2lvQSj6BRA4+qwFL0=
|
||||
github.com/go-chi/chi/v5 v5.2.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8=
|
||||
github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
|
||||
github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g=
|
||||
github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks=
|
||||
github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY=
|
||||
@ -1442,8 +1442,8 @@ github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqr
|
||||
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
|
||||
github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
|
||||
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
|
||||
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
|
||||
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk=
|
||||
github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
@ -1461,8 +1461,8 @@ github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9
|
||||
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
|
||||
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
|
||||
github.com/prometheus/common v0.61.0 h1:3gv/GThfX0cV2lpO7gkTUwZru38mxevy90Bj8YFSRQQ=
|
||||
github.com/prometheus/common v0.61.0/go.mod h1:zr29OCN/2BsJRaFwG8QOBr41D6kkchKbpeNH7pAjb/s=
|
||||
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
|
||||
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
@ -1583,16 +1583,18 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY=
|
||||
go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE=
|
||||
go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE=
|
||||
go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY=
|
||||
go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk=
|
||||
go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8=
|
||||
go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys=
|
||||
go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
|
||||
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
|
||||
go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
|
||||
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
|
||||
go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
|
||||
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
|
||||
go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
|
||||
@ -2339,8 +2341,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130/go.
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230731190214-cbb8c96f2d6d/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230807174057-1744710a1577/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d h1:xJJRGY7TJcvIlpSrN3K6LAWgNFUILlO+OMAqtg9aqnw=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
|
||||
@ -2391,8 +2393,8 @@ google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGO
|
||||
google.golang.org/grpc v1.56.1/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
|
||||
google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
|
||||
google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo=
|
||||
google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A=
|
||||
google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
|
||||
google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
|
||||
google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
@ -2412,8 +2414,8 @@ google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
|
||||
google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM=
|
||||
google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/Acconut/lockfile.v1 v1.1.0/go.mod h1:6UCz3wJ8tSFUsPR6uP/j8uegEtDuEEqFxlpi0JI4Umw=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
@ -1199,6 +1199,7 @@ func (s *svc) statSharesFolder(ctx context.Context) (*provider.StatResponse, err
|
||||
}
|
||||
|
||||
func (s *svc) stat(ctx context.Context, req *provider.StatRequest) (*provider.StatResponse, error) {
|
||||
log := appctx.GetLogger(ctx)
|
||||
providers, err := s.findProviders(ctx, req.Ref)
|
||||
if err != nil {
|
||||
return &provider.StatResponse{
|
||||
@ -1217,6 +1218,7 @@ func (s *svc) stat(ctx context.Context, req *provider.StatRequest) (*provider.St
|
||||
}
|
||||
rsp, err := c.Stat(ctx, req)
|
||||
if err != nil || rsp.Status.Code != rpc.Code_CODE_OK {
|
||||
log.Error().Err(err).Msg("Failed to stat " + resPath)
|
||||
return rsp, err
|
||||
}
|
||||
return rsp, nil
|
||||
|
@ -191,7 +191,8 @@ func (s *service) getWebdavProtocol(share *ocm.Share, m *ocm.AccessMethod_Webdav
|
||||
|
||||
return &ocmd.WebDAV{
|
||||
Permissions: perms,
|
||||
URL: s.webdavURL(share),
|
||||
Requirements: m.WebdavOptions.Requirements,
|
||||
URI: s.webdavURL(share),
|
||||
SharedSecret: share.Token,
|
||||
}
|
||||
}
|
||||
@ -202,7 +203,7 @@ func (s *service) getWebappProtocol(share *ocm.Share) *ocmd.Webapp {
|
||||
panic(err)
|
||||
}
|
||||
return &ocmd.Webapp{
|
||||
URITemplate: b.String(),
|
||||
URI: b.String(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@ import (
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
@ -235,6 +236,7 @@ func (s *service) SetArbitraryMetadata(ctx context.Context, req *provider.SetArb
|
||||
}
|
||||
|
||||
func (s *service) UnsetArbitraryMetadata(ctx context.Context, req *provider.UnsetArbitraryMetadataRequest) (*provider.UnsetArbitraryMetadataResponse, error) {
|
||||
log := appctx.GetLogger(ctx)
|
||||
newRef, err := s.unwrap(ctx, req.Ref)
|
||||
if err != nil {
|
||||
err := errors.Wrap(err, "storageprovidersvc: error unwrapping path")
|
||||
@ -251,6 +253,7 @@ func (s *service) UnsetArbitraryMetadata(ctx context.Context, req *provider.Unse
|
||||
case errtypes.PermissionDenied:
|
||||
st = status.NewPermissionDenied(ctx, err, "permission denied")
|
||||
default:
|
||||
log.Error().Err(err).Str("ref", req.Ref.String()).Any("keys", req.ArbitraryMetadataKeys).Msg("error unsetting arbitrary metadata")
|
||||
st = status.NewInternal(ctx, err, "error unsetting arbitrary metadata: "+req.Ref.String())
|
||||
}
|
||||
return &provider.UnsetArbitraryMetadataResponse{
|
||||
@ -810,6 +813,7 @@ func (s *service) Stat(ctx context.Context, req *provider.StatRequest) (*provide
|
||||
}, nil
|
||||
}
|
||||
s.fixPermissions(md)
|
||||
s.stripNonUtf8Metadata(ctx, md)
|
||||
s.addSpaceInfo(md)
|
||||
res := &provider.StatResponse{
|
||||
Status: status.NewOK(ctx),
|
||||
@ -837,6 +841,28 @@ func (s *service) fixPermissions(md *provider.ResourceInfo) {
|
||||
}
|
||||
}
|
||||
|
||||
// This method removes any entries in the ArbitraryMetadata map that
|
||||
// are not valid UTF-8
|
||||
// This is necessary because protobuf requires strings to only contain valid UTF-8
|
||||
func (s *service) stripNonUtf8Metadata(ctx context.Context, md *provider.ResourceInfo) {
|
||||
log := appctx.GetLogger(ctx)
|
||||
if md.ArbitraryMetadata == nil {
|
||||
return
|
||||
}
|
||||
|
||||
toDelete := []string{}
|
||||
for k, v := range md.ArbitraryMetadata.Metadata {
|
||||
if !utf8.ValidString(v) {
|
||||
toDelete = append(toDelete, k)
|
||||
}
|
||||
}
|
||||
|
||||
for _, k := range toDelete {
|
||||
log.Debug().Str("attribute", k).Msg("Dropping non-UTF8 metadata entry")
|
||||
delete(md.ArbitraryMetadata.Metadata, k)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *service) statVirtualView(ctx context.Context, ref *provider.Reference) (*provider.StatResponse, error) {
|
||||
// The reference in the request encompasses this provider
|
||||
// So we need to stat root, and update the required path
|
||||
@ -934,6 +960,7 @@ func (s *service) ListContainerStream(req *provider.ListContainerStreamRequest,
|
||||
}
|
||||
|
||||
func (s *service) ListContainer(ctx context.Context, req *provider.ListContainerRequest) (*provider.ListContainerResponse, error) {
|
||||
log := appctx.GetLogger(ctx)
|
||||
newRef, err := s.unwrap(ctx, req.Ref)
|
||||
if err != nil {
|
||||
// The path might be a virtual view; handle that case
|
||||
@ -955,6 +982,7 @@ func (s *service) ListContainer(ctx context.Context, req *provider.ListContainer
|
||||
case errtypes.PermissionDenied:
|
||||
st = status.NewPermissionDenied(ctx, err, "permission denied")
|
||||
default:
|
||||
log.Error().Any("ref", newRef).Err(err).Msg("storageprovider: error listing container")
|
||||
st = status.NewInternal(ctx, err, "error listing container: "+req.Ref.String())
|
||||
}
|
||||
return &provider.ListContainerResponse{
|
||||
@ -971,7 +999,7 @@ func (s *service) ListContainer(ctx context.Context, req *provider.ListContainer
|
||||
}, nil
|
||||
}
|
||||
s.fixPermissions(md)
|
||||
s.addSpaceInfo(md)
|
||||
s.stripNonUtf8Metadata(ctx, md)
|
||||
infos = append(infos, md)
|
||||
}
|
||||
res := &provider.ListContainerResponse{
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
||||
apppb "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1"
|
||||
appregistry "github.com/cs3org/go-cs3apis/cs3/app/registry/v1beta1"
|
||||
@ -436,7 +437,14 @@ func (s *svc) handleOpen(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
log := appctx.GetLogger(ctx)
|
||||
log.Info().Interface("resource", &fileRef).Str("url", openRes.AppUrl.AppUrl).Str("method", openRes.AppUrl.Method).Interface("viewMode", viewMode).Msg("returning app URL for file")
|
||||
log.Info().Interface("resource", fileRef.ResourceId).
|
||||
Str("url", openRes.AppUrl.AppUrl).
|
||||
Str("method", openRes.AppUrl.Method).
|
||||
Interface("viewMode", viewMode).
|
||||
Str("fileExt", filepath.Ext(statRes.Info.Path)).
|
||||
Str("agent", utils.SimplifiedUserAgent(r)).
|
||||
Msg("returning app URL for file")
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if _, err = w.Write(js); err != nil {
|
||||
writeError(w, r, appErrorServerError, "Internal error with JSON payload",
|
||||
@ -476,9 +484,9 @@ func (s *svc) handleNotify(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
log := appctx.GetLogger(ctx)
|
||||
if len(failure) == 0 {
|
||||
log.Info().Interface("resource", fileRef).Msg("file successfully opened in app")
|
||||
log.Info().Interface("resource", fileRef.ResourceId).Msg("file successfully opened in app")
|
||||
} else {
|
||||
log.Info().Interface("resource", fileRef).Str("failure", string(failure)).Msg("failed to open file in app")
|
||||
log.Info().Interface("resource", fileRef.ResourceId).Str("failure", string(failure)).Msg("failed to open file in app")
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
@ -56,7 +56,7 @@ type appError struct {
|
||||
// writeError handles writing error responses.
|
||||
func writeError(w http.ResponseWriter, r *http.Request, code appErrorCode, message string, err error) {
|
||||
if err != nil {
|
||||
appctx.GetLogger(r.Context()).Error().Err(err).Msg(message)
|
||||
appctx.GetLogger(r.Context()).Warn().Err(err).Msg(message)
|
||||
}
|
||||
|
||||
var encoded []byte
|
||||
|
@ -121,7 +121,7 @@ func (h *appsHandler) webappTemplate(ctx context.Context, id *ocmpb.ShareId) (st
|
||||
return "", errtypes.BadRequest("share does not contain webapp protocol")
|
||||
}
|
||||
|
||||
return webapp.UriTemplate, nil
|
||||
return webapp.Uri, nil
|
||||
}
|
||||
|
||||
func getWebappProtocol(protocols []*ocmpb.Protocol) (*ocmpb.WebappProtocol, bool) {
|
||||
|
@ -103,7 +103,7 @@ func (h *sharesHandler) CreateShare(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
perm, viewMode := getPermissionsByRole(req.Role)
|
||||
|
||||
log.Debug().Msg("calling gatewayClient.CreateOCMShare from sciencemesh/share.go")
|
||||
log.Debug().Msg("calling gatewayClient.CreateOCMShare")
|
||||
shareRes, err := h.gatewayClient.CreateOCMShare(ctx, &ocm.CreateOCMShareRequest{
|
||||
ResourceId: statRes.Info.Id,
|
||||
Grantee: &providerpb.Grantee{
|
||||
@ -117,11 +117,11 @@ func (h *sharesHandler) CreateShare(w http.ResponseWriter, r *http.Request) {
|
||||
},
|
||||
RecipientMeshProvider: recipientProviderInfo.ProviderInfo,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(perm),
|
||||
share.NewWebDavAccessMethod(perm, []string{}),
|
||||
share.NewWebappAccessMethod(viewMode),
|
||||
},
|
||||
})
|
||||
log.Debug().Msg("called gatewayClient.CreateOCMShare from sciencemesh/share.go")
|
||||
log.Debug().Any("response", shareRes).Msg("called gatewayClient.CreateOCMShare")
|
||||
|
||||
switch {
|
||||
case err != nil:
|
||||
|
@ -19,7 +19,6 @@
|
||||
package ocmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
@ -71,70 +70,59 @@ func NewClient(timeout time.Duration, insecure bool) *OCMClient {
|
||||
// Discover returns a number of properties used to discover the capabilities offered by a remote cloud storage.
|
||||
// https://cs3org.github.io/OCM-API/docs.html?branch=develop&repo=OCM-API&user=cs3org#/paths/~1ocm-provider/get
|
||||
func (c *OCMClient) Discover(ctx context.Context, endpoint string) (*wellknown.OcmDiscoveryData, error) {
|
||||
url, err := url.JoinPath(endpoint, "/ocm-provider")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log := appctx.GetLogger(ctx)
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error creating request")
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
remoteurl, _ := url.JoinPath(endpoint, "/.well-known/ocm")
|
||||
body, err := c.discover(ctx, remoteurl)
|
||||
if err != nil || len(body) == 0 {
|
||||
log.Debug().Err(err).Str("sender", remoteurl).Str("response", string(body)).Msg("invalid or empty response, falling back to legacy discovery")
|
||||
remoteurl, _ := url.JoinPath(endpoint, "/ocm-provider") // legacy discovery endpoint
|
||||
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error doing request")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
body, err = c.discover(ctx, remoteurl)
|
||||
if err != nil || len(body) == 0 {
|
||||
log.Warn().Err(err).Str("sender", remoteurl).Str("response", string(body)).Msg("invalid or empty response")
|
||||
return nil, errtypes.BadRequest("Invalid response on OCM discovery")
|
||||
}
|
||||
}
|
||||
|
||||
var disco wellknown.OcmDiscoveryData
|
||||
err = json.Unmarshal(body, &disco)
|
||||
if err != nil {
|
||||
log := appctx.GetLogger(ctx)
|
||||
log.Warn().Str("sender", endpoint).Str("response", string(body)).Msg("malformed response")
|
||||
return nil, errtypes.InternalError("Invalid payload on OCM discovery")
|
||||
log.Warn().Err(err).Str("sender", remoteurl).Str("response", string(body)).Msg("malformed response")
|
||||
return nil, errtypes.BadRequest("Invalid payload on OCM discovery")
|
||||
}
|
||||
|
||||
log.Debug().Str("sender", remoteurl).Any("response", disco).Msg("discovery response")
|
||||
return &disco, nil
|
||||
}
|
||||
|
||||
// NewShareRequest contains the parameters for creating a new OCM share.
|
||||
type NewShareRequest struct {
|
||||
ShareWith string `json:"shareWith"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
ProviderID string `json:"providerId"`
|
||||
Owner string `json:"owner"`
|
||||
Sender string `json:"sender"`
|
||||
OwnerDisplayName string `json:"ownerDisplayName"`
|
||||
SenderDisplayName string `json:"senderDisplayName"`
|
||||
ShareType string `json:"shareType"`
|
||||
Expiration uint64 `json:"expiration"`
|
||||
ResourceType string `json:"resourceType"`
|
||||
Protocols Protocols `json:"protocol"`
|
||||
}
|
||||
func (c *OCMClient) discover(ctx context.Context, url string) ([]byte, error) {
|
||||
log := appctx.GetLogger(ctx)
|
||||
|
||||
func (r *NewShareRequest) toJSON() (io.Reader, error) {
|
||||
var b bytes.Buffer
|
||||
if err := json.NewEncoder(&b).Encode(r); err != nil {
|
||||
return nil, err
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error creating OCM discovery request")
|
||||
}
|
||||
return &b, nil
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error doing OCM discovery request")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
log.Warn().Str("sender", url).Any("response", resp).Int("status", resp.StatusCode).Msg("discovery returned")
|
||||
return nil, errtypes.BadRequest("Remote does not offer a valid OCM discovery endpoint")
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "malformed remote OCM discovery")
|
||||
}
|
||||
return body, nil
|
||||
}
|
||||
|
||||
// NewShareResponse is the response returned when creating a new share.
|
||||
type NewShareResponse struct {
|
||||
RecipientDisplayName string `json:"recipientDisplayName"`
|
||||
}
|
||||
|
||||
// NewShare creates a new share.
|
||||
// https://github.com/cs3org/OCM-API/blob/develop/spec.yaml
|
||||
// NewShare sends a new OCM share to the remote system.
|
||||
func (c *OCMClient) NewShare(ctx context.Context, endpoint string, r *NewShareRequest) (*NewShareResponse, error) {
|
||||
url, err := url.JoinPath(endpoint, "shares")
|
||||
if err != nil {
|
||||
@ -182,35 +170,9 @@ func (c *OCMClient) parseNewShareResponse(r *http.Response) (*NewShareResponse,
|
||||
return nil, errtypes.InternalError(string(body))
|
||||
}
|
||||
|
||||
// InviteAcceptedRequest contains the parameters for accepting
|
||||
// an invitation.
|
||||
type InviteAcceptedRequest struct {
|
||||
UserID string `json:"userID"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
RecipientProvider string `json:"recipientProvider"`
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
// User contains the remote user's information when accepting
|
||||
// an invitation.
|
||||
type User struct {
|
||||
UserID string `json:"userID"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func (r *InviteAcceptedRequest) toJSON() (io.Reader, error) {
|
||||
var b bytes.Buffer
|
||||
if err := json.NewEncoder(&b).Encode(r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &b, nil
|
||||
}
|
||||
|
||||
// InviteAccepted informs the sender that the invitation was accepted to start sharing
|
||||
// InviteAccepted informs the remote end that the invitation was accepted to start sharing
|
||||
// https://cs3org.github.io/OCM-API/docs.html?branch=develop&repo=OCM-API&user=cs3org#/paths/~1invite-accepted/post
|
||||
func (c *OCMClient) InviteAccepted(ctx context.Context, endpoint string, r *InviteAcceptedRequest) (*User, error) {
|
||||
func (c *OCMClient) InviteAccepted(ctx context.Context, endpoint string, r *InviteAcceptedRequest) (*RemoteUser, error) {
|
||||
url, err := url.JoinPath(endpoint, "invite-accepted")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -236,10 +198,10 @@ func (c *OCMClient) InviteAccepted(ctx context.Context, endpoint string, r *Invi
|
||||
return c.parseInviteAcceptedResponse(resp)
|
||||
}
|
||||
|
||||
func (c *OCMClient) parseInviteAcceptedResponse(r *http.Response) (*User, error) {
|
||||
func (c *OCMClient) parseInviteAcceptedResponse(r *http.Response) (*RemoteUser, error) {
|
||||
switch r.StatusCode {
|
||||
case http.StatusOK:
|
||||
var u User
|
||||
var u RemoteUser
|
||||
if err := json.NewDecoder(r.Body).Decode(&u); err != nil {
|
||||
return nil, errors.Wrap(err, "error decoding response body")
|
||||
}
|
||||
|
@ -49,14 +49,6 @@ func (h *invitesHandler) init(c *config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type acceptInviteRequest struct {
|
||||
Token string `json:"token"`
|
||||
UserID string `json:"userID"`
|
||||
RecipientProvider string `json:"recipientProvider"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
|
||||
// AcceptInvite informs avout an accepted invitation so that the users
|
||||
// can initiate the OCM share creation.
|
||||
func (h *invitesHandler) AcceptInvite(w http.ResponseWriter, r *http.Request) {
|
||||
@ -68,6 +60,7 @@ func (h *invitesHandler) AcceptInvite(w http.ResponseWriter, r *http.Request) {
|
||||
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "missing parameters in request", err)
|
||||
return
|
||||
}
|
||||
log.Info().Any("req", req).Msg("OCM /invite-accepted request received")
|
||||
|
||||
if req.Token == "" || req.UserID == "" || req.RecipientProvider == "" {
|
||||
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "token, userID and recipiendProvider must not be null", nil)
|
||||
@ -138,7 +131,7 @@ func (h *invitesHandler) AcceptInvite(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
if err := json.NewEncoder(w).Encode(&user{
|
||||
if err := json.NewEncoder(w).Encode(&RemoteUser{
|
||||
UserID: acceptInviteResponse.UserId.OpaqueId,
|
||||
Email: acceptInviteResponse.Email,
|
||||
Name: acceptInviteResponse.DisplayName,
|
||||
@ -152,14 +145,8 @@ func (h *invitesHandler) AcceptInvite(w http.ResponseWriter, r *http.Request) {
|
||||
log.Info().Str("user", fmt.Sprintf("%s@%s", userObj.Id.OpaqueId, userObj.Id.Idp)).Str("token", req.Token).Msg("added to accepted users")
|
||||
}
|
||||
|
||||
type user struct {
|
||||
UserID string `json:"userID"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func getAcceptInviteRequest(r *http.Request) (*acceptInviteRequest, error) {
|
||||
var req acceptInviteRequest
|
||||
func getAcceptInviteRequest(r *http.Request) (*InviteAcceptedRequest, error) {
|
||||
var req InviteAcceptedRequest
|
||||
contentType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
||||
if err == nil && contentType == "application/json" {
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
|
@ -54,25 +54,26 @@ func TestUnmarshalProtocol(t *testing.T) {
|
||||
&WebDAV{
|
||||
SharedSecret: "secret",
|
||||
Permissions: []string{"read", "write", "share"},
|
||||
URL: "",
|
||||
URI: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
raw: `{"name":"multi","options":{},"webdav":{"sharedSecret":"secret","permissions":["read","write"],"url":"http://example.org"}}`,
|
||||
raw: `{"name":"multi","options":{},"webdav":{"sharedSecret":"secret","permissions":["read","write"],"requirements":["req"],"uri":"http://example.org"}}`,
|
||||
expected: []Protocol{
|
||||
&WebDAV{
|
||||
SharedSecret: "secret",
|
||||
Permissions: []string{"read", "write"},
|
||||
URL: "http://example.org",
|
||||
Requirements: []string{"req"},
|
||||
URI: "http://example.org",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
raw: `{"name":"multi","options":{},"webapp":{"uriTemplate":"http://example.org/{test}"}}`,
|
||||
raw: `{"name":"multi","options":{},"webapp":{"uri":"http://example.org/test"}}`,
|
||||
expected: []Protocol{
|
||||
&Webapp{
|
||||
URITemplate: "http://example.org/{test}",
|
||||
URI: "http://example.org/test",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -87,15 +88,15 @@ func TestUnmarshalProtocol(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
raw: `{"name":"multi","options":{},"webdav":{"sharedSecret":"secret","permissions":["read","write"],"url":"http://example.org"},"webapp":{"uriTemplate":"http://example.org/{test}"},"datatx":{"sharedSecret":"secret","srcUri":"http://example.org","size":10}}`,
|
||||
raw: `{"name":"multi","options":{},"webdav":{"sharedSecret":"secret","permissions":["read","write"],"uri":"http://example.org"},"webapp":{"uri":"http://example.org/test"},"datatx":{"sharedSecret":"secret","srcUri":"http://example.org","size":10}}`,
|
||||
expected: []Protocol{
|
||||
&WebDAV{
|
||||
SharedSecret: "secret",
|
||||
Permissions: []string{"read", "write"},
|
||||
URL: "http://example.org",
|
||||
URI: "http://example.org",
|
||||
},
|
||||
&Webapp{
|
||||
URITemplate: "http://example.org/{test}",
|
||||
URI: "http://example.org/test",
|
||||
},
|
||||
&Datatx{
|
||||
SharedSecret: "secret",
|
||||
@ -155,7 +156,8 @@ func TestMarshalProtocol(t *testing.T) {
|
||||
&WebDAV{
|
||||
SharedSecret: "secret",
|
||||
Permissions: []string{"read"},
|
||||
URL: "http://example.org",
|
||||
Requirements: []string{},
|
||||
URI: "http://example.org",
|
||||
},
|
||||
},
|
||||
expected: map[string]any{
|
||||
@ -164,23 +166,25 @@ func TestMarshalProtocol(t *testing.T) {
|
||||
"webdav": map[string]any{
|
||||
"sharedSecret": "secret",
|
||||
"permissions": []any{"read"},
|
||||
"url": "http://example.org",
|
||||
"requirements": []any{},
|
||||
"uri": "http://example.org",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
in: []Protocol{
|
||||
&Webapp{
|
||||
URITemplate: "http://example.org",
|
||||
ViewMode: "read",
|
||||
URI: "http://example.org",
|
||||
ViewMode: "read",
|
||||
},
|
||||
},
|
||||
expected: map[string]any{
|
||||
"name": "multi",
|
||||
"options": map[string]any{},
|
||||
"webapp": map[string]any{
|
||||
"uriTemplate": "http://example.org",
|
||||
"viewMode": "read",
|
||||
"uri": "http://example.org",
|
||||
"viewMode": "read",
|
||||
"sharedSecret": "",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -207,11 +211,12 @@ func TestMarshalProtocol(t *testing.T) {
|
||||
&WebDAV{
|
||||
SharedSecret: "secret",
|
||||
Permissions: []string{"read"},
|
||||
URL: "http://example.org",
|
||||
Requirements: []string{"req"},
|
||||
URI: "http://example.org",
|
||||
},
|
||||
&Webapp{
|
||||
URITemplate: "http://example.org",
|
||||
ViewMode: "read",
|
||||
URI: "http://example.org",
|
||||
ViewMode: "read",
|
||||
},
|
||||
&Datatx{
|
||||
SharedSecret: "secret",
|
||||
@ -225,11 +230,13 @@ func TestMarshalProtocol(t *testing.T) {
|
||||
"webdav": map[string]any{
|
||||
"sharedSecret": "secret",
|
||||
"permissions": []any{"read"},
|
||||
"url": "http://example.org",
|
||||
"requirements": []any{"req"},
|
||||
"uri": "http://example.org",
|
||||
},
|
||||
"webapp": map[string]any{
|
||||
"uriTemplate": "http://example.org",
|
||||
"viewMode": "read",
|
||||
"uri": "http://example.org",
|
||||
"viewMode": "read",
|
||||
"sharedSecret": "",
|
||||
},
|
||||
"datatx": map[string]any{
|
||||
"sharedSecret": "secret",
|
||||
|
@ -19,11 +19,12 @@
|
||||
package ocmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"mime"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@ -63,27 +64,12 @@ func (h *sharesHandler) init(c *config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type createShareRequest struct {
|
||||
ShareWith string `json:"shareWith" validate:"required"` // identifier of the recipient of the share
|
||||
Name string `json:"name" validate:"required"` // name of the resource
|
||||
Description string `json:"description"` // (optional) description of the resource
|
||||
ProviderID string `json:"providerId" validate:"required"` // unique identifier of the resource at provider side
|
||||
Owner string `json:"owner" validate:"required"` // unique identifier of the owner at provider side
|
||||
Sender string `json:"sender" validate:"required"` // unique indentifier of the user who wants to share the resource at provider side
|
||||
OwnerDisplayName string `json:"ownerDisplayName"` // display name of the owner of the resource
|
||||
SenderDisplayName string `json:"senderDisplayName"` // dispay name of the user who wants to share the resource
|
||||
ShareType string `json:"shareType" validate:"required,oneof=user group"` // recipient share type (user or group)
|
||||
ResourceType string `json:"resourceType" validate:"required,oneof=file folder"`
|
||||
Expiration uint64 `json:"expiration"`
|
||||
Protocols Protocols `json:"protocol" validate:"required"`
|
||||
}
|
||||
|
||||
// CreateShare sends all the informations to the consumer needed to start
|
||||
// synchronization between the two services.
|
||||
// CreateShare implements the OCM /shares call.
|
||||
func (h *sharesHandler) CreateShare(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
log := appctx.GetLogger(ctx)
|
||||
req, err := getCreateShareRequest(r)
|
||||
log.Info().Any("req", req).Msg("OCM /shares request received")
|
||||
if err != nil {
|
||||
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, err.Error(), nil)
|
||||
return
|
||||
@ -114,7 +100,7 @@ func (h *sharesHandler) CreateShare(w http.ResponseWriter, r *http.Request) {
|
||||
Provider: &providerInfo,
|
||||
})
|
||||
if err != nil {
|
||||
reqres.WriteError(w, r, reqres.APIErrorServerError, "error sending a grpc is provider allowed request", err)
|
||||
reqres.WriteError(w, r, reqres.APIErrorServerError, "error sending a grpc isProviderAllowed request", err)
|
||||
return
|
||||
}
|
||||
if providerAllowedResp.Status.Code != rpc.Code_CODE_OK {
|
||||
@ -124,7 +110,7 @@ func (h *sharesHandler) CreateShare(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
shareWith, _, err := getIDAndMeshProvider(req.ShareWith)
|
||||
if err != nil {
|
||||
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, err.Error(), nil)
|
||||
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "error with mesh provider", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -142,19 +128,19 @@ func (h *sharesHandler) CreateShare(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
owner, err := getUserIDFromOCMUser(req.Owner)
|
||||
if err != nil {
|
||||
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, err.Error(), nil)
|
||||
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "error with remote owner", err)
|
||||
return
|
||||
}
|
||||
|
||||
sender, err := getUserIDFromOCMUser(req.Sender)
|
||||
if err != nil {
|
||||
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, err.Error(), nil)
|
||||
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "error with remote sender", err)
|
||||
return
|
||||
}
|
||||
|
||||
protocols, err := getAndResolveProtocols(req.Protocols, r)
|
||||
protocols, err := getAndResolveProtocols(ctx, req.Protocols, owner.Idp)
|
||||
if err != nil {
|
||||
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, err.Error(), nil)
|
||||
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "error with protocols payload", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -176,6 +162,7 @@ func (h *sharesHandler) CreateShare(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
log.Info().Any("req", createShareReq).Msg("CreateOCMCoreShare payload")
|
||||
createShareResp, err := h.gatewayClient.CreateOCMCoreShare(ctx, createShareReq)
|
||||
if err != nil {
|
||||
reqres.WriteError(w, r, reqres.APIErrorServerError, "error creating ocm share", err)
|
||||
@ -220,15 +207,15 @@ func getIDAndMeshProvider(user string) (string, string, error) {
|
||||
return strings.Join(split[:len(split)-1], "@"), split[len(split)-1], nil
|
||||
}
|
||||
|
||||
func getCreateShareRequest(r *http.Request) (*createShareRequest, error) {
|
||||
var req createShareRequest
|
||||
func getCreateShareRequest(r *http.Request) (*NewShareRequest, error) {
|
||||
var req NewShareRequest
|
||||
contentType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
||||
if err == nil && contentType == "application/json" {
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "malformed OCM /shares request")
|
||||
}
|
||||
} else {
|
||||
return nil, errors.New("body request not recognised")
|
||||
return nil, errors.New("malformed OCM /shares request payload")
|
||||
}
|
||||
// validate the request
|
||||
if err := validate.Struct(req); err != nil {
|
||||
@ -260,45 +247,81 @@ func getOCMShareType(t string) ocm.ShareType {
|
||||
}
|
||||
}
|
||||
|
||||
func getAndResolveProtocols(p Protocols, r *http.Request) ([]*ocm.Protocol, error) {
|
||||
func getAndResolveProtocols(ctx context.Context, p Protocols, ownerServer string) ([]*ocm.Protocol, error) {
|
||||
protos := make([]*ocm.Protocol, 0, len(p))
|
||||
for _, data := range p {
|
||||
var uri string
|
||||
ocmProto := data.ToOCMProtocol()
|
||||
if GetProtocolName(data) == "webdav" && ocmProto.GetWebdavOptions().Uri == "" {
|
||||
// This is an OCM 1.0 payload with only webdav: we need to resolve the remote URL
|
||||
remoteRoot, err := discoverOcmWebdavRoot(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
protocolName := GetProtocolName(data)
|
||||
switch protocolName {
|
||||
case "webdav":
|
||||
uri = ocmProto.GetWebdavOptions().Uri
|
||||
reqs := ocmProto.GetWebdavOptions().Requirements
|
||||
if len(reqs) > 0 {
|
||||
// we currently do not support any kind of requirement
|
||||
return nil, errtypes.BadRequest(fmt.Sprintf("incoming OCM share with requirements %+v not supported at this endpoint", reqs))
|
||||
}
|
||||
ocmProto.GetWebdavOptions().Uri = filepath.Join(remoteRoot, ocmProto.GetWebdavOptions().SharedSecret)
|
||||
case "webapp":
|
||||
uri = ocmProto.GetWebappOptions().Uri
|
||||
}
|
||||
|
||||
// If the `uri` contains a hostname, use it as is
|
||||
u, _ := url.Parse(uri)
|
||||
if u.Host != "" {
|
||||
protos = append(protos, ocmProto)
|
||||
continue
|
||||
}
|
||||
// otherwise use as endpoint the owner's server from the payload
|
||||
remoteRoot, err := discoverOcmRoot(ctx, ownerServer, protocolName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if strings.HasPrefix(uri, "/") {
|
||||
// only take the host from remoteRoot and append the absolute uri
|
||||
u, _ := url.Parse(remoteRoot)
|
||||
u.Path = uri
|
||||
uri = u.String()
|
||||
} else {
|
||||
// relative uri
|
||||
uri, _ = url.JoinPath(remoteRoot, uri)
|
||||
}
|
||||
|
||||
switch protocolName {
|
||||
case "webdav":
|
||||
ocmProto.GetWebdavOptions().Uri = uri
|
||||
case "webapp":
|
||||
ocmProto.GetWebappOptions().Uri = uri
|
||||
}
|
||||
protos = append(protos, ocmProto)
|
||||
}
|
||||
|
||||
return protos, nil
|
||||
}
|
||||
|
||||
func discoverOcmWebdavRoot(r *http.Request) (string, error) {
|
||||
// implements the OCM discovery logic to fetch the WebDAV root at the remote host that sent the share, see
|
||||
func discoverOcmRoot(ctx context.Context, ownerServer string, proto string) (string, error) {
|
||||
// implements the OCM discovery logic to fetch the root at the remote host that sent the share for the given proto, see
|
||||
// https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1ocm-provider/get
|
||||
ctx := r.Context()
|
||||
log := appctx.GetLogger(ctx)
|
||||
log.Debug().Str("sender", r.Host).Msg("received OCM 1.0 share, attempting to discover sender endpoint")
|
||||
|
||||
ocmClient := NewClient(time.Duration(10)*time.Second, true)
|
||||
ocmCaps, err := ocmClient.Discover(ctx, r.Host)
|
||||
ocmCaps, err := ocmClient.Discover(ctx, "https://"+ownerServer)
|
||||
if err != nil {
|
||||
log.Warn().Str("sender", r.Host).Err(err).Msg("failed to discover OCM sender")
|
||||
log.Warn().Str("sender", ownerServer).Err(err).Msg("failed to discover OCM sender")
|
||||
return "", err
|
||||
}
|
||||
for _, t := range ocmCaps.ResourceTypes {
|
||||
webdavRoot, ok := t.Protocols["webdav"]
|
||||
protoRoot, ok := t.Protocols[proto]
|
||||
if ok {
|
||||
// assume the first resourceType that exposes a webdav root is OK to use: as a matter of fact,
|
||||
// assume the first resourceType that exposes a root is OK to use: as a matter of fact,
|
||||
// no implementation exists yet that exposes multiple resource types with different roots.
|
||||
return filepath.Join(ocmCaps.Endpoint, webdavRoot), nil
|
||||
u, _ := url.Parse(ocmCaps.Endpoint)
|
||||
u.Path = protoRoot
|
||||
u.RawQuery = ""
|
||||
log.Debug().Str("sender", ownerServer).Str("proto", proto).Str("URL", u.String()).Msg("resolved protocol URL")
|
||||
return u.String(), nil
|
||||
}
|
||||
}
|
||||
|
||||
log.Warn().Str("sender", r.Host).Interface("response", ocmCaps).Msg("missing webdav root")
|
||||
return "", errtypes.NotFound("WebDAV root not found on OCM discovery")
|
||||
log.Warn().Str("sender", ownerServer).Interface("response", ocmCaps).Msg("missing protocol root")
|
||||
return "", errtypes.NotFound(fmt.Sprintf("root not found on OCM discovery for protocol %s", proto))
|
||||
}
|
||||
|
@ -19,9 +19,11 @@
|
||||
package ocmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
@ -31,13 +33,72 @@ import (
|
||||
utils "github.com/cs3org/reva/pkg/utils"
|
||||
)
|
||||
|
||||
// Protocols is the list of protocols.
|
||||
// In this file we group the definitions of the OCM payloads according to the official specs
|
||||
// at https://github.com/cs3org/OCM-API/blob/develop/spec.yaml
|
||||
|
||||
// InviteAcceptedRequest contains the payload of an OCM /invite-accepted request.
|
||||
// https://cs3org.github.io/OCM-API/docs.html?branch=develop&repo=OCM-API&user=cs3org#/paths/~1invite-accepted/post
|
||||
type InviteAcceptedRequest struct {
|
||||
UserID string `json:"userID" validate:"required"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
RecipientProvider string `json:"recipientProvider"`
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
// RemoteUser contains the remote user's information both when sending an /invite-accepted call and when sending back a response to /invite-accepted
|
||||
type RemoteUser struct {
|
||||
UserID string `json:"userID"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func (r *InviteAcceptedRequest) toJSON() (io.Reader, error) {
|
||||
var b bytes.Buffer
|
||||
if err := json.NewEncoder(&b).Encode(r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &b, nil
|
||||
}
|
||||
|
||||
// NewShareRequest contains the payload of an OCM /share request.
|
||||
// https://cs3org.github.io/OCM-API/docs.html?branch=develop&repo=OCM-API&user=cs3org#/paths/~1shares/post
|
||||
type NewShareRequest struct {
|
||||
ShareWith string `json:"shareWith" validate:"required"` // identifier of the recipient of the share
|
||||
Name string `json:"name" validate:"required"` // name of the resource
|
||||
Description string `json:"description"` // (optional) description of the resource
|
||||
ProviderID string `json:"providerId" validate:"required"` // unique identifier of the resource at provider side
|
||||
Owner string `json:"owner" validate:"required"` // unique identifier of the owner at provider side
|
||||
Sender string `json:"sender" validate:"required"` // unique indentifier of the user who wants to share the resource at provider side
|
||||
OwnerDisplayName string `json:"ownerDisplayName"` // display name of the owner of the resource
|
||||
SenderDisplayName string `json:"senderDisplayName"` // dispay name of the user who wants to share the resource
|
||||
Code string `json:"code"` // nonce to be exchanged for a bearer token (not implemented for now)
|
||||
ShareType string `json:"shareType" validate:"required,oneof=user group"` // recipient share type (user or group)
|
||||
ResourceType string `json:"resourceType" validate:"required,oneof=file folder"`
|
||||
Expiration uint64 `json:"expiration"`
|
||||
Protocols Protocols `json:"protocol" validate:"required"`
|
||||
}
|
||||
|
||||
func (r *NewShareRequest) toJSON() (io.Reader, error) {
|
||||
var b bytes.Buffer
|
||||
if err := json.NewEncoder(&b).Encode(r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &b, nil
|
||||
}
|
||||
|
||||
// NewShareResponse is the response returned when creating a new share.
|
||||
type NewShareResponse struct {
|
||||
RecipientDisplayName string `json:"recipientDisplayName"`
|
||||
}
|
||||
|
||||
// Protocols is the list of OCM protocols.
|
||||
type Protocols []Protocol
|
||||
|
||||
// Protocol represents the way of access the resource
|
||||
// in the OCM share.
|
||||
type Protocol interface {
|
||||
// ToOCMProtocol convert the protocol to a ocm Protocol struct
|
||||
// ToOCMProtocol converts the protocol to a CS3API OCM `Protocol` struct
|
||||
ToOCMProtocol() *ocm.Protocol
|
||||
}
|
||||
|
||||
@ -47,7 +108,8 @@ type Protocol interface {
|
||||
type WebDAV struct {
|
||||
SharedSecret string `json:"sharedSecret" validate:"required"`
|
||||
Permissions []string `json:"permissions" validate:"required,dive,required,oneof=read write share"`
|
||||
URL string `json:"url" validate:"required"`
|
||||
Requirements []string `json:"requirements"`
|
||||
URI string `json:"uri" validate:"required"`
|
||||
}
|
||||
|
||||
// ToOCMProtocol convert the protocol to a ocm Protocol struct.
|
||||
@ -69,18 +131,19 @@ func (w *WebDAV) ToOCMProtocol() *ocm.Protocol {
|
||||
}
|
||||
}
|
||||
|
||||
return ocmshare.NewWebDAVProtocol(w.URL, w.SharedSecret, perms)
|
||||
return ocmshare.NewWebDAVProtocol(w.URI, w.SharedSecret, perms, w.Requirements)
|
||||
}
|
||||
|
||||
// Webapp contains the parameters for the Webapp protocol.
|
||||
type Webapp struct {
|
||||
URITemplate string `json:"uriTemplate" validate:"required"`
|
||||
ViewMode string `json:"viewMode" validate:"required,dive,required,oneof=view read write"`
|
||||
URI string `json:"uri" validate:"required"`
|
||||
ViewMode string `json:"viewMode" validate:"required,dive,required,oneof=view read write"`
|
||||
SharedSecret string `json:"sharedSecret"`
|
||||
}
|
||||
|
||||
// ToOCMProtocol convert the protocol to a ocm Protocol struct.
|
||||
func (w *Webapp) ToOCMProtocol() *ocm.Protocol {
|
||||
return ocmshare.NewWebappProtocol(w.URITemplate, utils.GetAppViewMode(w.ViewMode))
|
||||
return ocmshare.NewWebappProtocol(w.URI, utils.GetAppViewMode(w.ViewMode))
|
||||
}
|
||||
|
||||
// Datatx contains the parameters for the Datatx protocol.
|
||||
@ -134,7 +197,7 @@ func (p *Protocols) UnmarshalJSON(data []byte) error {
|
||||
res = &WebDAV{
|
||||
SharedSecret: ss,
|
||||
Permissions: []string{"read", "write", "share"},
|
||||
URL: "",
|
||||
URI: "",
|
||||
}
|
||||
*p = append(*p, res)
|
||||
}
|
||||
@ -163,7 +226,7 @@ func (p Protocols) MarshalJSON() ([]byte, error) {
|
||||
for _, prot := range p {
|
||||
d[GetProtocolName(prot)] = prot
|
||||
}
|
||||
// fill in the OCM v1.0 properties: for now we only create OCM 1.1 payloads,
|
||||
// fill in the OCM v1.0 properties: we only create OCM 1.1+ payloads,
|
||||
// irrespective from the capabilities of the remote server.
|
||||
d["name"] = "multi"
|
||||
d["options"] = map[string]any{}
|
@ -212,12 +212,13 @@ func (h *DavHandler) Handler(s *svc) http.Handler {
|
||||
|
||||
c, err := pool.GetGatewayServiceClient(pool.Endpoint(s.c.GatewaySvc))
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("error getting gateway during OCM authentication")
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
var token, ocmshare string
|
||||
// OCM v1.1 (OCIS et al.).
|
||||
// OCM v1.1+ (OCIS et al.).
|
||||
bearer := strings.TrimPrefix(r.Header.Get("Authorization"), "Bearer ")
|
||||
if bearer != "" {
|
||||
// Bearer token is the shared secret, path is /{shareId}/path/to/resource.
|
||||
@ -285,6 +286,7 @@ func (h *DavHandler) Handler(s *svc) http.Handler {
|
||||
var res *gatewayv1beta1.AuthenticateResponse
|
||||
token, _ := router.ShiftPath(r.URL.Path)
|
||||
if _, pass, ok := r.BasicAuth(); ok {
|
||||
log.Info().Str("token", token).Msg("Handling public-files DAV request with BasicAuth")
|
||||
res, err = handleBasicAuth(r.Context(), c, token, pass)
|
||||
} else {
|
||||
q := r.URL.Query()
|
||||
@ -293,13 +295,20 @@ func (h *DavHandler) Handler(s *svc) http.Handler {
|
||||
// We restrict the pre-signed urls to downloads.
|
||||
if sig != "" && expiration != "" && r.Method != http.MethodGet {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
log.Info().Str("token", token).Msg("Client tried to use pre-signed URL for a method other than GET, which is not allowed")
|
||||
return
|
||||
}
|
||||
res, err = handleSignatureAuth(r.Context(), c, token, sig, expiration)
|
||||
log.Info().Str("token", token).Str("sig", sig).Msg("Handling public-files DAV request with handleSignatureAuth()")
|
||||
res, err = handleSignatureAuth(ctx, c, token, sig, expiration)
|
||||
}
|
||||
|
||||
switch {
|
||||
case err != nil:
|
||||
log.Error().Str("token", token).Err(err).Msg("Error while handling public-files DAV request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
case res.Status == nil:
|
||||
log.Error().Msg("DAV public-files got a AuthenticateResponse without status!")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
case res.Status.Code == rpc.Code_CODE_PERMISSION_DENIED:
|
||||
|
@ -265,7 +265,7 @@ func (s *svc) getResourceInfos(ctx context.Context, w http.ResponseWriter, r *ht
|
||||
|
||||
res, err := client.Stat(ctx, req)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Interface("req", req).Msg("error sending a grpc stat request")
|
||||
log.Error().Err(err).Interface("req", req).Msg("error sending a stat request to the gateway")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return nil, nil, false
|
||||
} else if res.Status.Code != rpc.Code_CODE_OK {
|
||||
|
@ -111,7 +111,7 @@ func (h *Handler) createFederatedCloudShare(w http.ResponseWriter, r *http.Reque
|
||||
},
|
||||
RecipientMeshProvider: providerInfoResp.ProviderInfo,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(role.CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(role.CS3ResourcePermissions(), []string{}),
|
||||
share.NewWebappAccessMethod(getViewModeFromRole(role)),
|
||||
},
|
||||
})
|
||||
|
@ -60,9 +60,7 @@ type APIError struct {
|
||||
|
||||
// WriteError handles writing error responses.
|
||||
func WriteError(w http.ResponseWriter, r *http.Request, code APIErrorCode, message string, e error) {
|
||||
if e != nil {
|
||||
appctx.GetLogger(r.Context()).Error().Err(e).Msg(message)
|
||||
}
|
||||
appctx.GetLogger(r.Context()).Error().Err(e).Any("code", code).Str("message", message).Msg("sending back error response")
|
||||
|
||||
var encoded []byte
|
||||
var err error
|
||||
|
@ -27,25 +27,27 @@ import (
|
||||
"github.com/cs3org/reva/pkg/appctx"
|
||||
)
|
||||
|
||||
const OCMAPIVersion = "1.1.0"
|
||||
const OCMAPIVersion = "1.2.0"
|
||||
|
||||
type OcmProviderConfig struct {
|
||||
OCMPrefix string `docs:"ocm;The prefix URL where the OCM API is served." mapstructure:"ocm_prefix"`
|
||||
Endpoint string `docs:"This host's full URL. If it's not configured, it is assumed OCM is not available." mapstructure:"endpoint"`
|
||||
Provider string `docs:"reva;A friendly name that defines this service." mapstructure:"provider"`
|
||||
WebdavRoot string `docs:"/remote.php/dav/ocm;The root URL of the WebDAV endpoint to serve OCM shares." mapstructure:"webdav_root"`
|
||||
WebappRoot string `docs:"/external/sciencemesh;The root URL to serve Web apps via OCM." mapstructure:"webapp_root"`
|
||||
EnableWebapp bool `docs:"false;Whether web apps are enabled in OCM shares." mapstructure:"enable_webapp"`
|
||||
EnableDatatx bool `docs:"false;Whether data transfers are enabled in OCM shares." mapstructure:"enable_datatx"`
|
||||
OCMPrefix string `docs:"ocm;The prefix URL where the OCM API is served." mapstructure:"ocm_prefix"`
|
||||
Endpoint string `docs:"This host's full URL. If it's not configured, it is assumed OCM is not available." mapstructure:"endpoint"`
|
||||
Provider string `docs:"reva;A friendly name that defines this service." mapstructure:"provider"`
|
||||
WebdavRoot string `docs:"/remote.php/dav/ocm;The root URL of the WebDAV endpoint to serve OCM shares." mapstructure:"webdav_root"`
|
||||
WebappRoot string `docs:"/external/sciencemesh;The root URL to serve Web apps via OCM." mapstructure:"webapp_root"`
|
||||
InviteAcceptDialog string `docs:"/sciencemesh-app/invitations;The frontend URL where to land when receiving an invitation" mapstructure:"invite_accept_dialog"`
|
||||
EnableWebapp bool `docs:"false;Whether web apps are enabled in OCM shares." mapstructure:"enable_webapp"`
|
||||
EnableDatatx bool `docs:"false;Whether data transfers are enabled in OCM shares." mapstructure:"enable_datatx"`
|
||||
}
|
||||
|
||||
type OcmDiscoveryData struct {
|
||||
Enabled bool `json:"enabled" xml:"enabled"`
|
||||
APIVersion string `json:"apiVersion" xml:"apiVersion"`
|
||||
Endpoint string `json:"endPoint" xml:"endPoint"`
|
||||
Provider string `json:"provider" xml:"provider"`
|
||||
ResourceTypes []resourceTypes `json:"resourceTypes" xml:"resourceTypes"`
|
||||
Capabilities []string `json:"capabilities" xml:"capabilities"`
|
||||
Enabled bool `json:"enabled" xml:"enabled"`
|
||||
APIVersion string `json:"apiVersion" xml:"apiVersion"`
|
||||
Endpoint string `json:"endPoint" xml:"endPoint"`
|
||||
Provider string `json:"provider" xml:"provider"`
|
||||
ResourceTypes []resourceTypes `json:"resourceTypes" xml:"resourceTypes"`
|
||||
Capabilities []string `json:"capabilities" xml:"capabilities"`
|
||||
InviteAcceptDialog string `json:"inviteAcceptDialog" xml:"inviteAcceptDialog"`
|
||||
}
|
||||
|
||||
type resourceTypes struct {
|
||||
@ -77,6 +79,9 @@ func (c *OcmProviderConfig) ApplyDefaults() {
|
||||
if c.WebappRoot[len(c.WebappRoot)-1:] != "/" {
|
||||
c.WebappRoot += "/"
|
||||
}
|
||||
if c.InviteAcceptDialog == "" {
|
||||
c.InviteAcceptDialog = "/sciencemesh-app/invitations"
|
||||
}
|
||||
}
|
||||
|
||||
func (h *wkocmHandler) init(c *OcmProviderConfig) {
|
||||
@ -124,7 +129,8 @@ func (h *wkocmHandler) init(c *OcmProviderConfig) {
|
||||
Protocols: rtProtos, // expose the protocols as per configuration
|
||||
}}
|
||||
// for now we hardcode the capabilities, as this is currently only advisory
|
||||
d.Capabilities = []string{"/invite-accepted"}
|
||||
d.Capabilities = []string{"invites", "webdav-uri", "protocol-object"}
|
||||
d.InviteAcceptDialog, _ = url.JoinPath(c.Endpoint, c.InviteAcceptDialog)
|
||||
h.data = d
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ import (
|
||||
rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1"
|
||||
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
|
||||
"github.com/cs3org/reva/pkg/appctx"
|
||||
"github.com/cs3org/reva/pkg/auth"
|
||||
"github.com/cs3org/reva/pkg/auth/manager/registry"
|
||||
"github.com/cs3org/reva/pkg/auth/scope"
|
||||
@ -79,6 +80,8 @@ func (m *manager) Authenticate(ctx context.Context, token, secret string) (*user
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
log := appctx.GetLogger(ctx)
|
||||
|
||||
var auth *link.PublicShareAuthentication
|
||||
if strings.HasPrefix(secret, "password|") {
|
||||
secret = strings.TrimPrefix(secret, "password|")
|
||||
@ -106,11 +109,15 @@ func (m *manager) Authenticate(ctx context.Context, token, secret string) (*user
|
||||
}
|
||||
}
|
||||
|
||||
log.Debug().Str("token", token).Msg("Handling Authenticate() call")
|
||||
|
||||
publicShareResponse, err := gwConn.GetPublicShareByToken(ctx, &link.GetPublicShareByTokenRequest{
|
||||
Token: token,
|
||||
Authentication: auth,
|
||||
Sign: true,
|
||||
})
|
||||
log.Debug().Str("token", token).Err(err).Any("psresp", publicShareResponse).Msg("GetPublicShareByToken return")
|
||||
|
||||
switch {
|
||||
case err != nil:
|
||||
return nil, nil, err
|
||||
|
@ -291,7 +291,7 @@ func (c *Client) initMDRequest(ctx context.Context, auth eosclient.Authorization
|
||||
// AddACL adds an new acl to EOS with the given aclType.
|
||||
func (c *Client) AddACL(ctx context.Context, auth, rootAuth eosclient.Authorization, path string, pos uint, a *acl.Entry) error {
|
||||
log := appctx.GetLogger(ctx)
|
||||
log.Info().Str("func", "AddACL").Str("uid,gid", auth.Role.UID+","+auth.Role.GID).Str("path", path).Msg("")
|
||||
log.Info().Str("func", "AddACL").Str("uid,gid", auth.Role.UID+","+auth.Role.GID).Str("path", path).Str("acl", a.CitrineSerialize()).Msg("")
|
||||
|
||||
// First, we need to figure out if the path is a directory
|
||||
// to know whether our request should be recursive
|
||||
@ -604,6 +604,7 @@ func (c *Client) handleFavAttr(ctx context.Context, auth eosclient.Authorization
|
||||
favs.DeleteEntry(acl.TypeUser, u.Id.OpaqueId)
|
||||
}
|
||||
attr.Val = favs.Serialize()
|
||||
|
||||
if attr.Val == "" {
|
||||
return c.unsetEOSAttr(ctx, auth, attr, recursive, path, "", true)
|
||||
} else {
|
||||
|
@ -36,6 +36,8 @@ import (
|
||||
"github.com/cs3org/reva/pkg/logger"
|
||||
)
|
||||
|
||||
const EOS_APP_HEADER = "eos.app"
|
||||
|
||||
// HTTPOptions to configure the Client.
|
||||
type HTTPOptions struct {
|
||||
|
||||
@ -274,7 +276,7 @@ func (c *EOSHTTPClient) GETFile(ctx context.Context, remoteuser string, auth eos
|
||||
return nil, err
|
||||
}
|
||||
// similar to eosbinary.go::Read()
|
||||
req.Header.Set("app", "reva_eosclient::read")
|
||||
req.Header.Set(EOS_APP_HEADER, "reva_eosclient::read")
|
||||
|
||||
ntries := 0
|
||||
nredirs := 0
|
||||
@ -379,7 +381,7 @@ func (c *EOSHTTPClient) PUTFile(ctx context.Context, remoteuser string, auth eos
|
||||
}
|
||||
|
||||
if app != "" {
|
||||
req.Header.Set("app", app)
|
||||
req.Header.Set(EOS_APP_HEADER, app)
|
||||
}
|
||||
req.Close = true
|
||||
|
||||
|
@ -97,8 +97,8 @@ type EfssShare struct {
|
||||
Permissions int `json:"permissions" validate:"required"`
|
||||
} `json:"webdav" validate:"required"`
|
||||
WebApp struct {
|
||||
URITemplate string `json:"uri_template"`
|
||||
ViewMode string `json:"view_mode"`
|
||||
URI string `json:"uri_template"`
|
||||
ViewMode string `json:"view_mode"`
|
||||
} `json:"webapp" validate:"omitempty"`
|
||||
DataTx struct {
|
||||
SourceURI string `json:"source_uri"`
|
||||
@ -181,7 +181,7 @@ func (sm *Manager) efssShareToOcm(resp *EfssShare) *ocm.Share {
|
||||
// first generate the map of access methods, assuming WebDAV is always present
|
||||
var am = make([]*ocm.AccessMethod, 0, 3)
|
||||
am = append(am, share.NewWebDavAccessMethod(conversions.RoleFromOCSPermissions(
|
||||
conversions.Permissions(resp.Protocols.WebDAV.Permissions)).CS3ResourcePermissions()))
|
||||
conversions.Permissions(resp.Protocols.WebDAV.Permissions)).CS3ResourcePermissions(), []string{}))
|
||||
if resp.Protocols.WebApp.ViewMode != "" {
|
||||
am = append(am, share.NewWebappAccessMethod(utils.GetAppViewMode(resp.Protocols.WebApp.ViewMode)))
|
||||
}
|
||||
@ -326,9 +326,9 @@ func efssReceivedShareToOcm(resp *ReceivedEfssShare) *ocm.ReceivedShare {
|
||||
var proto = make([]*ocm.Protocol, 0, 3)
|
||||
proto = append(proto, share.NewWebDAVProtocol(resp.Share.Protocols.WebDAV.URI, resp.Share.Token, &ocm.SharePermissions{
|
||||
Permissions: conversions.RoleFromOCSPermissions(conversions.Permissions(resp.Share.Protocols.WebDAV.Permissions)).CS3ResourcePermissions(),
|
||||
}))
|
||||
}, []string{}))
|
||||
if resp.Share.Protocols.WebApp.ViewMode != "" {
|
||||
proto = append(proto, share.NewWebappProtocol(resp.Share.Protocols.WebApp.URITemplate, utils.GetAppViewMode(resp.Share.Protocols.WebApp.ViewMode)))
|
||||
proto = append(proto, share.NewWebappProtocol(resp.Share.Protocols.WebApp.URI, utils.GetAppViewMode(resp.Share.Protocols.WebApp.ViewMode)))
|
||||
}
|
||||
if resp.Share.Protocols.DataTx.SourceURI != "" {
|
||||
proto = append(proto, share.NewTransferProtocol(resp.Share.Protocols.DataTx.SourceURI, resp.Share.Token, uint64(resp.Share.Protocols.DataTx.Size)))
|
||||
|
@ -283,7 +283,7 @@ var _ = Describe("Nextcloud", func() {
|
||||
OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
|
||||
},
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
ocmshare.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
|
||||
ocmshare.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
|
||||
ocmshare.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_WRITE),
|
||||
ocmshare.NewTransferAccessMethod(),
|
||||
},
|
||||
@ -422,7 +422,7 @@ var _ = Describe("Nextcloud", func() {
|
||||
},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
ocmshare.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
|
||||
ocmshare.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
|
||||
ocmshare.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_WRITE),
|
||||
ocmshare.NewTransferAccessMethod(),
|
||||
},
|
||||
@ -475,7 +475,7 @@ var _ = Describe("Nextcloud", func() {
|
||||
Protocols: []*ocm.Protocol{
|
||||
ocmshare.NewWebDAVProtocol("webdav-uri", "some-token", &ocm.SharePermissions{
|
||||
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
|
||||
}),
|
||||
}, []string{}),
|
||||
ocmshare.NewWebappProtocol("app-uri-template", appprovider.ViewMode_VIEW_MODE_READ_WRITE),
|
||||
ocmshare.NewTransferProtocol("source-uri", "some-token", 1),
|
||||
},
|
||||
@ -533,7 +533,7 @@ var _ = Describe("Nextcloud", func() {
|
||||
Protocols: []*ocm.Protocol{
|
||||
ocmshare.NewWebDAVProtocol("webdav-uri", "some-token", &ocm.SharePermissions{
|
||||
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
|
||||
}),
|
||||
}, []string{}),
|
||||
ocmshare.NewWebappProtocol("app-uri-template", appprovider.ViewMode_VIEW_MODE_READ_WRITE),
|
||||
ocmshare.NewTransferProtocol("source-uri", "some-token", 1),
|
||||
},
|
||||
@ -622,7 +622,7 @@ var _ = Describe("Nextcloud", func() {
|
||||
Protocols: []*ocm.Protocol{
|
||||
ocmshare.NewWebDAVProtocol("webdav-uri", "some-token", &ocm.SharePermissions{
|
||||
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
|
||||
}),
|
||||
}, []string{}),
|
||||
ocmshare.NewWebappProtocol("app-uri-template", appprovider.ViewMode_VIEW_MODE_READ_WRITE),
|
||||
ocmshare.NewTransferProtocol("source-uri", "some-token", 1),
|
||||
},
|
||||
|
@ -169,7 +169,7 @@ type dbProtocol struct {
|
||||
WebDAVURI *string
|
||||
WebDAVSharedSecret *string
|
||||
WebDavPermissions *int
|
||||
WebappURITemplate *string
|
||||
WebappURI *string
|
||||
WebappViewMode *int
|
||||
TransferSourceURI *string
|
||||
TransferSharedSecret *string
|
||||
@ -267,7 +267,9 @@ func convertToCS3OCMReceivedShare(s *dbReceivedShare, p []*ocm.Protocol) *ocm.Re
|
||||
func convertToCS3AccessMethod(m *dbAccessMethod) *ocm.AccessMethod {
|
||||
switch m.Type {
|
||||
case WebDAVAccessMethod:
|
||||
return share.NewWebDavAccessMethod(conversions.RoleFromOCSPermissions(conversions.Permissions(*m.WebDAVPermissions)).CS3ResourcePermissions())
|
||||
return share.NewWebDavAccessMethod(
|
||||
conversions.RoleFromOCSPermissions(conversions.Permissions(*m.WebDAVPermissions)).CS3ResourcePermissions(),
|
||||
[]string{}) // TODO persist requirements
|
||||
case WebappAccessMethod:
|
||||
return share.NewWebappAccessMethod(appprovider.ViewMode(*m.WebAppViewMode))
|
||||
case TransferAccessMethod:
|
||||
@ -281,9 +283,9 @@ func convertToCS3Protocol(p *dbProtocol) *ocm.Protocol {
|
||||
case WebDAVProtocol:
|
||||
return share.NewWebDAVProtocol(*p.WebDAVURI, *p.WebDAVSharedSecret, &ocm.SharePermissions{
|
||||
Permissions: conversions.RoleFromOCSPermissions(conversions.Permissions(*p.WebDavPermissions)).CS3ResourcePermissions(),
|
||||
})
|
||||
}, []string{}) // TODO persist requirements
|
||||
case WebappProtocol:
|
||||
return share.NewWebappProtocol(*p.WebappURITemplate, appprovider.ViewMode(*p.WebappViewMode))
|
||||
return share.NewWebappProtocol(*p.WebappURI, appprovider.ViewMode(*p.WebappViewMode))
|
||||
case TransferProtocol:
|
||||
return share.NewTransferProtocol(*p.TransferSourceURI, *p.TransferSharedSecret, uint64(*p.TransferSize))
|
||||
}
|
||||
|
@ -572,7 +572,7 @@ func storeWebappProtocol(tx *sql.Tx, shareID int64, o *ocm.Protocol_WebappOption
|
||||
}
|
||||
|
||||
query := "INSERT INTO ocm_protocol_webapp SET ocm_protocol_id=?, uri_template=?, view_mode=?"
|
||||
params := []any{pID, o.WebappOptions.UriTemplate, o.WebappOptions.ViewMode}
|
||||
params := []any{pID, o.WebappOptions.Uri, o.WebappOptions.ViewMode}
|
||||
|
||||
_, err = tx.Exec(query, params...)
|
||||
return err
|
||||
@ -707,7 +707,7 @@ func (m *mgr) getProtocolsIds(ctx context.Context, ids []any) (map[string][]*ocm
|
||||
|
||||
var p dbProtocol
|
||||
for rows.Next() {
|
||||
if err := rows.Scan(&p.ShareID, &p.Type, &p.WebDAVURI, &p.WebDAVSharedSecret, &p.WebDavPermissions, &p.WebappURITemplate, &p.WebappViewMode, &p.TransferSourceURI, &p.TransferSharedSecret, &p.TransferSize); err != nil {
|
||||
if err := rows.Scan(&p.ShareID, &p.Type, &p.WebDAVURI, &p.WebDAVSharedSecret, &p.WebDavPermissions, &p.WebappURI, &p.WebappViewMode, &p.TransferSourceURI, &p.TransferSharedSecret, &p.TransferSize); err != nil {
|
||||
continue
|
||||
}
|
||||
protocols[p.ShareID] = append(protocols[p.ShareID], convertToCS3Protocol(&p))
|
||||
@ -763,7 +763,7 @@ func (m *mgr) getProtocols(ctx context.Context, id int) ([]*ocm.Protocol, error)
|
||||
|
||||
var p dbProtocol
|
||||
for rows.Next() {
|
||||
if err := rows.Scan(&p.Type, &p.WebDAVURI, &p.WebDAVSharedSecret, &p.WebDavPermissions, &p.WebappURITemplate, &p.WebappViewMode, &p.TransferSourceURI, &p.TransferSharedSecret, &p.TransferSize); err != nil {
|
||||
if err := rows.Scan(&p.Type, &p.WebDAVURI, &p.WebDAVSharedSecret, &p.WebDavPermissions, &p.WebappURI, &p.WebappViewMode, &p.TransferSourceURI, &p.TransferSharedSecret, &p.TransferSize); err != nil {
|
||||
continue
|
||||
}
|
||||
protocols = append(protocols, convertToCS3Protocol(&p))
|
||||
|
@ -286,7 +286,7 @@ func createReceivedShareTables(ctx *sql.Context, initData []*ocm.ReceivedShare)
|
||||
must(webdav.Insert(ctx, sql.NewRow(i, prot.WebdavOptions.Uri, prot.WebdavOptions.SharedSecret, int64(conversions.RoleFromResourcePermissions(prot.WebdavOptions.Permissions.Permissions).OCSPermissions()))))
|
||||
case *ocm.Protocol_WebappOptions:
|
||||
must(protocols.Insert(ctx, sql.NewRow(i, mustInt(share.Id.OpaqueId), int8(WebappProtocol))))
|
||||
must(webapp.Insert(ctx, sql.NewRow(i, prot.WebappOptions.UriTemplate, int8(prot.WebappOptions.ViewMode))))
|
||||
must(webapp.Insert(ctx, sql.NewRow(i, prot.WebappOptions.Uri, int8(prot.WebappOptions.ViewMode))))
|
||||
case *ocm.Protocol_TransferOptions:
|
||||
must(protocols.Insert(ctx, sql.NewRow(i, mustInt(share.Id.OpaqueId), int8(TransferProtocol))))
|
||||
must(transfer.Insert(ctx, sql.NewRow(i, prot.TransferOptions.SourceUri, prot.TransferOptions.SharedSecret, int64(prot.TransferOptions.Size))))
|
||||
@ -342,7 +342,7 @@ func TestGetShare(t *testing.T) {
|
||||
Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions())},
|
||||
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{})},
|
||||
},
|
||||
},
|
||||
query: &ocm.ShareReference{Spec: &ocm.ShareReference_Id{Id: &ocm.ShareId{OpaqueId: "1"}}},
|
||||
@ -359,7 +359,7 @@ func TestGetShare(t *testing.T) {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
Expiration: &typesv1beta1.Timestamp{},
|
||||
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions())},
|
||||
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{})},
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -376,7 +376,7 @@ func TestGetShare(t *testing.T) {
|
||||
Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions())},
|
||||
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{})},
|
||||
},
|
||||
},
|
||||
query: &ocm.ShareReference{
|
||||
@ -396,7 +396,7 @@ func TestGetShare(t *testing.T) {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
Expiration: &typesv1beta1.Timestamp{},
|
||||
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions())},
|
||||
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{})},
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -413,7 +413,7 @@ func TestGetShare(t *testing.T) {
|
||||
Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions())},
|
||||
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{})},
|
||||
},
|
||||
},
|
||||
query: &ocm.ShareReference{
|
||||
@ -437,7 +437,7 @@ func TestGetShare(t *testing.T) {
|
||||
Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions())},
|
||||
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{})},
|
||||
},
|
||||
},
|
||||
query: &ocm.ShareReference{
|
||||
@ -462,7 +462,7 @@ func TestGetShare(t *testing.T) {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
Expiration: &typesv1beta1.Timestamp{},
|
||||
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions())},
|
||||
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{})},
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -479,7 +479,7 @@ func TestGetShare(t *testing.T) {
|
||||
Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions())},
|
||||
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{})},
|
||||
},
|
||||
},
|
||||
query: &ocm.ShareReference{
|
||||
@ -508,7 +508,7 @@ func TestGetShare(t *testing.T) {
|
||||
Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions())},
|
||||
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{})},
|
||||
},
|
||||
},
|
||||
query: &ocm.ShareReference{
|
||||
@ -538,7 +538,7 @@ func TestGetShare(t *testing.T) {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
|
||||
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
|
||||
share.NewTransferAccessMethod(),
|
||||
},
|
||||
@ -559,7 +559,7 @@ func TestGetShare(t *testing.T) {
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
Expiration: &typesv1beta1.Timestamp{},
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
|
||||
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
|
||||
share.NewTransferAccessMethod(),
|
||||
},
|
||||
@ -580,7 +580,7 @@ func TestGetShare(t *testing.T) {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
|
||||
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
|
||||
share.NewTransferAccessMethod(),
|
||||
},
|
||||
@ -601,7 +601,7 @@ func TestGetShare(t *testing.T) {
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
Expiration: &typesv1beta1.Timestamp{},
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
|
||||
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
|
||||
share.NewTransferAccessMethod(),
|
||||
},
|
||||
@ -671,7 +671,7 @@ func TestListShares(t *testing.T) {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
|
||||
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
|
||||
share.NewTransferAccessMethod(),
|
||||
},
|
||||
@ -693,7 +693,7 @@ func TestListShares(t *testing.T) {
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
Expiration: &typesv1beta1.Timestamp{},
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
|
||||
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
|
||||
share.NewTransferAccessMethod(),
|
||||
},
|
||||
@ -715,7 +715,7 @@ func TestListShares(t *testing.T) {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
|
||||
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
|
||||
share.NewTransferAccessMethod(),
|
||||
},
|
||||
@ -732,7 +732,7 @@ func TestListShares(t *testing.T) {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -752,7 +752,7 @@ func TestListShares(t *testing.T) {
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
Expiration: &typesv1beta1.Timestamp{},
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
|
||||
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
|
||||
share.NewTransferAccessMethod(),
|
||||
},
|
||||
@ -770,7 +770,7 @@ func TestListShares(t *testing.T) {
|
||||
Expiration: &typesv1beta1.Timestamp{},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -790,7 +790,7 @@ func TestListShares(t *testing.T) {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
|
||||
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
|
||||
share.NewTransferAccessMethod(),
|
||||
},
|
||||
@ -807,7 +807,7 @@ func TestListShares(t *testing.T) {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -827,7 +827,7 @@ func TestListShares(t *testing.T) {
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
Expiration: &typesv1beta1.Timestamp{},
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -847,7 +847,7 @@ func TestListShares(t *testing.T) {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
|
||||
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
|
||||
share.NewTransferAccessMethod(),
|
||||
},
|
||||
@ -864,7 +864,7 @@ func TestListShares(t *testing.T) {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -891,7 +891,7 @@ func TestListShares(t *testing.T) {
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
Expiration: &typesv1beta1.Timestamp{},
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -911,7 +911,7 @@ func TestListShares(t *testing.T) {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
|
||||
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
|
||||
share.NewTransferAccessMethod(),
|
||||
},
|
||||
@ -928,7 +928,7 @@ func TestListShares(t *testing.T) {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -958,7 +958,7 @@ func TestListShares(t *testing.T) {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
|
||||
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
|
||||
share.NewTransferAccessMethod(),
|
||||
},
|
||||
@ -975,7 +975,7 @@ func TestListShares(t *testing.T) {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -990,7 +990,7 @@ func TestListShares(t *testing.T) {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -1023,7 +1023,7 @@ func TestListShares(t *testing.T) {
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
Expiration: &typesv1beta1.Timestamp{},
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
|
||||
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
|
||||
share.NewTransferAccessMethod(),
|
||||
},
|
||||
@ -1041,7 +1041,7 @@ func TestListShares(t *testing.T) {
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
Expiration: &typesv1beta1.Timestamp{},
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -1140,7 +1140,7 @@ func TestStoreShare(t *testing.T) {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
|
||||
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
|
||||
},
|
||||
},
|
||||
@ -1169,7 +1169,7 @@ func TestStoreShare(t *testing.T) {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -1184,7 +1184,7 @@ func TestStoreShare(t *testing.T) {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
|
||||
},
|
||||
},
|
||||
expected: storeShareExpected{
|
||||
@ -1218,7 +1218,7 @@ func TestStoreShare(t *testing.T) {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -1233,7 +1233,7 @@ func TestStoreShare(t *testing.T) {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
|
||||
},
|
||||
},
|
||||
err: share.ErrShareAlreadyExisting,
|
||||
@ -1297,7 +1297,7 @@ func TestUpdateShare(t *testing.T) {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1686061921},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
|
||||
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
|
||||
},
|
||||
},
|
||||
@ -1330,7 +1330,7 @@ func TestUpdateShare(t *testing.T) {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1686061921},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
|
||||
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
|
||||
},
|
||||
},
|
||||
@ -1340,7 +1340,7 @@ func TestUpdateShare(t *testing.T) {
|
||||
fields: []*ocm.UpdateOCMShareRequest_UpdateField{
|
||||
{
|
||||
Field: &ocm.UpdateOCMShareRequest_UpdateField_AccessMethods{
|
||||
AccessMethods: share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
|
||||
AccessMethods: share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -1374,7 +1374,7 @@ func TestUpdateShare(t *testing.T) {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1686061921},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
|
||||
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
|
||||
},
|
||||
},
|
||||
@ -1411,7 +1411,7 @@ func TestUpdateShare(t *testing.T) {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1686061921},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
|
||||
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
|
||||
},
|
||||
},
|
||||
@ -1425,7 +1425,7 @@ func TestUpdateShare(t *testing.T) {
|
||||
fields: []*ocm.UpdateOCMShareRequest_UpdateField{
|
||||
{
|
||||
Field: &ocm.UpdateOCMShareRequest_UpdateField_AccessMethods{
|
||||
AccessMethods: share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
|
||||
AccessMethods: share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -1459,7 +1459,7 @@ func TestUpdateShare(t *testing.T) {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1686061921},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
|
||||
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
|
||||
},
|
||||
},
|
||||
@ -1484,7 +1484,7 @@ func TestUpdateShare(t *testing.T) {
|
||||
Mtime: &typesv1beta1.Timestamp{Seconds: 1686061921},
|
||||
ShareType: ocm.ShareType_SHARE_TYPE_USER,
|
||||
AccessMethods: []*ocm.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
|
||||
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
|
||||
},
|
||||
},
|
||||
@ -1498,7 +1498,7 @@ func TestUpdateShare(t *testing.T) {
|
||||
fields: []*ocm.UpdateOCMShareRequest_UpdateField{
|
||||
{
|
||||
Field: &ocm.UpdateOCMShareRequest_UpdateField_AccessMethods{
|
||||
AccessMethods: share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
|
||||
AccessMethods: share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -1579,7 +1579,7 @@ func TestGetReceivedShare(t *testing.T) {
|
||||
Protocols: []*ocm.Protocol{
|
||||
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
|
||||
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
|
||||
}),
|
||||
}, []string{}),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -1601,7 +1601,7 @@ func TestGetReceivedShare(t *testing.T) {
|
||||
Protocols: []*ocm.Protocol{
|
||||
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
|
||||
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
|
||||
}),
|
||||
}, []string{}),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -1623,7 +1623,7 @@ func TestGetReceivedShare(t *testing.T) {
|
||||
Protocols: []*ocm.Protocol{
|
||||
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
|
||||
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
|
||||
}),
|
||||
}, []string{}),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -1649,7 +1649,7 @@ func TestGetReceivedShare(t *testing.T) {
|
||||
Protocols: []*ocm.Protocol{
|
||||
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
|
||||
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
|
||||
}),
|
||||
}, []string{}),
|
||||
share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234", appprovider.ViewMode_VIEW_MODE_READ_WRITE),
|
||||
share.NewTransferProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", 10),
|
||||
},
|
||||
@ -1673,7 +1673,7 @@ func TestGetReceivedShare(t *testing.T) {
|
||||
Protocols: []*ocm.Protocol{
|
||||
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
|
||||
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
|
||||
}),
|
||||
}, []string{}),
|
||||
share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234", appprovider.ViewMode_VIEW_MODE_READ_WRITE),
|
||||
share.NewTransferProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", 10),
|
||||
},
|
||||
@ -1743,7 +1743,7 @@ func TestUpdateReceivedShare(t *testing.T) {
|
||||
Protocols: []*ocm.Protocol{
|
||||
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
|
||||
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
|
||||
}),
|
||||
}, []string{}),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -1779,7 +1779,7 @@ func TestUpdateReceivedShare(t *testing.T) {
|
||||
Protocols: []*ocm.Protocol{
|
||||
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
|
||||
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
|
||||
}),
|
||||
}, []string{}),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -1855,7 +1855,7 @@ func TestListReceviedShares(t *testing.T) {
|
||||
Protocols: []*ocm.Protocol{
|
||||
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
|
||||
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
|
||||
}),
|
||||
}, []string{}),
|
||||
share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234", appprovider.ViewMode_VIEW_MODE_READ_WRITE),
|
||||
share.NewTransferProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", 10),
|
||||
},
|
||||
@ -1879,7 +1879,7 @@ func TestListReceviedShares(t *testing.T) {
|
||||
Protocols: []*ocm.Protocol{
|
||||
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
|
||||
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
|
||||
}),
|
||||
}, []string{}),
|
||||
share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234", appprovider.ViewMode_VIEW_MODE_READ_WRITE),
|
||||
share.NewTransferProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", 10),
|
||||
},
|
||||
@ -1904,7 +1904,7 @@ func TestListReceviedShares(t *testing.T) {
|
||||
Protocols: []*ocm.Protocol{
|
||||
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
|
||||
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
|
||||
}),
|
||||
}, []string{}),
|
||||
share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234", appprovider.ViewMode_VIEW_MODE_READ_WRITE),
|
||||
share.NewTransferProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", 10),
|
||||
},
|
||||
@ -1944,7 +1944,7 @@ func TestListReceviedShares(t *testing.T) {
|
||||
Protocols: []*ocm.Protocol{
|
||||
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
|
||||
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
|
||||
}),
|
||||
}, []string{}),
|
||||
share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234", appprovider.ViewMode_VIEW_MODE_READ_WRITE),
|
||||
share.NewTransferProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", 10),
|
||||
},
|
||||
@ -1986,7 +1986,7 @@ func TestListReceviedShares(t *testing.T) {
|
||||
Protocols: []*ocm.Protocol{
|
||||
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
|
||||
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
|
||||
}),
|
||||
}, []string{}),
|
||||
share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234", appprovider.ViewMode_VIEW_MODE_READ_WRITE),
|
||||
share.NewTransferProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", 10),
|
||||
},
|
||||
@ -2026,7 +2026,7 @@ func TestListReceviedShares(t *testing.T) {
|
||||
Protocols: []*ocm.Protocol{
|
||||
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
|
||||
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
|
||||
}),
|
||||
}, []string{}),
|
||||
share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234", appprovider.ViewMode_VIEW_MODE_READ_WRITE),
|
||||
share.NewTransferProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", 10),
|
||||
},
|
||||
@ -2106,7 +2106,7 @@ func TestStoreReceivedShare(t *testing.T) {
|
||||
Protocols: []*ocm.Protocol{
|
||||
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
|
||||
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
|
||||
}),
|
||||
}, []string{}),
|
||||
},
|
||||
},
|
||||
expected: storeReceivedShareExpected{
|
||||
@ -2135,7 +2135,7 @@ func TestStoreReceivedShare(t *testing.T) {
|
||||
Protocols: []*ocm.Protocol{
|
||||
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
|
||||
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
|
||||
}),
|
||||
}, []string{}),
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -2153,7 +2153,7 @@ func TestStoreReceivedShare(t *testing.T) {
|
||||
Protocols: []*ocm.Protocol{
|
||||
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
|
||||
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
|
||||
}),
|
||||
}, []string{}),
|
||||
share.NewTransferProtocol("https://transfer.cernbox.cern.ch/ocm/1234", "secret", 100),
|
||||
share.NewWebappProtocol("https://app.cernbox.cern.ch/ocm/1234", appprovider.ViewMode_VIEW_MODE_READ_WRITE),
|
||||
},
|
||||
|
@ -25,25 +25,26 @@ import (
|
||||
)
|
||||
|
||||
// NewWebDAVProtocol is an abstraction for creating a WebDAV protocol.
|
||||
func NewWebDAVProtocol(uri, sharedSecret string, perms *ocm.SharePermissions) *ocm.Protocol {
|
||||
func NewWebDAVProtocol(uri, sharedSecret string, perms *ocm.SharePermissions, reqs []string) *ocm.Protocol {
|
||||
return &ocm.Protocol{
|
||||
Term: &ocm.Protocol_WebdavOptions{
|
||||
WebdavOptions: &ocm.WebDAVProtocol{
|
||||
Uri: uri,
|
||||
SharedSecret: sharedSecret,
|
||||
Permissions: perms,
|
||||
Requirements: reqs,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewWebappProtocol is an abstraction for creating a Webapp protocol.
|
||||
func NewWebappProtocol(uriTemplate string, viewMode appprovider.ViewMode) *ocm.Protocol {
|
||||
func NewWebappProtocol(uri string, viewMode appprovider.ViewMode) *ocm.Protocol {
|
||||
return &ocm.Protocol{
|
||||
Term: &ocm.Protocol_WebappOptions{
|
||||
WebappOptions: &ocm.WebappProtocol{
|
||||
UriTemplate: uriTemplate,
|
||||
ViewMode: viewMode,
|
||||
Uri: uri,
|
||||
ViewMode: viewMode,
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -63,11 +64,12 @@ func NewTransferProtocol(sourceURI, sharedSecret string, size uint64) *ocm.Proto
|
||||
}
|
||||
|
||||
// NewWebDavAccessMethod is an abstraction for creating a WebDAV access method.
|
||||
func NewWebDavAccessMethod(perms *provider.ResourcePermissions) *ocm.AccessMethod {
|
||||
func NewWebDavAccessMethod(perms *provider.ResourcePermissions, reqs []string) *ocm.AccessMethod {
|
||||
return &ocm.AccessMethod{
|
||||
Term: &ocm.AccessMethod_WebdavOptions{
|
||||
WebdavOptions: &ocm.WebDAVAccessMethod{
|
||||
Permissions: perms,
|
||||
Permissions: perms,
|
||||
Requirements: reqs,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import (
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
@ -43,15 +44,22 @@ import (
|
||||
"github.com/cs3org/reva/pkg/storage/fs/registry"
|
||||
"github.com/cs3org/reva/pkg/utils/cfg"
|
||||
"github.com/studio-b12/gowebdav"
|
||||
"github.com/ReneKroon/ttlcache/v2"
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.Register("ocmreceived", New)
|
||||
}
|
||||
|
||||
type cachedClient struct {
|
||||
client *gowebdav.Client
|
||||
share *ocmpb.ReceivedShare
|
||||
}
|
||||
|
||||
type driver struct {
|
||||
c *config
|
||||
gateway gateway.GatewayAPIClient
|
||||
ccache *ttlcache.Cache
|
||||
}
|
||||
|
||||
type config struct {
|
||||
@ -78,8 +86,8 @@ func New(ctx context.Context, m map[string]interface{}) (storage.FS, error) {
|
||||
d := &driver{
|
||||
c: &c,
|
||||
gateway: gateway,
|
||||
ccache: ttlcache.NewCache(), // this is a cache of webdav clients
|
||||
}
|
||||
|
||||
return d, nil
|
||||
}
|
||||
|
||||
@ -106,7 +114,6 @@ func shareInfoFromReference(ref *provider.Reference) (*ocmpb.ShareId, string) {
|
||||
}
|
||||
|
||||
func (d *driver) getWebDAVFromShare(ctx context.Context, shareID *ocmpb.ShareId) (*ocmpb.ReceivedShare, string, string, error) {
|
||||
// TODO: we may want to cache the share
|
||||
res, err := d.gateway.GetReceivedOCMShare(ctx, &ocmpb.GetReceivedOCMShareRequest{
|
||||
Ref: &ocmpb.ShareReference{
|
||||
Spec: &ocmpb.ShareReference_Id{
|
||||
@ -143,13 +150,21 @@ func getWebDAVProtocol(protocols []*ocmpb.Protocol) (*ocmpb.WebDAVProtocol, bool
|
||||
}
|
||||
|
||||
func (d *driver) webdavClient(ctx context.Context, ref *provider.Reference) (*gowebdav.Client, *ocmpb.ReceivedShare, string, error) {
|
||||
log := appctx.GetLogger(ctx)
|
||||
id, rel := shareInfoFromReference(ref)
|
||||
|
||||
// check first if we have a cached webdav client
|
||||
if entry, err := d.ccache.Get(id.OpaqueId); err == nil {
|
||||
cc := entry.(*cachedClient)
|
||||
log.Info().Interface("share", cc.share).Str("rel", rel).Msg("accessing OCM share via cached client")
|
||||
return cc.client, cc.share, rel, nil
|
||||
}
|
||||
|
||||
// we don't, build a webdav client
|
||||
share, endpoint, secret, err := d.getWebDAVFromShare(ctx, id)
|
||||
if err != nil {
|
||||
return nil, nil, "", err
|
||||
}
|
||||
|
||||
endpoint, err = url.PathUnescape(endpoint)
|
||||
if err != nil {
|
||||
return nil, nil, "", err
|
||||
@ -158,9 +173,20 @@ func (d *driver) webdavClient(ctx context.Context, ref *provider.Reference) (*go
|
||||
// use the secret as bearer authentication according to OCM v1.1+
|
||||
c := gowebdav.NewClient(endpoint, "", "")
|
||||
c.SetHeader("Authorization", "Bearer "+secret)
|
||||
_, err = c.Stat(rel)
|
||||
if err != nil {
|
||||
// if we got an error, try to use OCM v1.0 basic auth
|
||||
log.Info().Str("endpoint", endpoint).Interface("share", share).Str("rel", rel).Str("secret", secret).Err(err).Msg("falling back to OCM v1.0 access")
|
||||
c.SetHeader("Authorization", "Basic "+secret+":")
|
||||
} else {
|
||||
log.Info().Str("endpoint", endpoint).Interface("share", share).Str("rel", rel).Str("secret", secret).Msg("using OCM v1.1 access")
|
||||
}
|
||||
|
||||
log := appctx.GetLogger(ctx)
|
||||
log.Info().Str("endpoint", endpoint).Interface("share", share).Str("rel", rel).Str("secret", secret).Msg("Accessing OCM share")
|
||||
// add to cache and return
|
||||
d.ccache.SetWithTTL(id.OpaqueId, &cachedClient{
|
||||
client: c,
|
||||
share: share,
|
||||
}, time.Hour)
|
||||
return c, share, rel, nil
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,5 @@ import (
|
||||
// Load core share manager drivers.
|
||||
_ "github.com/cs3org/reva/pkg/publicshare/manager/json"
|
||||
_ "github.com/cs3org/reva/pkg/publicshare/manager/memory"
|
||||
_ "github.com/cs3org/reva/pkg/publicshare/manager/sql"
|
||||
// Add your own here.
|
||||
)
|
||||
|
@ -1,593 +0,0 @@
|
||||
// Copyright 2018-2024 CERN
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// In applying this license, CERN does not waive the privileges and immunities
|
||||
// granted to it by virtue of its status as an Intergovernmental Organization
|
||||
// or submit itself to any jurisdiction.
|
||||
|
||||
package sql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
gatewayv1beta1 "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||
user "github.com/cs3org/go-cs3apis/cs3/identity/user/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"
|
||||
typespb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
|
||||
conversions "github.com/cs3org/reva/pkg/cbox/utils"
|
||||
"github.com/cs3org/reva/pkg/errtypes"
|
||||
"github.com/cs3org/reva/pkg/publicshare"
|
||||
"github.com/cs3org/reva/pkg/publicshare/manager/registry"
|
||||
"github.com/cs3org/reva/pkg/rgrpc/todo/pool"
|
||||
"github.com/cs3org/reva/pkg/sharedconf"
|
||||
"github.com/cs3org/reva/pkg/utils"
|
||||
"github.com/cs3org/reva/pkg/utils/cfg"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
const (
|
||||
publicShareType = 3
|
||||
|
||||
projectInstancesPrefix = "newproject"
|
||||
projectSpaceGroupsPrefix = "cernbox-project-"
|
||||
projectSpaceAdminGroupsSuffix = "-admins"
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.Register("sql", New)
|
||||
}
|
||||
|
||||
type config struct {
|
||||
SharePasswordHashCost int `mapstructure:"password_hash_cost"`
|
||||
JanitorRunInterval int `mapstructure:"janitor_run_interval"`
|
||||
EnableExpiredSharesCleanup bool `mapstructure:"enable_expired_shares_cleanup"`
|
||||
DBUsername string `mapstructure:"db_username"`
|
||||
DBPassword string `mapstructure:"db_password"`
|
||||
DBHost string `mapstructure:"db_host"`
|
||||
DBPort int `mapstructure:"db_port"`
|
||||
DBName string `mapstructure:"db_name"`
|
||||
GatewaySvc string `mapstructure:"gatewaysvc"`
|
||||
}
|
||||
|
||||
type manager struct {
|
||||
c *config
|
||||
db *sql.DB
|
||||
client gatewayv1beta1.GatewayAPIClient
|
||||
}
|
||||
|
||||
func (c *config) ApplyDefaults() {
|
||||
if c.SharePasswordHashCost == 0 {
|
||||
c.SharePasswordHashCost = 11
|
||||
}
|
||||
if c.JanitorRunInterval == 0 {
|
||||
c.JanitorRunInterval = 3600
|
||||
}
|
||||
|
||||
c.GatewaySvc = sharedconf.GetGatewaySVC(c.GatewaySvc)
|
||||
}
|
||||
|
||||
func (m *manager) startJanitorRun() {
|
||||
if !m.c.EnableExpiredSharesCleanup {
|
||||
return
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(time.Duration(m.c.JanitorRunInterval) * time.Second)
|
||||
work := make(chan os.Signal, 1)
|
||||
signal.Notify(work, syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-work:
|
||||
return
|
||||
case <-ticker.C:
|
||||
_ = m.cleanupExpiredShares()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// New returns a new public share manager.
|
||||
func New(ctx context.Context, m map[string]interface{}) (publicshare.Manager, error) {
|
||||
var c config
|
||||
if err := cfg.Decode(m, &c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", c.DBUsername, c.DBPassword, c.DBHost, c.DBPort, c.DBName))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gw, err := pool.GetGatewayServiceClient(pool.Endpoint(c.GatewaySvc))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mgr := manager{
|
||||
c: &c,
|
||||
db: db,
|
||||
client: gw,
|
||||
}
|
||||
go mgr.startJanitorRun()
|
||||
|
||||
return &mgr, nil
|
||||
}
|
||||
|
||||
func (m *manager) CreatePublicShare(ctx context.Context, u *user.User, rInfo *provider.ResourceInfo, g *link.Grant, description string, internal bool, notifyUploads bool, notifyUploadsExtraRecipients string) (*link.PublicShare, error) {
|
||||
tkn := utils.RandString(15)
|
||||
now := time.Now().Unix()
|
||||
|
||||
quicklink, _ := strconv.ParseBool(rInfo.ArbitraryMetadata.Metadata["quicklink"])
|
||||
|
||||
displayName, ok := rInfo.ArbitraryMetadata.Metadata["name"]
|
||||
if !ok {
|
||||
displayName = tkn
|
||||
}
|
||||
createdAt := &typespb.Timestamp{
|
||||
Seconds: uint64(now),
|
||||
}
|
||||
|
||||
creator := conversions.FormatUserID(u.Id)
|
||||
owner := conversions.FormatUserID(rInfo.Owner)
|
||||
permissions := conversions.SharePermToInt(g.Permissions.Permissions)
|
||||
itemType := conversions.ResourceTypeToItem(rInfo.Type)
|
||||
prefix := rInfo.Id.StorageId
|
||||
itemSource := rInfo.Id.OpaqueId
|
||||
fileSource, err := strconv.ParseUint(itemSource, 10, 64)
|
||||
if err != nil {
|
||||
// it can be the case that the item source may be a character string
|
||||
// we leave fileSource blank in that case
|
||||
fileSource = 0
|
||||
}
|
||||
|
||||
query := "insert into oc_share set share_type=?,uid_owner=?,uid_initiator=?,item_type=?,fileid_prefix=?,item_source=?,file_source=?,permissions=?,stime=?,token=?,share_name=?,quicklink=?,description=?,internal=?,notify_uploads=?,notify_uploads_extra_recipients=?"
|
||||
params := []interface{}{publicShareType, owner, creator, itemType, prefix, itemSource, fileSource, permissions, now, tkn, displayName, quicklink, description, internal, notifyUploads, notifyUploadsExtraRecipients}
|
||||
|
||||
var passwordProtected bool
|
||||
password := g.Password
|
||||
if password != "" {
|
||||
password, err = hashPassword(password, m.c.SharePasswordHashCost)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not hash share password")
|
||||
}
|
||||
passwordProtected = true
|
||||
|
||||
query += ",share_with=?"
|
||||
params = append(params, password)
|
||||
}
|
||||
|
||||
if g.Expiration != nil && g.Expiration.Seconds != 0 {
|
||||
t := time.Unix(int64(g.Expiration.Seconds), 0)
|
||||
query += ",expiration=?"
|
||||
params = append(params, t)
|
||||
}
|
||||
|
||||
stmt, err := m.db.Prepare(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result, err := stmt.Exec(params...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lastID, err := result.LastInsertId()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &link.PublicShare{
|
||||
Id: &link.PublicShareId{
|
||||
OpaqueId: strconv.FormatInt(lastID, 10),
|
||||
},
|
||||
Owner: rInfo.GetOwner(),
|
||||
Creator: u.Id,
|
||||
ResourceId: rInfo.Id,
|
||||
Token: tkn,
|
||||
Permissions: g.Permissions,
|
||||
Ctime: createdAt,
|
||||
Mtime: createdAt,
|
||||
PasswordProtected: passwordProtected,
|
||||
Expiration: g.Expiration,
|
||||
DisplayName: displayName,
|
||||
Quicklink: quicklink,
|
||||
Description: description,
|
||||
NotifyUploads: notifyUploads,
|
||||
NotifyUploadsExtraRecipients: notifyUploadsExtraRecipients,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *manager) UpdatePublicShare(ctx context.Context, u *user.User, req *link.UpdatePublicShareRequest, g *link.Grant) (*link.PublicShare, error) {
|
||||
query := "update oc_share set "
|
||||
paramsMap := map[string]interface{}{}
|
||||
params := []interface{}{}
|
||||
|
||||
now := time.Now().Unix()
|
||||
uid := conversions.FormatUserID(u.Id)
|
||||
|
||||
switch req.GetUpdate().GetType() {
|
||||
case link.UpdatePublicShareRequest_Update_TYPE_DISPLAYNAME:
|
||||
paramsMap["share_name"] = req.Update.GetDisplayName()
|
||||
case link.UpdatePublicShareRequest_Update_TYPE_PERMISSIONS:
|
||||
paramsMap["permissions"] = conversions.SharePermToInt(req.Update.GetGrant().GetPermissions().Permissions)
|
||||
case link.UpdatePublicShareRequest_Update_TYPE_EXPIRATION:
|
||||
paramsMap["expiration"] = time.Unix(int64(req.Update.GetGrant().Expiration.Seconds), 0)
|
||||
case link.UpdatePublicShareRequest_Update_TYPE_PASSWORD:
|
||||
if req.Update.GetGrant().Password == "" {
|
||||
paramsMap["share_with"] = ""
|
||||
} else {
|
||||
h, err := hashPassword(req.Update.GetGrant().Password, m.c.SharePasswordHashCost)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not hash share password")
|
||||
}
|
||||
paramsMap["share_with"] = h
|
||||
}
|
||||
case link.UpdatePublicShareRequest_Update_TYPE_DESCRIPTION:
|
||||
paramsMap["description"] = req.Update.GetDescription()
|
||||
case link.UpdatePublicShareRequest_Update_TYPE_NOTIFYUPLOADS:
|
||||
paramsMap["notify_uploads"] = req.Update.GetNotifyUploads()
|
||||
case link.UpdatePublicShareRequest_Update_TYPE_NOTIFYUPLOADSEXTRARECIPIENTS:
|
||||
paramsMap["notify_uploads_extra_recipients"] = req.Update.GetNotifyUploadsExtraRecipients()
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid update type: %v", req.GetUpdate().GetType())
|
||||
}
|
||||
|
||||
for k, v := range paramsMap {
|
||||
query += k + "=?"
|
||||
params = append(params, v)
|
||||
}
|
||||
|
||||
switch {
|
||||
case req.Ref.GetId() != nil:
|
||||
query += ",stime=? where id=? AND (uid_owner=? or uid_initiator=?)"
|
||||
params = append(params, now, req.Ref.GetId().OpaqueId, uid, uid)
|
||||
case req.Ref.GetToken() != "":
|
||||
query += ",stime=? where token=? AND (uid_owner=? or uid_initiator=?)"
|
||||
params = append(params, now, req.Ref.GetToken(), uid, uid)
|
||||
default:
|
||||
return nil, errtypes.NotFound(req.Ref.String())
|
||||
}
|
||||
|
||||
stmt, err := m.db.Prepare(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err = stmt.Exec(params...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return m.GetPublicShare(ctx, u, req.Ref, false)
|
||||
}
|
||||
|
||||
func (m *manager) getByToken(ctx context.Context, token string, u *user.User) (*link.PublicShare, string, error) {
|
||||
s := conversions.DBShare{Token: token}
|
||||
query := "select coalesce(uid_owner, '') as uid_owner, coalesce(uid_initiator, '') as uid_initiator, coalesce(share_with, '') as share_with, coalesce(fileid_prefix, '') as fileid_prefix, coalesce(item_source, '') as item_source, coalesce(item_type, '') as item_type, coalesce(expiration, '') as expiration, coalesce(share_name, '') as share_name, id, stime, permissions, quicklink, description, notify_uploads, notify_uploads_extra_recipients FROM oc_share WHERE (orphan = 0 or orphan IS NULL) AND share_type=? AND token=?"
|
||||
if err := m.db.QueryRow(query, publicShareType, token).Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.Prefix, &s.ItemSource, &s.ItemType, &s.Expiration, &s.ShareName, &s.ID, &s.STime, &s.Permissions, &s.Quicklink, &s.Description, &s.NotifyUploads, &s.NotifyUploadsExtraRecipients); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, "", errtypes.NotFound(token)
|
||||
}
|
||||
return nil, "", err
|
||||
}
|
||||
return conversions.ConvertToCS3PublicShare(s), s.ShareWith, nil
|
||||
}
|
||||
|
||||
func (m *manager) getByID(ctx context.Context, id *link.PublicShareId, u *user.User) (*link.PublicShare, string, error) {
|
||||
uid := conversions.FormatUserID(u.Id)
|
||||
s := conversions.DBShare{ID: id.OpaqueId}
|
||||
query := "select coalesce(uid_owner, '') as uid_owner, coalesce(uid_initiator, '') as uid_initiator, coalesce(share_with, '') as share_with, coalesce(fileid_prefix, '') as fileid_prefix, coalesce(item_source, '') as item_source, coalesce(item_type, '') as item_type, coalesce(token,'') as token, coalesce(expiration, '') as expiration, coalesce(share_name, '') as share_name, stime, permissions, quicklink, description, notify_uploads, notify_uploads_extra_recipients FROM oc_share WHERE (orphan = 0 or orphan IS NULL) AND share_type=? AND id=? AND (uid_owner=? OR uid_initiator=?)"
|
||||
if err := m.db.QueryRow(query, publicShareType, id.OpaqueId, uid, uid).Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.Prefix, &s.ItemSource, &s.ItemType, &s.Token, &s.Expiration, &s.ShareName, &s.STime, &s.Permissions, &s.Quicklink, &s.Description, &s.NotifyUploads, &s.NotifyUploadsExtraRecipients); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, "", errtypes.NotFound(id.OpaqueId)
|
||||
}
|
||||
return nil, "", err
|
||||
}
|
||||
return conversions.ConvertToCS3PublicShare(s), s.ShareWith, nil
|
||||
}
|
||||
|
||||
func (m *manager) GetPublicShare(ctx context.Context, u *user.User, ref *link.PublicShareReference, sign bool) (*link.PublicShare, error) {
|
||||
var s *link.PublicShare
|
||||
var pw string
|
||||
var err error
|
||||
switch {
|
||||
case ref.GetId() != nil:
|
||||
s, pw, err = m.getByID(ctx, ref.GetId(), u)
|
||||
case ref.GetToken() != "":
|
||||
s, pw, err = m.getByToken(ctx, ref.GetToken(), u)
|
||||
default:
|
||||
err = errtypes.NotFound(ref.String())
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if expired(s) {
|
||||
if err := m.cleanupExpiredShares(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, errtypes.NotFound(ref.String())
|
||||
}
|
||||
|
||||
if s.PasswordProtected && sign {
|
||||
if err := publicshare.AddSignature(s, pw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (m *manager) ListPublicShares(ctx context.Context, u *user.User, filters []*link.ListPublicSharesRequest_Filter, md *provider.ResourceInfo, sign bool) ([]*link.PublicShare, error) {
|
||||
query := "select coalesce(uid_owner, '') as uid_owner, coalesce(uid_initiator, '') as uid_initiator, coalesce(share_with, '') as share_with, coalesce(fileid_prefix, '') as fileid_prefix, coalesce(item_source, '') as item_source, coalesce(item_type, '') as item_type, coalesce(token,'') as token, coalesce(expiration, '') as expiration, coalesce(share_name, '') as share_name, id, stime, permissions, quicklink, description, notify_uploads, notify_uploads_extra_recipients FROM oc_share WHERE (orphan = 0 or orphan IS NULL) AND (share_type=?) AND internal=false"
|
||||
var resourceFilters, ownerFilters, creatorFilters string
|
||||
var resourceParams, ownerParams, creatorParams []interface{}
|
||||
params := []interface{}{publicShareType}
|
||||
for _, f := range filters {
|
||||
switch f.Type {
|
||||
case link.ListPublicSharesRequest_Filter_TYPE_RESOURCE_ID:
|
||||
if len(resourceFilters) != 0 {
|
||||
resourceFilters += " OR "
|
||||
}
|
||||
resourceFilters += "(fileid_prefix=? AND item_source=?)"
|
||||
resourceParams = append(resourceParams, f.GetResourceId().StorageId, f.GetResourceId().OpaqueId)
|
||||
case link.ListPublicSharesRequest_Filter_TYPE_OWNER:
|
||||
if len(ownerFilters) != 0 {
|
||||
ownerFilters += " OR "
|
||||
}
|
||||
ownerFilters += "(uid_owner=?)"
|
||||
ownerParams = append(ownerParams, conversions.FormatUserID(f.GetOwner()))
|
||||
case link.ListPublicSharesRequest_Filter_TYPE_CREATOR:
|
||||
if len(creatorFilters) != 0 {
|
||||
creatorFilters += " OR "
|
||||
}
|
||||
creatorFilters += "(uid_initiator=?)"
|
||||
creatorParams = append(creatorParams, conversions.FormatUserID(f.GetCreator()))
|
||||
}
|
||||
}
|
||||
|
||||
if resourceFilters != "" {
|
||||
query = fmt.Sprintf("%s AND (%s)", query, resourceFilters)
|
||||
params = append(params, resourceParams...)
|
||||
}
|
||||
if ownerFilters != "" {
|
||||
query = fmt.Sprintf("%s AND (%s)", query, ownerFilters)
|
||||
params = append(params, ownerParams...)
|
||||
}
|
||||
if creatorFilters != "" {
|
||||
query = fmt.Sprintf("%s AND (%s)", query, creatorFilters)
|
||||
params = append(params, creatorParams...)
|
||||
}
|
||||
|
||||
uidOwnersQuery, uidOwnersParams, err := m.uidOwnerFilters(ctx, u, filters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
params = append(params, uidOwnersParams...)
|
||||
if uidOwnersQuery != "" {
|
||||
query = fmt.Sprintf("%s AND (%s)", query, uidOwnersQuery)
|
||||
}
|
||||
|
||||
rows, err := m.db.Query(query, params...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var s conversions.DBShare
|
||||
shares := []*link.PublicShare{}
|
||||
for rows.Next() {
|
||||
if err := rows.Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.Prefix, &s.ItemSource, &s.ItemType, &s.Token, &s.Expiration, &s.ShareName, &s.ID, &s.STime, &s.Permissions, &s.Quicklink, &s.Description, &s.NotifyUploads, &s.NotifyUploadsExtraRecipients); err != nil {
|
||||
continue
|
||||
}
|
||||
cs3Share := conversions.ConvertToCS3PublicShare(s)
|
||||
if expired(cs3Share) {
|
||||
_ = m.cleanupExpiredShares()
|
||||
} else {
|
||||
if cs3Share.PasswordProtected && sign {
|
||||
if err := publicshare.AddSignature(cs3Share, s.ShareWith); err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
shares = append(shares, cs3Share)
|
||||
}
|
||||
}
|
||||
if err = rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return shares, nil
|
||||
}
|
||||
|
||||
func (m *manager) RevokePublicShare(ctx context.Context, u *user.User, ref *link.PublicShareReference) error {
|
||||
uid := conversions.FormatUserID(u.Id)
|
||||
query := "delete from oc_share where "
|
||||
params := []interface{}{}
|
||||
|
||||
switch {
|
||||
case ref.GetId() != nil && ref.GetId().OpaqueId != "":
|
||||
query += "id=? AND (uid_owner=? or uid_initiator=?)"
|
||||
params = append(params, ref.GetId().OpaqueId, uid, uid)
|
||||
case ref.GetToken() != "":
|
||||
query += "token=? AND (uid_owner=? or uid_initiator=?)"
|
||||
params = append(params, ref.GetToken(), uid, uid)
|
||||
default:
|
||||
return errtypes.NotFound(ref.String())
|
||||
}
|
||||
|
||||
stmt, err := m.db.Prepare(query)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
res, err := stmt.Exec(params...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rowCnt, err := res.RowsAffected()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if rowCnt == 0 {
|
||||
return errtypes.NotFound(ref.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *manager) GetPublicShareByToken(ctx context.Context, token string, auth *link.PublicShareAuthentication, sign bool) (*link.PublicShare, error) {
|
||||
s := conversions.DBShare{Token: token}
|
||||
query := "select coalesce(uid_owner, '') as uid_owner, coalesce(uid_initiator, '') as uid_initiator, coalesce(share_with, '') as share_with, coalesce(fileid_prefix, '') as fileid_prefix, coalesce(item_source, '') as item_source, coalesce(item_type, '') as item_type, coalesce(expiration, '') as expiration, coalesce(share_name, '') as share_name, id, stime, permissions, quicklink, description, notify_uploads, notify_uploads_extra_recipients FROM oc_share WHERE share_type=? AND token=?"
|
||||
if err := m.db.QueryRow(query, publicShareType, token).Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.Prefix, &s.ItemSource, &s.ItemType, &s.Expiration, &s.ShareName, &s.ID, &s.STime, &s.Permissions, &s.Quicklink, &s.Description, &s.NotifyUploads, &s.NotifyUploadsExtraRecipients); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, errtypes.NotFound(token)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
cs3Share := conversions.ConvertToCS3PublicShare(s)
|
||||
if expired(cs3Share) {
|
||||
if err := m.cleanupExpiredShares(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, errtypes.NotFound(token)
|
||||
}
|
||||
if s.ShareWith != "" {
|
||||
if !authenticate(cs3Share, s.ShareWith, auth) {
|
||||
// if check := checkPasswordHash(auth.Password, s.ShareWith); !check {
|
||||
return nil, errtypes.InvalidCredentials(token)
|
||||
}
|
||||
|
||||
if sign {
|
||||
if err := publicshare.AddSignature(cs3Share, s.ShareWith); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cs3Share, nil
|
||||
}
|
||||
|
||||
func (m *manager) cleanupExpiredShares() error {
|
||||
if !m.c.EnableExpiredSharesCleanup {
|
||||
return nil
|
||||
}
|
||||
|
||||
query := "update oc_share set orphan = 1 where expiration IS NOT NULL AND expiration < ?"
|
||||
params := []interface{}{time.Now().Format("2006-01-02 03:04:05")}
|
||||
|
||||
stmt, err := m.db.Prepare(query)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = stmt.Exec(params...); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *manager) uidOwnerFilters(ctx context.Context, u *user.User, filters []*link.ListPublicSharesRequest_Filter) (string, []interface{}, error) {
|
||||
uid := conversions.FormatUserID(u.Id)
|
||||
|
||||
query := "uid_owner=? or uid_initiator=?"
|
||||
params := []interface{}{uid, uid}
|
||||
|
||||
client, err := pool.GetGatewayServiceClient(pool.Endpoint(m.c.GatewaySvc))
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
for _, f := range filters {
|
||||
if f.Type == link.ListPublicSharesRequest_Filter_TYPE_RESOURCE_ID {
|
||||
// For shares inside project spaces, if the user is an admin, we try to list all shares created by other admins
|
||||
if strings.HasPrefix(f.GetResourceId().GetStorageId(), projectInstancesPrefix) {
|
||||
res, err := client.Stat(ctx, &provider.StatRequest{Ref: &provider.Reference{ResourceId: f.GetResourceId()}})
|
||||
if err != nil || res.Status.Code != rpc.Code_CODE_OK {
|
||||
continue
|
||||
}
|
||||
|
||||
// The path will look like /eos/project/c/cernbox, we need to extract the project name
|
||||
parts := strings.SplitN(res.Info.Path, "/", 6)
|
||||
if len(parts) < 5 {
|
||||
continue
|
||||
}
|
||||
|
||||
adminGroup := projectSpaceGroupsPrefix + parts[4] + projectSpaceAdminGroupsSuffix
|
||||
for _, g := range u.Groups {
|
||||
if g == adminGroup {
|
||||
// User belongs to the admin group, list all shares for the resource
|
||||
|
||||
// TODO: this only works if shares for a single project are requested.
|
||||
// If shares for multiple projects are requested, then we're not checking if the
|
||||
// user is an admin for all of those. We can append the query ` or uid_owner=?`
|
||||
// for all the project owners, which works fine for new reva
|
||||
// but won't work for revaold since there, we store the uid of the share creator as uid_owner.
|
||||
// For this to work across the two versions, this change would have to be made in revaold
|
||||
// but it won't be straightforward as there, the storage provider doesn't return the
|
||||
// resource owners.
|
||||
return "", []interface{}{}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return query, params, nil
|
||||
}
|
||||
|
||||
func expired(s *link.PublicShare) bool {
|
||||
if s.Expiration != nil {
|
||||
if t := time.Unix(int64(s.Expiration.GetSeconds()), int64(s.Expiration.GetNanos())); t.Before(time.Now()) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func hashPassword(password string, cost int) (string, error) {
|
||||
bytes, err := bcrypt.GenerateFromPassword([]byte(password), cost)
|
||||
return "1|" + string(bytes), err
|
||||
}
|
||||
|
||||
func checkPasswordHash(password, hash string) bool {
|
||||
err := bcrypt.CompareHashAndPassword([]byte(strings.TrimPrefix(hash, "1|")), []byte(password))
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func authenticate(share *link.PublicShare, pw string, auth *link.PublicShareAuthentication) bool {
|
||||
switch {
|
||||
case auth.GetPassword() != "":
|
||||
return checkPasswordHash(auth.GetPassword(), pw)
|
||||
case auth.GetSignature() != nil:
|
||||
sig := auth.GetSignature()
|
||||
now := time.Now()
|
||||
expiration := time.Unix(int64(sig.GetSignatureExpiration().GetSeconds()), int64(sig.GetSignatureExpiration().GetNanos()))
|
||||
if now.After(expiration) {
|
||||
return false
|
||||
}
|
||||
s, err := publicshare.CreateSignature(share.Token, pw, expiration)
|
||||
if err != nil {
|
||||
// TODO(labkode): pass context to call to log err.
|
||||
// No we are blind
|
||||
return false
|
||||
}
|
||||
return sig.GetSignature() == s
|
||||
}
|
||||
return false
|
||||
}
|
@ -145,6 +145,7 @@ type eosfs struct {
|
||||
singleUserAuth eosclient.Authorization
|
||||
userIDCache *ttlcache.Cache
|
||||
tokenCache gcache.Cache
|
||||
binaryClient eosclient.EOSClient
|
||||
}
|
||||
|
||||
// NewEOSFS returns a storage.FS interface implementation that connects to an EOS instance.
|
||||
@ -160,6 +161,7 @@ func NewEOSFS(ctx context.Context, c *Config) (storage.FS, error) {
|
||||
}
|
||||
|
||||
var eosClient eosclient.EOSClient
|
||||
var eosBinaryClient eosclient.EOSClient
|
||||
var err error
|
||||
if c.UseGRPC {
|
||||
eosClientOpts := &eosgrpc.Options{
|
||||
@ -189,6 +191,27 @@ func NewEOSFS(ctx context.Context, c *Config) (storage.FS, error) {
|
||||
Authkey: c.HTTPSAuthkey,
|
||||
}
|
||||
eosClient, err = eosgrpc.New(ctx, eosClientOpts, eosHTTPOpts)
|
||||
|
||||
// Very ugly temporary workaround for CERNBOX-3797
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error initializing eosclient")
|
||||
}
|
||||
|
||||
eosBinaryClientOpts := &eosbinary.Options{
|
||||
XrdcopyBinary: c.XrdcopyBinary,
|
||||
URL: c.MasterURL,
|
||||
EosBinary: c.EosBinary,
|
||||
CacheDirectory: c.CacheDirectory,
|
||||
ForceSingleUserMode: c.ForceSingleUserMode,
|
||||
SingleUsername: c.SingleUsername,
|
||||
UseKeytab: c.UseKeytab,
|
||||
Keytab: c.Keytab,
|
||||
SecProtocol: c.SecProtocol,
|
||||
VersionInvariant: c.VersionInvariant,
|
||||
TokenExpiry: c.TokenExpiry,
|
||||
}
|
||||
eosBinaryClient, err = eosbinary.New(eosBinaryClientOpts)
|
||||
|
||||
} else {
|
||||
eosClientOpts := &eosbinary.Options{
|
||||
XrdcopyBinary: c.XrdcopyBinary,
|
||||
@ -212,6 +235,7 @@ func NewEOSFS(ctx context.Context, c *Config) (storage.FS, error) {
|
||||
|
||||
eosfs := &eosfs{
|
||||
c: eosClient,
|
||||
binaryClient: eosBinaryClient,
|
||||
conf: c,
|
||||
chunkHandler: chunking.NewChunkHandler(c.CacheDirectory),
|
||||
userIDCache: ttlcache.NewCache(),
|
||||
@ -473,7 +497,7 @@ func (fs *eosfs) UnsetArbitraryMetadata(ctx context.Context, ref *provider.Refer
|
||||
return err
|
||||
}
|
||||
|
||||
cboxAuth := utils.GetEmptyAuth()
|
||||
//cboxAuth := utils.GetEmptyAuth()
|
||||
|
||||
for _, k := range keys {
|
||||
if k == "" {
|
||||
@ -485,7 +509,17 @@ func (fs *eosfs) UnsetArbitraryMetadata(ctx context.Context, ref *provider.Refer
|
||||
Key: k,
|
||||
}
|
||||
|
||||
err := fs.c.UnsetAttr(ctx, cboxAuth, attr, false, fn, "")
|
||||
// Temporary workaround for CERNBOX-3797
|
||||
|
||||
// err := fs.c.UnsetAttr(ctx, cboxAuth, attr, false, fn, "")
|
||||
rootAuth := eosclient.Authorization{
|
||||
Role: eosclient.Role{
|
||||
UID: "0",
|
||||
GID: "0",
|
||||
},
|
||||
}
|
||||
err := fs.binaryClient.UnsetAttr(ctx, rootAuth, attr, false, fn, "")
|
||||
|
||||
if err != nil {
|
||||
if errors.Is(err, eosclient.AttrNotExistsError) {
|
||||
continue
|
||||
@ -898,7 +932,13 @@ func (fs *eosfs) AddGrant(ctx context.Context, ref *provider.Reference, g *provi
|
||||
Key: fmt.Sprintf("%s.%s", lwShareAttrKey, eosACL.Qualifier),
|
||||
Val: eosACL.Permissions,
|
||||
}
|
||||
if err := fs.c.SetAttr(ctx, cboxAuth, attr, false, true, fn, ""); err != nil {
|
||||
|
||||
// Temporary workaround (See #5123)
|
||||
// EOS < 5.3 gRPC does not recognize the "recursive" attribute
|
||||
// So we use the binary client for now
|
||||
|
||||
if err := fs.binaryClient.SetAttr(ctx, cboxAuth, attr, false, true, fn, ""); err != nil {
|
||||
// if err := fs.c.SetAttr(ctx, cboxAuth, attr, false, true, fn, ""); err != nil {
|
||||
return errors.Wrap(err, "eosfs: error adding acl for lightweight account")
|
||||
}
|
||||
return nil
|
||||
@ -995,7 +1035,16 @@ func (fs *eosfs) RemoveGrant(ctx context.Context, ref *provider.Reference, g *pr
|
||||
Type: SystemAttr,
|
||||
Key: fmt.Sprintf("%s.%s", lwShareAttrKey, eosACL.Qualifier),
|
||||
}
|
||||
if err := fs.c.UnsetAttr(ctx, cboxAuth, attr, true, fn, ""); err != nil {
|
||||
|
||||
// Temporary workaround for CERNBOX-3797
|
||||
rootAuth := eosclient.Authorization{
|
||||
Role: eosclient.Role{
|
||||
UID: "0",
|
||||
GID: "0",
|
||||
},
|
||||
}
|
||||
if err := fs.binaryClient.UnsetAttr(ctx, rootAuth, attr, true, fn, ""); err != nil {
|
||||
//if err := fs.c.UnsetAttr(ctx, cboxAuth, attr, true, fn, ""); err != nil {
|
||||
return errors.Wrap(err, "eosfs: error removing acl for lightweight account")
|
||||
}
|
||||
return nil
|
||||
@ -1120,6 +1169,9 @@ func (fs *eosfs) GetMD(ctx context.Context, ref *provider.Reference, mdKeys []st
|
||||
// We cannot use the current user, because the file may be a shared file
|
||||
// and lightweight accounts don't have a uid
|
||||
auth, err := fs.getDaemonAuth(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting daemon auth")
|
||||
}
|
||||
|
||||
if ref.ResourceId != nil {
|
||||
fid, err := strconv.ParseUint(ref.ResourceId.OpaqueId, 10, 64)
|
||||
@ -1129,12 +1181,15 @@ func (fs *eosfs) GetMD(ctx context.Context, ref *provider.Reference, mdKeys []st
|
||||
|
||||
eosFileInfo, err := fs.c.GetFileInfoByInode(ctx, auth, fid)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("fid", strconv.Itoa(int(fid))).Msg("Failed to get file info by inode")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ref.Path != "" {
|
||||
eosFileInfo, err = fs.c.GetFileInfoByPath(ctx, auth, filepath.Join(eosFileInfo.File, ref.Path))
|
||||
fn := filepath.Join(eosFileInfo.File, ref.Path)
|
||||
eosFileInfo, err = fs.c.GetFileInfoByPath(ctx, auth, fn)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("path", fn).Msg("Failed to get file info by path")
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@ -1143,6 +1198,7 @@ func (fs *eosfs) GetMD(ctx context.Context, ref *provider.Reference, mdKeys []st
|
||||
|
||||
eosFileInfo, err := fs.c.GetFileInfoByPath(ctx, auth, fn)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("path", fn).Msg("Failed to get file info by path")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -1174,6 +1230,7 @@ func (fs *eosfs) listWithNominalHome(ctx context.Context, p string) (finfos []*p
|
||||
|
||||
eosFileInfos, err := fs.c.List(ctx, auth, fn)
|
||||
if err != nil {
|
||||
log.Error().Str("filename", fn).Err(err).Msg("eosfs: error listing")
|
||||
return nil, errors.Wrap(err, "eosfs: error listing")
|
||||
}
|
||||
|
||||
|
@ -162,6 +162,7 @@ func getUser(ctx context.Context) (*userpb.User, error) {
|
||||
}
|
||||
|
||||
func (fs *localfs) wrap(ctx context.Context, p string) string {
|
||||
log := appctx.GetLogger(ctx)
|
||||
// This is to prevent path traversal.
|
||||
// With this p can't break out of its parent folder
|
||||
p = path.Join("/", p)
|
||||
@ -175,6 +176,7 @@ func (fs *localfs) wrap(ctx context.Context, p string) string {
|
||||
} else {
|
||||
internal = path.Join(fs.conf.DataDirectory, p)
|
||||
}
|
||||
log.Debug().Str("old", p).Str("wrapped", internal).Msg("localfs: wrap")
|
||||
return internal
|
||||
}
|
||||
|
||||
@ -842,6 +844,8 @@ func (fs *localfs) Delete(ctx context.Context, ref *provider.Reference) error {
|
||||
}
|
||||
|
||||
func (fs *localfs) Move(ctx context.Context, oldRef, newRef *provider.Reference) error {
|
||||
log := appctx.GetLogger(ctx)
|
||||
log.Debug().Any("from", oldRef).Any("to", newRef).Msg("localfs: move")
|
||||
oldName, err := fs.resolve(ctx, oldRef)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "localfs: error resolving ref")
|
||||
@ -860,6 +864,7 @@ func (fs *localfs) Move(ctx context.Context, oldRef, newRef *provider.Reference)
|
||||
newName = fs.wrap(ctx, newName)
|
||||
|
||||
if err := os.Rename(oldName, newName); err != nil {
|
||||
log.Error().Err(err).Msg("localfs: error moving " + oldName + " to " + newName)
|
||||
return errors.Wrap(err, "localfs: error moving "+oldName+" to "+newName)
|
||||
}
|
||||
|
||||
@ -912,6 +917,7 @@ func (fs *localfs) moveReferences(ctx context.Context, oldName, newName string)
|
||||
}
|
||||
|
||||
func (fs *localfs) GetMD(ctx context.Context, ref *provider.Reference, mdKeys []string) (*provider.ResourceInfo, error) {
|
||||
log := appctx.GetLogger(ctx)
|
||||
fn, err := fs.resolve(ctx, ref)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "localfs: error resolving ref")
|
||||
@ -926,6 +932,7 @@ func (fs *localfs) GetMD(ctx context.Context, ref *provider.Reference, mdKeys []
|
||||
fn = fs.wrap(ctx, fn)
|
||||
md, err := os.Stat(fn)
|
||||
if err != nil {
|
||||
log.Warn().Str("path", fn).Any("md", md).Err(err).Msg("failed stat call in localfs")
|
||||
if os.IsNotExist(err) {
|
||||
return nil, errtypes.NotFound(fn)
|
||||
}
|
||||
@ -952,6 +959,7 @@ func (fs *localfs) getMDShareFolder(ctx context.Context, p string, mdKeys []stri
|
||||
}
|
||||
|
||||
func (fs *localfs) ListFolder(ctx context.Context, ref *provider.Reference, mdKeys []string) ([]*provider.ResourceInfo, error) {
|
||||
log := appctx.GetLogger(ctx)
|
||||
fn, err := fs.resolve(ctx, ref)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "localfs: error resolving ref")
|
||||
@ -960,6 +968,7 @@ func (fs *localfs) ListFolder(ctx context.Context, ref *provider.Reference, mdKe
|
||||
if fn == "/" {
|
||||
homeFiles, err := fs.listFolder(ctx, fn, mdKeys)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msg("failed to execute listFolder for root")
|
||||
return nil, err
|
||||
}
|
||||
if !fs.conf.DisableHome {
|
||||
@ -973,14 +982,22 @@ func (fs *localfs) ListFolder(ctx context.Context, ref *provider.Reference, mdKe
|
||||
}
|
||||
|
||||
if fs.isShareFolderRoot(ctx, fn) {
|
||||
return fs.listShareFolderRoot(ctx, fn, mdKeys)
|
||||
res, err := fs.listShareFolderRoot(ctx, fn, mdKeys)
|
||||
if err != nil {
|
||||
log.Warn().Str("fn", fn).Err(err).Msg("failed to execute listShareFolderRoot")
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
|
||||
if fs.isShareFolderChild(ctx, fn) {
|
||||
return nil, errtypes.PermissionDenied("localfs: error listing folders inside the shared folder, only file references are stored inside")
|
||||
}
|
||||
|
||||
return fs.listFolder(ctx, fn, mdKeys)
|
||||
res, err := fs.listFolder(ctx, fn, mdKeys)
|
||||
if err != nil {
|
||||
log.Warn().Str("fn", fn).Err(err).Msg("failed to execute listFolder")
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (fs *localfs) listFolder(ctx context.Context, fn string, mdKeys []string) ([]*provider.ResourceInfo, error) {
|
||||
@ -1050,7 +1067,10 @@ func (fs *localfs) listShareFolderRoot(ctx context.Context, home string, mdKeys
|
||||
|
||||
func (fs *localfs) Download(ctx context.Context, ref *provider.Reference) (io.ReadCloser, error) {
|
||||
fn, err := fs.resolve(ctx, ref)
|
||||
log := appctx.GetLogger(ctx)
|
||||
|
||||
if err != nil {
|
||||
log.Error().Err(err).Any("ref", ref).Msg("localfs: error resolving ref")
|
||||
return nil, errors.Wrap(err, "localfs: error resolving ref")
|
||||
}
|
||||
|
||||
@ -1062,8 +1082,10 @@ func (fs *localfs) Download(ctx context.Context, ref *provider.Reference) (io.Re
|
||||
r, err := os.Open(fn)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
log.Error().Err(err).Str("path", fn).Msg("localfs: file not found")
|
||||
return nil, errtypes.NotFound(fn)
|
||||
}
|
||||
log.Error().Err(err).Str("path", fn).Msg("localfs: error opening file")
|
||||
return nil, errors.Wrap(err, "localfs: error reading "+fn)
|
||||
}
|
||||
return r, nil
|
||||
|
@ -40,7 +40,9 @@ import (
|
||||
var defaultFilePerm = os.FileMode(0664)
|
||||
|
||||
func (fs *localfs) Upload(ctx context.Context, ref *provider.Reference, r io.ReadCloser, metadata map[string]string) error {
|
||||
log := appctx.GetLogger(ctx)
|
||||
upload, err := fs.GetUpload(ctx, ref.GetPath())
|
||||
log.Info().Any("upload", upload).Msg("localfs: upload")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "localfs: error retrieving upload")
|
||||
}
|
||||
@ -156,6 +158,7 @@ func (fs *localfs) NewUpload(ctx context.Context, info tusd.FileInfo) (upload tu
|
||||
info.ID = uuid.New().String()
|
||||
|
||||
binPath, err := fs.getUploadPath(ctx, info.ID)
|
||||
log.Info().Str("upload-path", binPath).Err(err).Msg("localfs: got upload path")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "localfs: error resolving upload path")
|
||||
}
|
||||
@ -307,6 +310,7 @@ func (upload *fileUpload) writeInfo() error {
|
||||
|
||||
// FinishUpload finishes an upload and moves the file to the internal destination.
|
||||
func (upload *fileUpload) FinishUpload(ctx context.Context) error {
|
||||
log := appctx.GetLogger(ctx)
|
||||
np := upload.info.Storage["InternalDestination"]
|
||||
|
||||
// TODO check etag with If-Match header
|
||||
@ -318,6 +322,7 @@ func (upload *fileUpload) FinishUpload(ctx context.Context) error {
|
||||
//}
|
||||
|
||||
// if destination exists
|
||||
log.Info().Str("oldpath", upload.binPath).Str("newpath", np).Msg("localfs: FinishUpload")
|
||||
if _, err := os.Stat(np); err == nil {
|
||||
// create revision
|
||||
if err := upload.fs.archiveRevision(upload.ctx, np); err != nil {
|
||||
@ -327,6 +332,7 @@ func (upload *fileUpload) FinishUpload(ctx context.Context) error {
|
||||
|
||||
err := os.Rename(upload.binPath, np)
|
||||
if err != nil {
|
||||
log.Error().Msg("localfs: Failed to rename in FinishUpload")
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -499,3 +499,19 @@ func GetUser(ctx context.Context) (*userpb.User, error) {
|
||||
}
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// Extract a simplified user agent
|
||||
func SimplifiedUserAgent(r *http.Request) string {
|
||||
switch {
|
||||
case strings.Contains(r.UserAgent(), "Firefox"):
|
||||
return "Firefox"
|
||||
case strings.Contains(r.UserAgent(), "Safari") && (strings.Contains(r.UserAgent(), "Mac OS X")):
|
||||
// the order is important! Safari advertises itself as "Safari/Chrome"
|
||||
return "Safari"
|
||||
case strings.Contains(r.UserAgent(), "Chrome"):
|
||||
// this includes any Chromium-based browser such as Edge and Opera
|
||||
return "Chrome"
|
||||
default:
|
||||
return "Other"
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
[log]
|
||||
mode = "json"
|
||||
|
||||
[shared]
|
||||
gatewaysvc = "{{grpc_address}}"
|
||||
|
@ -1,5 +1,4 @@
|
||||
[log]
|
||||
mode = "json"
|
||||
|
||||
[shared]
|
||||
gatewaysvc = "{{cernboxgw_address}}"
|
||||
@ -21,3 +20,12 @@ driver = "json"
|
||||
|
||||
[http.middlewares.providerauthorizer.drivers.json]
|
||||
providers = "fixtures/ocm-providers.demo.json"
|
||||
|
||||
[http.services.wellknown]
|
||||
|
||||
[http.services.wellknown.ocmprovider]
|
||||
ocm_prefix = "ocm"
|
||||
provider = "Reva for CERNBox"
|
||||
endpoint = "http://{{cernboxhttp_address}}"
|
||||
enable_webapp = true
|
||||
enable_datatx = true
|
||||
|
@ -1,5 +1,4 @@
|
||||
[log]
|
||||
mode = "json"
|
||||
|
||||
[shared]
|
||||
gatewaysvc = "{{grpc_address}}"
|
||||
|
@ -1,5 +1,4 @@
|
||||
[log]
|
||||
mode = "json"
|
||||
|
||||
[shared]
|
||||
gatewaysvc = "{{cesnetgw_address}}"
|
||||
@ -21,3 +20,12 @@ driver = "json"
|
||||
|
||||
[http.middlewares.providerauthorizer.drivers.json]
|
||||
providers = "fixtures/ocm-providers.demo.json"
|
||||
|
||||
[http.services.wellknown]
|
||||
|
||||
[http.services.wellknown.ocmprovider]
|
||||
ocm_prefix = "ocm"
|
||||
provider = "Reva for CESNET"
|
||||
endpoint = "http://{{cesnethttp_address}}"
|
||||
enable_webapp = true
|
||||
enable_datatx = true
|
||||
|
@ -1,5 +1,4 @@
|
||||
[log]
|
||||
mode = "json"
|
||||
|
||||
[shared]
|
||||
gatewaysvc = "{{cernboxgw_address}}"
|
||||
|
@ -1,5 +1,4 @@
|
||||
[log]
|
||||
mode = "json"
|
||||
|
||||
[shared]
|
||||
gatewaysvc = "{{cernboxgw_address}}"
|
||||
|
@ -1,5 +1,4 @@
|
||||
[log]
|
||||
mode = "json"
|
||||
|
||||
[shared]
|
||||
gatewaysvc = "{{cernboxgw_address}}"
|
||||
|
@ -1,5 +1,4 @@
|
||||
[log]
|
||||
mode = "json"
|
||||
|
||||
[shared]
|
||||
gatewaysvc = "{{cernboxgw_address}}"
|
||||
@ -19,4 +18,4 @@ machine_secret = "secret"
|
||||
[grpc.services.authprovider]
|
||||
auth_manager = "ocmshares"
|
||||
|
||||
[grpc.services.authprovider.auth_managers.ocmshares]
|
||||
[grpc.services.authprovider.auth_managers.ocmshares]
|
||||
|
@ -1,5 +1,4 @@
|
||||
[log]
|
||||
mode = "json"
|
||||
|
||||
[shared]
|
||||
gatewaysvc = "{{grpc_address}}"
|
||||
@ -39,6 +38,7 @@ driver = "static"
|
||||
|
||||
[grpc.services.authregistry.drivers.static.rules]
|
||||
basic = "{{grpc_address}}"
|
||||
bearer = "{{grpc_address}}"
|
||||
ocmshares = "{{cernboxoutcomingocm_address}}"
|
||||
machine = "{{cernboxmachineauth_address}}"
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
[log]
|
||||
mode = "json"
|
||||
|
||||
[shared]
|
||||
gatewaysvc = "{{cernboxgw_address}}"
|
||||
@ -14,6 +13,10 @@ provider_domain = "{{cernboxhttp_address}}"
|
||||
mesh_directory_url = "http://meshdir"
|
||||
smtp_credentials = {}
|
||||
|
||||
[http.middlewares.auth]
|
||||
credential_chain = ["publicshares", "basic", "bearer"]
|
||||
token_strategy_chain = ["bearer", "header"]
|
||||
|
||||
[http.middlewares.cors]
|
||||
|
||||
[http.middlewares.providerauthorizer]
|
||||
@ -31,3 +34,11 @@ driver = "localhome"
|
||||
root = "{{localhome_root}}"
|
||||
|
||||
[http.services.ocdav]
|
||||
|
||||
[http.services.wellknown]
|
||||
[http.services.wellknown.ocmprovider]
|
||||
ocm_prefix = "ocm"
|
||||
provider = "Reva for CERNBox"
|
||||
endpoint = "http://{{cernboxhttp_address}}"
|
||||
enable_webapp = true
|
||||
enable_datatx = true
|
||||
|
@ -1,5 +1,4 @@
|
||||
[log]
|
||||
mode = "json"
|
||||
|
||||
[shared]
|
||||
gatewaysvc = "{{grpc_address}}"
|
||||
|
@ -1,5 +1,4 @@
|
||||
[log]
|
||||
mode = "json"
|
||||
|
||||
[shared]
|
||||
gatewaysvc = "{{cesnetgw_address}}"
|
||||
@ -28,3 +27,11 @@ providers = "fixtures/ocm-providers.demo.json"
|
||||
driver = "ocmreceived"
|
||||
|
||||
[http.services.dataprovider.drivers.ocmreceived]
|
||||
|
||||
[http.services.wellknown]
|
||||
[http.services.wellknown.ocmprovider]
|
||||
ocm_prefix = "ocm"
|
||||
provider = "Reva for CESNET"
|
||||
endpoint = "http://{{cesnethttp_address}}"
|
||||
enable_webapp = true
|
||||
enable_datatx = true
|
||||
|
@ -1,3 +1,5 @@
|
||||
[log]
|
||||
|
||||
[grpc]
|
||||
address = "{{grpc_address}}"
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
[log]
|
||||
|
||||
[grpc]
|
||||
address = "{{grpc_address}}"
|
||||
|
||||
@ -9,4 +11,4 @@ root = "{{root}}"
|
||||
treetime_accounting = true
|
||||
treesize_accounting = true
|
||||
enable_home = true
|
||||
userprovidersvc = "localhost:18000"
|
||||
userprovidersvc = "localhost:18000"
|
||||
|
@ -1,3 +1,5 @@
|
||||
[log]
|
||||
|
||||
[grpc]
|
||||
address = "{{grpc_address}}"
|
||||
|
||||
|
@ -197,7 +197,7 @@ var _ = Describe("ocm share", func() {
|
||||
},
|
||||
},
|
||||
AccessMethods: []*ocmv1beta1.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
|
||||
},
|
||||
RecipientMeshProvider: cesnet.ProviderInfo,
|
||||
})
|
||||
@ -278,7 +278,7 @@ var _ = Describe("ocm share", func() {
|
||||
},
|
||||
},
|
||||
AccessMethods: []*ocmv1beta1.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
|
||||
},
|
||||
RecipientMeshProvider: cesnet.ProviderInfo,
|
||||
})
|
||||
@ -374,7 +374,7 @@ var _ = Describe("ocm share", func() {
|
||||
},
|
||||
},
|
||||
AccessMethods: []*ocmv1beta1.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
|
||||
},
|
||||
RecipientMeshProvider: cesnet.ProviderInfo,
|
||||
})
|
||||
@ -477,7 +477,7 @@ var _ = Describe("ocm share", func() {
|
||||
},
|
||||
},
|
||||
AccessMethods: []*ocmv1beta1.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
|
||||
},
|
||||
RecipientMeshProvider: cesnet.ProviderInfo,
|
||||
})
|
||||
@ -626,7 +626,7 @@ var _ = Describe("ocm share", func() {
|
||||
},
|
||||
},
|
||||
AccessMethods: []*ocmv1beta1.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
|
||||
},
|
||||
RecipientMeshProvider: cesnet.ProviderInfo,
|
||||
})
|
||||
@ -643,7 +643,7 @@ var _ = Describe("ocm share", func() {
|
||||
},
|
||||
},
|
||||
AccessMethods: []*ocmv1beta1.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
|
||||
},
|
||||
RecipientMeshProvider: cesnet.ProviderInfo,
|
||||
})
|
||||
@ -668,7 +668,7 @@ var _ = Describe("ocm share", func() {
|
||||
},
|
||||
},
|
||||
AccessMethods: []*ocmv1beta1.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
|
||||
},
|
||||
RecipientMeshProvider: cesnet.ProviderInfo,
|
||||
})
|
||||
@ -677,6 +677,40 @@ var _ = Describe("ocm share", func() {
|
||||
})
|
||||
})
|
||||
|
||||
Context("einstein creates a share with a requirement that cannot be met", func() {
|
||||
It("fail with bad request error", func() {
|
||||
fileToShare := &provider.Reference{
|
||||
Path: "/home/file-with-req",
|
||||
}
|
||||
By("creating a file")
|
||||
Expect(helpers.CreateFile(ctxEinstein, cernboxgw, fileToShare.Path, []byte("test"))).To(Succeed())
|
||||
|
||||
By("share the file with marie")
|
||||
info, err := stat(ctxEinstein, cernboxgw, fileToShare)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
cesnet, err := cernboxgw.GetInfoByDomain(ctxEinstein, &ocmproviderpb.GetInfoByDomainRequest{
|
||||
Domain: "cesnet.cz",
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(cesnet.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
|
||||
|
||||
createShareRes, err := cernboxgw.CreateOCMShare(ctxEinstein, &ocmv1beta1.CreateOCMShareRequest{
|
||||
ResourceId: info.Id,
|
||||
Grantee: &provider.Grantee{
|
||||
Id: &provider.Grantee_UserId{
|
||||
UserId: marie.Id,
|
||||
},
|
||||
},
|
||||
AccessMethods: []*ocmv1beta1.AccessMethod{
|
||||
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{"unsupported-requirement"}),
|
||||
},
|
||||
RecipientMeshProvider: cesnet.ProviderInfo,
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(createShareRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_INVALID_ARGUMENT))
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user