Bump reva to pull in the ocm changes in reva edge.

Fixes #7003
This commit is contained in:
André Duffeck
2023-10-11 11:08:31 +02:00
parent 9e07f2f0d1
commit b6d5cd78f0
210 changed files with 24559 additions and 5587 deletions

13
go.mod
View File

@@ -12,8 +12,8 @@ require (
github.com/blevesearch/bleve/v2 v2.3.10
github.com/coreos/go-oidc v2.2.1+incompatible
github.com/coreos/go-oidc/v3 v3.6.0
github.com/cs3org/go-cs3apis v0.0.0-20230516150832-730ac860c71d
github.com/cs3org/reva/v2 v2.16.1-0.20231004143709-c089e31b8175
github.com/cs3org/go-cs3apis v0.0.0-20230727093620-0f4399be4543
github.com/cs3org/reva/v2 v2.16.1-0.20231011081722-044d686b88e1
github.com/disintegration/imaging v1.6.2
github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e
github.com/egirna/icap-client v0.1.1
@@ -192,6 +192,9 @@ require (
github.com/go-micro/plugins/v4/events/natsjs v1.2.2-0.20230807070816-bc05fb076ce7 // indirect
github.com/go-micro/plugins/v4/store/nats-js v1.1.0 // indirect
github.com/go-micro/plugins/v4/store/redis v1.2.1-0.20230510195111-07cd57e1bc9d // indirect
github.com/go-playground/locales v0.13.0 // indirect
github.com/go-playground/universal-translator v0.17.0 // indirect
github.com/go-playground/validator/v10 v10.4.1 // indirect
github.com/go-redis/redis/v8 v8.11.5 // indirect
github.com/go-resty/resty/v2 v2.7.0 // indirect
github.com/go-sql-driver/mysql v1.6.0 // indirect
@@ -242,6 +245,7 @@ require (
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/klauspost/compress v1.17.0 // indirect
github.com/klauspost/cpuid/v2 v2.1.0 // indirect
github.com/leodido/go-urn v1.2.0 // indirect
github.com/libregraph/oidc-go v1.0.0 // indirect
github.com/longsleep/go-metrics v1.0.0 // indirect
github.com/longsleep/rndm v1.2.0 // indirect
@@ -289,7 +293,6 @@ require (
github.com/rs/xid v1.5.0 // indirect
github.com/russellhaering/goxmldsig v1.4.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sciencemesh/meshdirectory-web v1.0.4 // indirect
github.com/segmentio/ksuid v1.0.4 // indirect
github.com/sergi/go-diff v1.2.0 // indirect
github.com/sethvargo/go-password v0.2.0 // indirect
@@ -299,6 +302,7 @@ require (
github.com/spacewander/go-suffix-tree v0.0.0-20191010040751-0865e368c784 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.5.0 // indirect
github.com/studio-b12/gowebdav v0.0.0-20221015232716-17255f2e7423 // indirect
github.com/tchap/go-patricia/v2 v2.3.1 // indirect
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 // indirect
github.com/trustelem/zxcvbn v1.0.1 // indirect
@@ -337,5 +341,4 @@ require (
sigs.k8s.io/yaml v1.3.0 // indirect
)
// the replacement build is based on https://github.com/dragonchaser/cs3apis/tree/master
replace github.com/cs3org/go-cs3apis => github.com/dragonchaser/go-cs3apis v0.0.0-20230918130959-ae732d4b8147
replace github.com/cs3org/go-cs3apis => github.com/aduffeck/go-cs3apis v0.0.0-20231009082215-ad45e19edac0

19
go.sum
View File

@@ -825,6 +825,8 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk=
github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
github.com/aduffeck/go-cs3apis v0.0.0-20231009082215-ad45e19edac0 h1:y9gvblZJHMENTzgolQ9sChKONSILkJ4U/j7OqMIF4QM=
github.com/aduffeck/go-cs3apis v0.0.0-20231009082215-ad45e19edac0/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
@@ -1011,8 +1013,8 @@ github.com/crewjam/httperr v0.2.0 h1:b2BfXR8U3AlIHwNeFFvZ+BV1LFvKLlzMjzaTnZMybNo
github.com/crewjam/httperr v0.2.0/go.mod h1:Jlz+Sg/XqBQhyMjdDiC+GNNRzZTD7x39Gu3pglZ5oH4=
github.com/crewjam/saml v0.4.13 h1:TYHggH/hwP7eArqiXSJUvtOPNzQDyQ7vwmwEqlFWhMc=
github.com/crewjam/saml v0.4.13/go.mod h1:igEejV+fihTIlHXYP8zOec3V5A8y3lws5bQBFsTm4gA=
github.com/cs3org/reva/v2 v2.16.1-0.20231004143709-c089e31b8175 h1:3rWU0bw0q2SlaScyTKX5Xb5usVdznz4ygV2DnHKtlzM=
github.com/cs3org/reva/v2 v2.16.1-0.20231004143709-c089e31b8175/go.mod h1:WFSfkOQNmUggMed4lUQTF2vd9hg0acvsHI6awGwnwxQ=
github.com/cs3org/reva/v2 v2.16.1-0.20231011081722-044d686b88e1 h1:Efy7Yx7zyqtCmGhR6qRhSmvjNSxnPt69LF0UyV9kd9U=
github.com/cs3org/reva/v2 v2.16.1-0.20231011081722-044d686b88e1/go.mod h1:6M5k4UvGUgZh31t4r70RwbesW+w2EM/gd/gpuQZxAPg=
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -1044,8 +1046,6 @@ github.com/dnsimple/dnsimple-go v0.63.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/dragonchaser/go-cs3apis v0.0.0-20230918130959-ae732d4b8147 h1:DIEKyIGBNDDzdwnHlbX2BFABHol6c9EEHuCDdVKgWsA=
github.com/dragonchaser/go-cs3apis v0.0.0-20230918130959-ae732d4b8147/go.mod h1:TKUgPjk4kNU0KLd9ZxoFE74Wv6PiXckF4RB3749FztA=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
@@ -1214,9 +1214,14 @@ github.com/go-ozzo/ozzo-validation/v4 v4.3.0 h1:byhDUpfEwjsVQb1vBunvIjh2BHQ9ead5
github.com/go-ozzo/ozzo-validation/v4 v4.3.0/go.mod h1:2NKgrcHl3z6cJs+3Oo940FPRiTzuqKbvfrL2RxCj6Ew=
github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M=
github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48/go.mod h1:dZGr0i9PLlaaTD4H/hoZIDjQ+r6xq8mgbRzHZf7f2J8=
@@ -1591,6 +1596,7 @@ github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c
github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g=
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/leonelquinteros/gotext v1.5.3-0.20230317130943-71a59c05b2c1 h1:k56sFOOJ0CYuQtGoRSeAMhP1R692+iNH+S1dC/CEz0w=
github.com/leonelquinteros/gotext v1.5.3-0.20230317130943-71a59c05b2c1/go.mod h1:AT4NpQrOmyj1L/+hLja6aR0lk81yYYL4ePnj2kp7d6M=
github.com/libregraph/idm v0.4.1-0.20230221143410-3503963047a5 h1:brLMXSjWoWhGXs8LpK+Lx+FQCtGLUa51Mq/ggHv9AV0=
@@ -1898,8 +1904,6 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sacloud/libsacloud v1.36.2/go.mod h1:P7YAOVmnIn3DKHqCZcUKYUXmSwGBm3yS7IBEjKVSrjg=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8=
github.com/sciencemesh/meshdirectory-web v1.0.4 h1:1YSctF6PAXhoHUYCaeRTj7rHaF7b3rYrZf2R0VXBIbo=
github.com/sciencemesh/meshdirectory-web v1.0.4/go.mod h1:fJSThTS3xf+sTdL0iXQoaQJssLI7tn7DetHMHUl4SRk=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c=
@@ -1974,6 +1978,8 @@ github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/studio-b12/gowebdav v0.0.0-20221015232716-17255f2e7423 h1:Wd8WDEEusB5+En4PiRWJp1cP59QLNsQun+mOTW8+s6s=
github.com/studio-b12/gowebdav v0.0.0-20221015232716-17255f2e7423/go.mod h1:bHA7t77X/QFExdeAnDzK6vKM34kEZAcE1OX4MfiwjkE=
github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BGhTkes=
@@ -2686,6 +2692,7 @@ google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=

View File

@@ -27,58 +27,16 @@ var _ = math.Inf
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
// REQUIRED.
// View mode.
type OpenInAppRequest_ViewMode int32
const (
OpenInAppRequest_VIEW_MODE_INVALID OpenInAppRequest_ViewMode = 0
// The resource can be opened but not downloaded.
OpenInAppRequest_VIEW_MODE_VIEW_ONLY OpenInAppRequest_ViewMode = 1
// The resource can be downloaded.
OpenInAppRequest_VIEW_MODE_READ_ONLY OpenInAppRequest_ViewMode = 2
// The resource can be downloaded and updated. The underlying application
// MUST be a fully capable editor to support this mode.
OpenInAppRequest_VIEW_MODE_READ_WRITE OpenInAppRequest_ViewMode = 3
// The resource can be downloaded and updated, but must be shown in
// preview mode. If the underlying application does not support a preview mode,
// or if in a view-only mode users are not allowed to switch to edit mode,
// then this mode MUST fall back to READ_WRITE.
OpenInAppRequest_VIEW_MODE_PREVIEW OpenInAppRequest_ViewMode = 4
)
var OpenInAppRequest_ViewMode_name = map[int32]string{
0: "VIEW_MODE_INVALID",
1: "VIEW_MODE_VIEW_ONLY",
2: "VIEW_MODE_READ_ONLY",
3: "VIEW_MODE_READ_WRITE",
4: "VIEW_MODE_PREVIEW",
}
var OpenInAppRequest_ViewMode_value = map[string]int32{
"VIEW_MODE_INVALID": 0,
"VIEW_MODE_VIEW_ONLY": 1,
"VIEW_MODE_READ_ONLY": 2,
"VIEW_MODE_READ_WRITE": 3,
"VIEW_MODE_PREVIEW": 4,
}
func (x OpenInAppRequest_ViewMode) String() string {
return proto.EnumName(OpenInAppRequest_ViewMode_name, int32(x))
}
func (OpenInAppRequest_ViewMode) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_c007b70b037097fe, []int{0, 0}
}
type OpenInAppRequest struct {
// OPTIONAL.
// Opaque information.
Opaque *v1beta1.Opaque `protobuf:"bytes,1,opt,name=opaque,proto3" json:"opaque,omitempty"`
// REQUIRED.
// The resourceInfo to be opened. The gateway grpc message has a ref instead.
ResourceInfo *v1beta11.ResourceInfo `protobuf:"bytes,2,opt,name=resource_info,json=resourceInfo,proto3" json:"resource_info,omitempty"`
ViewMode OpenInAppRequest_ViewMode `protobuf:"varint,3,opt,name=view_mode,json=viewMode,proto3,enum=cs3.app.provider.v1beta1.OpenInAppRequest_ViewMode" json:"view_mode,omitempty"`
ResourceInfo *v1beta11.ResourceInfo `protobuf:"bytes,2,opt,name=resource_info,json=resourceInfo,proto3" json:"resource_info,omitempty"`
// REQUIRED.
// View mode.
ViewMode ViewMode `protobuf:"varint,3,opt,name=view_mode,json=viewMode,proto3,enum=cs3.app.provider.v1beta1.ViewMode" json:"view_mode,omitempty"`
// REQUIRED.
// The access token this application provider will use when contacting
// the storage provider to read and write.
@@ -133,11 +91,11 @@ func (m *OpenInAppRequest) GetResourceInfo() *v1beta11.ResourceInfo {
return nil
}
func (m *OpenInAppRequest) GetViewMode() OpenInAppRequest_ViewMode {
func (m *OpenInAppRequest) GetViewMode() ViewMode {
if m != nil {
return m.ViewMode
}
return OpenInAppRequest_VIEW_MODE_INVALID
return ViewMode_VIEW_MODE_INVALID
}
func (m *OpenInAppRequest) GetAccessToken() string {
@@ -210,7 +168,6 @@ func (m *OpenInAppResponse) GetAppUrl() *OpenInAppURL {
}
func init() {
proto.RegisterEnum("cs3.app.provider.v1beta1.OpenInAppRequest_ViewMode", OpenInAppRequest_ViewMode_name, OpenInAppRequest_ViewMode_value)
proto.RegisterType((*OpenInAppRequest)(nil), "cs3.app.provider.v1beta1.OpenInAppRequest")
proto.RegisterType((*OpenInAppResponse)(nil), "cs3.app.provider.v1beta1.OpenInAppResponse")
}
@@ -220,39 +177,35 @@ func init() {
}
var fileDescriptor_c007b70b037097fe = []byte{
// 510 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x93, 0xd1, 0x6e, 0xd3, 0x30,
0x14, 0x86, 0x49, 0x3b, 0x95, 0xd5, 0x1d, 0x90, 0x19, 0xd0, 0x42, 0x35, 0xa4, 0xd2, 0x0b, 0x54,
0x6d, 0xc8, 0x55, 0xdb, 0x07, 0x40, 0xe9, 0xda, 0x8b, 0x48, 0xdd, 0x1a, 0x99, 0xad, 0x13, 0xa8,
0x52, 0xe4, 0xa5, 0x1e, 0x8a, 0xd8, 0xe2, 0x33, 0x3b, 0xe9, 0xc4, 0x15, 0x37, 0x3c, 0x01, 0x8f,
0xc0, 0x25, 0x4f, 0xc0, 0x33, 0xf0, 0x54, 0x28, 0x8e, 0x13, 0xba, 0xa1, 0x6a, 0xbd, 0x8b, 0xcf,
0xff, 0xfd, 0xc7, 0xf6, 0x7f, 0x1c, 0x74, 0x18, 0xaa, 0x41, 0x97, 0x01, 0x74, 0x41, 0x8a, 0x65,
0xb4, 0xe0, 0xb2, 0xbb, 0xec, 0x5d, 0xf0, 0x84, 0xf5, 0xca, 0x42, 0xc0, 0x20, 0x22, 0x20, 0x45,
0x22, 0xb0, 0x13, 0xaa, 0x01, 0x61, 0x00, 0xa4, 0xd0, 0x88, 0x81, 0x9b, 0x9d, 0xb5, 0x6d, 0x24,
0x57, 0x22, 0x95, 0x21, 0x57, 0x79, 0x8f, 0xe6, 0x7e, 0x46, 0x4a, 0x08, 0x4b, 0x40, 0x25, 0x2c,
0x49, 0x0b, 0xf5, 0x5d, 0xa6, 0xaa, 0x44, 0x48, 0xf6, 0x99, 0x3f, 0xdc, 0xeb, 0x75, 0x46, 0x27,
0x5f, 0x81, 0xab, 0x12, 0xd1, 0xab, 0x5c, 0x6e, 0xff, 0xa8, 0x22, 0x7b, 0x0a, 0x3c, 0xf6, 0x62,
0x17, 0x80, 0xf2, 0x9b, 0x94, 0xab, 0x04, 0xf7, 0x50, 0x4d, 0x00, 0xbb, 0x49, 0xb9, 0x63, 0xb5,
0xac, 0x4e, 0xa3, 0xff, 0x8a, 0x64, 0x97, 0xca, 0x6d, 0xa6, 0x09, 0x99, 0x6a, 0x80, 0x1a, 0x10,
0x4f, 0xd1, 0x93, 0x62, 0xe7, 0x20, 0x8a, 0x2f, 0x85, 0x53, 0xd1, 0xce, 0x03, 0xed, 0x34, 0x87,
0xfd, 0x2f, 0x12, 0x42, 0x8d, 0xc5, 0x8b, 0x2f, 0x05, 0xdd, 0x91, 0x2b, 0x2b, 0xec, 0xa3, 0xfa,
0x32, 0xe2, 0xb7, 0xc1, 0xb5, 0x58, 0x70, 0xa7, 0xda, 0xb2, 0x3a, 0x4f, 0xfb, 0x03, 0xb2, 0x2e,
0x5b, 0x72, 0xff, 0x0a, 0x64, 0x16, 0xf1, 0xdb, 0x63, 0xb1, 0xe0, 0x74, 0x7b, 0x69, 0xbe, 0xf0,
0x1b, 0xb4, 0xc3, 0xc2, 0x90, 0x2b, 0x15, 0x24, 0xe2, 0x0b, 0x8f, 0x9d, 0xad, 0x96, 0xd5, 0xa9,
0xd3, 0x46, 0x5e, 0x3b, 0xcd, 0x4a, 0xed, 0xef, 0x16, 0xda, 0x2e, 0x9c, 0xf8, 0x25, 0xda, 0x9d,
0x79, 0xe3, 0xf3, 0xe0, 0x78, 0x3a, 0x1a, 0x07, 0xde, 0xc9, 0xcc, 0x9d, 0x78, 0x23, 0xfb, 0x11,
0xde, 0x43, 0xcf, 0xff, 0x95, 0xf5, 0xd7, 0xf4, 0x64, 0xf2, 0xd1, 0xb6, 0xee, 0x0a, 0x74, 0xec,
0x8e, 0x72, 0xa1, 0x82, 0x1d, 0xf4, 0xe2, 0x9e, 0x70, 0x4e, 0xbd, 0xd3, 0xb1, 0x5d, 0xbd, 0xbb,
0x85, 0x4f, 0xc7, 0xd9, 0xc2, 0xde, 0x6a, 0xff, 0xb6, 0xd0, 0xee, 0xca, 0x8d, 0x14, 0x88, 0x58,
0x71, 0xdc, 0x45, 0xb5, 0xfc, 0x1d, 0x98, 0xa9, 0xec, 0xe9, 0x38, 0x24, 0x84, 0x65, 0x0a, 0x1f,
0xb4, 0x4c, 0x0d, 0xb6, 0x32, 0xc6, 0xca, 0xa6, 0x63, 0x7c, 0x8f, 0x1e, 0x33, 0x80, 0x20, 0x95,
0x57, 0x3a, 0xf3, 0x46, 0xff, 0xed, 0x06, 0x99, 0x9f, 0xd1, 0x09, 0xad, 0x31, 0x80, 0x33, 0x79,
0xd5, 0x57, 0xa8, 0xe1, 0x1b, 0xd0, 0xf5, 0x3d, 0xbc, 0x40, 0xf5, 0x12, 0xc3, 0x07, 0x9b, 0xcf,
0xaf, 0x79, 0xb8, 0x11, 0x9b, 0x27, 0x33, 0xfc, 0x86, 0xf6, 0x43, 0x71, 0xbd, 0xd6, 0x31, 0xb4,
0xcb, 0x23, 0x41, 0xe4, 0x67, 0xcf, 0xde, 0xb7, 0x3e, 0x3d, 0x2b, 0x28, 0x03, 0xfd, 0xac, 0x54,
0x8f, 0x5c, 0xff, 0x57, 0xc5, 0x39, 0x52, 0x03, 0xe2, 0x02, 0x90, 0xc2, 0x43, 0x66, 0xbd, 0x61,
0x06, 0xfc, 0xd1, 0xd2, 0xdc, 0x05, 0x98, 0x17, 0xd2, 0xdc, 0x48, 0x17, 0x35, 0xfd, 0x33, 0x0d,
0xfe, 0x06, 0x00, 0x00, 0xff, 0xff, 0x27, 0x47, 0xc0, 0x89, 0x2a, 0x04, 0x00, 0x00,
// 438 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0x4f, 0x6f, 0xd3, 0x30,
0x18, 0xc6, 0x95, 0x0e, 0x15, 0xea, 0x0e, 0x18, 0xbe, 0x10, 0xaa, 0x21, 0x95, 0x1e, 0x50, 0xb5,
0x21, 0x57, 0x6d, 0x3f, 0xc0, 0x94, 0xee, 0x54, 0x09, 0xd4, 0xc8, 0xb0, 0x1d, 0x50, 0xa5, 0xc8,
0x73, 0xde, 0xa1, 0x88, 0x2d, 0x7e, 0x67, 0x3b, 0xa9, 0x38, 0xf1, 0x5d, 0x38, 0xf2, 0x09, 0xf8,
0x0c, 0x7c, 0x24, 0x4e, 0x28, 0x8e, 0x13, 0x55, 0x42, 0x11, 0xbd, 0xc5, 0x7e, 0x7e, 0xcf, 0xfb,
0xe7, 0x89, 0xc9, 0xb9, 0x34, 0xcb, 0x99, 0x40, 0x9c, 0xa1, 0x56, 0x65, 0x96, 0x82, 0x9e, 0x95,
0xf3, 0x1b, 0xb0, 0x62, 0xde, 0x5e, 0x24, 0x02, 0x33, 0x86, 0x5a, 0x59, 0x45, 0x43, 0x69, 0x96,
0x4c, 0x20, 0xb2, 0x46, 0x63, 0x1e, 0x1e, 0x4d, 0x3b, 0xcb, 0x68, 0x30, 0xaa, 0xd0, 0x12, 0x4c,
0x5d, 0x63, 0x74, 0x5a, 0x91, 0x1a, 0x65, 0x0b, 0x18, 0x2b, 0x6c, 0xd1, 0xa8, 0xef, 0x2a, 0xd5,
0x58, 0xa5, 0xc5, 0x17, 0xf8, 0x7f, 0xad, 0xd7, 0x15, 0x6d, 0xbf, 0x21, 0x98, 0x16, 0x71, 0xa7,
0x5a, 0x9e, 0xfc, 0x09, 0xc8, 0xc9, 0x06, 0x21, 0x5f, 0xe7, 0x11, 0x22, 0x87, 0x87, 0x02, 0x8c,
0xa5, 0x73, 0xd2, 0x57, 0x28, 0x1e, 0x0a, 0x08, 0x83, 0x71, 0x30, 0x1d, 0x2e, 0x5e, 0xb1, 0x6a,
0xa9, 0xda, 0xe6, 0x8b, 0xb0, 0x8d, 0x03, 0xb8, 0x07, 0xe9, 0x86, 0x3c, 0x6d, 0x3a, 0x27, 0x59,
0x7e, 0xab, 0xc2, 0x9e, 0x73, 0x9e, 0x39, 0xa7, 0x1f, 0xf6, 0x9f, 0x48, 0x18, 0xf7, 0x96, 0x75,
0x7e, 0xab, 0xf8, 0xb1, 0xde, 0x3b, 0xd1, 0x0b, 0x32, 0x28, 0x33, 0xd8, 0x25, 0xf7, 0x2a, 0x85,
0xf0, 0x68, 0x1c, 0x4c, 0x9f, 0x2d, 0x26, 0xac, 0x2b, 0x5b, 0x76, 0x9d, 0xc1, 0xee, 0x83, 0x4a,
0x81, 0x3f, 0x29, 0xfd, 0x17, 0x7d, 0x43, 0x8e, 0x85, 0x94, 0x60, 0x4c, 0x62, 0xd5, 0x57, 0xc8,
0xc3, 0x47, 0xe3, 0x60, 0x3a, 0xe0, 0xc3, 0xfa, 0xee, 0x53, 0x75, 0x35, 0xf9, 0x15, 0x90, 0x17,
0x7b, 0xcb, 0x1b, 0x54, 0xb9, 0x01, 0x3a, 0x23, 0xfd, 0x3a, 0x6f, 0xbf, 0xfd, 0x4b, 0xd7, 0x56,
0xa3, 0x6c, 0xbb, 0x7d, 0x74, 0x32, 0xf7, 0xd8, 0x5e, 0x5c, 0xbd, 0x43, 0xe3, 0xba, 0x20, 0x8f,
0x05, 0x62, 0x52, 0xe8, 0x3b, 0xb7, 0xdb, 0x70, 0xf1, 0xb6, 0x7b, 0xb7, 0x76, 0xc2, 0x2b, 0xfe,
0x9e, 0xf7, 0x05, 0xe2, 0x95, 0xbe, 0x5b, 0x18, 0x32, 0x8c, 0x3d, 0x18, 0xc5, 0x6b, 0x9a, 0x92,
0x41, 0x8b, 0xd1, 0xb3, 0x03, 0x6a, 0xf9, 0x5f, 0x3d, 0x3a, 0x3f, 0x88, 0xad, 0x93, 0x59, 0x7d,
0x27, 0xa7, 0x52, 0xdd, 0x77, 0x3a, 0x56, 0x27, 0xed, 0x48, 0x98, 0xc5, 0xd5, 0xf3, 0x8a, 0x83,
0xcf, 0xcf, 0x1b, 0xca, 0x43, 0x3f, 0x7a, 0x47, 0x97, 0x51, 0xfc, 0xb3, 0x17, 0x5e, 0x9a, 0x25,
0x8b, 0x10, 0x59, 0xe3, 0x61, 0xd7, 0xf3, 0x55, 0x05, 0xfc, 0x76, 0xd2, 0x36, 0x42, 0xdc, 0x36,
0xd2, 0xd6, 0x4b, 0x37, 0x7d, 0xf7, 0x68, 0x97, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xb9, 0xb9,
0x16, 0xb5, 0x92, 0x03, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.

View File

@@ -20,6 +20,80 @@ var _ = math.Inf
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
// Defines the view modes.
type ViewMode int32
const (
ViewMode_VIEW_MODE_INVALID ViewMode = 0
// The resource can be opened but not downloaded.
ViewMode_VIEW_MODE_VIEW_ONLY ViewMode = 1
// The resource can be downloaded.
ViewMode_VIEW_MODE_READ_ONLY ViewMode = 2
// The resource can be downloaded and updated. The underlying application
// MUST be a fully capable editor to support this mode.
ViewMode_VIEW_MODE_READ_WRITE ViewMode = 3
// The resource can be downloaded and updated, but must be shown in
// preview mode. If the underlying application does not support a preview mode,
// or if in a view-only mode users are not allowed to switch to edit mode,
// then this mode MUST fall back to READ_WRITE.
ViewMode_VIEW_MODE_PREVIEW ViewMode = 4
)
var ViewMode_name = map[int32]string{
0: "VIEW_MODE_INVALID",
1: "VIEW_MODE_VIEW_ONLY",
2: "VIEW_MODE_READ_ONLY",
3: "VIEW_MODE_READ_WRITE",
4: "VIEW_MODE_PREVIEW",
}
var ViewMode_value = map[string]int32{
"VIEW_MODE_INVALID": 0,
"VIEW_MODE_VIEW_ONLY": 1,
"VIEW_MODE_READ_ONLY": 2,
"VIEW_MODE_READ_WRITE": 3,
"VIEW_MODE_PREVIEW": 4,
}
func (x ViewMode) String() string {
return proto.EnumName(ViewMode_name, int32(x))
}
func (ViewMode) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_f3a36ae8e74be4dc, []int{0}
}
// Defines the valid targets for an app URL.
type Target int32
const (
Target_TARGET_INVALID Target = 0
// The app URL is to be opened within an iframe
Target_TARGET_IFRAME Target = 1
// The app URL is to be opened on a new blank page
Target_TARGET_BLANK Target = 2
)
var Target_name = map[int32]string{
0: "TARGET_INVALID",
1: "TARGET_IFRAME",
2: "TARGET_BLANK",
}
var Target_value = map[string]int32{
"TARGET_INVALID": 0,
"TARGET_IFRAME": 1,
"TARGET_BLANK": 2,
}
func (x Target) String() string {
return proto.EnumName(Target_name, int32(x))
}
func (Target) EnumDescriptor() ([]byte, []int) {
return fileDescriptor_f3a36ae8e74be4dc, []int{1}
}
// Represents the information for the app URL to be called by the clients.
type OpenInAppURL struct {
// REQUIRED.
@@ -35,10 +109,13 @@ type OpenInAppURL struct {
FormParameters map[string]string `protobuf:"bytes,3,rep,name=form_parameters,json=formParameters,proto3" json:"form_parameters,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
// OPTIONAL.
// The headers to be added to the request.
Headers map[string]string `protobuf:"bytes,4,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
Headers map[string]string `protobuf:"bytes,4,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
// REQUIRED.
// Whether the target for the app URL is an iframe or a new page.
Target Target `protobuf:"varint,5,opt,name=target,proto3,enum=cs3.app.provider.v1beta1.Target" json:"target,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *OpenInAppURL) Reset() { *m = OpenInAppURL{} }
@@ -94,7 +171,16 @@ func (m *OpenInAppURL) GetHeaders() map[string]string {
return nil
}
func (m *OpenInAppURL) GetTarget() Target {
if m != nil {
return m.Target
}
return Target_TARGET_INVALID
}
func init() {
proto.RegisterEnum("cs3.app.provider.v1beta1.ViewMode", ViewMode_name, ViewMode_value)
proto.RegisterEnum("cs3.app.provider.v1beta1.Target", Target_name, Target_value)
proto.RegisterType((*OpenInAppURL)(nil), "cs3.app.provider.v1beta1.OpenInAppURL")
proto.RegisterMapType((map[string]string)(nil), "cs3.app.provider.v1beta1.OpenInAppURL.FormParametersEntry")
proto.RegisterMapType((map[string]string)(nil), "cs3.app.provider.v1beta1.OpenInAppURL.HeadersEntry")
@@ -105,26 +191,34 @@ func init() {
}
var fileDescriptor_f3a36ae8e74be4dc = []byte{
// 324 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x92, 0x4f, 0x4b, 0xf3, 0x40,
0x10, 0xc6, 0x49, 0xf2, 0xbe, 0x2d, 0xae, 0xa5, 0x95, 0x55, 0x34, 0x14, 0x0f, 0xc5, 0x53, 0x4f,
0x1b, 0x6a, 0x2e, 0xd2, 0x5b, 0x5a, 0x14, 0x05, 0xc5, 0x10, 0xa8, 0x07, 0x29, 0x94, 0x6d, 0xb2,
0xa5, 0x62, 0x92, 0x1d, 0x66, 0x93, 0x40, 0x0f, 0x7e, 0x19, 0x8f, 0x7e, 0x14, 0x3f, 0x8e, 0x9f,
0x40, 0xf2, 0x67, 0xa5, 0x82, 0x05, 0xbd, 0xed, 0xcc, 0x3c, 0xf3, 0x7b, 0x78, 0x98, 0x25, 0xc3,
0x50, 0xb9, 0x0e, 0x07, 0x70, 0x00, 0x65, 0xf1, 0x14, 0x09, 0x74, 0x8a, 0xd1, 0x52, 0x64, 0x7c,
0xe4, 0xa0, 0x50, 0x32, 0xc7, 0x50, 0x28, 0x06, 0x28, 0x33, 0x49, 0xed, 0x50, 0xb9, 0x8c, 0x03,
0x30, 0xad, 0x64, 0x8d, 0xf2, 0xec, 0xc3, 0x24, 0x9d, 0x7b, 0x10, 0xe9, 0x4d, 0xea, 0x01, 0xcc,
0x82, 0x5b, 0x7a, 0x42, 0xda, 0x1c, 0x60, 0x91, 0x63, 0x6c, 0x1b, 0x03, 0x63, 0xb8, 0x17, 0xb4,
0x38, 0xc0, 0x0c, 0x63, 0x7a, 0x4c, 0x5a, 0x89, 0xc8, 0xd6, 0x32, 0xb2, 0xcd, 0xba, 0x5f, 0x57,
0x34, 0x24, 0xbd, 0x95, 0xc4, 0x64, 0x01, 0x1c, 0x79, 0x22, 0x32, 0x81, 0xca, 0xb6, 0x06, 0xd6,
0x70, 0xff, 0x7c, 0xcc, 0x76, 0xb9, 0xb2, 0x6d, 0x47, 0x76, 0x25, 0x31, 0xf1, 0xbf, 0x96, 0x2f,
0xd3, 0x0c, 0x37, 0x41, 0x77, 0xf5, 0xad, 0x49, 0xef, 0x48, 0x7b, 0x2d, 0x78, 0x54, 0xc2, 0xff,
0x55, 0x70, 0xf7, 0x97, 0xf0, 0xeb, 0x7a, 0xab, 0xa6, 0x6a, 0x46, 0xdf, 0x23, 0x87, 0x3f, 0xb8,
0xd2, 0x03, 0x62, 0x3d, 0x8b, 0x4d, 0x93, 0xbb, 0x7c, 0xd2, 0x23, 0xf2, 0xbf, 0xe0, 0x71, 0x2e,
0x9a, 0xcc, 0x75, 0x31, 0x36, 0x2f, 0x8c, 0xfe, 0x98, 0x74, 0xb6, 0xd9, 0x7f, 0xd9, 0x9d, 0xbc,
0x90, 0xd3, 0x50, 0x26, 0x3b, 0x13, 0x4c, 0xba, 0x81, 0xbe, 0x9f, 0x5f, 0x9e, 0xcf, 0x37, 0x1e,
0x7b, 0x5a, 0xd3, 0x48, 0x5e, 0x4d, 0x6b, 0xea, 0xf9, 0x6f, 0xa6, 0x3d, 0x55, 0x2e, 0xf3, 0x00,
0x98, 0xaf, 0x19, 0x0f, 0xa3, 0x49, 0x29, 0x78, 0xaf, 0x46, 0x73, 0x0f, 0x60, 0xae, 0x47, 0xf3,
0x66, 0xb4, 0x6c, 0x55, 0x9f, 0xc2, 0xfd, 0x0c, 0x00, 0x00, 0xff, 0xff, 0x1a, 0xd8, 0x2b, 0xca,
0x40, 0x02, 0x00, 0x00,
// 458 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x53, 0x4d, 0x6f, 0xd3, 0x40,
0x10, 0xc5, 0x76, 0x9b, 0xc2, 0x10, 0x52, 0x77, 0x5b, 0xa8, 0x55, 0x71, 0x88, 0x38, 0x45, 0x3d,
0x6c, 0x94, 0xfa, 0x52, 0xe5, 0xb6, 0x69, 0x5c, 0xb0, 0xc8, 0x87, 0xb5, 0x4a, 0x53, 0x81, 0x22,
0x45, 0x5b, 0x67, 0x4b, 0x2b, 0xe2, 0xec, 0x68, 0xed, 0x04, 0xf5, 0xc0, 0x8d, 0x5f, 0xc2, 0x11,
0xf1, 0x4b, 0xf8, 0x55, 0xc8, 0x5f, 0x90, 0x20, 0x22, 0xc1, 0x6d, 0xe7, 0xbd, 0x37, 0x6f, 0x46,
0x4f, 0xb3, 0xd0, 0x08, 0x63, 0xb7, 0x29, 0x10, 0x9b, 0xa8, 0xd5, 0xea, 0x7e, 0x26, 0x75, 0x73,
0xd5, 0xba, 0x91, 0x89, 0x68, 0x35, 0xb5, 0x8c, 0xd5, 0x52, 0x87, 0x32, 0xa6, 0xa8, 0x55, 0xa2,
0x88, 0x13, 0xc6, 0x2e, 0x15, 0x88, 0xb4, 0x54, 0xd2, 0x42, 0xf9, 0xea, 0xbb, 0x05, 0xd5, 0x21,
0xca, 0x85, 0xbf, 0x60, 0x88, 0x57, 0xbc, 0x47, 0x8e, 0x61, 0x4f, 0x20, 0x4e, 0x97, 0x7a, 0xee,
0x18, 0x75, 0xa3, 0xf1, 0x84, 0x57, 0x04, 0xe2, 0x95, 0x9e, 0x93, 0x17, 0x50, 0x89, 0x64, 0x72,
0xa7, 0x66, 0x8e, 0x99, 0xe3, 0x79, 0x45, 0x42, 0xd8, 0xbf, 0x55, 0x3a, 0x9a, 0xa2, 0xd0, 0x22,
0x92, 0x89, 0xd4, 0xb1, 0x63, 0xd5, 0xad, 0xc6, 0xd3, 0xb3, 0x36, 0xdd, 0x36, 0x95, 0xae, 0x4f,
0xa4, 0x97, 0x4a, 0x47, 0xc1, 0xaf, 0x66, 0x6f, 0x91, 0xe8, 0x07, 0x5e, 0xbb, 0xdd, 0x00, 0x49,
0x1f, 0xf6, 0xee, 0xa4, 0x98, 0xa5, 0xe6, 0x3b, 0x99, 0xb9, 0xfb, 0x8f, 0xe6, 0x6f, 0xf2, 0xae,
0xdc, 0xb5, 0xf4, 0x20, 0xe7, 0x50, 0x49, 0x84, 0xfe, 0x20, 0x13, 0x67, 0xb7, 0x6e, 0x34, 0x6a,
0x67, 0xf5, 0xed, 0x6e, 0xa3, 0x4c, 0xc7, 0x0b, 0xfd, 0x09, 0x83, 0xc3, 0xbf, 0xec, 0x4b, 0x6c,
0xb0, 0x3e, 0xca, 0x87, 0x22, 0xb1, 0xf4, 0x49, 0x8e, 0x60, 0x77, 0x25, 0xe6, 0x4b, 0x59, 0xa4,
0x95, 0x17, 0x6d, 0xf3, 0xdc, 0x38, 0x69, 0x43, 0x75, 0x7d, 0xab, 0xff, 0xe9, 0x3d, 0xfd, 0x62,
0xc0, 0xe3, 0xf1, 0xbd, 0xfc, 0xd4, 0x57, 0x33, 0x49, 0x9e, 0xc3, 0xc1, 0xd8, 0xf7, 0xae, 0xa7,
0xfd, 0x61, 0xd7, 0x9b, 0xfa, 0x83, 0x31, 0xeb, 0xf9, 0x5d, 0xfb, 0x11, 0x39, 0x86, 0xc3, 0xdf,
0x70, 0xf6, 0x1a, 0x0e, 0x7a, 0xef, 0x6c, 0x63, 0x93, 0xe0, 0x1e, 0xeb, 0xe6, 0x84, 0x49, 0x1c,
0x38, 0xfa, 0x83, 0xb8, 0xe6, 0xfe, 0xc8, 0xb3, 0xad, 0xcd, 0x11, 0x01, 0xf7, 0xd2, 0xc2, 0xde,
0x39, 0x65, 0x50, 0xc9, 0x73, 0x21, 0x04, 0x6a, 0x23, 0xc6, 0x5f, 0x7b, 0xa3, 0xb5, 0x05, 0x0e,
0xe0, 0x59, 0x89, 0x5d, 0x72, 0xd6, 0xf7, 0x6c, 0x83, 0xd8, 0x50, 0x2d, 0xa0, 0x4e, 0x8f, 0x0d,
0xde, 0xda, 0x66, 0xe7, 0x33, 0xbc, 0x0c, 0x55, 0xb4, 0x35, 0xf7, 0x4e, 0x8d, 0x97, 0x37, 0x1c,
0xa4, 0x27, 0x1c, 0x18, 0xef, 0xf7, 0x4b, 0x4d, 0x21, 0xf9, 0x6a, 0x5a, 0x17, 0x2c, 0xf8, 0x66,
0x3a, 0x17, 0xb1, 0x4b, 0x19, 0x22, 0x0d, 0x4a, 0x8f, 0x71, 0xab, 0x93, 0x0a, 0x7e, 0x64, 0xd4,
0x84, 0x21, 0x4e, 0x4a, 0x6a, 0x52, 0x50, 0x37, 0x95, 0xec, 0x63, 0xb8, 0x3f, 0x03, 0x00, 0x00,
0xff, 0xff, 0x85, 0x9b, 0x05, 0x50, 0x44, 0x03, 0x00, 0x00,
}

View File

@@ -63,7 +63,7 @@ type ProviderInfo struct {
MimeTypes []string `protobuf:"bytes,2,rep,name=mime_types,json=mimeTypes,proto3" json:"mime_types,omitempty"`
// REQUIRED.
// The address where the app provider can be reached.
// For example, tcp://localhost:1099.
// For example, localhost:1099.
Address string `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"`
Capability ProviderInfo_Capability `protobuf:"varint,4,opt,name=capability,proto3,enum=cs3.app.registry.v1beta1.ProviderInfo_Capability" json:"capability,omitempty"`
// OPTIONAL.
@@ -79,7 +79,11 @@ type ProviderInfo struct {
Icon string `protobuf:"bytes,7,opt,name=icon,proto3" json:"icon,omitempty"`
// OPTIONAL.
// Whether the app can be opened only on desktop
DesktopOnly bool `protobuf:"varint,8,opt,name=desktop_only,json=desktopOnly,proto3" json:"desktop_only,omitempty"`
DesktopOnly bool `protobuf:"varint,8,opt,name=desktop_only,json=desktopOnly,proto3" json:"desktop_only,omitempty"`
// OPTIONAL.
// The action to be displayed to the user on the context menu.
// By default this is "Open with".
Action string `protobuf:"bytes,9,opt,name=action,proto3" json:"action,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@@ -166,6 +170,13 @@ func (m *ProviderInfo) GetDesktopOnly() bool {
return false
}
func (m *ProviderInfo) GetAction() string {
if m != nil {
return m.Action
}
return ""
}
// Represents a mime type and its corresponding file extension.
type MimeTypeInfo struct {
// OPTIONAL.
@@ -301,37 +312,38 @@ func init() {
}
var fileDescriptor_2e6a666226304af3 = []byte{
// 506 bytes of a gzipped FileDescriptorProto
// 514 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x53, 0xdd, 0x8e, 0xd2, 0x40,
0x14, 0xb6, 0x2d, 0xb2, 0x70, 0x60, 0x11, 0xc7, 0x68, 0xc6, 0x9f, 0x4d, 0x2a, 0x89, 0xa6, 0x57,
0x25, 0xc0, 0x13, 0x14, 0x96, 0x8b, 0xc6, 0x55, 0x70, 0x42, 0x30, 0x1a, 0x92, 0x66, 0x68, 0x67,
0x4d, 0x63, 0xe9, 0x1c, 0x3b, 0x65, 0x95, 0x0b, 0x5f, 0xc1, 0x87, 0xf0, 0xd2, 0x47, 0xf1, 0x25,
0x7c, 0x15, 0xd3, 0xa1, 0x65, 0x89, 0xc9, 0x26, 0xc6, 0xec, 0xdd, 0xf4, 0xfb, 0xeb, 0x9c, 0xf9,
0x72, 0xc0, 0x09, 0xd5, 0xa8, 0xcf, 0x11, 0xfb, 0x99, 0xf8, 0x18, 0xab, 0x3c, 0xdb, 0xf5, 0xaf,
0x06, 0x6b, 0x91, 0xf3, 0x41, 0x3f, 0x13, 0x4a, 0x6e, 0xb3, 0x50, 0x28, 0x17, 0x33, 0x99, 0x4b,
0x42, 0x43, 0x35, 0x72, 0x39, 0xa2, 0x5b, 0x29, 0xdd, 0x52, 0xf9, 0xe4, 0xac, 0xc8, 0xc8, 0x77,
0x28, 0xd4, 0xc1, 0xac, 0xbf, 0xf6, 0xc6, 0xde, 0x77, 0x0b, 0xda, 0xf3, 0x4c, 0x5e, 0xc5, 0x91,
0xc8, 0xfc, 0xf4, 0x52, 0x92, 0x01, 0xd4, 0x25, 0xf2, 0xcf, 0x5b, 0x41, 0x0d, 0xdb, 0x70, 0x5a,
0xc3, 0xc7, 0x6e, 0x11, 0xbd, 0xb7, 0x94, 0x01, 0xee, 0x4c, 0x0b, 0x58, 0x29, 0x24, 0x67, 0x00,
0x9b, 0x78, 0x23, 0x02, 0x2d, 0xa2, 0xa6, 0x6d, 0x39, 0x4d, 0xd6, 0x2c, 0x90, 0x45, 0x01, 0x10,
0x0a, 0x27, 0x3c, 0x8a, 0x32, 0xa1, 0x14, 0xb5, 0x6c, 0xc3, 0x69, 0xb2, 0xea, 0x93, 0xbc, 0x05,
0x08, 0x39, 0xf2, 0x75, 0x9c, 0xc4, 0xf9, 0x8e, 0xd6, 0x6c, 0xc3, 0xe9, 0x0c, 0x07, 0xee, 0x4d,
0xa3, 0xb8, 0xc7, 0xf7, 0x74, 0x27, 0x07, 0x23, 0x3b, 0x0a, 0x21, 0x04, 0x6a, 0x29, 0xdf, 0x08,
0x7a, 0x57, 0xff, 0x49, 0x9f, 0x89, 0x0d, 0xad, 0x48, 0xa8, 0x30, 0x8b, 0x31, 0x8f, 0x65, 0x4a,
0xeb, 0x9a, 0x3a, 0x86, 0x0a, 0x57, 0x1c, 0xca, 0x94, 0x9e, 0xec, 0x5d, 0xc5, 0x99, 0x3c, 0x87,
0x76, 0x24, 0xd4, 0xa7, 0x5c, 0x62, 0x20, 0xd3, 0x64, 0x47, 0x1b, 0xb6, 0xe1, 0x34, 0xb4, 0xad,
0xc0, 0x66, 0x69, 0xb2, 0xeb, 0x31, 0x80, 0xeb, 0x6b, 0x90, 0x47, 0x40, 0x26, 0xde, 0xdc, 0x1b,
0xfb, 0x17, 0xfe, 0xe2, 0x7d, 0xe0, 0xbf, 0x59, 0x7a, 0x17, 0xfe, 0x79, 0xf7, 0x0e, 0x79, 0x08,
0xf7, 0x8f, 0xf0, 0xa5, 0x3f, 0x7d, 0x37, 0x65, 0x5d, 0xe3, 0x2f, 0x78, 0x7a, 0xee, 0x2f, 0x66,
0xac, 0x6b, 0xf6, 0x7e, 0x9b, 0xd0, 0x7e, 0x5d, 0xbe, 0xdd, 0xff, 0x16, 0xf2, 0x14, 0x9a, 0x87,
0x42, 0xa8, 0xa9, 0x67, 0x6a, 0x54, 0x7d, 0x90, 0x2e, 0x58, 0xe2, 0x6b, 0x5e, 0x56, 0x51, 0x1c,
0xc9, 0x2b, 0x38, 0xe5, 0x88, 0x01, 0x96, 0xcf, 0xab, 0x68, 0xcd, 0xb6, 0x9c, 0xd6, 0xf0, 0xe5,
0xbf, 0x35, 0xc1, 0xda, 0x1c, 0xb1, 0x02, 0xd4, 0x2d, 0x16, 0xf0, 0x02, 0x3a, 0x3c, 0x49, 0xe4,
0x97, 0x20, 0xcc, 0x04, 0xd7, 0xc6, 0x7d, 0x05, 0xa7, 0x1a, 0x9d, 0x94, 0x20, 0xe9, 0xc3, 0x83,
0x48, 0x5c, 0xf2, 0x6d, 0x92, 0x07, 0x1c, 0x31, 0x89, 0xc3, 0xbd, 0xb6, 0xa9, 0x93, 0x48, 0x49,
0x79, 0xd7, 0xcc, 0xf8, 0x1b, 0x3c, 0x0b, 0xe5, 0xe6, 0xc6, 0xe1, 0xc6, 0x1d, 0x56, 0x2d, 0xd7,
0xbc, 0x58, 0x91, 0xb9, 0xf1, 0xe1, 0x5e, 0xa5, 0x29, 0x25, 0x3f, 0x4c, 0x6b, 0xe2, 0xb1, 0x9f,
0x26, 0x9d, 0xa8, 0x91, 0xeb, 0x21, 0xba, 0xac, 0xca, 0x58, 0x0e, 0xc6, 0x85, 0xe0, 0x97, 0xa6,
0x56, 0x1e, 0xe2, 0xaa, 0xa2, 0x56, 0x25, 0xb5, 0xae, 0xeb, 0xc5, 0x1b, 0xfd, 0x09, 0x00, 0x00,
0xff, 0xff, 0x0b, 0x11, 0x40, 0xb4, 0xdd, 0x03, 0x00, 0x00,
0x14, 0xb6, 0x2d, 0xb2, 0x70, 0x60, 0x11, 0xc7, 0xb8, 0x19, 0x7f, 0x36, 0xa9, 0x24, 0x9a, 0x5e,
0x0d, 0x01, 0x9e, 0xa0, 0xb0, 0x5c, 0x34, 0xae, 0x82, 0x13, 0x82, 0xd1, 0x90, 0x34, 0x43, 0x3b,
0x6b, 0x1a, 0x4b, 0x67, 0xec, 0x94, 0x55, 0x2e, 0x7c, 0x19, 0x2f, 0xbc, 0xf0, 0x51, 0x7c, 0x09,
0x5f, 0xc5, 0x74, 0x98, 0xb2, 0xc4, 0x64, 0x13, 0x63, 0xbc, 0x9b, 0xf9, 0xfe, 0x7a, 0x3a, 0x5f,
0x0e, 0x78, 0x91, 0x1a, 0xf5, 0x99, 0x94, 0xfd, 0x9c, 0x7f, 0x48, 0x54, 0x91, 0xef, 0xfa, 0xd7,
0x83, 0x35, 0x2f, 0xd8, 0xa0, 0x9f, 0x73, 0x25, 0xb6, 0x79, 0xc4, 0x15, 0x91, 0xb9, 0x28, 0x04,
0xc2, 0x91, 0x1a, 0x11, 0x26, 0x25, 0xa9, 0x94, 0xc4, 0x28, 0x1f, 0x9f, 0x97, 0x19, 0xc5, 0x4e,
0x72, 0x75, 0x30, 0xeb, 0xdb, 0xde, 0xd8, 0xfb, 0xee, 0x40, 0x7b, 0x9e, 0x8b, 0xeb, 0x24, 0xe6,
0x79, 0x90, 0x5d, 0x09, 0x34, 0x80, 0xba, 0x90, 0xec, 0xd3, 0x96, 0x63, 0xcb, 0xb5, 0xbc, 0xd6,
0xf0, 0x11, 0x29, 0xa3, 0xf7, 0x16, 0x13, 0x40, 0x66, 0x5a, 0x40, 0x8d, 0x10, 0x9d, 0x03, 0x6c,
0x92, 0x0d, 0x0f, 0xb5, 0x08, 0xdb, 0xae, 0xe3, 0x35, 0x69, 0xb3, 0x44, 0x16, 0x25, 0x80, 0x30,
0x9c, 0xb0, 0x38, 0xce, 0xb9, 0x52, 0xd8, 0x71, 0x2d, 0xaf, 0x49, 0xab, 0x2b, 0x7a, 0x03, 0x10,
0x31, 0xc9, 0xd6, 0x49, 0x9a, 0x14, 0x3b, 0x5c, 0x73, 0x2d, 0xaf, 0x33, 0x1c, 0x90, 0xdb, 0x7e,
0x85, 0x1c, 0xcf, 0x49, 0x26, 0x07, 0x23, 0x3d, 0x0a, 0x41, 0x08, 0x6a, 0x19, 0xdb, 0x70, 0x7c,
0x57, 0x7f, 0x49, 0x9f, 0x91, 0x0b, 0xad, 0x98, 0xab, 0x28, 0x4f, 0x64, 0x91, 0x88, 0x0c, 0xd7,
0x35, 0x75, 0x0c, 0x95, 0xae, 0x24, 0x12, 0x19, 0x3e, 0xd9, 0xbb, 0xca, 0x33, 0x7a, 0x06, 0xed,
0x98, 0xab, 0x8f, 0x85, 0x90, 0xa1, 0xc8, 0xd2, 0x1d, 0x6e, 0xb8, 0x96, 0xd7, 0xd0, 0xb6, 0x12,
0x9b, 0x65, 0xe9, 0x0e, 0x9d, 0x41, 0x9d, 0x45, 0x3a, 0xb3, 0xa9, 0x8d, 0xe6, 0xd6, 0xa3, 0x00,
0x37, 0xe3, 0xa1, 0x33, 0x40, 0x13, 0x7f, 0xee, 0x8f, 0x83, 0xcb, 0x60, 0xf1, 0x2e, 0x0c, 0x5e,
0x2f, 0xfd, 0xcb, 0xe0, 0xa2, 0x7b, 0x07, 0x3d, 0x84, 0xfb, 0x47, 0xf8, 0x32, 0x98, 0xbe, 0x9d,
0xd2, 0xae, 0xf5, 0x07, 0x3c, 0xbd, 0x08, 0x16, 0x33, 0xda, 0xb5, 0x7b, 0xbf, 0x6c, 0x68, 0xbf,
0x32, 0x6f, 0xfa, 0xaf, 0x45, 0x3d, 0x81, 0xe6, 0xa1, 0x28, 0x6c, 0xeb, 0x91, 0x1b, 0x55, 0x4f,
0xa8, 0x0b, 0x0e, 0xff, 0x52, 0x98, 0x8a, 0xca, 0x23, 0x7a, 0x09, 0xa7, 0x4c, 0xca, 0x50, 0x9a,
0x67, 0x57, 0xb8, 0xe6, 0x3a, 0x5e, 0x6b, 0xf8, 0xe2, 0xef, 0x1a, 0xa2, 0x6d, 0x26, 0x65, 0x05,
0xa8, 0xff, 0x58, 0xcc, 0x73, 0xe8, 0xb0, 0x34, 0x15, 0x9f, 0xc3, 0x28, 0xe7, 0x4c, 0x1b, 0xf7,
0xd5, 0x9c, 0x6a, 0x74, 0x62, 0x40, 0xd4, 0x87, 0x07, 0x31, 0xbf, 0x62, 0xdb, 0xb4, 0x08, 0x99,
0x94, 0x69, 0x12, 0xb1, 0xa3, 0xa6, 0x90, 0xa1, 0xfc, 0x1b, 0x66, 0xfc, 0x15, 0x9e, 0x46, 0x62,
0x73, 0xeb, 0xcf, 0x8d, 0x3b, 0xb4, 0x5a, 0xba, 0x79, 0xb9, 0x3a, 0x73, 0xeb, 0xfd, 0xbd, 0x4a,
0x63, 0x24, 0xdf, 0x6c, 0x67, 0xe2, 0xd3, 0x1f, 0x36, 0x9e, 0xa8, 0x11, 0xf1, 0xa5, 0x24, 0xb4,
0xca, 0x58, 0x0e, 0xc6, 0xa5, 0xe0, 0xa7, 0xa6, 0x56, 0xbe, 0x94, 0xab, 0x8a, 0x5a, 0x19, 0x6a,
0x5d, 0xd7, 0x0b, 0x39, 0xfa, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x25, 0x86, 0x7b, 0x9b, 0xf5, 0x03,
0x00, 0x00,
}

View File

@@ -680,179 +680,183 @@ func init() {
}
var fileDescriptor_2d35d050f2c88549 = []byte{
// 2740 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x5b, 0x5b, 0x6f, 0xdc, 0xc6,
0x15, 0x2e, 0x25, 0x47, 0xb1, 0x46, 0x96, 0x2c, 0x53, 0x76, 0xac, 0x28, 0x29, 0x6a, 0x28, 0x75,
0x6c, 0xc7, 0xf6, 0xca, 0x96, 0x6c, 0x27, 0x8e, 0x93, 0x02, 0xab, 0x8b, 0x37, 0x0b, 0x5b, 0x91,
0xb2, 0x6b, 0xc9, 0x49, 0xe1, 0x42, 0xa1, 0xb8, 0x47, 0x12, 0xa1, 0x5d, 0x92, 0x1e, 0xce, 0x4a,
0xde, 0x22, 0x4d, 0x5b, 0x34, 0xe8, 0x05, 0x6d, 0x1f, 0x7a, 0x7b, 0xed, 0x43, 0xdf, 0xd2, 0xff,
0x51, 0x14, 0x68, 0xff, 0x40, 0xff, 0x4d, 0x8b, 0x19, 0x9e, 0x21, 0x67, 0xb8, 0xdc, 0xe5, 0x50,
0x06, 0xdc, 0x37, 0xed, 0xcc, 0xf7, 0x9d, 0xf3, 0xcd, 0x99, 0xdb, 0x99, 0xe1, 0x88, 0x5c, 0x76,
0xa3, 0xa5, 0x85, 0x7d, 0x87, 0xc1, 0xb1, 0xd3, 0x5b, 0x38, 0xba, 0xbd, 0x0b, 0xcc, 0xb9, 0x2d,
0x7f, 0xef, 0x38, 0xa1, 0x57, 0x09, 0x69, 0xc0, 0x02, 0x7b, 0xc6, 0x8d, 0x96, 0x2a, 0x58, 0x5c,
0x41, 0xd8, 0xdc, 0x75, 0xce, 0x75, 0xc2, 0x70, 0x21, 0xa4, 0xc1, 0x91, 0xd7, 0x02, 0x9a, 0x18,
0x90, 0x05, 0xa9, 0x85, 0x14, 0x4c, 0x61, 0xdf, 0x8b, 0x18, 0x4d, 0xbd, 0xc9, 0x02, 0x05, 0x7c,
0x47, 0x80, 0xbb, 0xec, 0x80, 0x33, 0xda, 0x9e, 0xeb, 0x30, 0x2f, 0xf0, 0xa3, 0x84, 0xa1, 0x16,
0x2a, 0xac, 0x1b, 0x09, 0xcb, 0xc4, 0xc7, 0x3b, 0x79, 0x2d, 0xa7, 0x10, 0x05, 0x5d, 0xea, 0x42,
0x84, 0xa0, 0xf7, 0x38, 0xc8, 0x6b, 0x81, 0xcf, 0x3c, 0xd6, 0x5b, 0xd8, 0xa7, 0x41, 0x37, 0x4c,
0xa3, 0xc4, 0x7f, 0x29, 0x06, 0xaf, 0x69, 0xd8, 0x6e, 0xa4, 0xc4, 0x23, 0x6b, 0xf6, 0xea, 0x60,
0x28, 0xff, 0xa1, 0x18, 0xbd, 0xc2, 0x91, 0x81, 0xdb, 0x59, 0x70, 0x03, 0x0a, 0x09, 0x28, 0x70,
0x3b, 0x3b, 0xbc, 0x20, 0x0f, 0xe8, 0xf9, 0x47, 0x1e, 0x4b, 0xa1, 0xf1, 0xcf, 0x6c, 0x47, 0x70,
0xa0, 0x49, 0xaf, 0xdd, 0xe4, 0xe0, 0x10, 0x68, 0xc7, 0x8b, 0x22, 0xad, 0x0b, 0x94, 0xb2, 0x3e,
0x38, 0x85, 0x3d, 0xa0, 0xe0, 0xbb, 0xa0, 0xc0, 0xd3, 0x32, 0x05, 0xfe, 0x36, 0x87, 0xd3, 0xd0,
0x4d, 0x60, 0x11, 0x73, 0x58, 0x57, 0x06, 0xe9, 0x3e, 0xaf, 0x8d, 0x0e, 0x1c, 0xea, 0xf9, 0xfb,
0x0b, 0x6e, 0xd0, 0x6e, 0x3b, 0xbb, 0x01, 0x15, 0x9d, 0x9e, 0xe0, 0xb5, 0xd2, 0x6c, 0x30, 0x24,
0xb5, 0xed, 0xf9, 0x87, 0x09, 0x83, 0xff, 0x50, 0x80, 0x97, 0x55, 0x20, 0x0f, 0x8a, 0x1a, 0xe1,
0x14, 0xb6, 0x20, 0x60, 0x2c, 0xa0, 0xce, 0x3e, 0x18, 0xc5, 0xed, 0xc6, 0x50, 0x42, 0x76, 0x38,
0xbc, 0xc5, 0xd1, 0xec, 0x45, 0x52, 0xcf, 0x5e, 0x28, 0xa6, 0xbe, 0x2b, 0x2a, 0x7b, 0xa1, 0x12,
0x4d, 0xf1, 0x2b, 0xae, 0x9e, 0xff, 0xab, 0x45, 0x66, 0xaa, 0x5d, 0x76, 0xc0, 0xc7, 0x92, 0xeb,
0x30, 0x68, 0xc0, 0xf3, 0x2e, 0x44, 0xcc, 0xbe, 0x4d, 0xc6, 0x82, 0xd0, 0x79, 0xde, 0x85, 0x59,
0xeb, 0x92, 0x75, 0x75, 0x62, 0xf1, 0xcd, 0x0a, 0x9f, 0xc2, 0x31, 0x13, 0xed, 0x54, 0x36, 0x04,
0xa0, 0x81, 0x40, 0xdb, 0x26, 0xa7, 0x78, 0xfd, 0xec, 0xc8, 0x25, 0xeb, 0xea, 0x78, 0x43, 0xfc,
0x6d, 0xbf, 0x45, 0xc6, 0xdd, 0xb6, 0x07, 0x3e, 0xdb, 0xf1, 0x5a, 0xb3, 0xa3, 0xa2, 0xe2, 0x74,
0x5c, 0x50, 0x6f, 0xd9, 0xef, 0x90, 0x49, 0xac, 0x8c, 0xc0, 0xa5, 0xc0, 0x66, 0x4f, 0x09, 0xc0,
0x99, 0xb8, 0xb0, 0x29, 0xca, 0xe6, 0xff, 0x61, 0x91, 0xf3, 0xba, 0xc0, 0x28, 0x0c, 0xfc, 0x08,
0xec, 0x05, 0x32, 0x16, 0xf7, 0x37, 0x2a, 0xbc, 0x28, 0x14, 0xd2, 0xd0, 0x4d, 0xf4, 0x35, 0x45,
0x75, 0x03, 0x61, 0x4a, 0x93, 0x46, 0x4c, 0x9b, 0x74, 0x9e, 0xbc, 0xc6, 0x82, 0x43, 0xf0, 0x51,
0x7a, 0xfc, 0xc3, 0x5e, 0x22, 0xa7, 0xf8, 0x34, 0x13, 0x72, 0x27, 0x16, 0xbf, 0x27, 0xcc, 0xc8,
0xd9, 0x58, 0xe1, 0x35, 0x89, 0xb9, 0xad, 0x08, 0x68, 0x43, 0x80, 0xe7, 0x3f, 0x27, 0x93, 0x4f,
0x0f, 0x82, 0x6a, 0xa7, 0xfe, 0x12, 0x11, 0x4e, 0xe4, 0x8c, 0x28, 0x72, 0xe6, 0xbf, 0xb5, 0xc8,
0x94, 0x34, 0xfd, 0x0a, 0x63, 0x23, 0xa3, 0x30, 0x5a, 0x26, 0x0a, 0x3f, 0x25, 0x67, 0x6b, 0xc0,
0x3e, 0xeb, 0x06, 0xcc, 0x79, 0x89, 0x38, 0xdc, 0x27, 0xa3, 0x14, 0xf6, 0x50, 0xea, 0x15, 0x81,
0xc7, 0xc9, 0x52, 0x91, 0x93, 0x25, 0xa1, 0x36, 0xe4, 0xca, 0xd1, 0xe0, 0x9c, 0xf9, 0x7f, 0x5b,
0xe4, 0xed, 0xba, 0xef, 0x31, 0xcf, 0x61, 0xf0, 0xd0, 0x6b, 0xc3, 0x6a, 0x70, 0xec, 0xb7, 0x03,
0xa7, 0xf5, 0x4a, 0x43, 0x57, 0x23, 0xe3, 0x62, 0xf6, 0xb9, 0x41, 0x3b, 0x9a, 0x1d, 0xbd, 0x34,
0x7a, 0x75, 0x62, 0xf1, 0x5a, 0x25, 0x67, 0x8b, 0xac, 0xa8, 0x0a, 0x37, 0x91, 0xd1, 0x48, 0xb9,
0xf3, 0xff, 0xb4, 0xc8, 0x9c, 0xda, 0x9a, 0xad, 0xf0, 0x95, 0xb7, 0x65, 0xad, 0xbf, 0x2d, 0x57,
0x06, 0xb6, 0x25, 0xd6, 0x97, 0xd7, 0x92, 0xbf, 0x58, 0xe4, 0xcd, 0xc7, 0x5e, 0xc4, 0xf8, 0x54,
0xdf, 0xc4, 0x3e, 0x8c, 0x5e, 0xf9, 0x5c, 0xe7, 0xf5, 0xa2, 0x11, 0x7c, 0x72, 0xf1, 0x1f, 0xf3,
0xff, 0x1d, 0x21, 0xd3, 0x1b, 0x21, 0xf8, 0x75, 0xbf, 0x1a, 0x86, 0xff, 0x97, 0x21, 0x6b, 0x3f,
0x22, 0xe3, 0x47, 0x1e, 0x1c, 0xef, 0x74, 0x82, 0x16, 0x88, 0xd9, 0x36, 0xb5, 0x58, 0xc9, 0x8d,
0x70, 0x56, 0x67, 0x65, 0xdb, 0x83, 0xe3, 0xf5, 0xa0, 0x05, 0x8d, 0xd3, 0x47, 0xf8, 0x97, 0x3d,
0x4d, 0x46, 0x9d, 0x30, 0xc4, 0x95, 0x96, 0xff, 0x69, 0x5f, 0x24, 0xaf, 0xb7, 0x03, 0xf7, 0x90,
0x2f, 0xd0, 0xaf, 0x89, 0xd2, 0x31, 0xfe, 0xb3, 0xde, 0x9a, 0xff, 0xc6, 0x22, 0xa7, 0xa5, 0x05,
0xfb, 0x02, 0x39, 0xb7, 0x5d, 0x5f, 0x7b, 0xba, 0xb3, 0xbe, 0xb1, 0xba, 0xb6, 0x53, 0xff, 0x74,
0xbb, 0xfa, 0xb8, 0xbe, 0x3a, 0xfd, 0x1d, 0xfb, 0x22, 0x99, 0x49, 0x8b, 0xc5, 0x5f, 0x1b, 0x9f,
0x3e, 0xfe, 0x62, 0xda, 0xd2, 0x2b, 0x1a, 0x6b, 0xd5, 0xd5, 0xb8, 0x62, 0xc4, 0x9e, 0x25, 0xe7,
0x33, 0x15, 0x4f, 0x1b, 0xf5, 0x27, 0x6b, 0xd3, 0xa3, 0xba, 0x8b, 0xcd, 0xc6, 0x1a, 0xff, 0x31,
0x7d, 0x6a, 0xf1, 0x3f, 0xdb, 0x84, 0xd4, 0xe2, 0x96, 0x56, 0x37, 0xeb, 0xb6, 0x4b, 0xce, 0xa8,
0xdb, 0x81, 0x7d, 0x35, 0x37, 0x14, 0x39, 0x5b, 0xda, 0xdc, 0x35, 0x03, 0x24, 0x8e, 0xb7, 0xcf,
0xc8, 0x58, 0xbc, 0xa2, 0xda, 0xf3, 0xb9, 0x24, 0x6d, 0x25, 0x9f, 0x7b, 0x67, 0x28, 0x06, 0x4d,
0xfe, 0xce, 0x22, 0x33, 0x35, 0xf0, 0x81, 0x3a, 0x0c, 0xaa, 0x61, 0xb8, 0xe9, 0x44, 0xd1, 0x71,
0x40, 0x5b, 0xf6, 0x7d, 0x41, 0xe6, 0x69, 0x67, 0x45, 0xcd, 0x4b, 0x13, 0x33, 0x39, 0x1c, 0xe9,
0xf7, 0xc3, 0x93, 0x50, 0x51, 0xce, 0x2f, 0x2c, 0x32, 0x2d, 0xe6, 0x5b, 0x5a, 0x17, 0xd9, 0xf7,
0x0a, 0x0c, 0x66, 0x09, 0x52, 0xc8, 0xfb, 0xa5, 0x79, 0xa8, 0xe2, 0x8f, 0x16, 0xb9, 0x50, 0xf7,
0x8f, 0x9c, 0xb6, 0xd7, 0xca, 0x84, 0xe5, 0x41, 0x81, 0xc9, 0x5c, 0x96, 0xd4, 0xf3, 0xd1, 0xc9,
0xc8, 0x28, 0xea, 0x27, 0x64, 0xaa, 0x06, 0xaa, 0x5e, 0xfb, 0x4e, 0x61, 0xa0, 0x59, 0x8e, 0x8a,
0xbb, 0x25, 0x59, 0xe8, 0xfe, 0x6b, 0x72, 0x76, 0x85, 0x82, 0xc3, 0x60, 0x25, 0xf0, 0x99, 0xe3,
0xf9, 0x40, 0xd1, 0xff, 0xc0, 0xf5, 0x22, 0x03, 0xd7, 0xfd, 0x9b, 0xb3, 0xd0, 0x7f, 0x9b, 0x8c,
0x3f, 0x09, 0xba, 0xee, 0x01, 0x5f, 0xaf, 0xed, 0xca, 0x70, 0x1b, 0x09, 0x50, 0xfa, 0x5c, 0x30,
0xc6, 0xa3, 0x37, 0x97, 0x8c, 0xad, 0x42, 0x1b, 0x18, 0xd8, 0xd7, 0x87, 0x53, 0x63, 0x94, 0xf4,
0x73, 0xc3, 0x0c, 0x8c, 0x4e, 0xf6, 0xc8, 0xeb, 0x35, 0x60, 0x9b, 0x0e, 0x3b, 0xb0, 0x0b, 0x88,
0x08, 0x93, 0x6e, 0x6e, 0x1a, 0xa2, 0xd1, 0xcf, 0x97, 0xe4, 0xb4, 0xcc, 0x6e, 0xec, 0xef, 0xe7,
0x2e, 0x0a, 0x99, 0xe4, 0x67, 0xae, 0x52, 0xe8, 0x00, 0xe1, 0xe8, 0xe1, 0x1b, 0x8b, 0x9c, 0xcf,
0x4b, 0x5f, 0x70, 0x19, 0x19, 0x68, 0x28, 0x3f, 0xe5, 0x89, 0x35, 0xdc, 0xce, 0x55, 0x3a, 0x34,
0x49, 0xfa, 0x9a, 0xd8, 0xfd, 0x69, 0x87, 0xfd, 0xbe, 0xb9, 0x06, 0x99, 0xa8, 0xa8, 0xa3, 0x66,
0x98, 0x82, 0x4c, 0x62, 0xc3, 0x17, 0x53, 0xbe, 0xa8, 0x24, 0xa3, 0xb7, 0xc9, 0x28, 0x38, 0x1d,
0xfb, 0x83, 0xe1, 0x0a, 0x72, 0x28, 0x52, 0xc2, 0xfd, 0x13, 0x30, 0x63, 0x31, 0xb7, 0x2c, 0xfb,
0x05, 0x99, 0xd4, 0x00, 0xf6, 0x62, 0x09, 0x6b, 0x52, 0xc1, 0x52, 0x29, 0x0e, 0x06, 0xe2, 0xe7,
0xb8, 0x8c, 0xf3, 0x18, 0x6d, 0x03, 0x15, 0x07, 0x6a, 0xfb, 0x6e, 0xb1, 0x25, 0x15, 0x2f, 0x05,
0xdc, 0x2b, 0x4b, 0x43, 0x0d, 0xbf, 0xb4, 0xc8, 0x39, 0x5e, 0xd9, 0x00, 0xb7, 0xe7, 0xb6, 0x01,
0xbb, 0xc2, 0xc0, 0x9a, 0x46, 0xd0, 0xf7, 0x92, 0x32, 0xbc, 0xa4, 0x1b, 0x28, 0x99, 0x50, 0xaa,
0xed, 0x5b, 0xc6, 0x96, 0xf4, 0x99, 0x60, 0xc6, 0xc0, 0xc6, 0xff, 0x88, 0x9c, 0x5a, 0x0f, 0x8e,
0xc0, 0xbe, 0x36, 0x9c, 0xca, 0x31, 0xd2, 0xcb, 0x7b, 0x26, 0x50, 0x34, 0xdf, 0x25, 0x67, 0x36,
0xbb, 0x74, 0x1f, 0x64, 0x9b, 0x0a, 0x14, 0xaa, 0x58, 0xe9, 0x6e, 0xb1, 0x0c, 0x05, 0xdd, 0xfe,
0xca, 0x22, 0x76, 0x03, 0x38, 0x07, 0x94, 0x2e, 0x2f, 0x9a, 0xe0, 0xfd, 0x0c, 0xa9, 0xe1, 0x83,
0xf2, 0xc4, 0x7e, 0x25, 0x28, 0xb2, 0xce, 0xa0, 0x63, 0xa8, 0x44, 0x61, 0x94, 0x53, 0xa2, 0x11,
0xd3, 0x9e, 0xe6, 0x87, 0x8c, 0xa2, 0x9e, 0xe6, 0x18, 0xc3, 0x9e, 0x8e, 0xa1, 0x68, 0xfe, 0x05,
0x99, 0x8c, 0x77, 0xe4, 0x66, 0xaf, 0xd3, 0xf6, 0xfc, 0xc3, 0xa2, 0x35, 0x44, 0x03, 0x1b, 0xae,
0x21, 0x19, 0x0e, 0x7a, 0xfe, 0xbd, 0x45, 0xce, 0x37, 0x81, 0x55, 0xe9, 0xae, 0xc7, 0xa8, 0x43,
0x7b, 0xeb, 0xc0, 0x9c, 0x96, 0xc3, 0x9c, 0xa2, 0x3d, 0x25, 0x8f, 0xa3, 0xa7, 0xa6, 0x25, 0xa9,
0xa8, 0xe7, 0x4f, 0x16, 0x79, 0x63, 0xcb, 0x8f, 0xf2, 0x14, 0x3d, 0x18, 0x6e, 0x36, 0x9f, 0xa5,
0x67, 0x85, 0xa5, 0xc9, 0x69, 0x0e, 0xd1, 0x04, 0xf6, 0x38, 0x70, 0x0f, 0x8b, 0x72, 0x08, 0x84,
0x19, 0xe6, 0x10, 0x09, 0x5a, 0xcb, 0x55, 0x4c, 0xfc, 0xd4, 0x4a, 0xf9, 0xa9, 0x65, 0xfc, 0x50,
0x32, 0xd1, 0x80, 0x3d, 0x0a, 0xd1, 0x81, 0xf0, 0x75, 0xab, 0xf0, 0x48, 0x2a, 0xa1, 0x86, 0x8b,
0xa5, 0xc6, 0x48, 0x93, 0xbd, 0x2d, 0x9f, 0x9f, 0x2e, 0x8b, 0x92, 0xbd, 0x18, 0x65, 0x98, 0xec,
0x49, 0x30, 0x3a, 0x09, 0x08, 0x89, 0xc7, 0xf9, 0x27, 0x41, 0x07, 0xec, 0x05, 0x93, 0x19, 0xc1,
0x91, 0xd2, 0xd9, 0x2d, 0x73, 0x82, 0xb2, 0x44, 0xe1, 0xcc, 0x8a, 0x59, 0xcd, 0xd0, 0x71, 0xa1,
0x68, 0x89, 0xea, 0x67, 0x18, 0x2e, 0x51, 0x79, 0xc4, 0x34, 0x3b, 0x14, 0x3b, 0xb1, 0x5a, 0x19,
0x99, 0xec, 0xc4, 0x1a, 0xa1, 0xc4, 0x4e, 0x9c, 0xe1, 0x29, 0x01, 0xd9, 0x0a, 0x5b, 0x25, 0x03,
0xd2, 0xcf, 0x30, 0x0c, 0x48, 0x1e, 0x51, 0x51, 0x12, 0x9f, 0x05, 0xca, 0x28, 0xe9, 0x67, 0x18,
0x2a, 0xc9, 0x23, 0xa2, 0x92, 0x1d, 0x32, 0x9e, 0x5c, 0xcf, 0xd8, 0x97, 0x8d, 0xae, 0x6f, 0xe6,
0xe2, 0x49, 0xe2, 0x84, 0x61, 0xbf, 0x27, 0x05, 0x8b, 0x0e, 0xbe, 0x22, 0x13, 0x38, 0x32, 0x0e,
0x1c, 0x0a, 0x32, 0x07, 0x8c, 0x3f, 0x4d, 0x54, 0xb4, 0x0f, 0x1d, 0xd9, 0x91, 0xc4, 0xf1, 0x99,
0x1c, 0xd0, 0x9c, 0x96, 0x7a, 0x6f, 0x40, 0x27, 0x38, 0x2a, 0xe1, 0x5d, 0xc1, 0x97, 0xf1, 0xae,
0xd1, 0xd0, 0x7b, 0x24, 0xce, 0x5d, 0xb1, 0xeb, 0x45, 0x03, 0x1b, 0x12, 0x9c, 0xd9, 0x36, 0x0d,
0x39, 0xe8, 0xb4, 0x47, 0x88, 0x98, 0x02, 0xbc, 0x30, 0x92, 0x47, 0xf4, 0xa1, 0x26, 0x52, 0x78,
0xe6, 0x88, 0x6e, 0xcc, 0x4a, 0xa3, 0x8d, 0x83, 0xde, 0x38, 0xda, 0x0a, 0xbe, 0x4c, 0xb4, 0x35,
0x1a, 0x7a, 0xff, 0x83, 0x45, 0x6c, 0x4c, 0x85, 0xc1, 0x3b, 0x82, 0x16, 0x46, 0xe0, 0x23, 0xc3,
0xb6, 0xe8, 0x34, 0x29, 0xe6, 0xe3, 0x13, 0xb2, 0x51, 0xd3, 0x9f, 0x2d, 0x32, 0x13, 0x6b, 0xd5,
0x00, 0xf6, 0xc7, 0xc6, 0x6d, 0xd4, 0x78, 0x52, 0xd5, 0x0f, 0x4e, 0x4a, 0x47, 0x59, 0xbf, 0xb5,
0xc8, 0x74, 0x0d, 0x74, 0xd1, 0xf6, 0x87, 0x66, 0xa3, 0x2d, 0x57, 0xd0, 0x83, 0x13, 0x71, 0x51,
0xcd, 0x17, 0x64, 0xac, 0x09, 0xec, 0x11, 0xf4, 0xec, 0x77, 0x85, 0x19, 0xe5, 0xab, 0xaa, 0x9a,
0x8e, 0x3c, 0x82, 0x9e, 0x74, 0x77, 0xa5, 0x10, 0x97, 0x9a, 0xae, 0x15, 0x99, 0xae, 0x19, 0x9a,
0xae, 0xe9, 0xa6, 0xbf, 0x22, 0xe7, 0xe2, 0x15, 0x67, 0xb3, 0xbb, 0xdb, 0xf6, 0xdc, 0xbc, 0x59,
0xce, 0xd3, 0xd9, 0xcc, 0xf2, 0xa4, 0x80, 0xf3, 0x67, 0x79, 0x11, 0x27, 0xf5, 0x1e, 0xaf, 0x38,
0x86, 0xde, 0xfb, 0xc0, 0x06, 0xde, 0x73, 0x38, 0xc9, 0xc2, 0x36, 0x55, 0x03, 0xa6, 0xba, 0x5e,
0x18, 0x6c, 0x46, 0x47, 0x66, 0xf2, 0x19, 0x13, 0x02, 0x3a, 0xfd, 0xb5, 0x45, 0x2e, 0xe8, 0x55,
0xcb, 0xbd, 0x27, 0xe2, 0xc3, 0xe7, 0x3d, 0x53, 0x5b, 0x48, 0xc8, 0x64, 0x12, 0x25, 0x78, 0xc9,
0x1a, 0x2b, 0x6e, 0x37, 0x14, 0x44, 0x24, 0x8f, 0xc0, 0x79, 0xc6, 0xb2, 0xd8, 0xcc, 0x11, 0xd8,
0x8c, 0x92, 0x76, 0x7c, 0x3c, 0xb3, 0x0d, 0x3b, 0xbe, 0x0f, 0x6c, 0xd0, 0xf1, 0x39, 0x1c, 0xf4,
0xfe, 0x9c, 0x4c, 0xc5, 0x63, 0x72, 0x63, 0x65, 0x3d, 0x76, 0x5d, 0xd1, 0xcc, 0x04, 0x6e, 0x27,
0x33, 0x78, 0x25, 0x30, 0x73, 0x13, 0x6b, 0x80, 0x4f, 0x5d, 0xc6, 0x03, 0xd1, 0xc0, 0xa5, 0x0e,
0x2c, 0x76, 0x99, 0xc5, 0xa3, 0xcb, 0x03, 0x32, 0x51, 0x03, 0x96, 0xf8, 0xbb, 0x3e, 0x90, 0xaf,
0xa0, 0x32, 0x87, 0x82, 0x22, 0x30, 0x7a, 0xf2, 0xe3, 0x1b, 0x3a, 0x59, 0x1e, 0xd9, 0x37, 0x07,
0xd2, 0x35, 0x5c, 0xe6, 0x9e, 0xb6, 0x18, 0x9e, 0x06, 0x33, 0xee, 0x5c, 0x83, 0x60, 0xea, 0xc0,
0xe2, 0x60, 0x66, 0xf1, 0xe9, 0x35, 0xdc, 0x05, 0x75, 0x87, 0x4c, 0xdb, 0x7a, 0x77, 0xa8, 0xf8,
0x3e, 0x7c, 0x7e, 0x7e, 0x60, 0x40, 0x43, 0x21, 0xbf, 0xe1, 0xe7, 0x77, 0x6d, 0x53, 0x4c, 0x82,
0x70, 0xaf, 0xa0, 0x51, 0x59, 0x42, 0xfe, 0x02, 0x62, 0xc2, 0x43, 0x2d, 0x3f, 0x13, 0x5f, 0xdd,
0xfa, 0xc4, 0xda, 0x4b, 0xc3, 0x46, 0xcf, 0x20, 0x15, 0x77, 0xca, 0x91, 0x50, 0xc2, 0x91, 0x78,
0xf2, 0x50, 0x0d, 0xc3, 0xe4, 0xb3, 0x36, 0x1e, 0xb6, 0x79, 0x62, 0x2f, 0x1f, 0x96, 0x65, 0x3f,
0x0a, 0xa5, 0x5f, 0xc0, 0xd5, 0xc3, 0xb6, 0x19, 0x23, 0xdd, 0x3b, 0xaa, 0xad, 0x96, 0x52, 0x85,
0x7b, 0x47, 0xae, 0x11, 0x1d, 0xa9, 0xef, 0x1d, 0x46, 0x04, 0x7d, 0xc1, 0xd6, 0x5a, 0x3b, 0x44,
0x7b, 0x16, 0xab, 0x2f, 0xd8, 0x86, 0x94, 0x34, 0xd7, 0x7a, 0x43, 0xe4, 0xca, 0xdd, 0x30, 0x0c,
0x28, 0x83, 0xd6, 0xba, 0xd7, 0x81, 0x27, 0xbd, 0x10, 0x22, 0x3c, 0xef, 0x0d, 0x34, 0xd7, 0xcf,
0xd0, 0xcf, 0x7b, 0xa5, 0x88, 0xa8, 0xe6, 0x5b, 0x8b, 0x5c, 0xaa, 0x01, 0x5b, 0x85, 0x3d, 0xa7,
0xdb, 0x56, 0x05, 0x3f, 0x0c, 0xa8, 0x44, 0xdb, 0xd5, 0xa1, 0xbd, 0x3a, 0x94, 0x2b, 0x15, 0x2e,
0xbf, 0x8c, 0x09, 0x45, 0x6b, 0xf3, 0x25, 0xb4, 0x36, 0x5f, 0x5e, 0x6b, 0xd3, 0x54, 0xeb, 0x97,
0xe2, 0x7a, 0x6c, 0x2b, 0x02, 0x8a, 0x17, 0xb1, 0xf9, 0x4f, 0x8e, 0x10, 0xa3, 0x5f, 0xc4, 0x16,
0x40, 0x93, 0x2b, 0xf7, 0x29, 0x2c, 0x5a, 0xee, 0xad, 0xb4, 0x1d, 0xaf, 0x83, 0xd3, 0x75, 0x28,
0x1b, 0xa1, 0xfa, 0x74, 0x35, 0x63, 0x24, 0xf7, 0x71, 0x93, 0x58, 0x53, 0xa3, 0x41, 0x37, 0x8c,
0x70, 0xb6, 0x0e, 0xb5, 0x11, 0x23, 0xf5, 0xd9, 0x6a, 0x44, 0x48, 0xee, 0x1a, 0xc7, 0x1f, 0x7a,
0x7e, 0x8b, 0xd7, 0x44, 0xb8, 0xfb, 0xe6, 0xd3, 0x13, 0x94, 0xbe, 0xfb, 0x16, 0x82, 0xd1, 0x0f,
0x88, 0xf3, 0xb9, 0x70, 0x9e, 0x75, 0x23, 0x5e, 0xc1, 0xaa, 0x32, 0x05, 0x6a, 0x80, 0x9b, 0x41,
0x60, 0x74, 0xf3, 0x63, 0xb1, 0xd2, 0x8a, 0x32, 0xd9, 0x75, 0x8b, 0x26, 0x06, 0x32, 0x9d, 0xb7,
0x54, 0x8a, 0x83, 0xbe, 0x0f, 0x09, 0xa9, 0x01, 0x5b, 0x87, 0xce, 0x2e, 0x8f, 0xe5, 0xcd, 0x02,
0x13, 0x88, 0xd3, 0xb3, 0x0b, 0x03, 0x78, 0x92, 0x37, 0x8d, 0x7f, 0xe2, 0x44, 0x71, 0xa9, 0x3d,
0x34, 0x46, 0x09, 0x4c, 0xbf, 0x25, 0x2e, 0x46, 0xa7, 0xcd, 0xe2, 0xdd, 0x89, 0x43, 0x72, 0x28,
0x39, 0xc5, 0x19, 0x35, 0x4b, 0x85, 0x27, 0x9f, 0x40, 0xce, 0xf5, 0x3d, 0x01, 0xc3, 0x9d, 0x5a,
0xbc, 0xa2, 0xc8, 0xdf, 0x0b, 0xf4, 0x07, 0x63, 0xaa, 0xe7, 0xec, 0x05, 0xdb, 0xe0, 0xf7, 0x65,
0xf1, 0xa5, 0xbb, 0xb8, 0x30, 0x2e, 0xbe, 0x74, 0x57, 0x6f, 0x8b, 0x6f, 0x1a, 0xa2, 0x93, 0xef,
0xe6, 0xc9, 0x1b, 0xa0, 0xba, 0x78, 0x58, 0x1d, 0x9f, 0xab, 0xe2, 0x51, 0xca, 0x13, 0x8a, 0xf8,
0xb9, 0x75, 0xdf, 0x0b, 0x1e, 0x05, 0xac, 0x8f, 0x52, 0x53, 0x4e, 0xf2, 0xb6, 0x63, 0xf2, 0x61,
0x40, 0x8f, 0x1d, 0xda, 0x8a, 0x6b, 0xb1, 0xb5, 0x39, 0x56, 0x34, 0x98, 0xde, 0xda, 0x62, 0x34,
0x7a, 0xf3, 0xc8, 0x99, 0xaa, 0xeb, 0x42, 0xc8, 0xd0, 0xd9, 0xf5, 0x41, 0x74, 0x15, 0xa5, 0x4f,
0xfd, 0x42, 0x70, 0xb2, 0x7a, 0x8a, 0x24, 0x4b, 0x54, 0x81, 0x58, 0x7d, 0x30, 0xe1, 0xce, 0x0d,
0x90, 0x06, 0xd4, 0x13, 0x6e, 0x13, 0x7c, 0x3a, 0x5c, 0xf9, 0x20, 0x56, 0xeb, 0x64, 0x6a, 0x97,
0x17, 0xa2, 0x2c, 0x54, 0xdf, 0x2b, 0xcc, 0x18, 0xe9, 0xd9, 0xb4, 0x1e, 0xc9, 0x51, 0x5c, 0x6d,
0xb7, 0x83, 0x63, 0x68, 0x29, 0x83, 0xa8, 0xff, 0xe5, 0x45, 0x16, 0xdc, 0x3f, 0x88, 0x4c, 0x38,
0x5a, 0x42, 0x5b, 0xf7, 0xf7, 0x82, 0xe5, 0xde, 0x6a, 0xd0, 0x71, 0x3c, 0x5f, 0x69, 0x75, 0xde,
0x14, 0x50, 0xa1, 0xfd, 0xad, 0x2e, 0x66, 0x64, 0x72, 0xcb, 0x76, 0x3b, 0x9b, 0x5b, 0xe6, 0x9a,
0xc9, 0x62, 0xf5, 0xdc, 0xd2, 0x90, 0x82, 0xae, 0x8f, 0xe5, 0x17, 0x9e, 0x8d, 0x95, 0xf5, 0x95,
0x80, 0x82, 0x7a, 0x17, 0xc3, 0x2d, 0xb9, 0x01, 0x85, 0xfe, 0xf3, 0x75, 0x82, 0xd4, 0x77, 0x68,
0x23, 0x42, 0xf2, 0xd9, 0x00, 0xef, 0x01, 0x9e, 0x50, 0xc7, 0x8f, 0xf6, 0x80, 0xe2, 0xb7, 0x03,
0xf6, 0x22, 0xc3, 0x96, 0xf5, 0xd2, 0xd5, 0xbb, 0x45, 0xb0, 0x64, 0x2b, 0x39, 0x57, 0x03, 0x26,
0x8b, 0xe3, 0x57, 0xb4, 0xf8, 0xa6, 0x52, 0x21, 0xf7, 0x41, 0xf4, 0x37, 0x95, 0xc3, 0x91, 0x4a,
0x53, 0x1c, 0xdf, 0x85, 0xf6, 0x90, 0xa6, 0x68, 0xf5, 0x83, 0x9b, 0x92, 0x81, 0xa1, 0x83, 0x67,
0xf1, 0x19, 0x5f, 0x96, 0x47, 0xf8, 0x04, 0x4b, 0x21, 0x6a, 0xd5, 0xd2, 0xfc, 0xe5, 0x02, 0x54,
0x6a, 0xbd, 0x01, 0x8c, 0xf6, 0x12, 0xf5, 0x7d, 0xd6, 0xb5, 0xea, 0x81, 0xd6, 0x33, 0x28, 0xb4,
0xce, 0xc8, 0xd9, 0x95, 0x03, 0x70, 0x0f, 0x37, 0x93, 0xff, 0x8b, 0xc1, 0xd1, 0xa5, 0xfc, 0xa3,
0x4c, 0xda, 0x7e, 0x1d, 0xa9, 0x8f, 0x2e, 0x23, 0x42, 0xec, 0x75, 0xd9, 0x27, 0x17, 0xdd, 0xa0,
0x93, 0xb7, 0x57, 0x2e, 0x9f, 0x95, 0x4f, 0x6e, 0x43, 0x4f, 0x3c, 0xd7, 0xde, 0xb4, 0x7e, 0x38,
0x85, 0x18, 0x84, 0xfc, 0x6d, 0x64, 0x74, 0xa5, 0xf6, 0xf9, 0xdf, 0x47, 0x66, 0x56, 0xa2, 0xa5,
0x0a, 0xa2, 0x2b, 0xdb, 0xb7, 0x97, 0x79, 0xdd, 0xbf, 0x44, 0xe9, 0x33, 0x2c, 0x7d, 0x86, 0xa5,
0xbb, 0x63, 0xe2, 0xbd, 0xf7, 0xd2, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0x3b, 0x12, 0x3f, 0x74,
0x36, 0x36, 0x00, 0x00,
// 2813 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x5b, 0x5b, 0x73, 0xdc, 0xb6,
0x15, 0x2e, 0x25, 0x47, 0xb1, 0x20, 0x4b, 0x96, 0x29, 0x3b, 0x56, 0x94, 0x74, 0xea, 0x91, 0xeb,
0xd8, 0x8e, 0xed, 0x95, 0x2d, 0xd9, 0x4e, 0x1c, 0x27, 0x9d, 0x59, 0x5d, 0xbc, 0xd9, 0xb1, 0x15,
0x29, 0xbb, 0x96, 0x9d, 0xb4, 0xee, 0x28, 0x14, 0x17, 0x92, 0x38, 0xe2, 0x92, 0x34, 0x88, 0x95,
0xbc, 0x6d, 0x9a, 0xb6, 0xd3, 0x4c, 0x2f, 0xd3, 0xf6, 0xa1, 0xb7, 0xd7, 0x3e, 0xf4, 0x2d, 0xfd,
0x0f, 0x7d, 0xec, 0x74, 0xa6, 0xfd, 0x51, 0xed, 0x00, 0x3c, 0x20, 0x01, 0x90, 0xbb, 0x04, 0xe5,
0x19, 0xf7, 0x6d, 0x09, 0x7c, 0xdf, 0xf9, 0x0e, 0x0e, 0x6e, 0x87, 0x20, 0x16, 0x5d, 0x72, 0xe3,
0xa5, 0x85, 0x3d, 0x87, 0xe2, 0x23, 0xa7, 0xbf, 0x70, 0x78, 0x6b, 0x07, 0x53, 0xe7, 0x96, 0x78,
0xde, 0x76, 0x22, 0xaf, 0x16, 0x91, 0x90, 0x86, 0xf6, 0x8c, 0x1b, 0x2f, 0xd5, 0xa0, 0xb8, 0x06,
0xb0, 0xb9, 0x6b, 0x8c, 0xeb, 0x44, 0xd1, 0x42, 0x44, 0xc2, 0x43, 0xaf, 0x83, 0x49, 0x6a, 0x40,
0x14, 0x64, 0x16, 0x32, 0x30, 0xc1, 0x7b, 0x5e, 0x4c, 0x49, 0xa6, 0x26, 0x0a, 0x24, 0xf0, 0x6d,
0x0e, 0xee, 0xd1, 0x7d, 0xc6, 0xf0, 0x3d, 0xd7, 0xa1, 0x5e, 0x18, 0xc4, 0x29, 0x43, 0x2e, 0x94,
0x58, 0xd7, 0x53, 0x96, 0x89, 0xc6, 0xc5, 0xa2, 0x96, 0x13, 0x1c, 0x87, 0x3d, 0xe2, 0xe2, 0x18,
0x40, 0xef, 0x32, 0x90, 0xd7, 0xc1, 0x01, 0xf5, 0x68, 0x7f, 0x61, 0x8f, 0x84, 0xbd, 0x28, 0x8b,
0x12, 0x7b, 0x92, 0x0c, 0x5e, 0x55, 0xb0, 0xbd, 0x58, 0x8a, 0x87, 0x6e, 0xf6, 0xca, 0x60, 0x28,
0x7b, 0x90, 0x8c, 0x5e, 0x66, 0xc8, 0xd0, 0xed, 0x2e, 0xb8, 0x21, 0xc1, 0x29, 0x28, 0x74, 0xbb,
0xdb, 0xac, 0xa0, 0x08, 0xe8, 0x05, 0x87, 0x1e, 0xcd, 0xa0, 0xc9, 0xa3, 0xde, 0x11, 0x0c, 0x68,
0xd2, 0x6b, 0x37, 0x18, 0x38, 0xc2, 0xa4, 0xeb, 0xc5, 0xb1, 0xd2, 0x05, 0x52, 0x59, 0x0e, 0x4e,
0xf0, 0x2e, 0x26, 0x38, 0x70, 0xb1, 0x04, 0xcf, 0xca, 0x24, 0xf8, 0xdb, 0x0c, 0x4e, 0x22, 0x37,
0x85, 0xc5, 0xd4, 0xa1, 0x3d, 0x11, 0xa4, 0x7b, 0xac, 0x36, 0xde, 0x77, 0x88, 0x17, 0xec, 0x2d,
0xb8, 0xa1, 0xef, 0x3b, 0x3b, 0x21, 0xe1, 0x9d, 0x9e, 0xe2, 0x95, 0x52, 0x3d, 0x18, 0x82, 0xea,
0x7b, 0xc1, 0x41, 0xca, 0x60, 0x0f, 0x12, 0xf0, 0x92, 0x0c, 0x64, 0x41, 0x91, 0x23, 0x9c, 0xc1,
0x16, 0x38, 0x8c, 0x86, 0xc4, 0xd9, 0xc3, 0x46, 0x71, 0xbb, 0x3e, 0x94, 0xa0, 0x0f, 0x87, 0xb7,
0x18, 0x9a, 0xbe, 0x48, 0xeb, 0xe9, 0x0b, 0xc9, 0xd4, 0xb7, 0x79, 0x65, 0x3f, 0x92, 0xa2, 0xc9,
0x9f, 0x92, 0xea, 0xf9, 0xbf, 0x5a, 0x68, 0xa6, 0xde, 0xa3, 0xfb, 0x6c, 0x2c, 0xb9, 0x0e, 0xc5,
0x2d, 0xfc, 0xbc, 0x87, 0x63, 0x6a, 0xdf, 0x42, 0x63, 0x61, 0xe4, 0x3c, 0xef, 0xe1, 0x59, 0xeb,
0x82, 0x75, 0x65, 0x62, 0xf1, 0xcd, 0x1a, 0x9b, 0xc2, 0x09, 0x13, 0xec, 0xd4, 0x36, 0x38, 0xa0,
0x05, 0x40, 0xdb, 0x46, 0x27, 0x58, 0xfd, 0xec, 0xc8, 0x05, 0xeb, 0xca, 0x78, 0x8b, 0xff, 0xb6,
0xdf, 0x42, 0xe3, 0xae, 0xef, 0xe1, 0x80, 0x6e, 0x7b, 0x9d, 0xd9, 0x51, 0x5e, 0x71, 0x32, 0x29,
0x68, 0x76, 0xec, 0x8b, 0x68, 0x12, 0x2a, 0x63, 0xec, 0x12, 0x4c, 0x67, 0x4f, 0x70, 0xc0, 0xa9,
0xa4, 0xb0, 0xcd, 0xcb, 0xe6, 0xff, 0x69, 0xa1, 0xb3, 0xaa, 0x83, 0x71, 0x14, 0x06, 0x31, 0xb6,
0x17, 0xd0, 0x58, 0xd2, 0xdf, 0xe0, 0xe1, 0x79, 0xee, 0x21, 0x89, 0xdc, 0xd4, 0xbf, 0x36, 0xaf,
0x6e, 0x01, 0x4c, 0x6a, 0xd2, 0x88, 0x69, 0x93, 0xce, 0xa2, 0xd7, 0x68, 0x78, 0x80, 0x03, 0x70,
0x3d, 0x79, 0xb0, 0x97, 0xd0, 0x09, 0x36, 0xcd, 0xb8, 0xbb, 0x13, 0x8b, 0xdf, 0xe1, 0x66, 0xc4,
0x6c, 0xac, 0xb1, 0x9a, 0xd4, 0xdc, 0x56, 0x8c, 0x49, 0x8b, 0x83, 0xe7, 0x3f, 0x43, 0x93, 0x4f,
0xf7, 0xc3, 0x7a, 0xb7, 0xf9, 0x12, 0x11, 0x4e, 0xdd, 0x19, 0x91, 0xdc, 0x99, 0xff, 0xc6, 0x42,
0x53, 0xc2, 0xf4, 0x2b, 0x8c, 0x8d, 0x88, 0xc2, 0x68, 0x95, 0x28, 0xfc, 0x14, 0x9d, 0x6e, 0x60,
0xfa, 0x69, 0x2f, 0xa4, 0xce, 0x4b, 0xc4, 0xe1, 0x1e, 0x1a, 0x25, 0x78, 0x17, 0x5c, 0xbd, 0xcc,
0xf1, 0x30, 0x59, 0x6a, 0x62, 0xb2, 0xa4, 0xd4, 0x96, 0x58, 0x39, 0x5a, 0x8c, 0x33, 0xff, 0x1f,
0x0b, 0xbd, 0xdd, 0x0c, 0x3c, 0xea, 0x39, 0x14, 0x3f, 0xf0, 0x7c, 0xbc, 0x1a, 0x1e, 0x05, 0x7e,
0xe8, 0x74, 0x5e, 0x69, 0xe8, 0x1a, 0x68, 0x9c, 0xcf, 0x3e, 0x37, 0xf4, 0xe3, 0xd9, 0xd1, 0x0b,
0xa3, 0x57, 0x26, 0x16, 0xaf, 0xd6, 0x0a, 0xb6, 0xc8, 0x9a, 0xec, 0xe1, 0x26, 0x30, 0x5a, 0x19,
0x77, 0xfe, 0x5f, 0x16, 0x9a, 0x93, 0x5b, 0xb3, 0x15, 0xbd, 0xf2, 0xb6, 0xac, 0xe5, 0xdb, 0x72,
0x79, 0x60, 0x5b, 0x12, 0xff, 0x8a, 0x5a, 0xf2, 0x17, 0x0b, 0xbd, 0xf9, 0xc8, 0x8b, 0x29, 0x9b,
0xea, 0x9b, 0xd0, 0x87, 0xf1, 0x2b, 0x9f, 0xeb, 0xac, 0x9e, 0x37, 0x82, 0x4d, 0x2e, 0xf6, 0x30,
0xff, 0xdf, 0x11, 0x34, 0xbd, 0x11, 0xe1, 0xa0, 0x19, 0xd4, 0xa3, 0xe8, 0xff, 0x32, 0x64, 0xed,
0x87, 0x68, 0xfc, 0xd0, 0xc3, 0x47, 0xdb, 0xdd, 0xb0, 0x83, 0xf9, 0x6c, 0x9b, 0x5a, 0xac, 0x15,
0x46, 0x58, 0xf7, 0xb3, 0xf6, 0xc4, 0xc3, 0x47, 0xeb, 0x61, 0x07, 0xb7, 0x4e, 0x1e, 0xc2, 0x2f,
0x7b, 0x1a, 0x8d, 0x3a, 0x51, 0x04, 0x2b, 0x2d, 0xfb, 0x69, 0x9f, 0x47, 0xaf, 0xfb, 0xa1, 0x7b,
0xc0, 0x16, 0xe8, 0xd7, 0x78, 0xe9, 0x18, 0x7b, 0x6c, 0x76, 0xe6, 0xbf, 0xb6, 0xd0, 0x49, 0x61,
0xc1, 0x3e, 0x87, 0xce, 0x3c, 0x69, 0xae, 0x3d, 0xdd, 0x5e, 0xdf, 0x58, 0x5d, 0xdb, 0x6e, 0x7e,
0xf2, 0xa4, 0xfe, 0xa8, 0xb9, 0x3a, 0xfd, 0x2d, 0xfb, 0x3c, 0x9a, 0xc9, 0x8a, 0xf9, 0xaf, 0x8d,
0x4f, 0x1e, 0x7d, 0x3e, 0x6d, 0xa9, 0x15, 0xad, 0xb5, 0xfa, 0x6a, 0x52, 0x31, 0x62, 0xcf, 0xa2,
0xb3, 0x5a, 0xc5, 0xd3, 0x56, 0xf3, 0xf1, 0xda, 0xf4, 0xa8, 0x2a, 0xb1, 0xd9, 0x5a, 0x63, 0x0f,
0xd3, 0x27, 0x16, 0xff, 0xf1, 0x03, 0x84, 0x1a, 0x49, 0x4b, 0xeb, 0x9b, 0x4d, 0xdb, 0x45, 0xa7,
0xe4, 0xed, 0xc0, 0xbe, 0x52, 0x18, 0x8a, 0x82, 0x2d, 0x6d, 0xee, 0xaa, 0x01, 0x12, 0xc6, 0xdb,
0xa7, 0x68, 0x2c, 0x59, 0x51, 0xed, 0xf9, 0x42, 0x92, 0xb2, 0x92, 0xcf, 0x5d, 0x1c, 0x8a, 0x01,
0x93, 0xbf, 0xb3, 0xd0, 0x4c, 0x03, 0x07, 0x98, 0x38, 0x14, 0xd7, 0xa3, 0x68, 0xd3, 0x89, 0xe3,
0xa3, 0x90, 0x74, 0xec, 0x7b, 0x9c, 0xcc, 0xd2, 0xce, 0x9a, 0x9c, 0x97, 0xa6, 0x66, 0x0a, 0x38,
0x42, 0xf7, 0x83, 0xe3, 0x50, 0xc1, 0x9d, 0x5f, 0x58, 0x68, 0x9a, 0xcf, 0xb7, 0xac, 0x2e, 0xb6,
0xef, 0x96, 0x18, 0xd4, 0x09, 0xc2, 0x91, 0xf7, 0x2a, 0xf3, 0xc0, 0x8b, 0x3f, 0x5a, 0xe8, 0x5c,
0x33, 0x38, 0x74, 0x7c, 0xaf, 0xa3, 0x85, 0xe5, 0x7e, 0x89, 0xc9, 0x42, 0x96, 0xf0, 0xe7, 0xc3,
0xe3, 0x91, 0xc1, 0xa9, 0x9f, 0xa0, 0xa9, 0x06, 0x96, 0xfd, 0xb5, 0x6f, 0x97, 0x06, 0x9a, 0x16,
0x78, 0x71, 0xa7, 0x22, 0x0b, 0xe4, 0xbf, 0x42, 0xa7, 0x57, 0x08, 0x76, 0x28, 0x5e, 0x09, 0x03,
0xea, 0x78, 0x01, 0x26, 0xa0, 0x3f, 0x70, 0xbd, 0xd0, 0xe0, 0xaa, 0xbe, 0x39, 0x0b, 0xf4, 0x7d,
0x34, 0xfe, 0x38, 0xec, 0xb9, 0xfb, 0x6c, 0xbd, 0xb6, 0x6b, 0xc3, 0x6d, 0xa4, 0x40, 0xa1, 0xb9,
0x60, 0x8c, 0x07, 0x35, 0x17, 0x8d, 0xad, 0x62, 0x1f, 0x53, 0x6c, 0x5f, 0x1b, 0x4e, 0x4d, 0x50,
0x42, 0xe7, 0xba, 0x19, 0x18, 0x44, 0x76, 0xd1, 0xeb, 0x0d, 0x4c, 0x37, 0x1d, 0xba, 0x6f, 0x97,
0x10, 0x01, 0x26, 0x64, 0x6e, 0x18, 0xa2, 0x41, 0xe7, 0x0b, 0x74, 0x52, 0x64, 0x37, 0xf6, 0x77,
0x0b, 0x17, 0x05, 0x2d, 0xf9, 0x99, 0xab, 0x95, 0x0a, 0x00, 0x1c, 0x14, 0xbe, 0xb6, 0xd0, 0xd9,
0xa2, 0xf4, 0x05, 0x96, 0x91, 0x81, 0x86, 0x8a, 0x53, 0x9e, 0xc4, 0x87, 0x5b, 0x85, 0x9e, 0x0e,
0x4d, 0x92, 0xbe, 0x42, 0x76, 0x3e, 0xed, 0xb0, 0xdf, 0x33, 0xf7, 0x41, 0x24, 0x2a, 0xf2, 0xa8,
0x19, 0xe6, 0x81, 0x96, 0xd8, 0xb0, 0xc5, 0x94, 0x2d, 0x2a, 0xe9, 0xe8, 0x6d, 0x53, 0x82, 0x9d,
0xae, 0xfd, 0xfe, 0x70, 0x0f, 0x0a, 0x28, 0xc2, 0x85, 0x7b, 0xc7, 0x60, 0x26, 0xce, 0xdc, 0xb4,
0xec, 0x17, 0x68, 0x52, 0x01, 0xd8, 0x8b, 0x15, 0xac, 0x09, 0x0f, 0x96, 0x2a, 0x71, 0x20, 0x10,
0x3f, 0x87, 0x65, 0x9c, 0xc5, 0xe8, 0x09, 0x26, 0xfc, 0x85, 0xda, 0xbe, 0x53, 0x6e, 0x49, 0xc6,
0x0b, 0x07, 0xee, 0x56, 0xa5, 0x81, 0x0f, 0xbf, 0xb4, 0xd0, 0x19, 0x56, 0xd9, 0xc2, 0x6e, 0xdf,
0xf5, 0x31, 0x74, 0x85, 0x81, 0x35, 0x85, 0xa0, 0xee, 0x25, 0x55, 0x78, 0x69, 0x37, 0x10, 0x34,
0x21, 0x55, 0xdb, 0x37, 0x8d, 0x2d, 0xa9, 0x33, 0xc1, 0x8c, 0x01, 0x8d, 0xff, 0x21, 0x3a, 0xb1,
0x1e, 0x1e, 0x62, 0xfb, 0xea, 0x70, 0x2a, 0xc3, 0x08, 0x95, 0x77, 0x4d, 0xa0, 0x60, 0xbe, 0x87,
0x4e, 0x6d, 0xf6, 0xc8, 0x1e, 0x16, 0x6d, 0x2a, 0xf1, 0x50, 0xc6, 0x0a, 0xb9, 0xc5, 0x2a, 0x14,
0x90, 0xfd, 0x95, 0x85, 0xec, 0x16, 0x66, 0x1c, 0x2c, 0x75, 0x79, 0xd9, 0x04, 0xcf, 0x33, 0x84,
0x0f, 0xef, 0x57, 0x27, 0xe6, 0x3d, 0x01, 0x27, 0x9b, 0x14, 0x77, 0x0d, 0x3d, 0x91, 0x18, 0xd5,
0x3c, 0x51, 0x88, 0x59, 0x4f, 0xb3, 0x97, 0x8c, 0xb2, 0x9e, 0x66, 0x18, 0xc3, 0x9e, 0x4e, 0xa0,
0x60, 0xfe, 0x05, 0x9a, 0x4c, 0x76, 0xe4, 0x76, 0xbf, 0xeb, 0x7b, 0xc1, 0x41, 0xd9, 0x1a, 0xa2,
0x80, 0x0d, 0xd7, 0x10, 0x8d, 0x03, 0xca, 0xbf, 0xb7, 0xd0, 0xd9, 0x36, 0xa6, 0x75, 0xb2, 0xe3,
0x51, 0xe2, 0x90, 0xfe, 0x3a, 0xa6, 0x4e, 0xc7, 0xa1, 0x4e, 0xd9, 0x9e, 0x52, 0xc4, 0x51, 0x53,
0xd3, 0x8a, 0x54, 0xf0, 0xe7, 0x4f, 0x16, 0x7a, 0x63, 0x2b, 0x88, 0x8b, 0x3c, 0xba, 0x3f, 0xdc,
0x6c, 0x31, 0x4b, 0xcd, 0x0a, 0x2b, 0x93, 0xb3, 0x1c, 0xa2, 0x8d, 0xe9, 0xa3, 0xd0, 0x3d, 0x28,
0xcb, 0x21, 0x00, 0x66, 0x98, 0x43, 0xa4, 0x68, 0x25, 0x57, 0x31, 0xd1, 0x69, 0x54, 0xd2, 0x69,
0x68, 0x3a, 0x04, 0x4d, 0xb4, 0xf0, 0x2e, 0xc1, 0xf1, 0x3e, 0xd7, 0xba, 0x59, 0xfa, 0x4a, 0x2a,
0xa0, 0x86, 0x8b, 0xa5, 0xc2, 0xc8, 0x92, 0xbd, 0xad, 0x80, 0xbd, 0x5d, 0x96, 0x25, 0x7b, 0x09,
0xca, 0x30, 0xd9, 0x13, 0x60, 0x10, 0x09, 0x11, 0x4a, 0xc6, 0xf9, 0xc7, 0x61, 0x17, 0xdb, 0x0b,
0x26, 0x33, 0x82, 0x21, 0x85, 0xd8, 0x4d, 0x73, 0x82, 0xb4, 0x44, 0xc1, 0xcc, 0x4a, 0x58, 0xed,
0xc8, 0x71, 0x71, 0xd9, 0x12, 0x95, 0x67, 0x18, 0x2e, 0x51, 0x45, 0xc4, 0x2c, 0x3b, 0xe4, 0x3b,
0xb1, 0x5c, 0x19, 0x9b, 0xec, 0xc4, 0x0a, 0xa1, 0xc2, 0x4e, 0xac, 0xf1, 0xa4, 0x80, 0x6c, 0x45,
0x9d, 0x8a, 0x01, 0xc9, 0x33, 0x0c, 0x03, 0x52, 0x44, 0x94, 0x3c, 0x49, 0xde, 0x05, 0xaa, 0x78,
0x92, 0x67, 0x18, 0x7a, 0x52, 0x44, 0x04, 0x4f, 0xb6, 0xd1, 0x78, 0x7a, 0x3c, 0x63, 0x5f, 0x32,
0x3a, 0xbe, 0x99, 0x4b, 0x26, 0x89, 0x13, 0x45, 0x79, 0x25, 0x09, 0x0b, 0x02, 0x5f, 0xa2, 0x09,
0x18, 0x19, 0xfb, 0x0e, 0xc1, 0x22, 0x07, 0x4c, 0x3e, 0x4d, 0xd4, 0x94, 0x0f, 0x1d, 0xfa, 0x48,
0x62, 0x78, 0x2d, 0x07, 0x34, 0xa7, 0x65, 0xea, 0x2d, 0xdc, 0x0d, 0x0f, 0x2b, 0xa8, 0x4b, 0xf8,
0x2a, 0xea, 0x0a, 0x0d, 0xd4, 0x63, 0xfe, 0xde, 0x95, 0x48, 0x2f, 0x1a, 0xd8, 0x10, 0x60, 0x6d,
0xdb, 0x34, 0xe4, 0x80, 0x68, 0x1f, 0x21, 0x3e, 0x05, 0x58, 0x61, 0x2c, 0x5e, 0xd1, 0x87, 0x9a,
0xc8, 0xe0, 0xda, 0x2b, 0xba, 0x31, 0x2b, 0x8b, 0x36, 0x0c, 0x7a, 0xe3, 0x68, 0x4b, 0xf8, 0x2a,
0xd1, 0x56, 0x68, 0xa0, 0xfe, 0x07, 0x0b, 0xd9, 0x90, 0x0a, 0x63, 0xef, 0x10, 0x77, 0x20, 0x02,
0x1f, 0x1a, 0xb6, 0x45, 0xa5, 0x09, 0x67, 0x3e, 0x3a, 0x26, 0x1b, 0x7c, 0xfa, 0xb3, 0x85, 0x66,
0x12, 0x5f, 0x15, 0x80, 0xfd, 0x91, 0x71, 0x1b, 0x15, 0x9e, 0xf0, 0xea, 0x7b, 0xc7, 0xa5, 0x83,
0x5b, 0xbf, 0xb5, 0xd0, 0x74, 0x03, 0xab, 0x4e, 0xdb, 0x1f, 0x98, 0x8d, 0xb6, 0x42, 0x87, 0xee,
0x1f, 0x8b, 0x0b, 0xde, 0x7c, 0x8e, 0xc6, 0xda, 0x98, 0x3e, 0xc4, 0x7d, 0xfb, 0x1d, 0x6e, 0x46,
0xfa, 0xaa, 0x2a, 0xa7, 0x23, 0x0f, 0x71, 0x5f, 0xc8, 0x5d, 0x2e, 0xc5, 0x65, 0xa6, 0x1b, 0x65,
0xa6, 0x1b, 0x86, 0xa6, 0x1b, 0xaa, 0xe9, 0x2f, 0xd1, 0x99, 0x64, 0xc5, 0xd9, 0xec, 0xed, 0xf8,
0x9e, 0x5b, 0x34, 0xcb, 0x59, 0x3a, 0xab, 0x2d, 0x4f, 0x12, 0xb8, 0x78, 0x96, 0x97, 0x71, 0x32,
0xf5, 0x64, 0xc5, 0x31, 0x54, 0xcf, 0x81, 0x0d, 0xd4, 0x0b, 0x38, 0xe9, 0xc2, 0x36, 0xd5, 0xc0,
0x54, 0x96, 0x5e, 0x18, 0x6c, 0x46, 0x45, 0x6a, 0xf9, 0x8c, 0x09, 0x01, 0x44, 0x7f, 0x6d, 0xa1,
0x73, 0x6a, 0xd5, 0x72, 0xff, 0x31, 0xff, 0xf0, 0x79, 0xd7, 0xd4, 0x16, 0x10, 0xb4, 0x4c, 0xa2,
0x02, 0x2f, 0x5d, 0x63, 0xf9, 0xe9, 0x86, 0x84, 0x88, 0xc5, 0x2b, 0x70, 0x91, 0x31, 0x1d, 0xab,
0xbd, 0x02, 0x9b, 0x51, 0xb2, 0x8e, 0x4f, 0x66, 0xb6, 0x61, 0xc7, 0xe7, 0xc0, 0x06, 0x1d, 0x5f,
0xc0, 0x01, 0xf5, 0xe7, 0x68, 0x2a, 0x19, 0x93, 0x1b, 0x2b, 0xeb, 0x89, 0x74, 0x4d, 0x31, 0x13,
0xba, 0x5d, 0x6d, 0xf0, 0x0a, 0xa0, 0x76, 0x12, 0x6b, 0x80, 0xcf, 0x24, 0x93, 0x81, 0x68, 0x20,
0xa9, 0x02, 0xcb, 0x25, 0x75, 0x3c, 0x48, 0xee, 0xa3, 0x89, 0x06, 0xa6, 0xa9, 0xde, 0xb5, 0x81,
0x7c, 0x09, 0xa5, 0xbd, 0x14, 0x94, 0x81, 0xd3, 0x33, 0x7d, 0x5b, 0x2a, 0x16, 0xe3, 0x79, 0xd1,
0xc4, 0x86, 0x36, 0x96, 0x97, 0x2a, 0x71, 0x40, 0x3e, 0x48, 0x0e, 0x08, 0x45, 0x75, 0x6c, 0xdf,
0x18, 0x68, 0x45, 0xc1, 0x69, 0xc7, 0xc4, 0xe5, 0xf0, 0xac, 0x2f, 0x93, 0xb1, 0x65, 0xd0, 0x97,
0x2a, 0xb0, 0xbc, 0x2f, 0x75, 0x7c, 0x76, 0x0a, 0x78, 0x4e, 0xde, 0xa0, 0xb3, 0xb6, 0xde, 0x19,
0xea, 0x7c, 0x0e, 0x5f, 0x9c, 0x9e, 0x18, 0xd0, 0xc0, 0x91, 0xdf, 0x58, 0xe8, 0x0d, 0x75, 0x4f,
0x4e, 0x83, 0x70, 0xb7, 0xa4, 0x51, 0x3a, 0xa1, 0x78, 0xfd, 0x32, 0xe1, 0x81, 0x2f, 0x3f, 0xe3,
0x1f, 0xfd, 0x72, 0xce, 0xda, 0x43, 0x07, 0xd1, 0x20, 0x2f, 0x6e, 0x57, 0x23, 0x81, 0x0b, 0x87,
0xfc, 0xc6, 0x45, 0x3d, 0x8a, 0xd2, 0xaf, 0xea, 0xf0, 0xae, 0xcf, 0xde, 0x2b, 0xc4, 0xbd, 0x36,
0xfd, 0x9b, 0x54, 0xf6, 0x01, 0x5e, 0x7e, 0xd7, 0x37, 0x63, 0x64, 0x5b, 0x57, 0xbd, 0xd3, 0x91,
0xaa, 0x60, 0xeb, 0x2a, 0x34, 0xa2, 0x22, 0xd5, 0xad, 0xcb, 0x88, 0xa0, 0xee, 0x17, 0x4a, 0x6b,
0x87, 0xf8, 0xae, 0x63, 0xd5, 0xfd, 0xc2, 0x90, 0x92, 0xa5, 0x7a, 0x6f, 0xf0, 0x54, 0xbd, 0x17,
0x45, 0x21, 0xa1, 0xb8, 0xb3, 0xee, 0x75, 0xf1, 0xe3, 0x7e, 0x84, 0x63, 0x78, 0xdd, 0x1c, 0x68,
0x2e, 0xcf, 0x50, 0x5f, 0x37, 0x2b, 0x11, 0xc1, 0x9b, 0x6f, 0x2c, 0x74, 0xa1, 0x81, 0xe9, 0x2a,
0xde, 0x75, 0x7a, 0xbe, 0xec, 0xf0, 0x83, 0x90, 0x08, 0xb4, 0x5d, 0x1f, 0xda, 0xab, 0x43, 0xb9,
0xc2, 0xc3, 0xe5, 0x97, 0x31, 0x21, 0xf9, 0xda, 0x7e, 0x09, 0x5f, 0xdb, 0x2f, 0xef, 0x6b, 0xdb,
0xd4, 0xd7, 0x2f, 0xf8, 0xe9, 0xdc, 0x56, 0x8c, 0x09, 0x9c, 0x03, 0x17, 0xdf, 0x78, 0x02, 0x8c,
0x7a, 0x0e, 0x5c, 0x02, 0x4d, 0x4f, 0xfc, 0xa7, 0xa0, 0x68, 0xb9, 0xbf, 0xe2, 0x3b, 0x5e, 0x17,
0xa6, 0xeb, 0x50, 0x36, 0x40, 0xd5, 0xe9, 0x6a, 0xc6, 0x48, 0x8f, 0x03, 0x27, 0xa1, 0xa6, 0x41,
0xc2, 0x5e, 0x14, 0xc3, 0x6c, 0x1d, 0x6a, 0x23, 0x41, 0xaa, 0xb3, 0xd5, 0x88, 0x90, 0x1e, 0x75,
0x8e, 0x3f, 0xf0, 0x82, 0x0e, 0xab, 0x89, 0x61, 0xf3, 0x2f, 0xa6, 0xa7, 0x28, 0x75, 0xf3, 0x2f,
0x05, 0x83, 0x0e, 0xe6, 0xc7, 0x03, 0x5c, 0x5c, 0x97, 0xe1, 0x97, 0x70, 0x65, 0x37, 0x39, 0x6a,
0x80, 0xcc, 0x20, 0x30, 0xc8, 0xfc, 0x88, 0xaf, 0xb4, 0xbc, 0x4c, 0x74, 0xdd, 0xa2, 0x89, 0x01,
0xad, 0xf3, 0x96, 0x2a, 0x71, 0x40, 0xfb, 0x00, 0xa1, 0x06, 0xa6, 0xeb, 0xb8, 0xbb, 0xc3, 0x62,
0x79, 0xa3, 0xc4, 0x04, 0xe0, 0xd4, 0xec, 0xc2, 0x00, 0x9e, 0xa6, 0x6d, 0xe3, 0x1f, 0x3b, 0x71,
0x52, 0x6a, 0x0f, 0x8d, 0x51, 0x0a, 0x53, 0x0f, 0xa9, 0xcb, 0xd1, 0x59, 0xb3, 0x58, 0x77, 0xc2,
0x90, 0x1c, 0x4a, 0xce, 0x70, 0x46, 0xcd, 0x92, 0xe1, 0xe9, 0x17, 0x98, 0x33, 0xb9, 0x1b, 0x68,
0xb0, 0x53, 0xf3, 0x4b, 0x1c, 0xc5, 0x7b, 0x81, 0x7a, 0x5f, 0x4d, 0x56, 0xd6, 0xcf, 0xf7, 0x06,
0x5f, 0x6f, 0x4b, 0xce, 0xfc, 0xf9, 0x79, 0x75, 0xf9, 0x99, 0xbf, 0x7c, 0x58, 0x7d, 0xc3, 0x10,
0x9d, 0x7e, 0xb6, 0x4f, 0xaf, 0x20, 0x35, 0xf9, 0xbd, 0x6e, 0x39, 0x0d, 0x66, 0x09, 0x45, 0x72,
0xdb, 0x3b, 0x77, 0x81, 0x48, 0x02, 0xab, 0xa3, 0xd4, 0x94, 0x93, 0xae, 0x6d, 0x7c, 0x7b, 0x96,
0xaa, 0xc4, 0x3a, 0x53, 0x60, 0x48, 0x47, 0xaa, 0xeb, 0x8c, 0x11, 0x21, 0xbd, 0xd1, 0x32, 0xf9,
0x20, 0x24, 0x47, 0x0e, 0xe9, 0x24, 0xd5, 0x10, 0xe4, 0x02, 0x13, 0x0a, 0x4c, 0x0d, 0x72, 0x39,
0x1a, 0xd4, 0x3c, 0x74, 0xaa, 0xee, 0xba, 0x38, 0x02, 0x5f, 0x60, 0xc5, 0x29, 0xa0, 0xcb, 0x28,
0x75, 0xc5, 0x29, 0x05, 0xa7, 0x8b, 0x36, 0xcf, 0xed, 0x78, 0x15, 0xe6, 0x8b, 0x1e, 0xe4, 0xf9,
0x85, 0xfd, 0xa2, 0x00, 0xd5, 0x3c, 0xdf, 0x04, 0x9f, 0xcd, 0x12, 0x36, 0x77, 0xe4, 0x3a, 0x91,
0x51, 0x16, 0x85, 0x48, 0x87, 0xaa, 0x5b, 0x94, 0x19, 0x03, 0x94, 0x7f, 0x2c, 0xce, 0xf2, 0x95,
0x06, 0x0f, 0x34, 0x94, 0xc7, 0xaa, 0xe9, 0x9d, 0x21, 0x25, 0x3b, 0x0e, 0x68, 0xc6, 0x62, 0xe6,
0xd6, 0x7d, 0x3f, 0x3c, 0xc2, 0x1d, 0x69, 0xe2, 0xe4, 0x2f, 0xbb, 0xe8, 0xe0, 0xfc, 0xc4, 0x31,
0xe1, 0x28, 0x49, 0x7c, 0x33, 0xd8, 0x0d, 0x97, 0xfb, 0xab, 0x61, 0xd7, 0xf1, 0x02, 0x29, 0xe4,
0x45, 0xd3, 0x5e, 0x86, 0xe6, 0x43, 0x5e, 0xce, 0xd0, 0xf2, 0x69, 0xdf, 0xd7, 0xf3, 0xe9, 0x42,
0x33, 0x3a, 0x36, 0x1f, 0x70, 0x03, 0x0a, 0x48, 0x1f, 0x89, 0x8f, 0x6a, 0x1b, 0x2b, 0xeb, 0x2b,
0x21, 0xc1, 0xf2, 0xf1, 0x17, 0xb3, 0xe4, 0x86, 0x04, 0xe7, 0x8f, 0x34, 0x52, 0x64, 0x7e, 0xb5,
0x28, 0x25, 0x64, 0xc2, 0xe9, 0x2b, 0x6e, 0xa9, 0x70, 0x1e, 0x59, 0x22, 0x5c, 0x44, 0xc8, 0x84,
0x93, 0x01, 0x68, 0x22, 0x9c, 0x47, 0x96, 0x08, 0x17, 0x11, 0xd2, 0x6f, 0x53, 0x70, 0xd8, 0xf4,
0x98, 0x38, 0x41, 0xbc, 0x8b, 0x09, 0x7c, 0xa0, 0xa2, 0x2f, 0xb4, 0x78, 0x89, 0x7a, 0x21, 0xf5,
0x4e, 0x19, 0x2c, 0x4d, 0x18, 0xce, 0x34, 0x30, 0x15, 0xc5, 0xc9, 0x55, 0x6d, 0xb8, 0xb8, 0x2b,
0x91, 0x73, 0x10, 0xf5, 0xe2, 0xee, 0x70, 0xa4, 0xd4, 0x14, 0x27, 0x70, 0xb1, 0x3f, 0xa4, 0x29,
0x4a, 0xfd, 0xe0, 0xa6, 0x68, 0x30, 0x10, 0x78, 0x96, 0x9c, 0xe4, 0x88, 0xf2, 0x18, 0xee, 0xf9,
0x49, 0x44, 0xa5, 0x5a, 0x98, 0xbf, 0x54, 0x82, 0xca, 0xac, 0xb7, 0x30, 0x25, 0xfd, 0xd4, 0xfb,
0x9c, 0x75, 0xa5, 0x7a, 0xa0, 0x75, 0x0d, 0x05, 0xd6, 0x29, 0x3a, 0xbd, 0xb2, 0x8f, 0xdd, 0x83,
0xcd, 0xf4, 0xcf, 0x57, 0x30, 0xba, 0xa4, 0x7f, 0x63, 0x65, 0xed, 0x57, 0x91, 0xea, 0xe8, 0x32,
0x22, 0x24, 0xaa, 0xcb, 0x01, 0x3a, 0xef, 0x86, 0xdd, 0xa2, 0x8c, 0x68, 0xf9, 0xb4, 0xb8, 0xd7,
0x1d, 0x79, 0xfc, 0x3f, 0x01, 0x9b, 0xd6, 0xf7, 0xa7, 0x00, 0x03, 0x90, 0xbf, 0x8d, 0x8c, 0xae,
0x34, 0x3e, 0xfb, 0xfb, 0xc8, 0xcc, 0x4a, 0xbc, 0x54, 0x03, 0x74, 0xed, 0xc9, 0xad, 0x65, 0x56,
0xf7, 0x6f, 0x5e, 0xfa, 0x0c, 0x4a, 0x9f, 0x41, 0xe9, 0xce, 0x18, 0xff, 0x53, 0xc1, 0xd2, 0xff,
0x02, 0x00, 0x00, 0xff, 0xff, 0xfc, 0xc4, 0x74, 0x60, 0x9b, 0x38, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@@ -1060,6 +1064,9 @@ type GatewayAPIClient interface {
// Gets share information for a single share.
// MUST return CODE_NOT_FOUND if the share reference does not exist.
GetOCMShare(ctx context.Context, in *v1beta19.GetOCMShareRequest, opts ...grpc.CallOption) (*v1beta19.GetOCMShareResponse, error)
// Gets share information for a single share by its unlisted token.
// MUST return CODE_NOT_FOUND if the share does not exist.
GetOCMShareByToken(ctx context.Context, in *v1beta19.GetOCMShareByTokenRequest, opts ...grpc.CallOption) (*v1beta19.GetOCMShareByTokenResponse, error)
// List the shares the authproviderenticated principal has created,
// both as owner and creator. If a filter is specified, only
// shares satisfying the filter MUST be returned.
@@ -1115,6 +1122,8 @@ type GatewayAPIClient interface {
GetHome(ctx context.Context, in *v1beta13.GetHomeRequest, opts ...grpc.CallOption) (*v1beta13.GetHomeResponse, error)
// Generates a new token for the user with a validity of 24 hours.
GenerateInviteToken(ctx context.Context, in *v1beta113.GenerateInviteTokenRequest, opts ...grpc.CallOption) (*v1beta113.GenerateInviteTokenResponse, error)
// Lists the valid tokens generated by the user.
ListInviteTokens(ctx context.Context, in *v1beta113.ListInviteTokensRequest, opts ...grpc.CallOption) (*v1beta113.ListInviteTokensResponse, error)
// Forwards a received invite to the sync'n'share system provider.
ForwardInvite(ctx context.Context, in *v1beta113.ForwardInviteRequest, opts ...grpc.CallOption) (*v1beta113.ForwardInviteResponse, error)
// Completes an invitation acceptance.
@@ -1123,6 +1132,8 @@ type GatewayAPIClient interface {
GetAcceptedUser(ctx context.Context, in *v1beta113.GetAcceptedUserRequest, opts ...grpc.CallOption) (*v1beta113.GetAcceptedUserResponse, error)
// Finds users who accepted invite tokens by their attributes.
FindAcceptedUsers(ctx context.Context, in *v1beta113.FindAcceptedUsersRequest, opts ...grpc.CallOption) (*v1beta113.FindAcceptedUsersResponse, error)
// Delete a previously accepted remote user, that is unfriend that user.
DeleteAcceptedUser(ctx context.Context, in *v1beta113.DeleteAcceptedUserRequest, opts ...grpc.CallOption) (*v1beta113.DeleteAcceptedUserResponse, error)
// Check if a given system provider is registered in the mesh or not.
// MUST return CODE_UNAUTHENTICATED if the system is not registered
IsProviderAllowed(ctx context.Context, in *v1beta114.IsProviderAllowedRequest, opts ...grpc.CallOption) (*v1beta114.IsProviderAllowedResponse, error)
@@ -1131,8 +1142,12 @@ type GatewayAPIClient interface {
GetInfoByDomain(ctx context.Context, in *v1beta114.GetInfoByDomainRequest, opts ...grpc.CallOption) (*v1beta114.GetInfoByDomainResponse, error)
// Get the information of all the providers registered in the mesh.
ListAllProviders(ctx context.Context, in *v1beta114.ListAllProvidersRequest, opts ...grpc.CallOption) (*v1beta114.ListAllProvidersResponse, error)
// Creates a new ocm share.
// Creates a new OCM share.
CreateOCMCoreShare(ctx context.Context, in *v1beta115.CreateOCMCoreShareRequest, opts ...grpc.CallOption) (*v1beta115.CreateOCMCoreShareResponse, error)
// Updates an OCM share.
UpdateOCMCoreShare(ctx context.Context, in *v1beta115.UpdateOCMCoreShareRequest, opts ...grpc.CallOption) (*v1beta115.UpdateOCMCoreShareResponse, error)
// Deletes an OCM share.
DeleteOCMCoreShare(ctx context.Context, in *v1beta115.DeleteOCMCoreShareRequest, opts ...grpc.CallOption) (*v1beta115.DeleteOCMCoreShareResponse, error)
// Requests creation of a transfer.
CreateTransfer(ctx context.Context, in *v1beta116.CreateTransferRequest, opts ...grpc.CallOption) (*v1beta116.CreateTransferResponse, error)
// Requests a transfer status.
@@ -1696,6 +1711,15 @@ func (c *gatewayAPIClient) GetOCMShare(ctx context.Context, in *v1beta19.GetOCMS
return out, nil
}
func (c *gatewayAPIClient) GetOCMShareByToken(ctx context.Context, in *v1beta19.GetOCMShareByTokenRequest, opts ...grpc.CallOption) (*v1beta19.GetOCMShareByTokenResponse, error) {
out := new(v1beta19.GetOCMShareByTokenResponse)
err := c.cc.Invoke(ctx, "/cs3.gateway.v1beta1.GatewayAPI/GetOCMShareByToken", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *gatewayAPIClient) ListOCMShares(ctx context.Context, in *v1beta19.ListOCMSharesRequest, opts ...grpc.CallOption) (*v1beta19.ListOCMSharesResponse, error) {
out := new(v1beta19.ListOCMSharesResponse)
err := c.cc.Invoke(ctx, "/cs3.gateway.v1beta1.GatewayAPI/ListOCMShares", in, out, opts...)
@@ -1903,6 +1927,15 @@ func (c *gatewayAPIClient) GenerateInviteToken(ctx context.Context, in *v1beta11
return out, nil
}
func (c *gatewayAPIClient) ListInviteTokens(ctx context.Context, in *v1beta113.ListInviteTokensRequest, opts ...grpc.CallOption) (*v1beta113.ListInviteTokensResponse, error) {
out := new(v1beta113.ListInviteTokensResponse)
err := c.cc.Invoke(ctx, "/cs3.gateway.v1beta1.GatewayAPI/ListInviteTokens", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *gatewayAPIClient) ForwardInvite(ctx context.Context, in *v1beta113.ForwardInviteRequest, opts ...grpc.CallOption) (*v1beta113.ForwardInviteResponse, error) {
out := new(v1beta113.ForwardInviteResponse)
err := c.cc.Invoke(ctx, "/cs3.gateway.v1beta1.GatewayAPI/ForwardInvite", in, out, opts...)
@@ -1939,6 +1972,15 @@ func (c *gatewayAPIClient) FindAcceptedUsers(ctx context.Context, in *v1beta113.
return out, nil
}
func (c *gatewayAPIClient) DeleteAcceptedUser(ctx context.Context, in *v1beta113.DeleteAcceptedUserRequest, opts ...grpc.CallOption) (*v1beta113.DeleteAcceptedUserResponse, error) {
out := new(v1beta113.DeleteAcceptedUserResponse)
err := c.cc.Invoke(ctx, "/cs3.gateway.v1beta1.GatewayAPI/DeleteAcceptedUser", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *gatewayAPIClient) IsProviderAllowed(ctx context.Context, in *v1beta114.IsProviderAllowedRequest, opts ...grpc.CallOption) (*v1beta114.IsProviderAllowedResponse, error) {
out := new(v1beta114.IsProviderAllowedResponse)
err := c.cc.Invoke(ctx, "/cs3.gateway.v1beta1.GatewayAPI/IsProviderAllowed", in, out, opts...)
@@ -1975,6 +2017,24 @@ func (c *gatewayAPIClient) CreateOCMCoreShare(ctx context.Context, in *v1beta115
return out, nil
}
func (c *gatewayAPIClient) UpdateOCMCoreShare(ctx context.Context, in *v1beta115.UpdateOCMCoreShareRequest, opts ...grpc.CallOption) (*v1beta115.UpdateOCMCoreShareResponse, error) {
out := new(v1beta115.UpdateOCMCoreShareResponse)
err := c.cc.Invoke(ctx, "/cs3.gateway.v1beta1.GatewayAPI/UpdateOCMCoreShare", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *gatewayAPIClient) DeleteOCMCoreShare(ctx context.Context, in *v1beta115.DeleteOCMCoreShareRequest, opts ...grpc.CallOption) (*v1beta115.DeleteOCMCoreShareResponse, error) {
out := new(v1beta115.DeleteOCMCoreShareResponse)
err := c.cc.Invoke(ctx, "/cs3.gateway.v1beta1.GatewayAPI/DeleteOCMCoreShare", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *gatewayAPIClient) CreateTransfer(ctx context.Context, in *v1beta116.CreateTransferRequest, opts ...grpc.CallOption) (*v1beta116.CreateTransferResponse, error) {
out := new(v1beta116.CreateTransferResponse)
err := c.cc.Invoke(ctx, "/cs3.gateway.v1beta1.GatewayAPI/CreateTransfer", in, out, opts...)
@@ -2224,6 +2284,9 @@ type GatewayAPIServer interface {
// Gets share information for a single share.
// MUST return CODE_NOT_FOUND if the share reference does not exist.
GetOCMShare(context.Context, *v1beta19.GetOCMShareRequest) (*v1beta19.GetOCMShareResponse, error)
// Gets share information for a single share by its unlisted token.
// MUST return CODE_NOT_FOUND if the share does not exist.
GetOCMShareByToken(context.Context, *v1beta19.GetOCMShareByTokenRequest) (*v1beta19.GetOCMShareByTokenResponse, error)
// List the shares the authproviderenticated principal has created,
// both as owner and creator. If a filter is specified, only
// shares satisfying the filter MUST be returned.
@@ -2279,6 +2342,8 @@ type GatewayAPIServer interface {
GetHome(context.Context, *v1beta13.GetHomeRequest) (*v1beta13.GetHomeResponse, error)
// Generates a new token for the user with a validity of 24 hours.
GenerateInviteToken(context.Context, *v1beta113.GenerateInviteTokenRequest) (*v1beta113.GenerateInviteTokenResponse, error)
// Lists the valid tokens generated by the user.
ListInviteTokens(context.Context, *v1beta113.ListInviteTokensRequest) (*v1beta113.ListInviteTokensResponse, error)
// Forwards a received invite to the sync'n'share system provider.
ForwardInvite(context.Context, *v1beta113.ForwardInviteRequest) (*v1beta113.ForwardInviteResponse, error)
// Completes an invitation acceptance.
@@ -2287,6 +2352,8 @@ type GatewayAPIServer interface {
GetAcceptedUser(context.Context, *v1beta113.GetAcceptedUserRequest) (*v1beta113.GetAcceptedUserResponse, error)
// Finds users who accepted invite tokens by their attributes.
FindAcceptedUsers(context.Context, *v1beta113.FindAcceptedUsersRequest) (*v1beta113.FindAcceptedUsersResponse, error)
// Delete a previously accepted remote user, that is unfriend that user.
DeleteAcceptedUser(context.Context, *v1beta113.DeleteAcceptedUserRequest) (*v1beta113.DeleteAcceptedUserResponse, error)
// Check if a given system provider is registered in the mesh or not.
// MUST return CODE_UNAUTHENTICATED if the system is not registered
IsProviderAllowed(context.Context, *v1beta114.IsProviderAllowedRequest) (*v1beta114.IsProviderAllowedResponse, error)
@@ -2295,8 +2362,12 @@ type GatewayAPIServer interface {
GetInfoByDomain(context.Context, *v1beta114.GetInfoByDomainRequest) (*v1beta114.GetInfoByDomainResponse, error)
// Get the information of all the providers registered in the mesh.
ListAllProviders(context.Context, *v1beta114.ListAllProvidersRequest) (*v1beta114.ListAllProvidersResponse, error)
// Creates a new ocm share.
// Creates a new OCM share.
CreateOCMCoreShare(context.Context, *v1beta115.CreateOCMCoreShareRequest) (*v1beta115.CreateOCMCoreShareResponse, error)
// Updates an OCM share.
UpdateOCMCoreShare(context.Context, *v1beta115.UpdateOCMCoreShareRequest) (*v1beta115.UpdateOCMCoreShareResponse, error)
// Deletes an OCM share.
DeleteOCMCoreShare(context.Context, *v1beta115.DeleteOCMCoreShareRequest) (*v1beta115.DeleteOCMCoreShareResponse, error)
// Requests creation of a transfer.
CreateTransfer(context.Context, *v1beta116.CreateTransferRequest) (*v1beta116.CreateTransferResponse, error)
// Requests a transfer status.
@@ -2480,6 +2551,9 @@ func (*UnimplementedGatewayAPIServer) RemoveOCMShare(ctx context.Context, req *v
func (*UnimplementedGatewayAPIServer) GetOCMShare(ctx context.Context, req *v1beta19.GetOCMShareRequest) (*v1beta19.GetOCMShareResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetOCMShare not implemented")
}
func (*UnimplementedGatewayAPIServer) GetOCMShareByToken(ctx context.Context, req *v1beta19.GetOCMShareByTokenRequest) (*v1beta19.GetOCMShareByTokenResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetOCMShareByToken not implemented")
}
func (*UnimplementedGatewayAPIServer) ListOCMShares(ctx context.Context, req *v1beta19.ListOCMSharesRequest) (*v1beta19.ListOCMSharesResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListOCMShares not implemented")
}
@@ -2549,6 +2623,9 @@ func (*UnimplementedGatewayAPIServer) GetHome(ctx context.Context, req *v1beta13
func (*UnimplementedGatewayAPIServer) GenerateInviteToken(ctx context.Context, req *v1beta113.GenerateInviteTokenRequest) (*v1beta113.GenerateInviteTokenResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GenerateInviteToken not implemented")
}
func (*UnimplementedGatewayAPIServer) ListInviteTokens(ctx context.Context, req *v1beta113.ListInviteTokensRequest) (*v1beta113.ListInviteTokensResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListInviteTokens not implemented")
}
func (*UnimplementedGatewayAPIServer) ForwardInvite(ctx context.Context, req *v1beta113.ForwardInviteRequest) (*v1beta113.ForwardInviteResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ForwardInvite not implemented")
}
@@ -2561,6 +2638,9 @@ func (*UnimplementedGatewayAPIServer) GetAcceptedUser(ctx context.Context, req *
func (*UnimplementedGatewayAPIServer) FindAcceptedUsers(ctx context.Context, req *v1beta113.FindAcceptedUsersRequest) (*v1beta113.FindAcceptedUsersResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method FindAcceptedUsers not implemented")
}
func (*UnimplementedGatewayAPIServer) DeleteAcceptedUser(ctx context.Context, req *v1beta113.DeleteAcceptedUserRequest) (*v1beta113.DeleteAcceptedUserResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method DeleteAcceptedUser not implemented")
}
func (*UnimplementedGatewayAPIServer) IsProviderAllowed(ctx context.Context, req *v1beta114.IsProviderAllowedRequest) (*v1beta114.IsProviderAllowedResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method IsProviderAllowed not implemented")
}
@@ -2573,6 +2653,12 @@ func (*UnimplementedGatewayAPIServer) ListAllProviders(ctx context.Context, req
func (*UnimplementedGatewayAPIServer) CreateOCMCoreShare(ctx context.Context, req *v1beta115.CreateOCMCoreShareRequest) (*v1beta115.CreateOCMCoreShareResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method CreateOCMCoreShare not implemented")
}
func (*UnimplementedGatewayAPIServer) UpdateOCMCoreShare(ctx context.Context, req *v1beta115.UpdateOCMCoreShareRequest) (*v1beta115.UpdateOCMCoreShareResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method UpdateOCMCoreShare not implemented")
}
func (*UnimplementedGatewayAPIServer) DeleteOCMCoreShare(ctx context.Context, req *v1beta115.DeleteOCMCoreShareRequest) (*v1beta115.DeleteOCMCoreShareResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method DeleteOCMCoreShare not implemented")
}
func (*UnimplementedGatewayAPIServer) CreateTransfer(ctx context.Context, req *v1beta116.CreateTransferRequest) (*v1beta116.CreateTransferResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method CreateTransfer not implemented")
}
@@ -3592,6 +3678,24 @@ func _GatewayAPI_GetOCMShare_Handler(srv interface{}, ctx context.Context, dec f
return interceptor(ctx, in, info, handler)
}
func _GatewayAPI_GetOCMShareByToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(v1beta19.GetOCMShareByTokenRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(GatewayAPIServer).GetOCMShareByToken(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/cs3.gateway.v1beta1.GatewayAPI/GetOCMShareByToken",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(GatewayAPIServer).GetOCMShareByToken(ctx, req.(*v1beta19.GetOCMShareByTokenRequest))
}
return interceptor(ctx, in, info, handler)
}
func _GatewayAPI_ListOCMShares_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(v1beta19.ListOCMSharesRequest)
if err := dec(in); err != nil {
@@ -4006,6 +4110,24 @@ func _GatewayAPI_GenerateInviteToken_Handler(srv interface{}, ctx context.Contex
return interceptor(ctx, in, info, handler)
}
func _GatewayAPI_ListInviteTokens_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(v1beta113.ListInviteTokensRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(GatewayAPIServer).ListInviteTokens(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/cs3.gateway.v1beta1.GatewayAPI/ListInviteTokens",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(GatewayAPIServer).ListInviteTokens(ctx, req.(*v1beta113.ListInviteTokensRequest))
}
return interceptor(ctx, in, info, handler)
}
func _GatewayAPI_ForwardInvite_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(v1beta113.ForwardInviteRequest)
if err := dec(in); err != nil {
@@ -4078,6 +4200,24 @@ func _GatewayAPI_FindAcceptedUsers_Handler(srv interface{}, ctx context.Context,
return interceptor(ctx, in, info, handler)
}
func _GatewayAPI_DeleteAcceptedUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(v1beta113.DeleteAcceptedUserRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(GatewayAPIServer).DeleteAcceptedUser(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/cs3.gateway.v1beta1.GatewayAPI/DeleteAcceptedUser",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(GatewayAPIServer).DeleteAcceptedUser(ctx, req.(*v1beta113.DeleteAcceptedUserRequest))
}
return interceptor(ctx, in, info, handler)
}
func _GatewayAPI_IsProviderAllowed_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(v1beta114.IsProviderAllowedRequest)
if err := dec(in); err != nil {
@@ -4150,6 +4290,42 @@ func _GatewayAPI_CreateOCMCoreShare_Handler(srv interface{}, ctx context.Context
return interceptor(ctx, in, info, handler)
}
func _GatewayAPI_UpdateOCMCoreShare_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(v1beta115.UpdateOCMCoreShareRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(GatewayAPIServer).UpdateOCMCoreShare(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/cs3.gateway.v1beta1.GatewayAPI/UpdateOCMCoreShare",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(GatewayAPIServer).UpdateOCMCoreShare(ctx, req.(*v1beta115.UpdateOCMCoreShareRequest))
}
return interceptor(ctx, in, info, handler)
}
func _GatewayAPI_DeleteOCMCoreShare_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(v1beta115.DeleteOCMCoreShareRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(GatewayAPIServer).DeleteOCMCoreShare(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/cs3.gateway.v1beta1.GatewayAPI/DeleteOCMCoreShare",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(GatewayAPIServer).DeleteOCMCoreShare(ctx, req.(*v1beta115.DeleteOCMCoreShareRequest))
}
return interceptor(ctx, in, info, handler)
}
func _GatewayAPI_CreateTransfer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(v1beta116.CreateTransferRequest)
if err := dec(in); err != nil {
@@ -4474,6 +4650,10 @@ var _GatewayAPI_serviceDesc = grpc.ServiceDesc{
MethodName: "GetOCMShare",
Handler: _GatewayAPI_GetOCMShare_Handler,
},
{
MethodName: "GetOCMShareByToken",
Handler: _GatewayAPI_GetOCMShareByToken_Handler,
},
{
MethodName: "ListOCMShares",
Handler: _GatewayAPI_ListOCMShares_Handler,
@@ -4566,6 +4746,10 @@ var _GatewayAPI_serviceDesc = grpc.ServiceDesc{
MethodName: "GenerateInviteToken",
Handler: _GatewayAPI_GenerateInviteToken_Handler,
},
{
MethodName: "ListInviteTokens",
Handler: _GatewayAPI_ListInviteTokens_Handler,
},
{
MethodName: "ForwardInvite",
Handler: _GatewayAPI_ForwardInvite_Handler,
@@ -4582,6 +4766,10 @@ var _GatewayAPI_serviceDesc = grpc.ServiceDesc{
MethodName: "FindAcceptedUsers",
Handler: _GatewayAPI_FindAcceptedUsers_Handler,
},
{
MethodName: "DeleteAcceptedUser",
Handler: _GatewayAPI_DeleteAcceptedUser_Handler,
},
{
MethodName: "IsProviderAllowed",
Handler: _GatewayAPI_IsProviderAllowed_Handler,
@@ -4598,6 +4786,14 @@ var _GatewayAPI_serviceDesc = grpc.ServiceDesc{
MethodName: "CreateOCMCoreShare",
Handler: _GatewayAPI_CreateOCMCoreShare_Handler,
},
{
MethodName: "UpdateOCMCoreShare",
Handler: _GatewayAPI_UpdateOCMCoreShare_Handler,
},
{
MethodName: "DeleteOCMCoreShare",
Handler: _GatewayAPI_DeleteOCMCoreShare_Handler,
},
{
MethodName: "CreateTransfer",
Handler: _GatewayAPI_CreateTransfer_Handler,

View File

@@ -7,7 +7,9 @@ import (
context "context"
fmt "fmt"
v1beta11 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
v1beta12 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
v1beta14 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
v1beta13 "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
v1beta12 "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
v1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
proto "github.com/golang/protobuf/proto"
grpc "google.golang.org/grpc"
@@ -27,7 +29,6 @@ var _ = math.Inf
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
// https://rawgit.com/GEANT/OCM-API/v1/docs.html#null%2Fpaths%2F~1shares%2Fpost
type CreateOCMCoreShareRequest struct {
// OPTIONAL.
// Opaque information.
@@ -40,22 +41,37 @@ type CreateOCMCoreShareRequest struct {
Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
// REQUIRED.
// Identifier to identify the resource at the provider side. This is unique per provider.
ProviderId string `protobuf:"bytes,4,opt,name=provider_id,json=providerId,proto3" json:"provider_id,omitempty"`
ResourceId string `protobuf:"bytes,4,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"`
// REQUIRED.
// Provider specific identifier of the owner of the resource.
Owner *v1beta11.UserId `protobuf:"bytes,5,opt,name=owner,proto3" json:"owner,omitempty"`
// REQUIRED.
// Provider specific identifier of the user that wants to share the resource.
Owner *v1beta11.UserId `protobuf:"bytes,5,opt,name=owner,proto3" json:"owner,omitempty"`
Sender *v1beta11.UserId `protobuf:"bytes,6,opt,name=sender,proto3" json:"sender,omitempty"`
// REQUIRED.
// Consumer specific identifier of the user or group the provider wants to share the resource with.
// This is known in advance, for example using the OCM invitation flow.
// Please note that the consumer service endpoint is known in advance as well, so this is no part of the request body.
// TODO: this field needs to represent either a user or group in the future, not only a user.
ShareWith *v1beta11.UserId `protobuf:"bytes,6,opt,name=share_with,json=shareWith,proto3" json:"share_with,omitempty"`
ShareWith *v1beta11.UserId `protobuf:"bytes,7,opt,name=share_with,json=shareWith,proto3" json:"share_with,omitempty"`
// REQUIRED.
// The protocol which is used to establish synchronisation.
Protocol *Protocol `protobuf:"bytes,7,opt,name=protocol,proto3" json:"protocol,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
// Resource type.
ResourceType v1beta12.ResourceType `protobuf:"varint,8,opt,name=resource_type,json=resourceType,proto3,enum=cs3.storage.provider.v1beta1.ResourceType" json:"resource_type,omitempty"`
// REQUIRED.
// Recipient share type.
ShareType v1beta13.ShareType `protobuf:"varint,9,opt,name=share_type,json=shareType,proto3,enum=cs3.sharing.ocm.v1beta1.ShareType" json:"share_type,omitempty"`
// OPTIONAL.
// The expiration time for the OCM share.
Expiration *v1beta1.Timestamp `protobuf:"bytes,10,opt,name=expiration,proto3" json:"expiration,omitempty"`
// REQUIRED.
// The protocols which are used to establish synchronisation,
// with their access rights.
// See also cs3/sharing/ocm/v1beta1/resources.proto for how to map
// this to the OCM share payload.
Protocols []*v1beta13.Protocol `protobuf:"bytes,11,rep,name=protocols,proto3" json:"protocols,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CreateOCMCoreShareRequest) Reset() { *m = CreateOCMCoreShareRequest{} }
@@ -104,9 +120,9 @@ func (m *CreateOCMCoreShareRequest) GetName() string {
return ""
}
func (m *CreateOCMCoreShareRequest) GetProviderId() string {
func (m *CreateOCMCoreShareRequest) GetResourceId() string {
if m != nil {
return m.ProviderId
return m.ResourceId
}
return ""
}
@@ -118,6 +134,13 @@ func (m *CreateOCMCoreShareRequest) GetOwner() *v1beta11.UserId {
return nil
}
func (m *CreateOCMCoreShareRequest) GetSender() *v1beta11.UserId {
if m != nil {
return m.Sender
}
return nil
}
func (m *CreateOCMCoreShareRequest) GetShareWith() *v1beta11.UserId {
if m != nil {
return m.ShareWith
@@ -125,9 +148,30 @@ func (m *CreateOCMCoreShareRequest) GetShareWith() *v1beta11.UserId {
return nil
}
func (m *CreateOCMCoreShareRequest) GetProtocol() *Protocol {
func (m *CreateOCMCoreShareRequest) GetResourceType() v1beta12.ResourceType {
if m != nil {
return m.Protocol
return m.ResourceType
}
return v1beta12.ResourceType_RESOURCE_TYPE_INVALID
}
func (m *CreateOCMCoreShareRequest) GetShareType() v1beta13.ShareType {
if m != nil {
return m.ShareType
}
return v1beta13.ShareType_SHARE_TYPE_INVALID
}
func (m *CreateOCMCoreShareRequest) GetExpiration() *v1beta1.Timestamp {
if m != nil {
return m.Expiration
}
return nil
}
func (m *CreateOCMCoreShareRequest) GetProtocols() []*v1beta13.Protocol {
if m != nil {
return m.Protocols
}
return nil
}
@@ -135,7 +179,7 @@ func (m *CreateOCMCoreShareRequest) GetProtocol() *Protocol {
type CreateOCMCoreShareResponse struct {
// REQUIRED.
// The response status.
Status *v1beta12.Status `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
Status *v1beta14.Status `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
// OPTIONAL.
// Opaque information.
Opaque *v1beta1.Opaque `protobuf:"bytes,2,opt,name=opaque,proto3" json:"opaque,omitempty"`
@@ -174,7 +218,7 @@ func (m *CreateOCMCoreShareResponse) XXX_DiscardUnknown() {
var xxx_messageInfo_CreateOCMCoreShareResponse proto.InternalMessageInfo
func (m *CreateOCMCoreShareResponse) GetStatus() *v1beta12.Status {
func (m *CreateOCMCoreShareResponse) GetStatus() *v1beta14.Status {
if m != nil {
return m.Status
}
@@ -202,9 +246,258 @@ func (m *CreateOCMCoreShareResponse) GetCreated() *v1beta1.Timestamp {
return nil
}
type UpdateOCMCoreShareRequest struct {
// OPTIONAL.
// Opaque information.
Opaque *v1beta1.Opaque `protobuf:"bytes,1,opt,name=opaque,proto3" json:"opaque,omitempty"`
// REQUIRED.
// Unique ID to identify the share at the consumer side.
OcmShareId string `protobuf:"bytes,2,opt,name=ocm_share_id,json=ocmShareId,proto3" json:"ocm_share_id,omitempty"`
// OPTIONAL.
// Description for the share.
Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"`
// OPTIONAL.
// Recipient share type.
ShareType v1beta13.ShareType `protobuf:"varint,5,opt,name=share_type,json=shareType,proto3,enum=cs3.sharing.ocm.v1beta1.ShareType" json:"share_type,omitempty"`
// OPTIONAL.
// The expiration time for the OCM share.
Expiration *v1beta1.Timestamp `protobuf:"bytes,6,opt,name=expiration,proto3" json:"expiration,omitempty"`
// OPTIONAL.
// The protocols which are used to establish synchronisation,
// with their access rights.
Protocols []*v1beta13.Protocol `protobuf:"bytes,7,rep,name=protocols,proto3" json:"protocols,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *UpdateOCMCoreShareRequest) Reset() { *m = UpdateOCMCoreShareRequest{} }
func (m *UpdateOCMCoreShareRequest) String() string { return proto.CompactTextString(m) }
func (*UpdateOCMCoreShareRequest) ProtoMessage() {}
func (*UpdateOCMCoreShareRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_4e8f411283db0fc7, []int{2}
}
func (m *UpdateOCMCoreShareRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_UpdateOCMCoreShareRequest.Unmarshal(m, b)
}
func (m *UpdateOCMCoreShareRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_UpdateOCMCoreShareRequest.Marshal(b, m, deterministic)
}
func (m *UpdateOCMCoreShareRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_UpdateOCMCoreShareRequest.Merge(m, src)
}
func (m *UpdateOCMCoreShareRequest) XXX_Size() int {
return xxx_messageInfo_UpdateOCMCoreShareRequest.Size(m)
}
func (m *UpdateOCMCoreShareRequest) XXX_DiscardUnknown() {
xxx_messageInfo_UpdateOCMCoreShareRequest.DiscardUnknown(m)
}
var xxx_messageInfo_UpdateOCMCoreShareRequest proto.InternalMessageInfo
func (m *UpdateOCMCoreShareRequest) GetOpaque() *v1beta1.Opaque {
if m != nil {
return m.Opaque
}
return nil
}
func (m *UpdateOCMCoreShareRequest) GetOcmShareId() string {
if m != nil {
return m.OcmShareId
}
return ""
}
func (m *UpdateOCMCoreShareRequest) GetDescription() string {
if m != nil {
return m.Description
}
return ""
}
func (m *UpdateOCMCoreShareRequest) GetShareType() v1beta13.ShareType {
if m != nil {
return m.ShareType
}
return v1beta13.ShareType_SHARE_TYPE_INVALID
}
func (m *UpdateOCMCoreShareRequest) GetExpiration() *v1beta1.Timestamp {
if m != nil {
return m.Expiration
}
return nil
}
func (m *UpdateOCMCoreShareRequest) GetProtocols() []*v1beta13.Protocol {
if m != nil {
return m.Protocols
}
return nil
}
type UpdateOCMCoreShareResponse struct {
// REQUIRED.
// The response status.
Status *v1beta14.Status `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
// OPTIONAL.
// Opaque information.
Opaque *v1beta1.Opaque `protobuf:"bytes,2,opt,name=opaque,proto3" json:"opaque,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *UpdateOCMCoreShareResponse) Reset() { *m = UpdateOCMCoreShareResponse{} }
func (m *UpdateOCMCoreShareResponse) String() string { return proto.CompactTextString(m) }
func (*UpdateOCMCoreShareResponse) ProtoMessage() {}
func (*UpdateOCMCoreShareResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_4e8f411283db0fc7, []int{3}
}
func (m *UpdateOCMCoreShareResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_UpdateOCMCoreShareResponse.Unmarshal(m, b)
}
func (m *UpdateOCMCoreShareResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_UpdateOCMCoreShareResponse.Marshal(b, m, deterministic)
}
func (m *UpdateOCMCoreShareResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_UpdateOCMCoreShareResponse.Merge(m, src)
}
func (m *UpdateOCMCoreShareResponse) XXX_Size() int {
return xxx_messageInfo_UpdateOCMCoreShareResponse.Size(m)
}
func (m *UpdateOCMCoreShareResponse) XXX_DiscardUnknown() {
xxx_messageInfo_UpdateOCMCoreShareResponse.DiscardUnknown(m)
}
var xxx_messageInfo_UpdateOCMCoreShareResponse proto.InternalMessageInfo
func (m *UpdateOCMCoreShareResponse) GetStatus() *v1beta14.Status {
if m != nil {
return m.Status
}
return nil
}
func (m *UpdateOCMCoreShareResponse) GetOpaque() *v1beta1.Opaque {
if m != nil {
return m.Opaque
}
return nil
}
type DeleteOCMCoreShareRequest struct {
// REQUIRED.
// Unique ID to identify the share at the consumer side.
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
// OPTIONAL.
// Opaque information.
Opaque *v1beta1.Opaque `protobuf:"bytes,2,opt,name=opaque,proto3" json:"opaque,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *DeleteOCMCoreShareRequest) Reset() { *m = DeleteOCMCoreShareRequest{} }
func (m *DeleteOCMCoreShareRequest) String() string { return proto.CompactTextString(m) }
func (*DeleteOCMCoreShareRequest) ProtoMessage() {}
func (*DeleteOCMCoreShareRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_4e8f411283db0fc7, []int{4}
}
func (m *DeleteOCMCoreShareRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_DeleteOCMCoreShareRequest.Unmarshal(m, b)
}
func (m *DeleteOCMCoreShareRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_DeleteOCMCoreShareRequest.Marshal(b, m, deterministic)
}
func (m *DeleteOCMCoreShareRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_DeleteOCMCoreShareRequest.Merge(m, src)
}
func (m *DeleteOCMCoreShareRequest) XXX_Size() int {
return xxx_messageInfo_DeleteOCMCoreShareRequest.Size(m)
}
func (m *DeleteOCMCoreShareRequest) XXX_DiscardUnknown() {
xxx_messageInfo_DeleteOCMCoreShareRequest.DiscardUnknown(m)
}
var xxx_messageInfo_DeleteOCMCoreShareRequest proto.InternalMessageInfo
func (m *DeleteOCMCoreShareRequest) GetId() string {
if m != nil {
return m.Id
}
return ""
}
func (m *DeleteOCMCoreShareRequest) GetOpaque() *v1beta1.Opaque {
if m != nil {
return m.Opaque
}
return nil
}
type DeleteOCMCoreShareResponse struct {
// REQUIRED.
// The response status.
Status *v1beta14.Status `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
// OPTIONAL.
// Opaque information.
Opaque *v1beta1.Opaque `protobuf:"bytes,2,opt,name=opaque,proto3" json:"opaque,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *DeleteOCMCoreShareResponse) Reset() { *m = DeleteOCMCoreShareResponse{} }
func (m *DeleteOCMCoreShareResponse) String() string { return proto.CompactTextString(m) }
func (*DeleteOCMCoreShareResponse) ProtoMessage() {}
func (*DeleteOCMCoreShareResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_4e8f411283db0fc7, []int{5}
}
func (m *DeleteOCMCoreShareResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_DeleteOCMCoreShareResponse.Unmarshal(m, b)
}
func (m *DeleteOCMCoreShareResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_DeleteOCMCoreShareResponse.Marshal(b, m, deterministic)
}
func (m *DeleteOCMCoreShareResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_DeleteOCMCoreShareResponse.Merge(m, src)
}
func (m *DeleteOCMCoreShareResponse) XXX_Size() int {
return xxx_messageInfo_DeleteOCMCoreShareResponse.Size(m)
}
func (m *DeleteOCMCoreShareResponse) XXX_DiscardUnknown() {
xxx_messageInfo_DeleteOCMCoreShareResponse.DiscardUnknown(m)
}
var xxx_messageInfo_DeleteOCMCoreShareResponse proto.InternalMessageInfo
func (m *DeleteOCMCoreShareResponse) GetStatus() *v1beta14.Status {
if m != nil {
return m.Status
}
return nil
}
func (m *DeleteOCMCoreShareResponse) GetOpaque() *v1beta1.Opaque {
if m != nil {
return m.Opaque
}
return nil
}
func init() {
proto.RegisterType((*CreateOCMCoreShareRequest)(nil), "cs3.ocm.core.v1beta1.CreateOCMCoreShareRequest")
proto.RegisterType((*CreateOCMCoreShareResponse)(nil), "cs3.ocm.core.v1beta1.CreateOCMCoreShareResponse")
proto.RegisterType((*UpdateOCMCoreShareRequest)(nil), "cs3.ocm.core.v1beta1.UpdateOCMCoreShareRequest")
proto.RegisterType((*UpdateOCMCoreShareResponse)(nil), "cs3.ocm.core.v1beta1.UpdateOCMCoreShareResponse")
proto.RegisterType((*DeleteOCMCoreShareRequest)(nil), "cs3.ocm.core.v1beta1.DeleteOCMCoreShareRequest")
proto.RegisterType((*DeleteOCMCoreShareResponse)(nil), "cs3.ocm.core.v1beta1.DeleteOCMCoreShareResponse")
}
func init() {
@@ -212,38 +505,52 @@ func init() {
}
var fileDescriptor_4e8f411283db0fc7 = []byte{
// 484 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0xdd, 0x6a, 0xd4, 0x40,
0x14, 0x26, 0x69, 0xbb, 0xb5, 0x27, 0xa0, 0x30, 0x14, 0x4c, 0x97, 0xaa, 0x6b, 0x11, 0xac, 0x37,
0x13, 0x77, 0x17, 0x14, 0xbc, 0xd2, 0xcd, 0x55, 0x2f, 0x24, 0x4b, 0xea, 0x0f, 0xc8, 0xc2, 0x92,
0x4e, 0x0e, 0xec, 0x80, 0xc9, 0x4c, 0x67, 0x26, 0x5d, 0xfa, 0x00, 0xbe, 0x88, 0x97, 0x3e, 0x89,
0xf8, 0x0c, 0x3e, 0x8c, 0xcc, 0x64, 0x12, 0x8a, 0x46, 0xd8, 0xbb, 0xe4, 0xfb, 0x39, 0x39, 0xe7,
0xfb, 0x02, 0xcf, 0x99, 0x9e, 0x27, 0x82, 0x55, 0x09, 0x13, 0x0a, 0x93, 0x9b, 0xe9, 0x15, 0x9a,
0x62, 0x6a, 0x81, 0xb5, 0x05, 0xd6, 0x85, 0xe4, 0x54, 0x2a, 0x61, 0x04, 0x39, 0x66, 0x7a, 0x4e,
0x05, 0xab, 0xa8, 0xc5, 0xa9, 0x17, 0x8e, 0x5f, 0x58, 0x3b, 0x2f, 0xb1, 0x36, 0xdc, 0xdc, 0x26,
0x8d, 0x46, 0xd5, 0xcf, 0x50, 0xa8, 0x45, 0xa3, 0x18, 0xea, 0x76, 0xc0, 0xf8, 0xd9, 0xe0, 0x97,
0xfe, 0x56, 0x9d, 0x5a, 0x95, 0x92, 0xac, 0x17, 0x68, 0x53, 0x98, 0xa6, 0x63, 0x1f, 0x59, 0xd6,
0xdc, 0x4a, 0xd4, 0x3d, 0xef, 0xde, 0x5a, 0xfa, 0xec, 0x77, 0x08, 0x27, 0xa9, 0xc2, 0xc2, 0x60,
0x96, 0xbe, 0x4f, 0x85, 0xc2, 0xcb, 0x4d, 0xa1, 0x30, 0xc7, 0xeb, 0x06, 0xb5, 0x21, 0x53, 0x18,
0x09, 0x59, 0x5c, 0x37, 0x18, 0x07, 0x93, 0xe0, 0x3c, 0x9a, 0x9d, 0x50, 0x7b, 0x52, 0xeb, 0xf7,
0xd3, 0x68, 0xe6, 0x04, 0xb9, 0x17, 0x92, 0x09, 0x44, 0x25, 0x6a, 0xa6, 0xb8, 0x34, 0x5c, 0xd4,
0x71, 0x38, 0x09, 0xce, 0x8f, 0xf2, 0xbb, 0x10, 0x21, 0xb0, 0x5f, 0x17, 0x15, 0xc6, 0x7b, 0x8e,
0x72, 0xcf, 0xe4, 0x09, 0x44, 0x52, 0x89, 0x1b, 0x5e, 0xa2, 0x5a, 0xf3, 0x32, 0xde, 0x77, 0x14,
0x74, 0xd0, 0x45, 0x49, 0x5e, 0xc3, 0x81, 0xd8, 0xd6, 0xa8, 0xe2, 0x03, 0xb7, 0xc8, 0x53, 0xb7,
0x48, 0x97, 0x22, 0xb5, 0x29, 0xf6, 0x0b, 0x7d, 0xd4, 0xd6, 0x91, 0xb7, 0x7a, 0xf2, 0x16, 0x40,
0xdb, 0x93, 0xd6, 0x5b, 0x6e, 0x36, 0xf1, 0x68, 0x57, 0xf7, 0x91, 0x33, 0x7d, 0xe6, 0x66, 0x43,
0xde, 0xc0, 0x3d, 0x97, 0x15, 0x13, 0x5f, 0xe3, 0x43, 0xe7, 0x7f, 0x4c, 0x87, 0x9a, 0xa5, 0x4b,
0xaf, 0xca, 0x7b, 0xfd, 0xd9, 0xcf, 0x00, 0xc6, 0x43, 0xf1, 0x6a, 0x29, 0x6a, 0x8d, 0x24, 0x81,
0x51, 0x5b, 0x96, 0xcf, 0xf7, 0xa1, 0x1b, 0xac, 0x24, 0xeb, 0x67, 0x5e, 0x3a, 0x3a, 0xf7, 0xb2,
0x3b, 0x85, 0x84, 0xbb, 0x16, 0x72, 0x1f, 0x42, 0x5e, 0xfa, 0xb0, 0x43, 0x5e, 0x92, 0x57, 0x70,
0xc8, 0xdc, 0x46, 0x6d, 0xcc, 0xd1, 0xec, 0x74, 0x60, 0xc6, 0x07, 0x5e, 0xa1, 0x36, 0x45, 0x25,
0xf3, 0x4e, 0x3c, 0xfb, 0x16, 0x00, 0x64, 0xac, 0xb2, 0x47, 0xbc, 0x5b, 0x5e, 0x90, 0x2d, 0x90,
0x7f, 0x0f, 0x23, 0xc9, 0x70, 0x32, 0xff, 0xfd, 0xc3, 0xc6, 0x2f, 0x77, 0x37, 0xb4, 0x99, 0x2d,
0x6a, 0x88, 0x99, 0xa8, 0x06, 0x6d, 0x8b, 0x07, 0xdd, 0x82, 0x92, 0xbb, 0x32, 0x96, 0xc1, 0x97,
0xc8, 0x0a, 0x3c, 0xff, 0x3d, 0xdc, 0x4b, 0xb3, 0xf4, 0x47, 0x78, 0x9c, 0xea, 0x39, 0xcd, 0x58,
0x45, 0xad, 0x96, 0x7e, 0x9a, 0x2e, 0x2c, 0xf9, 0xcb, 0xc1, 0xab, 0x8c, 0x55, 0x2b, 0x0b, 0xaf,
0x3c, 0x7c, 0x35, 0x72, 0x65, 0xce, 0xff, 0x04, 0x00, 0x00, 0xff, 0xff, 0x1f, 0x27, 0xaa, 0xb1,
0xf7, 0x03, 0x00, 0x00,
// 711 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x55, 0x41, 0x6f, 0xd3, 0x4a,
0x10, 0x96, 0x9d, 0x36, 0x7d, 0x99, 0xf4, 0xf5, 0x49, 0xab, 0x4a, 0xcf, 0x89, 0xfa, 0xf4, 0x42,
0x2e, 0x14, 0x84, 0x1c, 0xd2, 0x48, 0x20, 0x24, 0x24, 0x68, 0xc3, 0x25, 0x07, 0xe4, 0xca, 0xb4,
0x20, 0xa1, 0x8a, 0xc8, 0x5d, 0xaf, 0x9a, 0x95, 0x6a, 0xaf, 0xbb, 0xeb, 0x34, 0xf4, 0xc6, 0x6f,
0xe1, 0xc8, 0x2f, 0x41, 0x9c, 0xf9, 0x1d, 0x5c, 0xb9, 0xa2, 0x1d, 0xaf, 0xdd, 0x40, 0xec, 0x12,
0xb5, 0xa8, 0xb7, 0x66, 0xe6, 0x9b, 0x6f, 0x66, 0xe7, 0xfb, 0xa6, 0x86, 0xbb, 0x54, 0x0d, 0x7a,
0x82, 0x46, 0x3d, 0x2a, 0x24, 0xeb, 0x9d, 0xf7, 0x8f, 0x59, 0x1a, 0xf4, 0x75, 0x60, 0xac, 0x03,
0xe3, 0x20, 0xe1, 0x6e, 0x22, 0x45, 0x2a, 0xc8, 0x26, 0x55, 0x03, 0x57, 0xd0, 0xc8, 0xd5, 0x71,
0xd7, 0x00, 0xdb, 0xf7, 0x74, 0x39, 0x0f, 0x59, 0x9c, 0xf2, 0xf4, 0xa2, 0x37, 0x55, 0x4c, 0x16,
0x1c, 0x92, 0x29, 0x31, 0x95, 0x94, 0xa9, 0x8c, 0xa0, 0xbd, 0xa5, 0xa1, 0x32, 0xa1, 0x05, 0x40,
0xa5, 0x41, 0x3a, 0xcd, 0xb3, 0x38, 0x87, 0x9a, 0x04, 0x92, 0xc7, 0x27, 0x38, 0x4f, 0x15, 0xcd,
0x03, 0x04, 0xa6, 0x42, 0x06, 0x27, 0xac, 0x97, 0x48, 0x71, 0xce, 0xc3, 0x2b, 0x9a, 0xfe, 0xa7,
0xd1, 0xe9, 0x45, 0xc2, 0x54, 0x01, 0xc1, 0x5f, 0x59, 0xba, 0xfb, 0x6d, 0x05, 0x5a, 0x43, 0xc9,
0x82, 0x94, 0x79, 0xc3, 0x97, 0x43, 0x21, 0xd9, 0xab, 0x49, 0x20, 0x99, 0xcf, 0xce, 0xa6, 0x4c,
0xa5, 0xa4, 0x0f, 0x75, 0x91, 0x04, 0x67, 0x53, 0xe6, 0x58, 0x1d, 0x6b, 0xbb, 0xb9, 0xd3, 0x72,
0xf5, 0x0e, 0xb2, 0x7a, 0xc3, 0xe6, 0x7a, 0x08, 0xf0, 0x0d, 0x90, 0x74, 0xa0, 0x19, 0x32, 0x45,
0x25, 0x4f, 0x52, 0x2e, 0x62, 0xc7, 0xee, 0x58, 0xdb, 0x0d, 0x7f, 0x3e, 0x44, 0x08, 0xac, 0xc4,
0x41, 0xc4, 0x9c, 0x1a, 0xa6, 0xf0, 0x6f, 0xf2, 0x3f, 0x34, 0xf3, 0xc1, 0xc7, 0x3c, 0x74, 0x56,
0x30, 0x05, 0x79, 0x68, 0x14, 0x92, 0xc7, 0xb0, 0x2a, 0x66, 0x31, 0x93, 0xce, 0x2a, 0x0e, 0x72,
0x07, 0x07, 0xc9, 0xd7, 0xee, 0xea, 0xb5, 0x17, 0x03, 0x1d, 0x2a, 0x26, 0x47, 0xa1, 0x9f, 0xe1,
0xc9, 0x13, 0xa8, 0x2b, 0x16, 0x87, 0x4c, 0x3a, 0xf5, 0x65, 0x2b, 0x4d, 0x01, 0x79, 0x0e, 0xa0,
0xf5, 0x60, 0xe3, 0x19, 0x4f, 0x27, 0xce, 0xda, 0xb2, 0xe5, 0x0d, 0x2c, 0x7a, 0xc3, 0xd3, 0x09,
0xf1, 0xe0, 0xef, 0xe2, 0x59, 0x7a, 0x6b, 0xce, 0x5f, 0x1d, 0x6b, 0x7b, 0x63, 0xe7, 0x3e, 0x92,
0x18, 0x09, 0xdd, 0x5c, 0xc2, 0x82, 0xc7, 0x37, 0x25, 0x07, 0x17, 0x09, 0xf3, 0xd7, 0xe5, 0xdc,
0x2f, 0xb2, 0x9b, 0x8f, 0x84, 0x6c, 0x0d, 0x64, 0xeb, 0x66, 0x6c, 0x99, 0x73, 0xd0, 0xa0, 0x39,
0x11, 0x6a, 0x89, 0x2c, 0xd9, 0x4c, 0x48, 0xf1, 0x14, 0x80, 0xbd, 0x4f, 0xb8, 0x0c, 0x50, 0x1f,
0xc0, 0x57, 0x6d, 0x95, 0xe8, 0x7a, 0xc0, 0x23, 0xa6, 0xd2, 0x20, 0x4a, 0xfc, 0x39, 0x3c, 0x79,
0x06, 0x0d, 0x34, 0x0e, 0x15, 0xa7, 0xca, 0x69, 0x76, 0x6a, 0xc5, 0x4a, 0xca, 0xfa, 0xef, 0x1b,
0xa4, 0x7f, 0x59, 0xd3, 0xfd, 0x6c, 0x41, 0xbb, 0xcc, 0x70, 0x2a, 0x11, 0xb1, 0x62, 0xa4, 0x07,
0xf5, 0xec, 0x2a, 0x8c, 0xe3, 0xfe, 0x45, 0x72, 0x99, 0xd0, 0xcb, 0x47, 0x61, 0xda, 0x37, 0xb0,
0x39, 0x8b, 0xda, 0xcb, 0x5a, 0x74, 0x03, 0x6c, 0x1e, 0x1a, 0xfb, 0xd9, 0x3c, 0x24, 0x8f, 0x60,
0x8d, 0xe2, 0x44, 0x99, 0xf1, 0x7e, 0xb7, 0x8e, 0x1c, 0xdc, 0xfd, 0x6a, 0x43, 0xeb, 0x30, 0x09,
0xff, 0xe4, 0xed, 0xac, 0xeb, 0xff, 0x3b, 0x99, 0xc2, 0x3c, 0x34, 0xc7, 0x03, 0x82, 0x46, 0xc8,
0x3c, 0x0a, 0x7f, 0xbd, 0xae, 0xda, 0xe2, 0x75, 0xfd, 0xec, 0x90, 0xd5, 0x9b, 0x3b, 0xa4, 0x7e,
0x13, 0x87, 0xac, 0x5d, 0xc3, 0x21, 0x1f, 0x2c, 0x68, 0x97, 0xad, 0xf5, 0xf6, 0x1c, 0xd2, 0x7d,
0x07, 0xad, 0x17, 0xec, 0x94, 0x95, 0x0b, 0x9b, 0xd9, 0xc7, 0x2a, 0xec, 0x73, 0x0d, 0x7e, 0xfd,
0xc4, 0xb2, 0x06, 0xb7, 0xf7, 0xc4, 0x9d, 0xef, 0x36, 0x80, 0x47, 0x23, 0xdd, 0x7c, 0x77, 0x7f,
0x44, 0x66, 0x40, 0x16, 0xaf, 0x92, 0xf4, 0xdc, 0xb2, 0x6f, 0x9e, 0x5b, 0xf9, 0xc1, 0x68, 0x3f,
0x5c, 0xbe, 0xc0, 0xbc, 0x75, 0x06, 0x64, 0x51, 0xec, 0xaa, 0xc6, 0x95, 0xd7, 0x56, 0xd5, 0xf8,
0x0a, 0x1f, 0xcd, 0x80, 0x2c, 0x4a, 0x50, 0xd5, 0xb8, 0xd2, 0x0d, 0x55, 0x8d, 0xab, 0xd5, 0xdd,
0x8b, 0xc1, 0xa1, 0x22, 0x2a, 0x2d, 0xdb, 0xfb, 0x27, 0x97, 0x24, 0xe1, 0x78, 0x1a, 0xfb, 0xd6,
0xdb, 0xa6, 0x06, 0x98, 0xfc, 0x47, 0xbb, 0x36, 0xf4, 0x86, 0x9f, 0xec, 0xcd, 0xa1, 0x1a, 0xb8,
0x1e, 0x8d, 0x5c, 0x8d, 0x75, 0x5f, 0xf7, 0xf7, 0x74, 0xf2, 0x0b, 0x86, 0x8f, 0x3c, 0x1a, 0x1d,
0xe9, 0xf0, 0x91, 0x09, 0x1f, 0xd7, 0xf1, 0xb4, 0x06, 0x3f, 0x02, 0x00, 0x00, 0xff, 0xff, 0xd8,
0xa2, 0xd7, 0x40, 0xe9, 0x08, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@@ -258,8 +565,15 @@ const _ = grpc.SupportPackageIsVersion4
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type OcmCoreAPIClient interface {
// Creates a new ocm share.
// Creates a new OCM share, in response to a call from remote to:
// https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1shares/post
CreateOCMCoreShare(ctx context.Context, in *CreateOCMCoreShareRequest, opts ...grpc.CallOption) (*CreateOCMCoreShareResponse, error)
// Updates an OCM share, in response to a notification from the remote system to:
// https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1notifications/post
UpdateOCMCoreShare(ctx context.Context, in *UpdateOCMCoreShareRequest, opts ...grpc.CallOption) (*UpdateOCMCoreShareResponse, error)
// Deletes an OCM share, in response to a notification from the remote system to:
// https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1notifications/post
DeleteOCMCoreShare(ctx context.Context, in *DeleteOCMCoreShareRequest, opts ...grpc.CallOption) (*DeleteOCMCoreShareResponse, error)
}
type ocmCoreAPIClient struct {
@@ -279,10 +593,35 @@ func (c *ocmCoreAPIClient) CreateOCMCoreShare(ctx context.Context, in *CreateOCM
return out, nil
}
func (c *ocmCoreAPIClient) UpdateOCMCoreShare(ctx context.Context, in *UpdateOCMCoreShareRequest, opts ...grpc.CallOption) (*UpdateOCMCoreShareResponse, error) {
out := new(UpdateOCMCoreShareResponse)
err := c.cc.Invoke(ctx, "/cs3.ocm.core.v1beta1.OcmCoreAPI/UpdateOCMCoreShare", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *ocmCoreAPIClient) DeleteOCMCoreShare(ctx context.Context, in *DeleteOCMCoreShareRequest, opts ...grpc.CallOption) (*DeleteOCMCoreShareResponse, error) {
out := new(DeleteOCMCoreShareResponse)
err := c.cc.Invoke(ctx, "/cs3.ocm.core.v1beta1.OcmCoreAPI/DeleteOCMCoreShare", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// OcmCoreAPIServer is the server API for OcmCoreAPI service.
type OcmCoreAPIServer interface {
// Creates a new ocm share.
// Creates a new OCM share, in response to a call from remote to:
// https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1shares/post
CreateOCMCoreShare(context.Context, *CreateOCMCoreShareRequest) (*CreateOCMCoreShareResponse, error)
// Updates an OCM share, in response to a notification from the remote system to:
// https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1notifications/post
UpdateOCMCoreShare(context.Context, *UpdateOCMCoreShareRequest) (*UpdateOCMCoreShareResponse, error)
// Deletes an OCM share, in response to a notification from the remote system to:
// https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1notifications/post
DeleteOCMCoreShare(context.Context, *DeleteOCMCoreShareRequest) (*DeleteOCMCoreShareResponse, error)
}
// UnimplementedOcmCoreAPIServer can be embedded to have forward compatible implementations.
@@ -292,6 +631,12 @@ type UnimplementedOcmCoreAPIServer struct {
func (*UnimplementedOcmCoreAPIServer) CreateOCMCoreShare(ctx context.Context, req *CreateOCMCoreShareRequest) (*CreateOCMCoreShareResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method CreateOCMCoreShare not implemented")
}
func (*UnimplementedOcmCoreAPIServer) UpdateOCMCoreShare(ctx context.Context, req *UpdateOCMCoreShareRequest) (*UpdateOCMCoreShareResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method UpdateOCMCoreShare not implemented")
}
func (*UnimplementedOcmCoreAPIServer) DeleteOCMCoreShare(ctx context.Context, req *DeleteOCMCoreShareRequest) (*DeleteOCMCoreShareResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method DeleteOCMCoreShare not implemented")
}
func RegisterOcmCoreAPIServer(s *grpc.Server, srv OcmCoreAPIServer) {
s.RegisterService(&_OcmCoreAPI_serviceDesc, srv)
@@ -315,6 +660,42 @@ func _OcmCoreAPI_CreateOCMCoreShare_Handler(srv interface{}, ctx context.Context
return interceptor(ctx, in, info, handler)
}
func _OcmCoreAPI_UpdateOCMCoreShare_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UpdateOCMCoreShareRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(OcmCoreAPIServer).UpdateOCMCoreShare(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/cs3.ocm.core.v1beta1.OcmCoreAPI/UpdateOCMCoreShare",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(OcmCoreAPIServer).UpdateOCMCoreShare(ctx, req.(*UpdateOCMCoreShareRequest))
}
return interceptor(ctx, in, info, handler)
}
func _OcmCoreAPI_DeleteOCMCoreShare_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DeleteOCMCoreShareRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(OcmCoreAPIServer).DeleteOCMCoreShare(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/cs3.ocm.core.v1beta1.OcmCoreAPI/DeleteOCMCoreShare",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(OcmCoreAPIServer).DeleteOCMCoreShare(ctx, req.(*DeleteOCMCoreShareRequest))
}
return interceptor(ctx, in, info, handler)
}
var _OcmCoreAPI_serviceDesc = grpc.ServiceDesc{
ServiceName: "cs3.ocm.core.v1beta1.OcmCoreAPI",
HandlerType: (*OcmCoreAPIServer)(nil),
@@ -323,6 +704,14 @@ var _OcmCoreAPI_serviceDesc = grpc.ServiceDesc{
MethodName: "CreateOCMCoreShare",
Handler: _OcmCoreAPI_CreateOCMCoreShare_Handler,
},
{
MethodName: "UpdateOCMCoreShare",
Handler: _OcmCoreAPI_UpdateOCMCoreShare_Handler,
},
{
MethodName: "DeleteOCMCoreShare",
Handler: _OcmCoreAPI_DeleteOCMCoreShare_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "cs3/ocm/core/v1beta1/ocm_core_api.proto",

View File

@@ -1,101 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: cs3/ocm/core/v1beta1/resources.proto
package corev1beta1
import (
fmt "fmt"
v1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
proto "github.com/golang/protobuf/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
// The protocol which is used to establish synchronisation.
type Protocol struct {
// REQUIRED.
// The name of the protocol to use.
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
// REQUIRED.
// JSON object with protocol specific options,
// e.g. uri, access_token, password, permissions etc.
Opaque *v1beta1.Opaque `protobuf:"bytes,2,opt,name=opaque,proto3" json:"opaque,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *Protocol) Reset() { *m = Protocol{} }
func (m *Protocol) String() string { return proto.CompactTextString(m) }
func (*Protocol) ProtoMessage() {}
func (*Protocol) Descriptor() ([]byte, []int) {
return fileDescriptor_2e4d9c6821c1d4ee, []int{0}
}
func (m *Protocol) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Protocol.Unmarshal(m, b)
}
func (m *Protocol) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Protocol.Marshal(b, m, deterministic)
}
func (m *Protocol) XXX_Merge(src proto.Message) {
xxx_messageInfo_Protocol.Merge(m, src)
}
func (m *Protocol) XXX_Size() int {
return xxx_messageInfo_Protocol.Size(m)
}
func (m *Protocol) XXX_DiscardUnknown() {
xxx_messageInfo_Protocol.DiscardUnknown(m)
}
var xxx_messageInfo_Protocol proto.InternalMessageInfo
func (m *Protocol) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *Protocol) GetOpaque() *v1beta1.Opaque {
if m != nil {
return m.Opaque
}
return nil
}
func init() {
proto.RegisterType((*Protocol)(nil), "cs3.ocm.core.v1beta1.Protocol")
}
func init() {
proto.RegisterFile("cs3/ocm/core/v1beta1/resources.proto", fileDescriptor_2e4d9c6821c1d4ee)
}
var fileDescriptor_2e4d9c6821c1d4ee = []byte{
// 219 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x49, 0x2e, 0x36, 0xd6,
0xcf, 0x4f, 0xce, 0xd5, 0x4f, 0xce, 0x2f, 0x4a, 0xd5, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, 0x49, 0x34,
0xd4, 0x2f, 0x4a, 0x2d, 0xce, 0x2f, 0x2d, 0x4a, 0x4e, 0x2d, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9,
0x17, 0x12, 0x49, 0x2e, 0x36, 0xd6, 0xcb, 0x4f, 0xce, 0xd5, 0x03, 0xa9, 0xd2, 0x83, 0xaa, 0x92,
0x92, 0x05, 0xe9, 0x2d, 0xa9, 0x2c, 0x48, 0x2d, 0x86, 0x6b, 0x04, 0xf3, 0x20, 0x9a, 0x94, 0x02,
0xb9, 0x38, 0x02, 0x40, 0x8c, 0xe4, 0xfc, 0x1c, 0x21, 0x21, 0x2e, 0x96, 0xbc, 0xc4, 0xdc, 0x54,
0x09, 0x46, 0x05, 0x46, 0x0d, 0xce, 0x20, 0x30, 0x5b, 0xc8, 0x90, 0x8b, 0x2d, 0xbf, 0x20, 0xb1,
0xb0, 0x34, 0x55, 0x82, 0x49, 0x81, 0x51, 0x83, 0xdb, 0x48, 0x52, 0x0f, 0x64, 0x0b, 0xc4, 0x04,
0xa8, 0x79, 0x7a, 0xfe, 0x60, 0x05, 0x41, 0x50, 0x85, 0x4e, 0xb9, 0x5c, 0x12, 0xc9, 0xf9, 0xb9,
0x7a, 0xd8, 0x5c, 0xe3, 0xc4, 0x17, 0x04, 0x73, 0x34, 0xd8, 0xd6, 0x00, 0xc6, 0x28, 0x6e, 0x90,
0x3c, 0x54, 0x7a, 0x11, 0x13, 0xb3, 0xb3, 0xbf, 0xf3, 0x2a, 0x26, 0x11, 0xe7, 0x62, 0x63, 0x3d,
0xff, 0xe4, 0x5c, 0x3d, 0x67, 0x90, 0xde, 0x30, 0x43, 0x27, 0x90, 0xe4, 0x29, 0xb0, 0x70, 0x8c,
0x7f, 0x72, 0x6e, 0x0c, 0x48, 0x38, 0x06, 0x2a, 0x9c, 0xc4, 0x06, 0xf6, 0x88, 0x31, 0x20, 0x00,
0x00, 0xff, 0xff, 0x20, 0x4f, 0x98, 0x27, 0x25, 0x01, 0x00, 0x00,
}

View File

@@ -140,6 +140,88 @@ func (m *GenerateInviteTokenResponse) GetInviteToken() *InviteToken {
return nil
}
type ListInviteTokensRequest struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ListInviteTokensRequest) Reset() { *m = ListInviteTokensRequest{} }
func (m *ListInviteTokensRequest) String() string { return proto.CompactTextString(m) }
func (*ListInviteTokensRequest) ProtoMessage() {}
func (*ListInviteTokensRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_b0e70953130e3677, []int{2}
}
func (m *ListInviteTokensRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ListInviteTokensRequest.Unmarshal(m, b)
}
func (m *ListInviteTokensRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ListInviteTokensRequest.Marshal(b, m, deterministic)
}
func (m *ListInviteTokensRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_ListInviteTokensRequest.Merge(m, src)
}
func (m *ListInviteTokensRequest) XXX_Size() int {
return xxx_messageInfo_ListInviteTokensRequest.Size(m)
}
func (m *ListInviteTokensRequest) XXX_DiscardUnknown() {
xxx_messageInfo_ListInviteTokensRequest.DiscardUnknown(m)
}
var xxx_messageInfo_ListInviteTokensRequest proto.InternalMessageInfo
type ListInviteTokensResponse struct {
// REQUIRED.
// The response status.
Status *v1beta11.Status `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
// REQUIRED.
// The list of valid tokens.
InviteTokens []*InviteToken `protobuf:"bytes,2,rep,name=invite_tokens,json=inviteTokens,proto3" json:"invite_tokens,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *ListInviteTokensResponse) Reset() { *m = ListInviteTokensResponse{} }
func (m *ListInviteTokensResponse) String() string { return proto.CompactTextString(m) }
func (*ListInviteTokensResponse) ProtoMessage() {}
func (*ListInviteTokensResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_b0e70953130e3677, []int{3}
}
func (m *ListInviteTokensResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ListInviteTokensResponse.Unmarshal(m, b)
}
func (m *ListInviteTokensResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_ListInviteTokensResponse.Marshal(b, m, deterministic)
}
func (m *ListInviteTokensResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_ListInviteTokensResponse.Merge(m, src)
}
func (m *ListInviteTokensResponse) XXX_Size() int {
return xxx_messageInfo_ListInviteTokensResponse.Size(m)
}
func (m *ListInviteTokensResponse) XXX_DiscardUnknown() {
xxx_messageInfo_ListInviteTokensResponse.DiscardUnknown(m)
}
var xxx_messageInfo_ListInviteTokensResponse proto.InternalMessageInfo
func (m *ListInviteTokensResponse) GetStatus() *v1beta11.Status {
if m != nil {
return m.Status
}
return nil
}
func (m *ListInviteTokensResponse) GetInviteTokens() []*InviteToken {
if m != nil {
return m.InviteTokens
}
return nil
}
type ForwardInviteRequest struct {
// OPTIONAL.
// Opaque information.
@@ -159,7 +241,7 @@ func (m *ForwardInviteRequest) Reset() { *m = ForwardInviteRequest{} }
func (m *ForwardInviteRequest) String() string { return proto.CompactTextString(m) }
func (*ForwardInviteRequest) ProtoMessage() {}
func (*ForwardInviteRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_b0e70953130e3677, []int{2}
return fileDescriptor_b0e70953130e3677, []int{4}
}
func (m *ForwardInviteRequest) XXX_Unmarshal(b []byte) error {
@@ -226,7 +308,7 @@ func (m *ForwardInviteResponse) Reset() { *m = ForwardInviteResponse{} }
func (m *ForwardInviteResponse) String() string { return proto.CompactTextString(m) }
func (*ForwardInviteResponse) ProtoMessage() {}
func (*ForwardInviteResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_b0e70953130e3677, []int{3}
return fileDescriptor_b0e70953130e3677, []int{5}
}
func (m *ForwardInviteResponse) XXX_Unmarshal(b []byte) error {
@@ -301,7 +383,7 @@ func (m *AcceptInviteRequest) Reset() { *m = AcceptInviteRequest{} }
func (m *AcceptInviteRequest) String() string { return proto.CompactTextString(m) }
func (*AcceptInviteRequest) ProtoMessage() {}
func (*AcceptInviteRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_b0e70953130e3677, []int{4}
return fileDescriptor_b0e70953130e3677, []int{6}
}
func (m *AcceptInviteRequest) XXX_Unmarshal(b []byte) error {
@@ -368,7 +450,7 @@ func (m *AcceptInviteResponse) Reset() { *m = AcceptInviteResponse{} }
func (m *AcceptInviteResponse) String() string { return proto.CompactTextString(m) }
func (*AcceptInviteResponse) ProtoMessage() {}
func (*AcceptInviteResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_b0e70953130e3677, []int{5}
return fileDescriptor_b0e70953130e3677, []int{7}
}
func (m *AcceptInviteResponse) XXX_Unmarshal(b []byte) error {
@@ -440,7 +522,7 @@ func (m *GetAcceptedUserRequest) Reset() { *m = GetAcceptedUserRequest{}
func (m *GetAcceptedUserRequest) String() string { return proto.CompactTextString(m) }
func (*GetAcceptedUserRequest) ProtoMessage() {}
func (*GetAcceptedUserRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_b0e70953130e3677, []int{6}
return fileDescriptor_b0e70953130e3677, []int{8}
}
func (m *GetAcceptedUserRequest) XXX_Unmarshal(b []byte) error {
@@ -494,7 +576,7 @@ func (m *GetAcceptedUserResponse) Reset() { *m = GetAcceptedUserResponse
func (m *GetAcceptedUserResponse) String() string { return proto.CompactTextString(m) }
func (*GetAcceptedUserResponse) ProtoMessage() {}
func (*GetAcceptedUserResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_b0e70953130e3677, []int{7}
return fileDescriptor_b0e70953130e3677, []int{9}
}
func (m *GetAcceptedUserResponse) XXX_Unmarshal(b []byte) error {
@@ -552,7 +634,7 @@ func (m *FindAcceptedUsersRequest) Reset() { *m = FindAcceptedUsersReque
func (m *FindAcceptedUsersRequest) String() string { return proto.CompactTextString(m) }
func (*FindAcceptedUsersRequest) ProtoMessage() {}
func (*FindAcceptedUsersRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_b0e70953130e3677, []int{8}
return fileDescriptor_b0e70953130e3677, []int{10}
}
func (m *FindAcceptedUsersRequest) XXX_Unmarshal(b []byte) error {
@@ -606,7 +688,7 @@ func (m *FindAcceptedUsersResponse) Reset() { *m = FindAcceptedUsersResp
func (m *FindAcceptedUsersResponse) String() string { return proto.CompactTextString(m) }
func (*FindAcceptedUsersResponse) ProtoMessage() {}
func (*FindAcceptedUsersResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_b0e70953130e3677, []int{9}
return fileDescriptor_b0e70953130e3677, []int{11}
}
func (m *FindAcceptedUsersResponse) XXX_Unmarshal(b []byte) error {
@@ -648,9 +730,113 @@ func (m *FindAcceptedUsersResponse) GetAcceptedUsers() []*v1beta13.User {
return nil
}
type DeleteAcceptedUserRequest struct {
// OPTIONAL.
// Opaque information.
Opaque *v1beta1.Opaque `protobuf:"bytes,1,opt,name=opaque,proto3" json:"opaque,omitempty"`
// REQUIRED.
// The id of the user.
RemoteUserId *v1beta13.UserId `protobuf:"bytes,2,opt,name=remote_user_id,json=remoteUserId,proto3" json:"remote_user_id,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *DeleteAcceptedUserRequest) Reset() { *m = DeleteAcceptedUserRequest{} }
func (m *DeleteAcceptedUserRequest) String() string { return proto.CompactTextString(m) }
func (*DeleteAcceptedUserRequest) ProtoMessage() {}
func (*DeleteAcceptedUserRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_b0e70953130e3677, []int{12}
}
func (m *DeleteAcceptedUserRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_DeleteAcceptedUserRequest.Unmarshal(m, b)
}
func (m *DeleteAcceptedUserRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_DeleteAcceptedUserRequest.Marshal(b, m, deterministic)
}
func (m *DeleteAcceptedUserRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_DeleteAcceptedUserRequest.Merge(m, src)
}
func (m *DeleteAcceptedUserRequest) XXX_Size() int {
return xxx_messageInfo_DeleteAcceptedUserRequest.Size(m)
}
func (m *DeleteAcceptedUserRequest) XXX_DiscardUnknown() {
xxx_messageInfo_DeleteAcceptedUserRequest.DiscardUnknown(m)
}
var xxx_messageInfo_DeleteAcceptedUserRequest proto.InternalMessageInfo
func (m *DeleteAcceptedUserRequest) GetOpaque() *v1beta1.Opaque {
if m != nil {
return m.Opaque
}
return nil
}
func (m *DeleteAcceptedUserRequest) GetRemoteUserId() *v1beta13.UserId {
if m != nil {
return m.RemoteUserId
}
return nil
}
type DeleteAcceptedUserResponse struct {
// REQUIRED.
// The response status.
Status *v1beta11.Status `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
// OPTIONAL.
// Opaque information.
Opaque *v1beta1.Opaque `protobuf:"bytes,2,opt,name=opaque,proto3" json:"opaque,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *DeleteAcceptedUserResponse) Reset() { *m = DeleteAcceptedUserResponse{} }
func (m *DeleteAcceptedUserResponse) String() string { return proto.CompactTextString(m) }
func (*DeleteAcceptedUserResponse) ProtoMessage() {}
func (*DeleteAcceptedUserResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_b0e70953130e3677, []int{13}
}
func (m *DeleteAcceptedUserResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_DeleteAcceptedUserResponse.Unmarshal(m, b)
}
func (m *DeleteAcceptedUserResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_DeleteAcceptedUserResponse.Marshal(b, m, deterministic)
}
func (m *DeleteAcceptedUserResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_DeleteAcceptedUserResponse.Merge(m, src)
}
func (m *DeleteAcceptedUserResponse) XXX_Size() int {
return xxx_messageInfo_DeleteAcceptedUserResponse.Size(m)
}
func (m *DeleteAcceptedUserResponse) XXX_DiscardUnknown() {
xxx_messageInfo_DeleteAcceptedUserResponse.DiscardUnknown(m)
}
var xxx_messageInfo_DeleteAcceptedUserResponse proto.InternalMessageInfo
func (m *DeleteAcceptedUserResponse) GetStatus() *v1beta11.Status {
if m != nil {
return m.Status
}
return nil
}
func (m *DeleteAcceptedUserResponse) GetOpaque() *v1beta1.Opaque {
if m != nil {
return m.Opaque
}
return nil
}
func init() {
proto.RegisterType((*GenerateInviteTokenRequest)(nil), "cs3.ocm.invite.v1beta1.GenerateInviteTokenRequest")
proto.RegisterType((*GenerateInviteTokenResponse)(nil), "cs3.ocm.invite.v1beta1.GenerateInviteTokenResponse")
proto.RegisterType((*ListInviteTokensRequest)(nil), "cs3.ocm.invite.v1beta1.ListInviteTokensRequest")
proto.RegisterType((*ListInviteTokensResponse)(nil), "cs3.ocm.invite.v1beta1.ListInviteTokensResponse")
proto.RegisterType((*ForwardInviteRequest)(nil), "cs3.ocm.invite.v1beta1.ForwardInviteRequest")
proto.RegisterType((*ForwardInviteResponse)(nil), "cs3.ocm.invite.v1beta1.ForwardInviteResponse")
proto.RegisterType((*AcceptInviteRequest)(nil), "cs3.ocm.invite.v1beta1.AcceptInviteRequest")
@@ -659,6 +845,8 @@ func init() {
proto.RegisterType((*GetAcceptedUserResponse)(nil), "cs3.ocm.invite.v1beta1.GetAcceptedUserResponse")
proto.RegisterType((*FindAcceptedUsersRequest)(nil), "cs3.ocm.invite.v1beta1.FindAcceptedUsersRequest")
proto.RegisterType((*FindAcceptedUsersResponse)(nil), "cs3.ocm.invite.v1beta1.FindAcceptedUsersResponse")
proto.RegisterType((*DeleteAcceptedUserRequest)(nil), "cs3.ocm.invite.v1beta1.DeleteAcceptedUserRequest")
proto.RegisterType((*DeleteAcceptedUserResponse)(nil), "cs3.ocm.invite.v1beta1.DeleteAcceptedUserResponse")
}
func init() {
@@ -666,53 +854,59 @@ func init() {
}
var fileDescriptor_b0e70953130e3677 = []byte{
// 733 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x56, 0xcf, 0x4e, 0x13, 0x41,
0x18, 0xcf, 0xb6, 0x50, 0xc3, 0xd7, 0x82, 0x71, 0xc1, 0x52, 0x56, 0x8d, 0xa5, 0x26, 0x88, 0x11,
0xb7, 0x96, 0xde, 0x3c, 0x09, 0x24, 0x90, 0x5e, 0x6c, 0x53, 0xd4, 0x83, 0x69, 0xd2, 0x2c, 0xbb,
0x1f, 0x66, 0x62, 0x77, 0x67, 0x99, 0x99, 0xa2, 0xbd, 0xf8, 0x14, 0x3e, 0x81, 0x47, 0x5f, 0xc2,
0xa3, 0xd1, 0x23, 0x2f, 0xa2, 0x8f, 0x60, 0x76, 0x66, 0xba, 0x2c, 0x65, 0x57, 0x0b, 0x24, 0xc4,
0x78, 0x6a, 0x67, 0x7e, 0xbf, 0xef, 0xfb, 0x7d, 0xff, 0x66, 0x66, 0xe1, 0xa1, 0xcb, 0x9b, 0x75,
0xea, 0xfa, 0x75, 0x12, 0x1c, 0x13, 0x81, 0xf5, 0xe3, 0xc6, 0x01, 0x0a, 0xa7, 0xa1, 0x97, 0x7d,
0x27, 0x24, 0x76, 0xc8, 0xa8, 0xa0, 0x66, 0xd9, 0xe5, 0x4d, 0x9b, 0xba, 0xbe, 0xad, 0x10, 0x5b,
0x13, 0xad, 0x47, 0x91, 0x03, 0xe2, 0x61, 0x20, 0x88, 0x18, 0xd5, 0x87, 0x1c, 0x59, 0xec, 0x83,
0x21, 0xa7, 0x43, 0xe6, 0x22, 0x57, 0x2e, 0xac, 0xb5, 0x0c, 0xad, 0x49, 0xde, 0xfa, 0x98, 0x17,
0x32, 0x7a, 0x4c, 0xbc, 0x3f, 0x78, 0xbc, 0x1b, 0x31, 0x59, 0xe8, 0xc6, 0x04, 0x2e, 0x1c, 0x31,
0x1c, 0xa3, 0xf7, 0x22, 0x54, 0x8c, 0x42, 0xe4, 0x31, 0x2e, 0x57, 0x0a, 0xae, 0x1d, 0x81, 0xb5,
0x87, 0x01, 0x32, 0x47, 0x60, 0x4b, 0x06, 0xf4, 0x92, 0xbe, 0xc3, 0xa0, 0x8b, 0x47, 0x43, 0xe4,
0xc2, 0x6c, 0x40, 0x81, 0x86, 0xce, 0xd1, 0x10, 0x2b, 0x46, 0xd5, 0x58, 0x2f, 0x6e, 0xae, 0xd8,
0x51, 0x01, 0x94, 0xbd, 0xf6, 0x66, 0xb7, 0x25, 0xa1, 0xab, 0x89, 0x66, 0x15, 0x8a, 0x1e, 0x72,
0x97, 0x91, 0x50, 0x10, 0x1a, 0x54, 0x72, 0x55, 0x63, 0x7d, 0xae, 0x9b, 0xdc, 0xaa, 0x7d, 0x37,
0xe0, 0x4e, 0xaa, 0x26, 0x0f, 0x69, 0xc0, 0xd1, 0xac, 0x43, 0x41, 0x65, 0xa0, 0x45, 0x97, 0xa5,
0x28, 0x0b, 0xdd, 0x58, 0x72, 0x5f, 0xc2, 0x5d, 0x4d, 0x4b, 0x44, 0x99, 0x9b, 0x36, 0xca, 0x5d,
0x28, 0xe9, 0xe6, 0x8a, 0x48, 0xbb, 0x92, 0x97, 0x86, 0x0f, 0xec, 0xf4, 0xfe, 0xda, 0xc9, 0x30,
0x8b, 0xe4, 0x74, 0x51, 0xfb, 0x69, 0xc0, 0xd2, 0x2e, 0x65, 0xef, 0x1d, 0xe6, 0x29, 0xce, 0x15,
0x2a, 0x37, 0x19, 0x53, 0xee, 0x72, 0x31, 0x99, 0x3d, 0x28, 0x53, 0x46, 0xde, 0x92, 0xa0, 0xcf,
0x47, 0x5c, 0xa0, 0xdf, 0x1f, 0x4f, 0x90, 0xce, 0x72, 0x2d, 0xf6, 0x38, 0x06, 0x62, 0x9f, 0x1d,
0xbd, 0xd1, 0x0a, 0x0e, 0x69, 0x77, 0x49, 0x79, 0xd9, 0x97, 0x4e, 0xc6, 0x48, 0xed, 0x97, 0x01,
0xb7, 0x27, 0x32, 0xbe, 0xc6, 0xbe, 0x3d, 0x83, 0x1b, 0xd1, 0xe9, 0xea, 0x13, 0x4f, 0x27, 0xb3,
0x2a, 0x6d, 0xc6, 0x47, 0xcf, 0x8e, 0xc0, 0xd8, 0xf6, 0x15, 0x47, 0xd6, 0xf2, 0xba, 0x85, 0xa1,
0xfc, 0x35, 0x97, 0x60, 0x16, 0x7d, 0x87, 0x0c, 0x2a, 0x33, 0x72, 0x26, 0xd5, 0xc2, 0x5c, 0x85,
0x92, 0x47, 0x78, 0x38, 0x70, 0x46, 0xfd, 0xc0, 0xf1, 0xb1, 0x32, 0xab, 0x07, 0x56, 0xed, 0xbd,
0x70, 0x7c, 0xac, 0x9d, 0x18, 0xb0, 0xb8, 0xe5, 0xba, 0x18, 0x8a, 0x7f, 0xa6, 0xc7, 0xcf, 0xa1,
0xc8, 0xd0, 0xa7, 0x02, 0xfb, 0x51, 0x72, 0xba, 0x16, 0xf7, 0xff, 0x52, 0x8b, 0x2e, 0x28, 0x9b,
0xe8, 0xbf, 0x9c, 0xdc, 0xb3, 0x49, 0xfd, 0xef, 0x6d, 0xfc, 0x64, 0x40, 0x79, 0x0f, 0x85, 0x4a,
0x1a, 0x3d, 0x59, 0x91, 0xcb, 0x77, 0x72, 0x0f, 0x16, 0x12, 0x1d, 0x88, 0x32, 0xc9, 0x4d, 0x9b,
0x49, 0xe9, 0xb4, 0x0d, 0x2d, 0xaf, 0xf6, 0xd5, 0x80, 0xe5, 0x73, 0x61, 0x5d, 0x63, 0x2f, 0xae,
0x3e, 0x4a, 0x08, 0x95, 0x5d, 0x12, 0x78, 0xc9, 0x0c, 0xf8, 0x15, 0x2a, 0x5b, 0x86, 0xc2, 0x21,
0x19, 0x08, 0x64, 0xfa, 0xf1, 0xd0, 0xab, 0xda, 0x37, 0x03, 0x56, 0x52, 0x74, 0xae, 0xf5, 0xd5,
0x58, 0x70, 0xb4, 0xb8, 0x2c, 0x16, 0xaf, 0xe4, 0xab, 0xf9, 0x69, 0xaa, 0x35, 0xef, 0x24, 0x63,
0xde, 0x3c, 0x99, 0x81, 0x39, 0x75, 0xea, 0xb6, 0x3a, 0x2d, 0xf3, 0x23, 0x2c, 0xa6, 0x3c, 0x87,
0xe6, 0x66, 0xd6, 0xa5, 0x90, 0xfd, 0x5e, 0x5b, 0xcd, 0x0b, 0xd9, 0xe8, 0xca, 0x0d, 0x60, 0xfe,
0xcc, 0x85, 0x6e, 0x6e, 0x64, 0x79, 0x49, 0x7b, 0xe9, 0xac, 0x27, 0x53, 0xb2, 0xb5, 0x1a, 0x81,
0x52, 0xf2, 0xda, 0x31, 0x1f, 0x67, 0x99, 0xa7, 0xdc, 0xb8, 0xd6, 0xc6, 0x74, 0x64, 0x2d, 0xc5,
0xe0, 0xe6, 0xc4, 0xc1, 0x32, 0xed, 0xec, 0x02, 0xa5, 0x5d, 0x0c, 0x56, 0x7d, 0x6a, 0xbe, 0xd6,
0xfc, 0x00, 0xb7, 0xce, 0xcd, 0xa8, 0xf9, 0x34, 0xb3, 0x44, 0x19, 0xc7, 0xc6, 0x6a, 0x5c, 0xc0,
0x42, 0x29, 0x6f, 0x0f, 0xc1, 0x72, 0xa9, 0x9f, 0x61, 0xb7, 0xbd, 0xa0, 0xe7, 0x2d, 0x24, 0x9d,
0xe8, 0xbb, 0xaf, 0x63, 0xbc, 0x99, 0x57, 0x0c, 0x4d, 0xf8, 0x9c, 0xcb, 0xef, 0xb4, 0x5b, 0x5f,
0x72, 0xe5, 0x1d, 0xde, 0xb4, 0xdb, 0xae, 0xaf, 0x9f, 0x1e, 0xfb, 0x75, 0x63, 0x3b, 0x82, 0x7f,
0x48, 0xa0, 0xd7, 0x76, 0xfd, 0x9e, 0x02, 0x7a, 0x1a, 0x38, 0x28, 0xc8, 0xef, 0xc8, 0xe6, 0xef,
0x00, 0x00, 0x00, 0xff, 0xff, 0x5d, 0xbe, 0x67, 0xda, 0x44, 0x0b, 0x00, 0x00,
// 828 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x57, 0xcd, 0x6e, 0xd3, 0x4e,
0x10, 0x97, 0x93, 0x7f, 0xf3, 0x57, 0x27, 0x69, 0x81, 0x6d, 0x49, 0x1d, 0x03, 0x22, 0x35, 0x52,
0x29, 0xa2, 0x38, 0x24, 0xb9, 0x71, 0xa2, 0x2d, 0x6a, 0x89, 0x84, 0x48, 0x94, 0x02, 0x07, 0x14,
0x29, 0x72, 0xed, 0x2d, 0x5a, 0x11, 0x7f, 0x74, 0x77, 0x5d, 0x88, 0x90, 0x10, 0x0f, 0x01, 0xe2,
0xce, 0x91, 0x97, 0xe0, 0x06, 0x82, 0x23, 0x2f, 0x02, 0x8f, 0x80, 0xbc, 0xde, 0xa4, 0x6e, 0x62,
0xd3, 0xb4, 0x95, 0xa2, 0x8a, 0x53, 0xb2, 0xfb, 0x9b, 0x99, 0xdf, 0x7c, 0xec, 0xce, 0x8e, 0xe1,
0xa6, 0xc5, 0xea, 0x15, 0xcf, 0x72, 0x2a, 0xc4, 0x3d, 0x20, 0x1c, 0x57, 0x0e, 0xaa, 0xbb, 0x98,
0x9b, 0x55, 0xb9, 0xec, 0x9a, 0x3e, 0x31, 0x7c, 0xea, 0x71, 0x0f, 0x15, 0x2d, 0x56, 0x37, 0x3c,
0xcb, 0x31, 0x22, 0xc4, 0x90, 0x82, 0xda, 0xad, 0xd0, 0x00, 0xb1, 0xb1, 0xcb, 0x09, 0xef, 0x57,
0x02, 0x86, 0xe9, 0xd0, 0x06, 0xc5, 0xcc, 0x0b, 0xa8, 0x85, 0x59, 0x64, 0x42, 0x5b, 0x49, 0xe1,
0x1a, 0x95, 0x5b, 0x1d, 0xc8, 0xf9, 0xd4, 0x3b, 0x20, 0xf6, 0x5f, 0x2c, 0x5e, 0x0d, 0x25, 0xa9,
0x6f, 0x0d, 0x05, 0x18, 0x37, 0x79, 0x30, 0x40, 0xaf, 0x85, 0x28, 0xef, 0xfb, 0x98, 0x0d, 0x71,
0xb1, 0x8a, 0x60, 0x7d, 0x1f, 0xb4, 0x6d, 0xec, 0x62, 0x6a, 0x72, 0xdc, 0x10, 0x0e, 0x3d, 0xf1,
0x5e, 0x62, 0xb7, 0x8d, 0xf7, 0x03, 0xcc, 0x38, 0xaa, 0x42, 0xce, 0xf3, 0xcd, 0xfd, 0x00, 0xab,
0x4a, 0x59, 0x59, 0xcd, 0xd7, 0x4a, 0x46, 0x98, 0x80, 0x48, 0x5f, 0x5a, 0x33, 0x9a, 0x42, 0xa0,
0x2d, 0x05, 0x51, 0x19, 0xf2, 0x36, 0x66, 0x16, 0x25, 0x3e, 0x27, 0x9e, 0xab, 0x66, 0xca, 0xca,
0xea, 0x6c, 0x3b, 0xbe, 0xa5, 0x7f, 0x57, 0xe0, 0x4a, 0x22, 0x27, 0xf3, 0x3d, 0x97, 0x61, 0x54,
0x81, 0x5c, 0x14, 0x81, 0x24, 0x5d, 0x12, 0xa4, 0xd4, 0xb7, 0x86, 0x94, 0x3b, 0x02, 0x6e, 0x4b,
0xb1, 0x98, 0x97, 0x99, 0x49, 0xbd, 0xdc, 0x82, 0x82, 0x2c, 0x2e, 0x0f, 0xb9, 0xd5, 0xac, 0x50,
0xbc, 0x61, 0x24, 0xd7, 0xd7, 0x88, 0xbb, 0x99, 0x27, 0x87, 0x0b, 0xbd, 0x04, 0x4b, 0x8f, 0x08,
0xe3, 0x31, 0x9c, 0xc9, 0xdc, 0xe9, 0x1f, 0x14, 0x50, 0xc7, 0xb1, 0xd3, 0xc6, 0xf8, 0x10, 0xe6,
0xe2, 0x0e, 0x33, 0x35, 0x53, 0xce, 0x4e, 0xea, 0x71, 0x21, 0xe6, 0x31, 0xd3, 0x7f, 0x29, 0xb0,
0xb8, 0xe5, 0xd1, 0x57, 0x26, 0xb5, 0x23, 0xa1, 0x33, 0x14, 0x7b, 0x34, 0x8d, 0x99, 0xd3, 0xa5,
0x11, 0x75, 0xa0, 0xe8, 0x51, 0xf2, 0x82, 0xb8, 0x5d, 0xd6, 0x67, 0x1c, 0x3b, 0xdd, 0xc1, 0xa1,
0x97, 0x85, 0x59, 0x19, 0x5a, 0x1c, 0x00, 0x43, 0x9b, 0x2d, 0xb9, 0xd1, 0x70, 0xf7, 0xbc, 0xf6,
0x62, 0x64, 0x65, 0x47, 0x18, 0x19, 0x20, 0xfa, 0x6f, 0x05, 0x2e, 0x8f, 0x44, 0x3c, 0xc5, 0xa3,
0x76, 0x0f, 0xfe, 0x0f, 0x1b, 0x42, 0x97, 0xd8, 0x32, 0x98, 0x65, 0xa1, 0x33, 0xe8, 0x16, 0x46,
0x08, 0x0e, 0x75, 0x9f, 0x32, 0x4c, 0x1b, 0x76, 0x3b, 0x17, 0x88, 0x5f, 0xb4, 0x08, 0x33, 0xd8,
0x31, 0x49, 0x4f, 0xfd, 0x4f, 0x5c, 0xa3, 0x68, 0x81, 0x96, 0xa1, 0x60, 0x13, 0xe6, 0xf7, 0xcc,
0x7e, 0xd7, 0x35, 0x1d, 0xac, 0xce, 0xc8, 0x3b, 0x16, 0xed, 0x3d, 0x36, 0x1d, 0xac, 0xff, 0x54,
0x60, 0x61, 0xdd, 0xb2, 0xb0, 0xcf, 0xcf, 0x4d, 0x8d, 0xef, 0x43, 0x9e, 0x62, 0xc7, 0xe3, 0xb8,
0x1b, 0x06, 0x27, 0x73, 0x71, 0xfd, 0x98, 0x5c, 0xb4, 0x21, 0xd2, 0x09, 0xff, 0x8b, 0x93, 0x7b,
0x34, 0xa8, 0x7f, 0xbd, 0x8c, 0xef, 0x15, 0x28, 0x6e, 0x63, 0x1e, 0x05, 0x8d, 0x6d, 0x91, 0x91,
0xd3, 0x57, 0x72, 0x1b, 0xe6, 0x63, 0x15, 0x08, 0x23, 0xc9, 0x4c, 0x1a, 0x49, 0xe1, 0xb0, 0x0c,
0x0d, 0x5b, 0xff, 0xa2, 0xc0, 0xd2, 0x98, 0x5b, 0x53, 0xac, 0xc5, 0xd9, 0x8f, 0x12, 0x06, 0x75,
0x8b, 0xb8, 0x76, 0x3c, 0x02, 0x76, 0x86, 0xcc, 0x16, 0x21, 0xb7, 0x47, 0x7a, 0x1c, 0x53, 0xf9,
0xde, 0xc9, 0x95, 0xfe, 0x4d, 0x81, 0x52, 0x02, 0xcf, 0x54, 0x1f, 0xba, 0x79, 0x53, 0x92, 0x8b,
0x64, 0x31, 0x35, 0x2b, 0x1e, 0x8e, 0x63, 0xb3, 0x35, 0x67, 0xc6, 0x7d, 0xd6, 0x3f, 0x2a, 0x50,
0x7a, 0x80, 0x7b, 0x98, 0xe3, 0xf3, 0x76, 0x18, 0xdf, 0x29, 0xa0, 0x25, 0x79, 0x36, 0xbd, 0x24,
0xd7, 0xbe, 0xe6, 0x60, 0x36, 0x6a, 0x49, 0xeb, 0xad, 0x06, 0x7a, 0x0b, 0x0b, 0x09, 0xe3, 0x0d,
0xaa, 0xa5, 0x75, 0xcc, 0xf4, 0xf9, 0x4b, 0xab, 0x9f, 0x48, 0x47, 0x46, 0x1c, 0xc0, 0xc5, 0xd1,
0xb9, 0x03, 0x55, 0xd2, 0x0c, 0xa5, 0x4c, 0x2f, 0xda, 0xdd, 0xc9, 0x15, 0x24, 0x6d, 0x0f, 0xe6,
0x8e, 0x3c, 0xb2, 0x68, 0x2d, 0xcd, 0x44, 0xd2, 0xf4, 0xa1, 0xdd, 0x99, 0x50, 0x5a, 0xb2, 0x11,
0x28, 0xc4, 0x9f, 0x02, 0x74, 0x3b, 0x4d, 0x3d, 0xe1, 0x15, 0xd4, 0xd6, 0x26, 0x13, 0x96, 0x54,
0x14, 0x2e, 0x8c, 0x34, 0x3b, 0x64, 0xa4, 0xd7, 0x25, 0xa9, 0x59, 0x6b, 0x95, 0x89, 0xe5, 0x25,
0xe7, 0x6b, 0xb8, 0x34, 0xd6, 0x37, 0x50, 0x6a, 0x4d, 0xd2, 0x5a, 0x99, 0x56, 0x3d, 0x81, 0x86,
0x64, 0x7e, 0x03, 0x68, 0xfc, 0x36, 0xa1, 0x54, 0x43, 0xa9, 0x3d, 0x41, 0xab, 0x9d, 0x44, 0x25,
0x22, 0xdf, 0x08, 0x40, 0xb3, 0x3c, 0x27, 0x45, 0x71, 0x63, 0x5e, 0xde, 0x31, 0x9f, 0xb4, 0xc2,
0x6f, 0x97, 0x96, 0xf2, 0x5c, 0xce, 0xc4, 0x52, 0xe0, 0x53, 0x26, 0xbb, 0xd9, 0x6c, 0x7c, 0xce,
0x14, 0x37, 0x59, 0xdd, 0x68, 0x5a, 0x8e, 0x9c, 0x45, 0x8c, 0x67, 0xd5, 0x8d, 0x10, 0xfe, 0x21,
0x80, 0x4e, 0xd3, 0x72, 0x3a, 0x11, 0xd0, 0x91, 0xc0, 0x6e, 0x4e, 0x7c, 0x0b, 0xd5, 0xff, 0x04,
0x00, 0x00, 0xff, 0xff, 0x18, 0x8d, 0xb3, 0xd2, 0x08, 0x0e, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@@ -729,7 +923,11 @@ const _ = grpc.SupportPackageIsVersion4
type InviteAPIClient interface {
// Generates a new token for the user with a validity of 24 hours.
GenerateInviteToken(ctx context.Context, in *GenerateInviteTokenRequest, opts ...grpc.CallOption) (*GenerateInviteTokenResponse, error)
// Forwards a received invite to the sync'n'share system provider.
// Lists the valid tokens generated by the user.
ListInviteTokens(ctx context.Context, in *ListInviteTokensRequest, opts ...grpc.CallOption) (*ListInviteTokensResponse, error)
// Forwards a received invite to the remote sync'n'share system provider. The remote
// system SHALL get an `invite-accepted` call as follows:
// https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1invite-accepted/post
// MUST return CODE_NOT_FOUND if the token does not exist.
// MUST return CODE_INVALID_ARGUMENT if the token expired.
// MUST return CODE_ALREADY_EXISTS if the user already accepted an invite.
@@ -745,6 +943,9 @@ type InviteAPIClient interface {
GetAcceptedUser(ctx context.Context, in *GetAcceptedUserRequest, opts ...grpc.CallOption) (*GetAcceptedUserResponse, error)
// Finds users who accepted invite tokens by their attributes.
FindAcceptedUsers(ctx context.Context, in *FindAcceptedUsersRequest, opts ...grpc.CallOption) (*FindAcceptedUsersResponse, error)
// Delete a previously accepted remote user, that is unfriend that user.
// MUST return CODE_NOT_FOUND if the user does not exist.
DeleteAcceptedUser(ctx context.Context, in *DeleteAcceptedUserRequest, opts ...grpc.CallOption) (*DeleteAcceptedUserResponse, error)
}
type inviteAPIClient struct {
@@ -764,6 +965,15 @@ func (c *inviteAPIClient) GenerateInviteToken(ctx context.Context, in *GenerateI
return out, nil
}
func (c *inviteAPIClient) ListInviteTokens(ctx context.Context, in *ListInviteTokensRequest, opts ...grpc.CallOption) (*ListInviteTokensResponse, error) {
out := new(ListInviteTokensResponse)
err := c.cc.Invoke(ctx, "/cs3.ocm.invite.v1beta1.InviteAPI/ListInviteTokens", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *inviteAPIClient) ForwardInvite(ctx context.Context, in *ForwardInviteRequest, opts ...grpc.CallOption) (*ForwardInviteResponse, error) {
out := new(ForwardInviteResponse)
err := c.cc.Invoke(ctx, "/cs3.ocm.invite.v1beta1.InviteAPI/ForwardInvite", in, out, opts...)
@@ -800,11 +1010,24 @@ func (c *inviteAPIClient) FindAcceptedUsers(ctx context.Context, in *FindAccepte
return out, nil
}
func (c *inviteAPIClient) DeleteAcceptedUser(ctx context.Context, in *DeleteAcceptedUserRequest, opts ...grpc.CallOption) (*DeleteAcceptedUserResponse, error) {
out := new(DeleteAcceptedUserResponse)
err := c.cc.Invoke(ctx, "/cs3.ocm.invite.v1beta1.InviteAPI/DeleteAcceptedUser", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// InviteAPIServer is the server API for InviteAPI service.
type InviteAPIServer interface {
// Generates a new token for the user with a validity of 24 hours.
GenerateInviteToken(context.Context, *GenerateInviteTokenRequest) (*GenerateInviteTokenResponse, error)
// Forwards a received invite to the sync'n'share system provider.
// Lists the valid tokens generated by the user.
ListInviteTokens(context.Context, *ListInviteTokensRequest) (*ListInviteTokensResponse, error)
// Forwards a received invite to the remote sync'n'share system provider. The remote
// system SHALL get an `invite-accepted` call as follows:
// https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1invite-accepted/post
// MUST return CODE_NOT_FOUND if the token does not exist.
// MUST return CODE_INVALID_ARGUMENT if the token expired.
// MUST return CODE_ALREADY_EXISTS if the user already accepted an invite.
@@ -820,6 +1043,9 @@ type InviteAPIServer interface {
GetAcceptedUser(context.Context, *GetAcceptedUserRequest) (*GetAcceptedUserResponse, error)
// Finds users who accepted invite tokens by their attributes.
FindAcceptedUsers(context.Context, *FindAcceptedUsersRequest) (*FindAcceptedUsersResponse, error)
// Delete a previously accepted remote user, that is unfriend that user.
// MUST return CODE_NOT_FOUND if the user does not exist.
DeleteAcceptedUser(context.Context, *DeleteAcceptedUserRequest) (*DeleteAcceptedUserResponse, error)
}
// UnimplementedInviteAPIServer can be embedded to have forward compatible implementations.
@@ -829,6 +1055,9 @@ type UnimplementedInviteAPIServer struct {
func (*UnimplementedInviteAPIServer) GenerateInviteToken(ctx context.Context, req *GenerateInviteTokenRequest) (*GenerateInviteTokenResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GenerateInviteToken not implemented")
}
func (*UnimplementedInviteAPIServer) ListInviteTokens(ctx context.Context, req *ListInviteTokensRequest) (*ListInviteTokensResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListInviteTokens not implemented")
}
func (*UnimplementedInviteAPIServer) ForwardInvite(ctx context.Context, req *ForwardInviteRequest) (*ForwardInviteResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ForwardInvite not implemented")
}
@@ -841,6 +1070,9 @@ func (*UnimplementedInviteAPIServer) GetAcceptedUser(ctx context.Context, req *G
func (*UnimplementedInviteAPIServer) FindAcceptedUsers(ctx context.Context, req *FindAcceptedUsersRequest) (*FindAcceptedUsersResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method FindAcceptedUsers not implemented")
}
func (*UnimplementedInviteAPIServer) DeleteAcceptedUser(ctx context.Context, req *DeleteAcceptedUserRequest) (*DeleteAcceptedUserResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method DeleteAcceptedUser not implemented")
}
func RegisterInviteAPIServer(s *grpc.Server, srv InviteAPIServer) {
s.RegisterService(&_InviteAPI_serviceDesc, srv)
@@ -864,6 +1096,24 @@ func _InviteAPI_GenerateInviteToken_Handler(srv interface{}, ctx context.Context
return interceptor(ctx, in, info, handler)
}
func _InviteAPI_ListInviteTokens_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListInviteTokensRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(InviteAPIServer).ListInviteTokens(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/cs3.ocm.invite.v1beta1.InviteAPI/ListInviteTokens",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(InviteAPIServer).ListInviteTokens(ctx, req.(*ListInviteTokensRequest))
}
return interceptor(ctx, in, info, handler)
}
func _InviteAPI_ForwardInvite_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ForwardInviteRequest)
if err := dec(in); err != nil {
@@ -936,6 +1186,24 @@ func _InviteAPI_FindAcceptedUsers_Handler(srv interface{}, ctx context.Context,
return interceptor(ctx, in, info, handler)
}
func _InviteAPI_DeleteAcceptedUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DeleteAcceptedUserRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(InviteAPIServer).DeleteAcceptedUser(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/cs3.ocm.invite.v1beta1.InviteAPI/DeleteAcceptedUser",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(InviteAPIServer).DeleteAcceptedUser(ctx, req.(*DeleteAcceptedUserRequest))
}
return interceptor(ctx, in, info, handler)
}
var _InviteAPI_serviceDesc = grpc.ServiceDesc{
ServiceName: "cs3.ocm.invite.v1beta1.InviteAPI",
HandlerType: (*InviteAPIServer)(nil),
@@ -944,6 +1212,10 @@ var _InviteAPI_serviceDesc = grpc.ServiceDesc{
MethodName: "GenerateInviteToken",
Handler: _InviteAPI_GenerateInviteToken_Handler,
},
{
MethodName: "ListInviteTokens",
Handler: _InviteAPI_ListInviteTokens_Handler,
},
{
MethodName: "ForwardInvite",
Handler: _InviteAPI_ForwardInvite_Handler,
@@ -960,6 +1232,10 @@ var _InviteAPI_serviceDesc = grpc.ServiceDesc{
MethodName: "FindAcceptedUsers",
Handler: _InviteAPI_FindAcceptedUsers_Handler,
},
{
MethodName: "DeleteAcceptedUser",
Handler: _InviteAPI_DeleteAcceptedUser_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "cs3/ocm/invite/v1beta1/invite_api.proto",

View File

@@ -32,12 +32,14 @@ const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type UpdatePublicShareRequest_Update_Type int32
const (
UpdatePublicShareRequest_Update_TYPE_INVALID UpdatePublicShareRequest_Update_Type = 0
UpdatePublicShareRequest_Update_TYPE_PERMISSIONS UpdatePublicShareRequest_Update_Type = 1
UpdatePublicShareRequest_Update_TYPE_PASSWORD UpdatePublicShareRequest_Update_Type = 2
UpdatePublicShareRequest_Update_TYPE_EXPIRATION UpdatePublicShareRequest_Update_Type = 3
UpdatePublicShareRequest_Update_TYPE_DISPLAYNAME UpdatePublicShareRequest_Update_Type = 4
UpdatePublicShareRequest_Update_TYPE_DESCRIPTION UpdatePublicShareRequest_Update_Type = 5
UpdatePublicShareRequest_Update_TYPE_INVALID UpdatePublicShareRequest_Update_Type = 0
UpdatePublicShareRequest_Update_TYPE_PERMISSIONS UpdatePublicShareRequest_Update_Type = 1
UpdatePublicShareRequest_Update_TYPE_PASSWORD UpdatePublicShareRequest_Update_Type = 2
UpdatePublicShareRequest_Update_TYPE_EXPIRATION UpdatePublicShareRequest_Update_Type = 3
UpdatePublicShareRequest_Update_TYPE_DISPLAYNAME UpdatePublicShareRequest_Update_Type = 4
UpdatePublicShareRequest_Update_TYPE_DESCRIPTION UpdatePublicShareRequest_Update_Type = 5
UpdatePublicShareRequest_Update_TYPE_NOTIFYUPLOADS UpdatePublicShareRequest_Update_Type = 6
UpdatePublicShareRequest_Update_TYPE_NOTIFYUPLOADSEXTRARECIPIENTS UpdatePublicShareRequest_Update_Type = 7
)
var UpdatePublicShareRequest_Update_Type_name = map[int32]string{
@@ -47,15 +49,19 @@ var UpdatePublicShareRequest_Update_Type_name = map[int32]string{
3: "TYPE_EXPIRATION",
4: "TYPE_DISPLAYNAME",
5: "TYPE_DESCRIPTION",
6: "TYPE_NOTIFYUPLOADS",
7: "TYPE_NOTIFYUPLOADSEXTRARECIPIENTS",
}
var UpdatePublicShareRequest_Update_Type_value = map[string]int32{
"TYPE_INVALID": 0,
"TYPE_PERMISSIONS": 1,
"TYPE_PASSWORD": 2,
"TYPE_EXPIRATION": 3,
"TYPE_DISPLAYNAME": 4,
"TYPE_DESCRIPTION": 5,
"TYPE_INVALID": 0,
"TYPE_PERMISSIONS": 1,
"TYPE_PASSWORD": 2,
"TYPE_EXPIRATION": 3,
"TYPE_DISPLAYNAME": 4,
"TYPE_DESCRIPTION": 5,
"TYPE_NOTIFYUPLOADS": 6,
"TYPE_NOTIFYUPLOADSEXTRARECIPIENTS": 7,
}
func (x UpdatePublicShareRequest_Update_Type) String() string {
@@ -114,10 +120,17 @@ type CreatePublicShareRequest struct {
// OPTIONAL
// Indicates a share used for internal usage,
// not exposed by a ListPublicShares.
Internal bool `protobuf:"varint,5,opt,name=internal,proto3" json:"internal,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
Internal bool `protobuf:"varint,5,opt,name=internal,proto3" json:"internal,omitempty"`
// OPTIONAL
// Whether to notify the owner of a share when a file is uploaded to it.
NotifyUploads bool `protobuf:"varint,6,opt,name=notify_uploads,json=notifyUploads,proto3" json:"notify_uploads,omitempty"`
// OPTIONAL
// Comma-separated list of extra email addresses to notify when a file is
// uploaded to the share.
NotifyUploadsExtraRecipients string `protobuf:"bytes,7,opt,name=notify_uploads_extra_recipients,json=notifyUploadsExtraRecipients,proto3" json:"notify_uploads_extra_recipients,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CreatePublicShareRequest) Reset() { *m = CreatePublicShareRequest{} }
@@ -180,6 +193,20 @@ func (m *CreatePublicShareRequest) GetInternal() bool {
return false
}
func (m *CreatePublicShareRequest) GetNotifyUploads() bool {
if m != nil {
return m.NotifyUploads
}
return false
}
func (m *CreatePublicShareRequest) GetNotifyUploadsExtraRecipients() string {
if m != nil {
return m.NotifyUploadsExtraRecipients
}
return ""
}
type CreatePublicShareResponse struct {
// REQUIRED.
// The response status.
@@ -313,10 +340,17 @@ type UpdatePublicShareRequest_Update struct {
DisplayName string `protobuf:"bytes,5,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"`
// OPTIONAL
// Defines the public link description.
Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"`
// OPTIONAL
// Whether to notify the owner of a share when a file is uploaded to it.
NotifyUploads bool `protobuf:"varint,7,opt,name=notify_uploads,json=notifyUploads,proto3" json:"notify_uploads,omitempty"`
// OPTIONAL
// Comma-separated list of extra email addresses to notify when a file is
// uploaded to the share.
NotifyUploadsExtraRecipients string `protobuf:"bytes,8,opt,name=notify_uploads_extra_recipients,json=notifyUploadsExtraRecipients,proto3" json:"notify_uploads_extra_recipients,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *UpdatePublicShareRequest_Update) Reset() { *m = UpdatePublicShareRequest_Update{} }
@@ -372,6 +406,20 @@ func (m *UpdatePublicShareRequest_Update) GetDescription() string {
return ""
}
func (m *UpdatePublicShareRequest_Update) GetNotifyUploads() bool {
if m != nil {
return m.NotifyUploads
}
return false
}
func (m *UpdatePublicShareRequest_Update) GetNotifyUploadsExtraRecipients() string {
if m != nil {
return m.NotifyUploadsExtraRecipients
}
return ""
}
type UpdatePublicShareResponse struct {
// REQUIRED.
// The response status.
@@ -1086,79 +1134,86 @@ func init() {
}
var fileDescriptor_fd835bb71eb73d1e = []byte{
// 1149 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x57, 0x4f, 0x6f, 0x1b, 0x45,
0x14, 0xef, 0xae, 0xff, 0x34, 0x7d, 0xf9, 0xd3, 0xcd, 0x50, 0xe8, 0xc6, 0x24, 0x22, 0xb5, 0x04,
0x35, 0x08, 0xad, 0x89, 0x2d, 0xfe, 0x54, 0xa8, 0x08, 0xdb, 0x31, 0xed, 0x8a, 0xd4, 0xde, 0xce,
0xa6, 0x2d, 0x85, 0x48, 0xd6, 0x66, 0x3d, 0x89, 0x57, 0x49, 0x76, 0xb7, 0x33, 0xeb, 0x04, 0x57,
0x95, 0x90, 0x38, 0x71, 0xe3, 0xc0, 0x17, 0x40, 0x1c, 0xf9, 0x06, 0x48, 0x9c, 0x38, 0xf2, 0x09,
0xb8, 0x70, 0xe2, 0xc4, 0x89, 0x2f, 0x80, 0x10, 0x9a, 0xd9, 0xb1, 0xe3, 0xc4, 0x59, 0x63, 0xb7,
0x08, 0x9a, 0xdb, 0xce, 0x7b, 0xef, 0xf7, 0xe6, 0x37, 0xef, 0xdf, 0xcc, 0xc2, 0x75, 0x97, 0x95,
0x8b, 0xac, 0xe3, 0x50, 0xcf, 0xdf, 0x2d, 0xee, 0x7b, 0xfe, 0x5e, 0xf1, 0x70, 0x6d, 0x9b, 0x44,
0xce, 0x9a, 0x58, 0xb4, 0x9c, 0xd0, 0x33, 0x42, 0x1a, 0x44, 0x01, 0xd2, 0x5d, 0x56, 0x36, 0xa4,
0xa1, 0xc1, 0x75, 0x86, 0x34, 0xcc, 0xbd, 0xce, 0x5d, 0x78, 0x6d, 0xe2, 0x47, 0x5e, 0xd4, 0x2b,
0x76, 0x19, 0xa1, 0x03, 0x1f, 0x94, 0xb0, 0xa0, 0x4b, 0x5d, 0xc2, 0x62, 0x27, 0xb9, 0x65, 0x6e,
0x4a, 0x43, 0x77, 0x60, 0xc0, 0x22, 0x27, 0xea, 0xf6, 0xb5, 0x85, 0x44, 0x2e, 0xa7, 0xfd, 0xbc,
0x29, 0x2c, 0xa3, 0x80, 0x3a, 0xbb, 0xa4, 0x18, 0xd2, 0xe0, 0xd0, 0x6b, 0x8f, 0xd9, 0x75, 0x85,
0x5b, 0x47, 0xbd, 0x90, 0xb0, 0x81, 0x89, 0x58, 0xc5, 0xea, 0xfc, 0x37, 0x2a, 0xe8, 0x35, 0x4a,
0x9c, 0x88, 0x58, 0xdd, 0xed, 0x7d, 0xcf, 0xb5, 0x3b, 0x0e, 0x25, 0x98, 0x3c, 0xea, 0x12, 0x16,
0xa1, 0x35, 0xc8, 0x06, 0xa1, 0xf3, 0xa8, 0x4b, 0x74, 0x65, 0x55, 0x29, 0xcc, 0x96, 0x96, 0x0c,
0x1e, 0x87, 0x18, 0x2e, 0x9d, 0x19, 0x4d, 0x61, 0x80, 0xa5, 0x21, 0x6a, 0xc2, 0x7c, 0x9f, 0x41,
0xcb, 0xf3, 0x77, 0x02, 0x5d, 0x15, 0xc8, 0x37, 0x04, 0x52, 0x92, 0x36, 0xfa, 0xa4, 0x07, 0x4e,
0xb0, 0x84, 0x98, 0xfe, 0x4e, 0x80, 0xe7, 0xe8, 0xd0, 0x0a, 0xbd, 0x0d, 0x99, 0x5d, 0xea, 0xf8,
0x91, 0x9e, 0x12, 0x8e, 0x5e, 0x31, 0x92, 0x52, 0x61, 0xdc, 0xe2, 0x66, 0x38, 0xb6, 0x46, 0xab,
0x30, 0xdb, 0x26, 0xcc, 0xa5, 0x5e, 0x18, 0x79, 0x81, 0xaf, 0xa7, 0x57, 0x95, 0xc2, 0x25, 0x3c,
0x2c, 0x42, 0x39, 0x98, 0xf1, 0xfc, 0x88, 0x50, 0xdf, 0xd9, 0xd7, 0x33, 0xab, 0x4a, 0x61, 0x06,
0x0f, 0xd6, 0xf9, 0x1f, 0x15, 0x58, 0x3a, 0x23, 0x2a, 0x2c, 0x0c, 0x7c, 0x46, 0x50, 0x11, 0xb2,
0x71, 0xea, 0x64, 0x58, 0xae, 0x0a, 0x4e, 0x34, 0x74, 0x07, 0x54, 0x6c, 0xa1, 0xc6, 0xd2, 0x6c,
0x28, 0x8e, 0xea, 0xa4, 0x71, 0x7c, 0x1f, 0x32, 0xfc, 0x90, 0x44, 0x1e, 0xfb, 0xd5, 0xe4, 0x63,
0x0f, 0x33, 0x8c, 0x31, 0xf9, 0x9f, 0xd2, 0xa0, 0xdf, 0x0b, 0xdb, 0xff, 0x5a, 0x52, 0x3f, 0x84,
0x14, 0x25, 0x3b, 0x92, 0xbc, 0x31, 0x19, 0x15, 0xb2, 0x43, 0x28, 0xf1, 0x5d, 0x82, 0x39, 0x14,
0xdd, 0x85, 0x6c, 0x57, 0x10, 0x92, 0xe7, 0xb9, 0x91, 0xec, 0x24, 0x89, 0xb8, 0x54, 0x60, 0xe9,
0x28, 0xf7, 0xab, 0x0a, 0xd9, 0x58, 0x84, 0x30, 0xa4, 0x39, 0x7f, 0xe1, 0x7b, 0xa1, 0xf4, 0xc1,
0x53, 0xfb, 0x36, 0x36, 0x7b, 0x21, 0xc1, 0xc2, 0xd7, 0x71, 0xdd, 0xa5, 0xa7, 0xaa, 0xbb, 0x6b,
0x30, 0xd7, 0xf6, 0x58, 0xb8, 0xef, 0xf4, 0x5a, 0xbe, 0x73, 0x40, 0x44, 0x65, 0xf1, 0xc2, 0x8b,
0x65, 0x0d, 0xe7, 0x80, 0x9c, 0x2e, 0xcd, 0xec, 0x48, 0x69, 0xe6, 0xbf, 0x54, 0x20, 0xcd, 0xa9,
0x20, 0x0d, 0xe6, 0x36, 0x1f, 0x5a, 0xf5, 0x96, 0xd9, 0xb8, 0x5f, 0xd9, 0x30, 0xd7, 0xb5, 0x0b,
0xe8, 0x0a, 0x68, 0x42, 0x62, 0xd5, 0xf1, 0x1d, 0xd3, 0xb6, 0xcd, 0x66, 0xc3, 0xd6, 0x14, 0xb4,
0x08, 0xf3, 0xb1, 0xb4, 0x62, 0xdb, 0x0f, 0x9a, 0x78, 0x5d, 0x53, 0xd1, 0x0b, 0x70, 0x59, 0x88,
0xea, 0x9f, 0x58, 0x26, 0xae, 0x6c, 0x9a, 0xcd, 0x86, 0x96, 0x1a, 0xa0, 0xd7, 0x4d, 0xdb, 0xda,
0xa8, 0x3c, 0x6c, 0x54, 0xee, 0xd4, 0xb5, 0xf4, 0xb1, 0xb4, 0x6e, 0xd7, 0xb0, 0x69, 0x09, 0xdb,
0x8c, 0xe8, 0x81, 0x33, 0xe2, 0x75, 0x5e, 0x7a, 0xe0, 0x8f, 0x34, 0x5c, 0xdd, 0xf0, 0x58, 0x34,
0xa4, 0x62, 0xcf, 0xd0, 0x02, 0x18, 0x2e, 0xee, 0x78, 0xfb, 0x11, 0xa1, 0x4c, 0x57, 0x57, 0x53,
0x85, 0xd9, 0xd2, 0x7b, 0xc9, 0x6c, 0x12, 0xb6, 0x35, 0x3e, 0x12, 0x0e, 0x70, 0xdf, 0x11, 0x42,
0x90, 0x66, 0xde, 0xae, 0x2f, 0x8e, 0x37, 0x83, 0xc5, 0x37, 0x7a, 0x19, 0x2e, 0x85, 0xce, 0x2e,
0x69, 0x31, 0xef, 0x31, 0x11, 0xa5, 0x97, 0xc1, 0x33, 0x5c, 0x60, 0x7b, 0x8f, 0x09, 0x5a, 0x01,
0x10, 0xca, 0x28, 0xd8, 0x23, 0xbe, 0x2c, 0x2d, 0x61, 0xbe, 0xc9, 0x05, 0xb9, 0x3f, 0x55, 0xc8,
0xc6, 0x7b, 0xa0, 0xbb, 0xb2, 0x23, 0x54, 0xd1, 0x11, 0x37, 0x9f, 0x96, 0xeb, 0x70, 0x43, 0x7c,
0x0c, 0xb3, 0xc7, 0x93, 0xbd, 0x2d, 0x73, 0x52, 0x98, 0x70, 0xae, 0xb7, 0x6f, 0x5f, 0xc0, 0x30,
0x98, 0xeb, 0x6d, 0x74, 0x03, 0x32, 0xc1, 0x91, 0x4f, 0xa8, 0xec, 0xae, 0x6b, 0xc2, 0x4d, 0xff,
0x1a, 0x35, 0xf8, 0x35, 0x7a, 0xdc, 0xb3, 0x8c, 0x50, 0x81, 0x8f, 0x11, 0xe8, 0x26, 0x5c, 0x74,
0xf9, 0x68, 0x0e, 0xa8, 0x88, 0xc0, 0x84, 0xe0, 0x3e, 0x26, 0x6f, 0xfd, 0x63, 0x6b, 0xe1, 0xba,
0xdd, 0xbc, 0x87, 0x6b, 0xf5, 0x96, 0xb9, 0xae, 0x29, 0x68, 0x01, 0x40, 0x48, 0x9b, 0x0f, 0x1a,
0x75, 0xac, 0xa9, 0x03, 0x5c, 0x0d, 0xd7, 0x2b, 0x9b, 0x4d, 0xac, 0xa5, 0xaa, 0x59, 0x48, 0x47,
0x84, 0x1e, 0xe4, 0x7f, 0x53, 0x40, 0x1f, 0x0d, 0xe7, 0xff, 0xd3, 0x2f, 0xa9, 0x69, 0xfb, 0x05,
0xbd, 0x06, 0x97, 0x7d, 0xf2, 0x79, 0xd4, 0x1a, 0x2a, 0xb0, 0xf8, 0xd2, 0x9c, 0xe7, 0x62, 0xab,
0x5f, 0x64, 0xf9, 0xaf, 0x15, 0xd0, 0x31, 0x39, 0x08, 0x0e, 0x9f, 0x97, 0xbb, 0x25, 0xff, 0x05,
0x2c, 0x9d, 0x41, 0xe8, 0xbf, 0x8b, 0x7b, 0xfe, 0x5b, 0x05, 0x5e, 0xbc, 0x45, 0xa2, 0xe7, 0xe5,
0xae, 0x3d, 0x63, 0xac, 0xe4, 0x7f, 0x50, 0xe0, 0xa5, 0xd3, 0x14, 0xcf, 0xcb, 0x24, 0xff, 0x45,
0x81, 0xe5, 0x93, 0xdc, 0xab, 0x3d, 0x51, 0x8b, 0xcf, 0x10, 0xe5, 0x2b, 0x90, 0x89, 0x6b, 0x5c,
0x15, 0x35, 0x1e, 0x2f, 0xd0, 0x67, 0xb0, 0xe0, 0x74, 0xa3, 0x0e, 0x1f, 0x24, 0xae, 0x23, 0x2e,
0xe7, 0x98, 0x6f, 0x79, 0x22, 0xbe, 0x95, 0x13, 0x50, 0x7c, 0xca, 0xd5, 0x20, 0x2d, 0xe9, 0xa1,
0xb4, 0xfc, 0xae, 0xc0, 0x4a, 0xc2, 0xd1, 0xce, 0x49, 0x76, 0xd0, 0x75, 0x98, 0x0f, 0x1d, 0xc6,
0x8e, 0x02, 0xda, 0x6e, 0x75, 0x1c, 0xd6, 0x89, 0xa7, 0x46, 0x55, 0xd5, 0x15, 0x3c, 0xd7, 0x57,
0xdc, 0x76, 0x58, 0xa7, 0xf4, 0x57, 0x06, 0x2e, 0x6e, 0x78, 0xfe, 0x5e, 0xc5, 0x32, 0xd1, 0x13,
0x58, 0x1c, 0x79, 0x5e, 0xa3, 0x52, 0xf2, 0xbe, 0x49, 0x7f, 0x28, 0xb9, 0xf2, 0x54, 0x18, 0x19,
0xd3, 0x27, 0xb0, 0x38, 0x32, 0x30, 0xc6, 0xed, 0x9e, 0x34, 0xee, 0xc6, 0xed, 0x9e, 0x3c, 0x91,
0x18, 0x2c, 0x9c, 0x4c, 0x39, 0x2a, 0x8e, 0x79, 0x5b, 0x9e, 0x35, 0x56, 0x72, 0x6f, 0x4d, 0x0e,
0x90, 0x9b, 0x7e, 0x35, 0x32, 0xa2, 0x64, 0xa1, 0xa1, 0x77, 0x26, 0xf5, 0x75, 0xb2, 0xe9, 0x72,
0xef, 0x4e, 0x8d, 0x93, 0x54, 0x7a, 0xa0, 0x9d, 0xbe, 0x25, 0xd1, 0xda, 0xd4, 0x0f, 0x94, 0x5c,
0x69, 0x1a, 0xc8, 0x71, 0xe2, 0x47, 0x5e, 0xb4, 0xe3, 0x12, 0x9f, 0xf4, 0xbb, 0x30, 0x2e, 0xf1,
0x89, 0x4f, 0xe6, 0xea, 0x11, 0x2c, 0xbb, 0xc1, 0x41, 0x22, 0xb2, 0x3a, 0x27, 0xba, 0x23, 0xf4,
0x2c, 0xfe, 0x63, 0x6e, 0x29, 0x9f, 0xce, 0x72, 0xad, 0x54, 0x7e, 0xa7, 0xa6, 0x6a, 0xf6, 0xc6,
0xf7, 0xaa, 0x5e, 0x63, 0x65, 0xc3, 0x96, 0x68, 0x6e, 0x6f, 0xdc, 0x5f, 0xab, 0x72, 0x83, 0x9f,
0x85, 0x6a, 0x4b, 0xaa, 0xb6, 0xb8, 0x6a, 0x4b, 0xaa, 0xb6, 0xb3, 0xe2, 0x57, 0xbf, 0xfc, 0x77,
0x00, 0x00, 0x00, 0xff, 0xff, 0xb6, 0x49, 0x45, 0x11, 0xef, 0x10, 0x00, 0x00,
// 1249 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x58, 0x5b, 0x8f, 0xdb, 0xc4,
0x17, 0xaf, 0x73, 0xdb, 0xed, 0xd9, 0x4b, 0xdd, 0xf9, 0xf7, 0xdf, 0xba, 0x61, 0xab, 0x6e, 0x23,
0x95, 0x2e, 0x08, 0x39, 0xec, 0xae, 0xb8, 0x54, 0xa8, 0x88, 0x24, 0xeb, 0xb6, 0x16, 0x69, 0xe2,
0x8e, 0xb3, 0xbd, 0x40, 0xa5, 0xc8, 0x75, 0x26, 0x1b, 0xab, 0x59, 0xdb, 0x9d, 0x99, 0xb4, 0x4d,
0x55, 0x09, 0xf1, 0x86, 0x78, 0xe1, 0x2b, 0x20, 0x1e, 0xf9, 0x06, 0x48, 0xbc, 0xf0, 0xca, 0x27,
0xe0, 0x9d, 0x27, 0x9e, 0xf8, 0x02, 0x08, 0x21, 0x8f, 0x27, 0xd9, 0x64, 0xb3, 0x0e, 0x49, 0x8b,
0xa0, 0xfb, 0x96, 0x39, 0xe7, 0xf7, 0x3b, 0x73, 0xe6, 0xdc, 0x66, 0x1c, 0xb8, 0xe2, 0xb2, 0xed,
0x22, 0xeb, 0x38, 0xd4, 0xf3, 0xf7, 0x8a, 0x5d, 0xcf, 0x7f, 0x54, 0x7c, 0xb2, 0xf9, 0x90, 0x70,
0x67, 0x53, 0x2c, 0x9a, 0x4e, 0xe8, 0xe9, 0x21, 0x0d, 0x78, 0x80, 0x34, 0x97, 0x6d, 0xeb, 0x12,
0xa8, 0x47, 0x3a, 0x5d, 0x02, 0xf3, 0x6f, 0x45, 0x26, 0xbc, 0x16, 0xf1, 0xb9, 0xc7, 0xfb, 0xc5,
0x1e, 0x23, 0x74, 0x68, 0x83, 0x12, 0x16, 0xf4, 0xa8, 0x4b, 0x58, 0x6c, 0x24, 0xbf, 0x16, 0x41,
0x69, 0xe8, 0x0e, 0x01, 0x8c, 0x3b, 0xbc, 0x37, 0xd0, 0x6e, 0x24, 0xfa, 0x72, 0xd8, 0xce, 0x3b,
0x02, 0xc9, 0x03, 0xea, 0xec, 0x91, 0x62, 0x48, 0x83, 0x27, 0x5e, 0x6b, 0xca, 0xae, 0x17, 0x22,
0x34, 0xef, 0x87, 0x84, 0x0d, 0x21, 0x62, 0x15, 0xab, 0x0b, 0x5f, 0xa6, 0x41, 0xab, 0x50, 0xe2,
0x70, 0x62, 0xf5, 0x1e, 0x76, 0x3d, 0xd7, 0xee, 0x38, 0x94, 0x60, 0xf2, 0xb8, 0x47, 0x18, 0x47,
0x9b, 0x90, 0x0b, 0x42, 0xe7, 0x71, 0x8f, 0x68, 0xca, 0xba, 0xb2, 0xb1, 0xb4, 0x75, 0x5e, 0x8f,
0xe2, 0x10, 0xd3, 0xa5, 0x31, 0xbd, 0x2e, 0x00, 0x58, 0x02, 0x51, 0x1d, 0x56, 0x06, 0x1e, 0x34,
0x3d, 0xbf, 0x1d, 0x68, 0x29, 0xc1, 0x7c, 0x5b, 0x30, 0xa5, 0xd3, 0xfa, 0xc0, 0xe9, 0xa1, 0x11,
0x2c, 0x29, 0xa6, 0xdf, 0x0e, 0xf0, 0x32, 0x1d, 0x59, 0xa1, 0xf7, 0x20, 0xbb, 0x47, 0x1d, 0x9f,
0x6b, 0x69, 0x61, 0xe8, 0xa2, 0x9e, 0x94, 0x0a, 0xfd, 0x46, 0x04, 0xc3, 0x31, 0x1a, 0xad, 0xc3,
0x52, 0x8b, 0x30, 0x97, 0x7a, 0x21, 0xf7, 0x02, 0x5f, 0xcb, 0xac, 0x2b, 0x1b, 0x27, 0xf1, 0xa8,
0x08, 0xe5, 0x61, 0xd1, 0xf3, 0x39, 0xa1, 0xbe, 0xd3, 0xd5, 0xb2, 0xeb, 0xca, 0xc6, 0x22, 0x1e,
0xae, 0xd1, 0x65, 0x58, 0xf5, 0x03, 0xee, 0xb5, 0xfb, 0xcd, 0x5e, 0xd8, 0x0d, 0x9c, 0x16, 0xd3,
0x72, 0x02, 0xb1, 0x12, 0x4b, 0x77, 0x63, 0x21, 0x32, 0xe0, 0xe2, 0x38, 0xac, 0x49, 0x9e, 0x71,
0xea, 0x34, 0x29, 0x71, 0xbd, 0xd0, 0x23, 0x3e, 0x67, 0xda, 0x82, 0xd8, 0x78, 0x6d, 0x8c, 0x67,
0x44, 0x20, 0x3c, 0xc4, 0x14, 0x7e, 0x54, 0xe0, 0xfc, 0x11, 0x39, 0x60, 0x61, 0xe0, 0x33, 0x82,
0x8a, 0x90, 0x8b, 0x0b, 0x45, 0x26, 0xe1, 0x9c, 0x88, 0x00, 0x0d, 0xdd, 0xe1, 0xc1, 0x6d, 0xa1,
0xc6, 0x12, 0x36, 0x92, 0xb5, 0xd4, 0xac, 0x59, 0xfb, 0x08, 0xb2, 0x51, 0x48, 0x89, 0x0c, 0xf2,
0xe5, 0xe4, 0x20, 0x8f, 0x7a, 0x18, 0x73, 0x0a, 0xbf, 0x67, 0x41, 0xdb, 0x0d, 0x5b, 0xff, 0x58,
0x09, 0x7d, 0x02, 0x69, 0x4a, 0xda, 0xd2, 0x79, 0x7d, 0x36, 0x57, 0x48, 0x9b, 0x50, 0xe2, 0xbb,
0x04, 0x47, 0x54, 0x74, 0x1b, 0x72, 0x3d, 0xe1, 0x90, 0x3c, 0xcf, 0xd5, 0x64, 0x23, 0x49, 0x8e,
0x4b, 0x05, 0x96, 0x86, 0xf2, 0x5f, 0x67, 0x20, 0x17, 0x8b, 0x10, 0x86, 0x4c, 0xe4, 0xbf, 0xb0,
0xbd, 0xba, 0xf5, 0xf1, 0x4b, 0xdb, 0xd6, 0x1b, 0xfd, 0x90, 0x60, 0x61, 0xeb, 0xa0, 0xca, 0x33,
0x73, 0x55, 0xf9, 0x25, 0x58, 0x6e, 0x79, 0x2c, 0xec, 0x3a, 0xfd, 0xa6, 0xef, 0xec, 0x13, 0x51,
0xc7, 0x51, 0x99, 0xc7, 0xb2, 0x9a, 0xb3, 0x4f, 0x0e, 0x37, 0x42, 0x6e, 0xb2, 0x11, 0x26, 0x8b,
0x7d, 0xe1, 0x25, 0x8b, 0x7d, 0x71, 0x86, 0x62, 0xff, 0x49, 0x81, 0x4c, 0x74, 0x70, 0xa4, 0xc2,
0x72, 0xe3, 0xbe, 0x65, 0x34, 0xcd, 0xda, 0x9d, 0x52, 0xd5, 0xdc, 0x51, 0x4f, 0xa0, 0x33, 0xa0,
0x0a, 0x89, 0x65, 0xe0, 0x5b, 0xa6, 0x6d, 0x9b, 0xf5, 0x9a, 0xad, 0x2a, 0xe8, 0x34, 0xac, 0xc4,
0xd2, 0x92, 0x6d, 0xdf, 0xad, 0xe3, 0x1d, 0x35, 0x85, 0xfe, 0x07, 0xa7, 0x84, 0xc8, 0xb8, 0x67,
0x99, 0xb8, 0xd4, 0x30, 0xeb, 0x35, 0x35, 0x3d, 0x64, 0xef, 0x98, 0xb6, 0x55, 0x2d, 0xdd, 0xaf,
0x95, 0x6e, 0x19, 0x6a, 0xe6, 0x40, 0x6a, 0xd8, 0x15, 0x6c, 0x5a, 0x02, 0x9b, 0x45, 0x67, 0x01,
0x09, 0x69, 0xad, 0xde, 0x30, 0xaf, 0xdf, 0xdf, 0xb5, 0xaa, 0xf5, 0xd2, 0x8e, 0xad, 0xe6, 0xd0,
0x65, 0xb8, 0x34, 0x29, 0x37, 0xee, 0x35, 0x70, 0x09, 0x1b, 0x15, 0xd3, 0x32, 0x8d, 0x5a, 0xc3,
0x56, 0x17, 0x44, 0xc3, 0x1e, 0x91, 0xdc, 0x63, 0xd3, 0xb0, 0x19, 0x38, 0x57, 0xf5, 0x18, 0x1f,
0x51, 0xb1, 0x57, 0xe8, 0x57, 0x0c, 0x0b, 0x6d, 0xaf, 0xcb, 0x09, 0x65, 0x5a, 0x6a, 0x3d, 0xbd,
0xb1, 0xb4, 0xf5, 0x61, 0xb2, 0x37, 0x09, 0xdb, 0xea, 0xd7, 0x85, 0x01, 0x3c, 0x30, 0x84, 0x10,
0x64, 0x98, 0xb7, 0xe7, 0x8b, 0xe3, 0x2d, 0x62, 0xf1, 0x1b, 0xbd, 0x01, 0x27, 0x43, 0x67, 0x8f,
0x34, 0x99, 0xf7, 0x9c, 0x88, 0x3e, 0xc9, 0xe2, 0xc5, 0x48, 0x60, 0x7b, 0xcf, 0x09, 0xba, 0x00,
0x20, 0x94, 0x3c, 0x78, 0x44, 0x7c, 0xd9, 0x07, 0x02, 0xde, 0x88, 0x04, 0xf9, 0x3f, 0x52, 0x90,
0x8b, 0xf7, 0x40, 0xb7, 0x65, 0xfb, 0xa6, 0x44, 0xfb, 0x5e, 0x7b, 0x59, 0x5f, 0x47, 0xbb, 0xf7,
0x53, 0x58, 0x3a, 0xb8, 0xf4, 0x5a, 0x32, 0x27, 0x1b, 0x33, 0x5e, 0x79, 0xad, 0x9b, 0x27, 0x30,
0x0c, 0xaf, 0xbc, 0x16, 0xba, 0x0a, 0xd9, 0xe0, 0xa9, 0x4f, 0xa8, 0x1c, 0x05, 0x97, 0x84, 0x99,
0xc1, 0x0b, 0x43, 0x8f, 0x5e, 0x18, 0x07, 0x03, 0x86, 0x11, 0x2a, 0xf8, 0x31, 0x03, 0x5d, 0x83,
0x05, 0x37, 0xba, 0x47, 0x02, 0x2a, 0x22, 0x30, 0x23, 0x79, 0xc0, 0x29, 0x58, 0x7f, 0xdb, 0x99,
0xd8, 0xb0, 0xeb, 0xbb, 0xb8, 0x62, 0x34, 0xcd, 0x1d, 0x55, 0x41, 0xab, 0x00, 0x42, 0x5a, 0xbf,
0x5b, 0x33, 0xb0, 0x9a, 0x1a, 0xf2, 0x2a, 0xd8, 0x28, 0x35, 0xea, 0x58, 0x4d, 0x97, 0x73, 0x90,
0xe1, 0x84, 0xee, 0x17, 0x7e, 0x55, 0x40, 0x9b, 0x0c, 0xe7, 0x7f, 0xd3, 0x2f, 0xe9, 0x79, 0xfb,
0x05, 0xbd, 0x09, 0xa7, 0x7c, 0xf2, 0x8c, 0x37, 0x47, 0x0a, 0x2c, 0x7e, 0x4f, 0xac, 0x44, 0x62,
0x6b, 0x50, 0x64, 0x85, 0x6f, 0x14, 0xd0, 0x30, 0xd9, 0x0f, 0x9e, 0xbc, 0x2e, 0x17, 0x61, 0xe1,
0x0b, 0x38, 0x7f, 0x84, 0x43, 0xff, 0x5e, 0xdc, 0x0b, 0xdf, 0x2a, 0xf0, 0xff, 0x1b, 0x84, 0xbf,
0x2e, 0x0f, 0x83, 0x23, 0xc6, 0x4a, 0xe1, 0x07, 0x05, 0xce, 0x1e, 0x76, 0xf1, 0xb8, 0x4c, 0xf2,
0x5f, 0x14, 0x58, 0x1b, 0xf7, 0xbd, 0xdc, 0x17, 0xb5, 0xf8, 0x0a, 0x51, 0x3e, 0x03, 0xd9, 0xb8,
0xc6, 0x53, 0xa2, 0xc6, 0xe3, 0x05, 0xfa, 0x1c, 0x56, 0x9d, 0x1e, 0xef, 0x44, 0x83, 0xc4, 0x75,
0xc4, 0x4b, 0x22, 0xf6, 0x77, 0x7b, 0x26, 0x7f, 0x4b, 0x63, 0x54, 0x7c, 0xc8, 0xd4, 0x30, 0x2d,
0x99, 0x91, 0xb4, 0xfc, 0xa6, 0xc0, 0x85, 0x84, 0xa3, 0x1d, 0x93, 0xec, 0xa0, 0x2b, 0xb0, 0x12,
0x3a, 0x8c, 0x3d, 0x0d, 0x68, 0xab, 0xd9, 0x71, 0x58, 0x27, 0x9e, 0x1a, 0xe5, 0x94, 0xa6, 0xe0,
0xe5, 0x81, 0xe2, 0xa6, 0xc3, 0x3a, 0x5b, 0x7f, 0x66, 0x61, 0xa1, 0xea, 0xf9, 0x8f, 0x4a, 0x96,
0x89, 0x5e, 0xc0, 0xe9, 0x89, 0x6f, 0x01, 0xb4, 0x95, 0xbc, 0x6f, 0xd2, 0xc7, 0x5b, 0x7e, 0x7b,
0x2e, 0x8e, 0x8c, 0xe9, 0x0b, 0x38, 0x3d, 0x31, 0x30, 0xa6, 0xed, 0x9e, 0x34, 0xee, 0xa6, 0xed,
0x9e, 0x3c, 0x91, 0x18, 0xac, 0x8e, 0xa7, 0x1c, 0x15, 0xa7, 0x3c, 0x84, 0x8f, 0x1a, 0x2b, 0xf9,
0x77, 0x67, 0x27, 0xc8, 0x4d, 0xbf, 0x9a, 0x18, 0x51, 0xb2, 0xd0, 0xd0, 0xfb, 0xb3, 0xda, 0x1a,
0x6f, 0xba, 0xfc, 0x07, 0x73, 0xf3, 0xa4, 0x2b, 0x7d, 0x50, 0x0f, 0xdf, 0x92, 0x68, 0x73, 0xee,
0x07, 0x4a, 0x7e, 0x6b, 0x1e, 0xca, 0x41, 0xe2, 0x27, 0x5e, 0xb4, 0xd3, 0x12, 0x9f, 0xf4, 0x6d,
0x33, 0x2d, 0xf1, 0x89, 0x4f, 0xe6, 0xf2, 0x53, 0x58, 0x73, 0x83, 0xfd, 0x44, 0x66, 0x79, 0x59,
0x74, 0x47, 0xe8, 0x59, 0x34, 0xe0, 0x81, 0xa5, 0x7c, 0xb6, 0x14, 0x69, 0xa5, 0xf2, 0xbb, 0x54,
0xba, 0x62, 0x57, 0xbf, 0x4f, 0x69, 0x15, 0xb6, 0xad, 0xdb, 0x92, 0x1d, 0xe1, 0xf5, 0x3b, 0x9b,
0xe5, 0x08, 0xf0, 0xb3, 0x50, 0x3d, 0x90, 0xaa, 0x07, 0x91, 0xea, 0x81, 0x54, 0x3d, 0xcc, 0x89,
0x7f, 0x41, 0xb6, 0xff, 0x0a, 0x00, 0x00, 0xff, 0xff, 0xf4, 0xcd, 0x0c, 0x89, 0x0a, 0x12, 0x00,
0x00,
}
// Reference imports to suppress errors if they are not otherwise used.

View File

@@ -86,10 +86,17 @@ type PublicShare struct {
Quicklink bool `protobuf:"varint,13,opt,name=quicklink,proto3" json:"quicklink,omitempty"`
// OPTIONAL
// Description of the share.
Description string `protobuf:"bytes,14,opt,name=description,proto3" json:"description,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
Description string `protobuf:"bytes,14,opt,name=description,proto3" json:"description,omitempty"`
// OPTIONAL
// Whether to notify the owner of a share when a file is uploaded to it.
NotifyUploads bool `protobuf:"varint,15,opt,name=notify_uploads,json=notifyUploads,proto3" json:"notify_uploads,omitempty"`
// OPTIONAL
// Comma-separated list of extra email addresses to notify when a file is
// uploaded to the share.
NotifyUploadsExtraRecipients string `protobuf:"bytes,16,opt,name=notify_uploads_extra_recipients,json=notifyUploadsExtraRecipients,proto3" json:"notify_uploads_extra_recipients,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *PublicShare) Reset() { *m = PublicShare{} }
@@ -215,6 +222,20 @@ func (m *PublicShare) GetDescription() string {
return ""
}
func (m *PublicShare) GetNotifyUploads() bool {
if m != nil {
return m.NotifyUploads
}
return false
}
func (m *PublicShare) GetNotifyUploadsExtraRecipients() string {
if m != nil {
return m.NotifyUploadsExtraRecipients
}
return ""
}
// The permissions for a share.
type PublicSharePermissions struct {
Permissions *v1beta1.ResourcePermissions `protobuf:"bytes,1,opt,name=permissions,proto3" json:"permissions,omitempty"`
@@ -597,49 +618,53 @@ func init() {
}
var fileDescriptor_2f13c61869aaebc4 = []byte{
// 694 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0xcb, 0x6e, 0xd3, 0x40,
0x14, 0xad, 0xdd, 0xa6, 0x4d, 0xae, 0xdb, 0x4a, 0x0c, 0x55, 0x35, 0x94, 0x20, 0xa5, 0xd9, 0x10,
0xa4, 0xe2, 0x90, 0x66, 0x51, 0x21, 0xd8, 0x90, 0x0a, 0x48, 0xa4, 0x0a, 0x22, 0x07, 0x58, 0xa0,
0x4a, 0xd1, 0xd4, 0x1e, 0xda, 0x51, 0x6b, 0x8f, 0x3b, 0x33, 0x6e, 0xc9, 0x8a, 0x0f, 0xe0, 0x2f,
0x58, 0xb2, 0xe7, 0x27, 0xf8, 0x1b, 0xfe, 0x00, 0xcd, 0xf8, 0x11, 0x07, 0x35, 0x28, 0x45, 0xec,
0xe2, 0x7b, 0xcf, 0xb9, 0x73, 0xc7, 0xe7, 0x1c, 0x07, 0x5a, 0xbe, 0xec, 0xb6, 0xe5, 0x19, 0x11,
0x2c, 0x3a, 0x6d, 0x5f, 0xb0, 0xe8, 0xbc, 0x7d, 0xd5, 0x39, 0xa1, 0x8a, 0x74, 0xda, 0x82, 0x4a,
0x9e, 0x08, 0x9f, 0x4a, 0x37, 0x16, 0x5c, 0x71, 0x84, 0x7d, 0xd9, 0x75, 0x33, 0xa4, 0xab, 0x91,
0x6e, 0x86, 0xdc, 0x79, 0xa4, 0x67, 0xb0, 0x80, 0x46, 0x8a, 0xa9, 0x49, 0x3b, 0x91, 0x54, 0xcc,
0x1b, 0xb2, 0xb3, 0x67, 0x8e, 0x53, 0x5c, 0x90, 0x53, 0xda, 0x8e, 0x05, 0xbf, 0x62, 0xc1, 0x5f,
0xd0, 0x0f, 0x34, 0x5a, 0x4d, 0x62, 0x2a, 0x0b, 0x88, 0x79, 0x4a, 0xdb, 0xcd, 0x5f, 0x15, 0x70,
0x86, 0xc9, 0xc9, 0x05, 0xf3, 0x47, 0x67, 0x44, 0x50, 0x74, 0x00, 0x36, 0x0b, 0xb0, 0xd5, 0xb0,
0x5a, 0xce, 0xfe, 0x43, 0x77, 0xde, 0xba, 0x6e, 0x89, 0x32, 0x08, 0x3c, 0x9b, 0x05, 0x68, 0x0b,
0x2a, 0x8a, 0x9f, 0xd3, 0x08, 0xdb, 0x0d, 0xab, 0x55, 0xf3, 0xd2, 0x07, 0x34, 0x00, 0x27, 0x5f,
0x68, 0xcc, 0x02, 0xbc, 0x6c, 0xe6, 0xb6, 0xd2, 0xb9, 0xe9, 0x0d, 0xdc, 0xfc, 0x06, 0xc5, 0x6c,
0x2f, 0x23, 0x0c, 0x02, 0x0f, 0x44, 0xf1, 0x1b, 0x79, 0xe0, 0xc4, 0x54, 0x84, 0x4c, 0x4a, 0xc6,
0x23, 0x89, 0x57, 0xcc, 0xa8, 0x27, 0x0b, 0xad, 0x38, 0x9c, 0xf2, 0xbc, 0xf2, 0x10, 0x74, 0x00,
0x15, 0x7e, 0x1d, 0x51, 0x81, 0x2b, 0x66, 0xda, 0xae, 0x99, 0x96, 0xab, 0xe0, 0x6a, 0x15, 0x8a,
0x71, 0xef, 0x25, 0x15, 0x83, 0xc0, 0x4b, 0xf1, 0xe8, 0x19, 0xac, 0xf9, 0x82, 0x12, 0xc5, 0x05,
0x5e, 0x5d, 0x94, 0x9a, 0x33, 0xd0, 0x3e, 0x54, 0x7c, 0xc5, 0x42, 0x8a, 0xd7, 0x0c, 0xb5, 0x6e,
0xa8, 0xa9, 0x28, 0x39, 0xe5, 0x1d, 0x0b, 0xa9, 0x54, 0x24, 0x8c, 0xbd, 0x14, 0xaa, 0x39, 0xa1,
0xe1, 0x54, 0x17, 0xe1, 0x18, 0x28, 0x7a, 0x0c, 0x28, 0x26, 0x52, 0x5e, 0x73, 0x11, 0x8c, 0xb5,
0xda, 0xd4, 0x57, 0x34, 0xc0, 0xb5, 0x86, 0xd5, 0xaa, 0x7a, 0x77, 0xf2, 0xce, 0x30, 0x6f, 0xa0,
0xe7, 0x00, 0xf4, 0x73, 0xcc, 0x04, 0x51, 0x8c, 0x47, 0x18, 0x16, 0x38, 0xa7, 0x84, 0x47, 0xbb,
0xb0, 0x1e, 0x30, 0x19, 0x5f, 0x90, 0xc9, 0x38, 0x22, 0x21, 0xc5, 0x8e, 0xb1, 0x81, 0x93, 0xd5,
0xde, 0x90, 0x90, 0xa2, 0x57, 0x50, 0x93, 0xec, 0x34, 0x22, 0x2a, 0x11, 0x14, 0xaf, 0x97, 0xad,
0x70, 0x93, 0x7e, 0x46, 0xb9, 0x51, 0x8e, 0xf7, 0xa6, 0x54, 0x54, 0x87, 0xda, 0x65, 0xc2, 0xfc,
0x73, 0x0d, 0xc7, 0x1b, 0xe6, 0x3a, 0xd3, 0x02, 0x6a, 0x80, 0x13, 0x50, 0xe9, 0x0b, 0x16, 0x9b,
0x7b, 0x6c, 0x66, 0x7b, 0x4c, 0x4b, 0xcd, 0x10, 0xb6, 0x6f, 0x36, 0x07, 0x1a, 0xcd, 0x7a, 0x2c,
0x8d, 0x41, 0x67, 0x31, 0xbb, 0xce, 0x33, 0x59, 0x73, 0x0f, 0x36, 0x66, 0xe2, 0x82, 0xee, 0x43,
0x8d, 0xc7, 0xe4, 0x32, 0x31, 0x91, 0x48, 0xe3, 0x52, 0x4d, 0x0b, 0x83, 0xa0, 0x79, 0x09, 0x5b,
0x25, 0xb4, 0x47, 0x3f, 0x51, 0x41, 0x23, 0x9f, 0xa2, 0xa7, 0xff, 0x10, 0xcc, 0xfe, 0x92, 0x89,
0xe6, 0xf6, 0x4c, 0x34, 0xfb, 0x4b, 0x59, 0x38, 0x7b, 0xab, 0xb0, 0x22, 0x63, 0xea, 0x37, 0xbf,
0x5a, 0x70, 0xaf, 0xc4, 0x7b, 0x91, 0xa8, 0x33, 0x6d, 0x63, 0x3f, 0x15, 0xb6, 0x0e, 0xd5, 0xdc,
0x2b, 0xe6, 0x78, 0x3d, 0xa0, 0xa8, 0xa0, 0x7e, 0x59, 0x53, 0xfb, 0x76, 0x9a, 0xf6, 0x97, 0x4a,
0xaa, 0x16, 0xdb, 0x7c, 0x81, 0xcd, 0x59, 0x98, 0xd6, 0x7b, 0x7a, 0x86, 0x59, 0xa1, 0xec, 0x86,
0xb7, 0xb0, 0x55, 0x3c, 0x8c, 0x4b, 0x06, 0xb6, 0x17, 0x30, 0xf0, 0xdd, 0x82, 0xf9, 0xb2, 0x20,
0x36, 0x7f, 0x58, 0x50, 0x79, 0x2d, 0x48, 0xa4, 0xfe, 0xfc, 0xe4, 0x58, 0xff, 0xe3, 0x93, 0xb3,
0x53, 0x7a, 0x9d, 0x99, 0xf6, 0xc5, 0xcb, 0x9c, 0x4d, 0xe0, 0xf2, 0xed, 0x12, 0xd8, 0x9b, 0x40,
0xdd, 0xe7, 0xe1, 0xdc, 0xed, 0x7a, 0x9b, 0xb9, 0x53, 0xa5, 0xce, 0x3c, 0x1f, 0x5a, 0x1f, 0x1d,
0xdd, 0xcf, 0xda, 0xdf, 0xec, 0xe5, 0xc3, 0xd1, 0xd1, 0x77, 0x1b, 0x1f, 0xca, 0xae, 0xd1, 0x49,
0xf3, 0x8f, 0x34, 0xff, 0x43, 0xa7, 0xa7, 0x01, 0x3f, 0x4d, 0xeb, 0x38, 0x6b, 0x1d, 0xeb, 0xd6,
0x71, 0xd6, 0x3a, 0x59, 0x35, 0x7f, 0x26, 0xdd, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xd5, 0xa3,
0xf1, 0xe1, 0x0a, 0x07, 0x00, 0x00,
// 753 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x55, 0xdd, 0x4e, 0x1b, 0x47,
0x14, 0x66, 0x0d, 0x36, 0xf6, 0x59, 0x70, 0xdb, 0x29, 0x42, 0x53, 0xea, 0xaa, 0xc6, 0x52, 0x55,
0x57, 0xa2, 0xeb, 0x1a, 0x5f, 0xa0, 0xaa, 0xbd, 0xa9, 0x11, 0xad, 0x2d, 0xa1, 0xc6, 0x5a, 0x87,
0x5c, 0x44, 0x48, 0xd6, 0xb0, 0x3b, 0xc0, 0x08, 0xef, 0xce, 0x32, 0x33, 0x0b, 0xf8, 0x2a, 0x0f,
0x90, 0xb7, 0xc8, 0x65, 0xee, 0xf3, 0x12, 0x79, 0x89, 0xbc, 0x4a, 0x34, 0xb3, 0x3f, 0x5e, 0x47,
0x38, 0x32, 0x51, 0xee, 0x3c, 0xe7, 0x7c, 0xdf, 0x37, 0x67, 0xf6, 0x7c, 0xe7, 0x18, 0xda, 0x9e,
0xec, 0x75, 0xe4, 0x35, 0x11, 0x2c, 0xbc, 0xea, 0x4c, 0x59, 0x78, 0xd3, 0xb9, 0xeb, 0x5e, 0x50,
0x45, 0xba, 0x1d, 0x41, 0x25, 0x8f, 0x85, 0x47, 0xa5, 0x13, 0x09, 0xae, 0x38, 0xc2, 0x9e, 0xec,
0x39, 0x29, 0xd2, 0xd1, 0x48, 0x27, 0x45, 0xee, 0xfd, 0xa6, 0x35, 0x98, 0x4f, 0x43, 0xc5, 0xd4,
0xac, 0x13, 0x4b, 0x2a, 0x96, 0x89, 0xec, 0x1d, 0x98, 0xeb, 0x14, 0x17, 0xe4, 0x8a, 0x76, 0x22,
0xc1, 0xef, 0x98, 0xff, 0x19, 0xf4, 0x4f, 0x1a, 0xad, 0x66, 0x11, 0x95, 0x39, 0xc4, 0x9c, 0x92,
0x74, 0xeb, 0x43, 0x05, 0xec, 0x51, 0x7c, 0x31, 0x65, 0xde, 0xf8, 0x9a, 0x08, 0x8a, 0x8e, 0xa0,
0xc4, 0x7c, 0x6c, 0x35, 0xad, 0xb6, 0x7d, 0xf8, 0xab, 0xb3, 0xac, 0x5c, 0xa7, 0x40, 0x19, 0xfa,
0x6e, 0x89, 0xf9, 0x68, 0x07, 0xca, 0x8a, 0xdf, 0xd0, 0x10, 0x97, 0x9a, 0x56, 0xbb, 0xe6, 0x26,
0x07, 0x34, 0x04, 0x3b, 0x2b, 0x68, 0xc2, 0x7c, 0xbc, 0x6e, 0x74, 0xdb, 0x89, 0x6e, 0xf2, 0x02,
0x27, 0x7b, 0x41, 0xae, 0xed, 0xa6, 0x84, 0xa1, 0xef, 0x82, 0xc8, 0x7f, 0x23, 0x17, 0xec, 0x88,
0x8a, 0x80, 0x49, 0xc9, 0x78, 0x28, 0xf1, 0x86, 0x91, 0xfa, 0x63, 0xa5, 0x12, 0x47, 0x73, 0x9e,
0x5b, 0x14, 0x41, 0x47, 0x50, 0xe6, 0xf7, 0x21, 0x15, 0xb8, 0x6c, 0xd4, 0xf6, 0x8d, 0x5a, 0xd6,
0x05, 0x47, 0x77, 0x21, 0x97, 0x3b, 0x93, 0x54, 0x0c, 0x7d, 0x37, 0xc1, 0xa3, 0xbf, 0x60, 0xd3,
0x13, 0x94, 0x28, 0x2e, 0x70, 0x65, 0x55, 0x6a, 0xc6, 0x40, 0x87, 0x50, 0xf6, 0x14, 0x0b, 0x28,
0xde, 0x34, 0xd4, 0x86, 0xa1, 0x26, 0x4d, 0xc9, 0x28, 0xcf, 0x59, 0x40, 0xa5, 0x22, 0x41, 0xe4,
0x26, 0x50, 0xcd, 0x09, 0x0c, 0xa7, 0xba, 0x0a, 0xc7, 0x40, 0xd1, 0xef, 0x80, 0x22, 0x22, 0xe5,
0x3d, 0x17, 0xfe, 0x44, 0x77, 0x9b, 0x7a, 0x8a, 0xfa, 0xb8, 0xd6, 0xb4, 0xda, 0x55, 0xf7, 0xbb,
0x2c, 0x33, 0xca, 0x12, 0xe8, 0x6f, 0x00, 0xfa, 0x10, 0x31, 0x41, 0x14, 0xe3, 0x21, 0x86, 0x15,
0xee, 0x29, 0xe0, 0xd1, 0x3e, 0x6c, 0xf9, 0x4c, 0x46, 0x53, 0x32, 0x9b, 0x84, 0x24, 0xa0, 0xd8,
0x36, 0x36, 0xb0, 0xd3, 0xd8, 0xff, 0x24, 0xa0, 0xe8, 0x5f, 0xa8, 0x49, 0x76, 0x15, 0x12, 0x15,
0x0b, 0x8a, 0xb7, 0x8a, 0x56, 0x78, 0xac, 0x7f, 0xa6, 0x73, 0xe3, 0x0c, 0xef, 0xce, 0xa9, 0xa8,
0x01, 0xb5, 0xdb, 0x98, 0x79, 0x37, 0x1a, 0x8e, 0xb7, 0xcd, 0x73, 0xe6, 0x01, 0xd4, 0x04, 0xdb,
0xa7, 0xd2, 0x13, 0x2c, 0x32, 0xef, 0xa8, 0xa7, 0x75, 0xcc, 0x43, 0xe8, 0x17, 0xa8, 0x87, 0x5c,
0xb1, 0xcb, 0xd9, 0x24, 0x8e, 0xa6, 0x9c, 0xf8, 0x12, 0x7f, 0x63, 0x44, 0xb6, 0x93, 0xe8, 0x59,
0x12, 0x44, 0x27, 0xf0, 0xf3, 0x22, 0x6c, 0x42, 0x1f, 0x94, 0x20, 0x13, 0x41, 0x3d, 0x16, 0x31,
0x1a, 0x2a, 0x89, 0xbf, 0x35, 0xe2, 0x8d, 0x05, 0xde, 0x89, 0x06, 0xb9, 0x39, 0xa6, 0x15, 0xc0,
0xee, 0xe3, 0x56, 0x44, 0xe3, 0x45, 0x47, 0x27, 0x43, 0xd7, 0x5d, 0x6d, 0x38, 0x96, 0x59, 0xba,
0x75, 0x00, 0xdb, 0x0b, 0xc3, 0x89, 0x7e, 0x84, 0x1a, 0x8f, 0xc8, 0x6d, 0x6c, 0x06, 0x30, 0x19,
0xce, 0x6a, 0x12, 0x18, 0xfa, 0xad, 0x5b, 0xd8, 0x29, 0xa0, 0x5d, 0x7a, 0x49, 0x05, 0x0d, 0x3d,
0x8a, 0xfe, 0xfc, 0x82, 0x35, 0x30, 0x58, 0x33, 0x8b, 0x60, 0x77, 0x61, 0x11, 0x0c, 0xd6, 0xd2,
0x55, 0xd0, 0xaf, 0xc0, 0x86, 0x8c, 0xa8, 0xd7, 0x7a, 0x6d, 0xc1, 0x0f, 0x05, 0xde, 0x3f, 0xb1,
0xba, 0xd6, 0x43, 0xe3, 0x25, 0x36, 0x6a, 0x40, 0x35, 0x73, 0xa6, 0xb9, 0x5e, 0x0b, 0xe4, 0x11,
0x34, 0x28, 0x3a, 0xa8, 0xf4, 0x34, 0x07, 0x0d, 0xd6, 0x0a, 0x1e, 0xca, 0xab, 0x79, 0x05, 0xf5,
0x45, 0x98, 0x76, 0xd7, 0xfc, 0x0e, 0x53, 0x42, 0xd1, 0x7b, 0xcf, 0x60, 0x27, 0x3f, 0x4c, 0x0a,
0xe3, 0x52, 0x5a, 0x61, 0x5c, 0xbe, 0xcf, 0x99, 0x27, 0x39, 0xb1, 0xf5, 0xce, 0x82, 0xf2, 0x7f,
0x82, 0x84, 0xea, 0xd3, 0x05, 0x67, 0x7d, 0x8d, 0x05, 0xb7, 0x57, 0xf8, 0x9c, 0x69, 0xef, 0xf3,
0x8f, 0xb9, 0x38, 0xef, 0xeb, 0x4f, 0x9b, 0xf7, 0xfe, 0x0c, 0x1a, 0x1e, 0x0f, 0x96, 0x56, 0xd7,
0xaf, 0x67, 0x4e, 0x95, 0x7a, 0xc3, 0xf0, 0x91, 0xf5, 0xd2, 0xd6, 0xf9, 0x34, 0xfd, 0xa6, 0xb4,
0x7e, 0x3c, 0x3e, 0x7d, 0x5b, 0xc2, 0xc7, 0xb2, 0x67, 0xfa, 0xa4, 0xf9, 0xa7, 0x9a, 0xff, 0xa2,
0xdb, 0xd7, 0x80, 0xf7, 0x26, 0x75, 0x9e, 0xa6, 0xce, 0x75, 0xea, 0x3c, 0x4d, 0x5d, 0x54, 0xcc,
0x5f, 0x57, 0xef, 0x63, 0x00, 0x00, 0x00, 0xff, 0xff, 0x6c, 0x46, 0xa1, 0x6b, 0x78, 0x07, 0x00,
0x00,
}

View File

@@ -80,14 +80,19 @@ type CreateOCMShareRequest struct {
// The unique identifier for the shared storage resource.
ResourceId *v1beta11.ResourceId `protobuf:"bytes,2,opt,name=resource_id,json=resourceId,proto3" json:"resource_id,omitempty"`
// REQUIRED.
// The share grant for the share.
Grant *ShareGrant `protobuf:"bytes,3,opt,name=grant,proto3" json:"grant,omitempty"`
// The grantee for the share.
Grantee *v1beta11.Grantee `protobuf:"bytes,3,opt,name=grantee,proto3" json:"grantee,omitempty"`
// REQUIRED.
// The details of the recipient user's mesh provider.
RecipientMeshProvider *v1beta12.ProviderInfo `protobuf:"bytes,4,opt,name=recipient_mesh_provider,json=recipientMeshProvider,proto3" json:"recipient_mesh_provider,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
// REQUIRED.
AccessMethods []*AccessMethod `protobuf:"bytes,5,rep,name=access_methods,json=accessMethods,proto3" json:"access_methods,omitempty"`
// OPTIONAL.
// The expiration time for the ocm share.
Expiration *v1beta1.Timestamp `protobuf:"bytes,6,opt,name=expiration,proto3" json:"expiration,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CreateOCMShareRequest) Reset() { *m = CreateOCMShareRequest{} }
@@ -129,9 +134,9 @@ func (m *CreateOCMShareRequest) GetResourceId() *v1beta11.ResourceId {
return nil
}
func (m *CreateOCMShareRequest) GetGrant() *ShareGrant {
func (m *CreateOCMShareRequest) GetGrantee() *v1beta11.Grantee {
if m != nil {
return m.Grant
return m.Grantee
}
return nil
}
@@ -143,6 +148,20 @@ func (m *CreateOCMShareRequest) GetRecipientMeshProvider() *v1beta12.ProviderInf
return nil
}
func (m *CreateOCMShareRequest) GetAccessMethods() []*AccessMethod {
if m != nil {
return m.AccessMethods
}
return nil
}
func (m *CreateOCMShareRequest) GetExpiration() *v1beta1.Timestamp {
if m != nil {
return m.Expiration
}
return nil
}
type CreateOCMShareResponse struct {
// REQUIRED.
// The response status.
@@ -152,7 +171,10 @@ type CreateOCMShareResponse struct {
Opaque *v1beta1.Opaque `protobuf:"bytes,2,opt,name=opaque,proto3" json:"opaque,omitempty"`
// REQUIRED.
// The created share.
Share *Share `protobuf:"bytes,3,opt,name=share,proto3" json:"share,omitempty"`
Share *Share `protobuf:"bytes,3,opt,name=share,proto3" json:"share,omitempty"`
// OPTIONAL.
// Display name of the recipient of the share.
RecipientDisplayName string `protobuf:"bytes,4,opt,name=recipient_display_name,json=recipientDisplayName,proto3" json:"recipient_display_name,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@@ -204,16 +226,23 @@ func (m *CreateOCMShareResponse) GetShare() *Share {
return nil
}
func (m *CreateOCMShareResponse) GetRecipientDisplayName() string {
if m != nil {
return m.RecipientDisplayName
}
return ""
}
type UpdateOCMShareRequest struct {
// OPTIONAL.
// Opaque information.
Opaque *v1beta1.Opaque `protobuf:"bytes,1,opt,name=opaque,proto3" json:"opaque,omitempty"`
// REQUIRED.
Ref *ShareReference `protobuf:"bytes,2,opt,name=ref,proto3" json:"ref,omitempty"`
Field *UpdateOCMShareRequest_UpdateField `protobuf:"bytes,3,opt,name=field,proto3" json:"field,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
Ref *ShareReference `protobuf:"bytes,2,opt,name=ref,proto3" json:"ref,omitempty"`
Field []*UpdateOCMShareRequest_UpdateField `protobuf:"bytes,3,rep,name=field,proto3" json:"field,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *UpdateOCMShareRequest) Reset() { *m = UpdateOCMShareRequest{} }
@@ -255,7 +284,7 @@ func (m *UpdateOCMShareRequest) GetRef() *ShareReference {
return nil
}
func (m *UpdateOCMShareRequest) GetField() *UpdateOCMShareRequest_UpdateField {
func (m *UpdateOCMShareRequest) GetField() []*UpdateOCMShareRequest_UpdateField {
if m != nil {
return m.Field
}
@@ -267,8 +296,8 @@ type UpdateOCMShareRequest_UpdateField struct {
// One of the update fields MUST be specified.
//
// Types that are valid to be assigned to Field:
// *UpdateOCMShareRequest_UpdateField_Permissions
// *UpdateOCMShareRequest_UpdateField_DisplayName
// *UpdateOCMShareRequest_UpdateField_Expiration
// *UpdateOCMShareRequest_UpdateField_AccessMethods
Field isUpdateOCMShareRequest_UpdateField_Field `protobuf_oneof:"field"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
@@ -304,17 +333,17 @@ type isUpdateOCMShareRequest_UpdateField_Field interface {
isUpdateOCMShareRequest_UpdateField_Field()
}
type UpdateOCMShareRequest_UpdateField_Permissions struct {
Permissions *SharePermissions `protobuf:"bytes,2,opt,name=permissions,proto3,oneof"`
type UpdateOCMShareRequest_UpdateField_Expiration struct {
Expiration *v1beta1.Timestamp `protobuf:"bytes,1,opt,name=expiration,proto3,oneof"`
}
type UpdateOCMShareRequest_UpdateField_DisplayName struct {
DisplayName string `protobuf:"bytes,3,opt,name=display_name,json=displayName,proto3,oneof"`
type UpdateOCMShareRequest_UpdateField_AccessMethods struct {
AccessMethods *AccessMethod `protobuf:"bytes,2,opt,name=access_methods,json=accessMethods,proto3,oneof"`
}
func (*UpdateOCMShareRequest_UpdateField_Permissions) isUpdateOCMShareRequest_UpdateField_Field() {}
func (*UpdateOCMShareRequest_UpdateField_Expiration) isUpdateOCMShareRequest_UpdateField_Field() {}
func (*UpdateOCMShareRequest_UpdateField_DisplayName) isUpdateOCMShareRequest_UpdateField_Field() {}
func (*UpdateOCMShareRequest_UpdateField_AccessMethods) isUpdateOCMShareRequest_UpdateField_Field() {}
func (m *UpdateOCMShareRequest_UpdateField) GetField() isUpdateOCMShareRequest_UpdateField_Field {
if m != nil {
@@ -323,25 +352,25 @@ func (m *UpdateOCMShareRequest_UpdateField) GetField() isUpdateOCMShareRequest_U
return nil
}
func (m *UpdateOCMShareRequest_UpdateField) GetPermissions() *SharePermissions {
if x, ok := m.GetField().(*UpdateOCMShareRequest_UpdateField_Permissions); ok {
return x.Permissions
func (m *UpdateOCMShareRequest_UpdateField) GetExpiration() *v1beta1.Timestamp {
if x, ok := m.GetField().(*UpdateOCMShareRequest_UpdateField_Expiration); ok {
return x.Expiration
}
return nil
}
func (m *UpdateOCMShareRequest_UpdateField) GetDisplayName() string {
if x, ok := m.GetField().(*UpdateOCMShareRequest_UpdateField_DisplayName); ok {
return x.DisplayName
func (m *UpdateOCMShareRequest_UpdateField) GetAccessMethods() *AccessMethod {
if x, ok := m.GetField().(*UpdateOCMShareRequest_UpdateField_AccessMethods); ok {
return x.AccessMethods
}
return ""
return nil
}
// XXX_OneofWrappers is for the internal use of the proto package.
func (*UpdateOCMShareRequest_UpdateField) XXX_OneofWrappers() []interface{} {
return []interface{}{
(*UpdateOCMShareRequest_UpdateField_Permissions)(nil),
(*UpdateOCMShareRequest_UpdateField_DisplayName)(nil),
(*UpdateOCMShareRequest_UpdateField_Expiration)(nil),
(*UpdateOCMShareRequest_UpdateField_AccessMethods)(nil),
}
}
@@ -863,6 +892,98 @@ func (m *GetOCMShareResponse) GetShare() *Share {
return nil
}
type GetOCMShareByTokenRequest struct {
// REQUIRED.
// The unlisted token to identify the public share.
Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *GetOCMShareByTokenRequest) Reset() { *m = GetOCMShareByTokenRequest{} }
func (m *GetOCMShareByTokenRequest) String() string { return proto.CompactTextString(m) }
func (*GetOCMShareByTokenRequest) ProtoMessage() {}
func (*GetOCMShareByTokenRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_3b1231a7f0a479a0, []int{10}
}
func (m *GetOCMShareByTokenRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_GetOCMShareByTokenRequest.Unmarshal(m, b)
}
func (m *GetOCMShareByTokenRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_GetOCMShareByTokenRequest.Marshal(b, m, deterministic)
}
func (m *GetOCMShareByTokenRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_GetOCMShareByTokenRequest.Merge(m, src)
}
func (m *GetOCMShareByTokenRequest) XXX_Size() int {
return xxx_messageInfo_GetOCMShareByTokenRequest.Size(m)
}
func (m *GetOCMShareByTokenRequest) XXX_DiscardUnknown() {
xxx_messageInfo_GetOCMShareByTokenRequest.DiscardUnknown(m)
}
var xxx_messageInfo_GetOCMShareByTokenRequest proto.InternalMessageInfo
func (m *GetOCMShareByTokenRequest) GetToken() string {
if m != nil {
return m.Token
}
return ""
}
type GetOCMShareByTokenResponse struct {
// REQUIRED.
// The response status.
Status *v1beta13.Status `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
// REQUIRED.
// The share.
Share *Share `protobuf:"bytes,2,opt,name=share,proto3" json:"share,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *GetOCMShareByTokenResponse) Reset() { *m = GetOCMShareByTokenResponse{} }
func (m *GetOCMShareByTokenResponse) String() string { return proto.CompactTextString(m) }
func (*GetOCMShareByTokenResponse) ProtoMessage() {}
func (*GetOCMShareByTokenResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_3b1231a7f0a479a0, []int{11}
}
func (m *GetOCMShareByTokenResponse) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_GetOCMShareByTokenResponse.Unmarshal(m, b)
}
func (m *GetOCMShareByTokenResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_GetOCMShareByTokenResponse.Marshal(b, m, deterministic)
}
func (m *GetOCMShareByTokenResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_GetOCMShareByTokenResponse.Merge(m, src)
}
func (m *GetOCMShareByTokenResponse) XXX_Size() int {
return xxx_messageInfo_GetOCMShareByTokenResponse.Size(m)
}
func (m *GetOCMShareByTokenResponse) XXX_DiscardUnknown() {
xxx_messageInfo_GetOCMShareByTokenResponse.DiscardUnknown(m)
}
var xxx_messageInfo_GetOCMShareByTokenResponse proto.InternalMessageInfo
func (m *GetOCMShareByTokenResponse) GetStatus() *v1beta13.Status {
if m != nil {
return m.Status
}
return nil
}
func (m *GetOCMShareByTokenResponse) GetShare() *Share {
if m != nil {
return m.Share
}
return nil
}
type ListReceivedOCMSharesRequest struct {
// OPTIONAL.
// Opaque information.
@@ -885,7 +1006,7 @@ func (m *ListReceivedOCMSharesRequest) Reset() { *m = ListReceivedOCMSha
func (m *ListReceivedOCMSharesRequest) String() string { return proto.CompactTextString(m) }
func (*ListReceivedOCMSharesRequest) ProtoMessage() {}
func (*ListReceivedOCMSharesRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_3b1231a7f0a479a0, []int{10}
return fileDescriptor_3b1231a7f0a479a0, []int{12}
}
func (m *ListReceivedOCMSharesRequest) XXX_Unmarshal(b []byte) error {
@@ -951,7 +1072,7 @@ func (m *ListReceivedOCMSharesResponse) Reset() { *m = ListReceivedOCMSh
func (m *ListReceivedOCMSharesResponse) String() string { return proto.CompactTextString(m) }
func (*ListReceivedOCMSharesResponse) ProtoMessage() {}
func (*ListReceivedOCMSharesResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_3b1231a7f0a479a0, []int{11}
return fileDescriptor_3b1231a7f0a479a0, []int{13}
}
func (m *ListReceivedOCMSharesResponse) XXX_Unmarshal(b []byte) error {
@@ -1020,7 +1141,7 @@ func (m *UpdateReceivedOCMShareRequest) Reset() { *m = UpdateReceivedOCM
func (m *UpdateReceivedOCMShareRequest) String() string { return proto.CompactTextString(m) }
func (*UpdateReceivedOCMShareRequest) ProtoMessage() {}
func (*UpdateReceivedOCMShareRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_3b1231a7f0a479a0, []int{12}
return fileDescriptor_3b1231a7f0a479a0, []int{14}
}
func (m *UpdateReceivedOCMShareRequest) XXX_Unmarshal(b []byte) error {
@@ -1078,7 +1199,7 @@ func (m *UpdateReceivedOCMShareResponse) Reset() { *m = UpdateReceivedOC
func (m *UpdateReceivedOCMShareResponse) String() string { return proto.CompactTextString(m) }
func (*UpdateReceivedOCMShareResponse) ProtoMessage() {}
func (*UpdateReceivedOCMShareResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_3b1231a7f0a479a0, []int{13}
return fileDescriptor_3b1231a7f0a479a0, []int{15}
}
func (m *UpdateReceivedOCMShareResponse) XXX_Unmarshal(b []byte) error {
@@ -1129,7 +1250,7 @@ func (m *GetReceivedOCMShareRequest) Reset() { *m = GetReceivedOCMShareR
func (m *GetReceivedOCMShareRequest) String() string { return proto.CompactTextString(m) }
func (*GetReceivedOCMShareRequest) ProtoMessage() {}
func (*GetReceivedOCMShareRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_3b1231a7f0a479a0, []int{14}
return fileDescriptor_3b1231a7f0a479a0, []int{16}
}
func (m *GetReceivedOCMShareRequest) XXX_Unmarshal(b []byte) error {
@@ -1183,7 +1304,7 @@ func (m *GetReceivedOCMShareResponse) Reset() { *m = GetReceivedOCMShare
func (m *GetReceivedOCMShareResponse) String() string { return proto.CompactTextString(m) }
func (*GetReceivedOCMShareResponse) ProtoMessage() {}
func (*GetReceivedOCMShareResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_3b1231a7f0a479a0, []int{15}
return fileDescriptor_3b1231a7f0a479a0, []int{17}
}
func (m *GetReceivedOCMShareResponse) XXX_Unmarshal(b []byte) error {
@@ -1239,6 +1360,8 @@ func init() {
proto.RegisterType((*RemoveOCMShareResponse)(nil), "cs3.sharing.ocm.v1beta1.RemoveOCMShareResponse")
proto.RegisterType((*GetOCMShareRequest)(nil), "cs3.sharing.ocm.v1beta1.GetOCMShareRequest")
proto.RegisterType((*GetOCMShareResponse)(nil), "cs3.sharing.ocm.v1beta1.GetOCMShareResponse")
proto.RegisterType((*GetOCMShareByTokenRequest)(nil), "cs3.sharing.ocm.v1beta1.GetOCMShareByTokenRequest")
proto.RegisterType((*GetOCMShareByTokenResponse)(nil), "cs3.sharing.ocm.v1beta1.GetOCMShareByTokenResponse")
proto.RegisterType((*ListReceivedOCMSharesRequest)(nil), "cs3.sharing.ocm.v1beta1.ListReceivedOCMSharesRequest")
proto.RegisterType((*ListReceivedOCMSharesResponse)(nil), "cs3.sharing.ocm.v1beta1.ListReceivedOCMSharesResponse")
proto.RegisterType((*UpdateReceivedOCMShareRequest)(nil), "cs3.sharing.ocm.v1beta1.UpdateReceivedOCMShareRequest")
@@ -1252,83 +1375,91 @@ func init() {
}
var fileDescriptor_3b1231a7f0a479a0 = []byte{
// 1210 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x57, 0xcf, 0x6f, 0x1b, 0x45,
0x14, 0xce, 0xda, 0xb1, 0x43, 0x9e, 0xdb, 0x60, 0x4d, 0xeb, 0xc6, 0x75, 0x9a, 0xaa, 0xb8, 0x22,
0x4d, 0x45, 0x59, 0x2b, 0x3f, 0x08, 0x0a, 0x14, 0xa4, 0xc4, 0x71, 0x53, 0x8b, 0x26, 0x6b, 0x4d,
0xd2, 0x20, 0x50, 0xc4, 0x6a, 0xb3, 0x1e, 0x3b, 0xab, 0x64, 0x7f, 0x64, 0x66, 0x1d, 0x48, 0xc5,
0x01, 0x21, 0x40, 0xa2, 0x12, 0x07, 0xf8, 0x13, 0x38, 0x72, 0x01, 0x71, 0xe4, 0xc2, 0x1d, 0x89,
0x13, 0x47, 0xae, 0xdc, 0xf8, 0x27, 0xd0, 0xcc, 0xce, 0xfa, 0x57, 0xbc, 0x4e, 0xdc, 0x44, 0x2e,
0x37, 0x7b, 0xde, 0xf7, 0xde, 0x7c, 0xf3, 0xed, 0x9b, 0x6f, 0x66, 0xe0, 0x75, 0x93, 0x2d, 0x14,
0xd8, 0xbe, 0x41, 0x2d, 0xa7, 0x5e, 0x70, 0x4d, 0xbb, 0x70, 0x3c, 0xb7, 0x47, 0x7c, 0x63, 0x8e,
0xff, 0xd6, 0x0d, 0xcf, 0x52, 0x3d, 0xea, 0xfa, 0x2e, 0x9a, 0x34, 0xd9, 0x82, 0x2a, 0x61, 0xaa,
0x6b, 0xda, 0xaa, 0x84, 0xe5, 0xee, 0xf3, 0x7c, 0xab, 0x4a, 0x1c, 0xdf, 0xf2, 0x4f, 0x0a, 0x0d,
0x46, 0x68, 0xb3, 0x02, 0x25, 0xcc, 0x6d, 0x50, 0x93, 0xb0, 0xa0, 0x46, 0x6e, 0x96, 0x43, 0xf9,
0x14, 0x1e, 0x75, 0x8f, 0xad, 0x6a, 0x1f, 0xe4, 0x2d, 0x8e, 0xa4, 0x9e, 0xd9, 0x04, 0x30, 0xdf,
0xf0, 0x1b, 0x61, 0xf4, 0x5e, 0x14, 0xe5, 0xee, 0x32, 0x0f, 0x04, 0xd0, 0x77, 0xa9, 0x51, 0x27,
0x67, 0x4f, 0x3a, 0xcd, 0xd1, 0xfe, 0x89, 0x47, 0x58, 0x13, 0x22, 0xfe, 0xc9, 0xf0, 0x9d, 0xba,
0xeb, 0xd6, 0x0f, 0x45, 0x1d, 0xdf, 0xdd, 0x6b, 0xd4, 0x0a, 0x35, 0x8b, 0x1c, 0x56, 0x75, 0xdb,
0x60, 0x07, 0x01, 0x22, 0xff, 0x4b, 0x0c, 0x32, 0x45, 0x4a, 0x0c, 0x9f, 0x68, 0xc5, 0x8d, 0xad,
0x7d, 0x83, 0x12, 0x4c, 0x8e, 0x1a, 0x84, 0xf9, 0x68, 0x0e, 0x92, 0xae, 0x67, 0x1c, 0x35, 0x48,
0x56, 0xb9, 0xa3, 0xcc, 0xa6, 0xe6, 0x6f, 0xaa, 0x5c, 0xce, 0xa0, 0xba, 0x9c, 0x4b, 0xd5, 0x04,
0x00, 0x4b, 0x20, 0x2a, 0x43, 0x2a, 0x24, 0xa8, 0x5b, 0xd5, 0x6c, 0x4c, 0xe4, 0xcd, 0x8a, 0x3c,
0xb9, 0x22, 0x35, 0x5c, 0x51, 0xb3, 0x04, 0x96, 0x09, 0xe5, 0x2a, 0x06, 0xda, 0xfc, 0x8d, 0x96,
0x21, 0x51, 0xa7, 0x86, 0xe3, 0x67, 0xe3, 0xa2, 0xc8, 0x5d, 0x35, 0xe2, 0x5b, 0xaa, 0x82, 0xf3,
0x3a, 0x87, 0xe2, 0x20, 0x03, 0x7d, 0x02, 0x93, 0x94, 0x98, 0x96, 0x67, 0x11, 0xc7, 0xd7, 0x6d,
0xc2, 0xf6, 0xf5, 0x70, 0xd2, 0xec, 0xa8, 0x28, 0x36, 0x23, 0x8a, 0xf1, 0x22, 0xa7, 0xd8, 0x54,
0xe4, 0x40, 0xd9, 0xa9, 0xb9, 0x38, 0xd3, 0x2c, 0xb3, 0x41, 0xd8, 0x7e, 0x18, 0xca, 0xff, 0xaa,
0xc0, 0x8d, 0x6e, 0xc9, 0x98, 0xe7, 0x3a, 0x8c, 0xa0, 0x02, 0x24, 0x83, 0xaf, 0x2e, 0x35, 0x9b,
0x14, 0x33, 0x51, 0xcf, 0x6c, 0xd1, 0x15, 0x61, 0x2c, 0x61, 0x6d, 0x22, 0xc7, 0xce, 0x2b, 0xf2,
0x22, 0x24, 0xb8, 0x0e, 0x44, 0x2a, 0x73, 0xbb, 0xbf, 0x32, 0x38, 0x00, 0xe7, 0xff, 0x89, 0x41,
0xe6, 0xa9, 0x57, 0xbd, 0x9c, 0xef, 0xbc, 0x0c, 0x71, 0x4a, 0x6a, 0x92, 0xf2, 0xbd, 0x33, 0x08,
0x90, 0x1a, 0xa1, 0xc4, 0x31, 0x09, 0xe6, 0x39, 0xa8, 0x02, 0x09, 0xd1, 0x83, 0x92, 0xfd, 0x3b,
0x91, 0xc9, 0x3d, 0xc9, 0xca, 0xd1, 0x47, 0xbc, 0x02, 0x0e, 0x0a, 0xe5, 0x9e, 0x2b, 0x90, 0x6a,
0x1b, 0x46, 0x1b, 0x90, 0xf2, 0x08, 0xb5, 0x2d, 0xc6, 0x2c, 0xd7, 0x61, 0x92, 0xe4, 0xfd, 0xfe,
0x24, 0x2b, 0xad, 0x84, 0xc7, 0x23, 0xb8, 0x3d, 0x1f, 0xdd, 0x85, 0x2b, 0x55, 0x8b, 0x79, 0x87,
0xc6, 0x89, 0xee, 0x18, 0x76, 0xa0, 0xfa, 0x38, 0x07, 0xc9, 0xd1, 0x4d, 0xc3, 0x26, 0xab, 0x63,
0x72, 0x55, 0xf9, 0xcf, 0xe1, 0x46, 0x37, 0xf1, 0xe1, 0xb5, 0x46, 0xfe, 0x87, 0x04, 0x5c, 0x7f,
0x62, 0x31, 0x3f, 0x9c, 0x9c, 0x5d, 0xe0, 0x1b, 0x6f, 0xc2, 0x58, 0xcd, 0x3a, 0xf4, 0x09, 0xe5,
0x12, 0xc6, 0x67, 0x53, 0xf3, 0x8b, 0x91, 0x12, 0xf6, 0x9a, 0x52, 0x7d, 0x24, 0x92, 0x71, 0x58,
0x04, 0x4d, 0xc1, 0xb8, 0x67, 0xd4, 0x89, 0xce, 0xac, 0x67, 0x81, 0x88, 0x09, 0xfc, 0x0a, 0x1f,
0xd8, 0xb2, 0x9e, 0x11, 0x34, 0x0d, 0x20, 0x82, 0xbe, 0x7b, 0x40, 0x1c, 0xb1, 0x4b, 0xc7, 0xb1,
0x80, 0x6f, 0xf3, 0x81, 0xdc, 0x6f, 0x71, 0x48, 0x06, 0xf5, 0xd0, 0x06, 0x8c, 0x72, 0xda, 0x42,
0x93, 0x89, 0xf9, 0xe5, 0x17, 0xe1, 0xa4, 0x6e, 0x9f, 0x78, 0x04, 0x8b, 0x32, 0xe8, 0x83, 0x4e,
0xc7, 0x8a, 0x0f, 0xe6, 0x58, 0x8f, 0x47, 0xba, 0x3d, 0xcb, 0xfd, 0xd4, 0x69, 0xda, 0xcc, 0x6b,
0xa2, 0x4c, 0x78, 0xcc, 0xa8, 0xfc, 0x98, 0x69, 0x75, 0x37, 0x23, 0x54, 0xe4, 0x07, 0x19, 0xe8,
0x3d, 0x18, 0x33, 0xb9, 0xa5, 0xb8, 0x34, 0x9b, 0x38, 0x7f, 0x72, 0x98, 0x93, 0xff, 0x5e, 0x81,
0x51, 0xbe, 0x2a, 0x94, 0x86, 0x2b, 0xdb, 0x1f, 0x55, 0x4a, 0x7a, 0x79, 0x73, 0x67, 0xe5, 0x49,
0x79, 0x2d, 0x3d, 0x82, 0x52, 0x30, 0x26, 0x46, 0x36, 0xb5, 0xb4, 0x82, 0xae, 0x43, 0x5a, 0xfc,
0xc1, 0xa5, 0x2d, 0xed, 0x29, 0x2e, 0x96, 0xf4, 0xf2, 0x5a, 0x3a, 0x86, 0x26, 0x00, 0xc4, 0xa8,
0xf6, 0xe1, 0x66, 0x09, 0xa7, 0xe3, 0xcd, 0x22, 0x45, 0x5c, 0x5a, 0xd9, 0xd6, 0x70, 0x7a, 0x14,
0x4d, 0xc2, 0xb5, 0x16, 0x42, 0xaf, 0x60, 0x6d, 0xa7, 0xbc, 0x56, 0xc2, 0xe9, 0x04, 0xba, 0x09,
0x99, 0x76, 0x68, 0x2b, 0x94, 0x5c, 0x4d, 0xc2, 0xa8, 0x4f, 0xa8, 0x9d, 0xff, 0x5b, 0x81, 0x4c,
0xd7, 0xd7, 0x18, 0xa2, 0x5b, 0x2e, 0x41, 0x52, 0x18, 0x20, 0xcb, 0xc6, 0x45, 0x17, 0x9f, 0x65,
0x97, 0x12, 0x8d, 0x66, 0xe0, 0x55, 0x87, 0x7c, 0xe6, 0xeb, 0xa7, 0xda, 0xf2, 0x2a, 0x1f, 0xae,
0x84, 0xad, 0x99, 0xff, 0x5a, 0x81, 0x0c, 0x26, 0xb6, 0x7b, 0xfc, 0x72, 0x7d, 0x95, 0x1b, 0x4f,
0x37, 0x8d, 0x21, 0x1a, 0xcf, 0x97, 0x0a, 0xa0, 0x75, 0xe2, 0xbf, 0x5c, 0x09, 0x7e, 0x56, 0xe0,
0x5a, 0x07, 0x89, 0xff, 0xfd, 0xa1, 0xfc, 0x9d, 0x02, 0xb7, 0xf8, 0xd6, 0xc0, 0xc4, 0x24, 0xd6,
0x31, 0xa9, 0x5e, 0x86, 0x6f, 0x77, 0xf8, 0x6c, 0xac, 0xaf, 0xcf, 0xc6, 0xbb, 0x7c, 0x36, 0xff,
0xaf, 0x02, 0xd3, 0x11, 0x7c, 0x86, 0xa8, 0xe5, 0xfb, 0x5d, 0x5b, 0x76, 0x26, 0x52, 0xcc, 0x90,
0xe7, 0x8b, 0x6d, 0xdd, 0x3f, 0x15, 0x98, 0x0e, 0x0e, 0xeb, 0xee, 0xf5, 0x5e, 0x40, 0xfe, 0x87,
0x61, 0x23, 0xc4, 0xda, 0xae, 0x9a, 0x67, 0x73, 0x0f, 0x92, 0xd0, 0xbb, 0x90, 0x6a, 0x08, 0x46,
0xe2, 0x8a, 0x2e, 0x9b, 0x29, 0xa7, 0x06, 0xb7, 0x78, 0x35, 0xbc, 0xc5, 0xab, 0xe2, 0xa2, 0xb3,
0x61, 0xb0, 0x03, 0x0c, 0x01, 0x9c, 0xff, 0xce, 0x7f, 0xa5, 0xc0, 0xed, 0xa8, 0xf5, 0x0c, 0xd1,
0x0b, 0x9e, 0x2b, 0x90, 0x5b, 0x27, 0xfe, 0x25, 0x6a, 0x7a, 0x01, 0x4f, 0xf8, 0x5d, 0x81, 0xa9,
0x9e, 0x64, 0x86, 0xd8, 0xcf, 0x0f, 0x3b, 0xbd, 0x61, 0xb0, 0x96, 0x98, 0xff, 0x6b, 0x0c, 0x92,
0x9a, 0x69, 0xaf, 0x54, 0xca, 0xe8, 0x08, 0x26, 0x3a, 0xdf, 0x1d, 0x48, 0x8d, 0xac, 0xd5, 0xf3,
0x4d, 0x97, 0x2b, 0x9c, 0x1b, 0x2f, 0xf5, 0x39, 0x82, 0x89, 0xce, 0x63, 0xa5, 0xcf, 0x94, 0x3d,
0x8f, 0xc1, 0x3e, 0x53, 0x46, 0x9c, 0x57, 0xfb, 0x90, 0x6a, 0x73, 0x71, 0xf4, 0x46, 0x64, 0xfe,
0xe9, 0x03, 0x27, 0xf7, 0xe0, 0x7c, 0x60, 0x39, 0x93, 0x03, 0x57, 0x3b, 0x2e, 0x26, 0xe8, 0xcd,
0x81, 0xae, 0x93, 0x39, 0xf5, 0xbc, 0xf0, 0x96, 0x98, 0x9d, 0x8f, 0x83, 0x3e, 0x62, 0xf6, 0x7c,
0xfe, 0xf4, 0x11, 0x33, 0xe2, 0xd5, 0xf1, 0x8d, 0xbc, 0x7c, 0x9d, 0x72, 0x74, 0xf4, 0x56, 0x5f,
0xf2, 0x51, 0x27, 0x52, 0x6e, 0x69, 0xd0, 0x34, 0x49, 0xe4, 0x5b, 0x25, 0x7c, 0x19, 0x75, 0x63,
0xd0, 0xd2, 0x19, 0x8b, 0x8a, 0x70, 0x92, 0xdc, 0xdb, 0x03, 0xe7, 0x49, 0x2e, 0x5f, 0x04, 0x17,
0x85, 0x53, 0x44, 0x16, 0xfa, 0x75, 0x4f, 0x14, 0x8b, 0xc5, 0xc1, 0x92, 0x02, 0x0a, 0xab, 0x14,
0xa6, 0x4c, 0xd7, 0x8e, 0x4a, 0x5d, 0x4d, 0xf1, 0x1d, 0xef, 0x59, 0x15, 0x6e, 0xf8, 0x15, 0xe5,
0x63, 0x70, 0x4d, 0x5b, 0x86, 0x7e, 0x8c, 0xc5, 0x8b, 0x5b, 0xda, 0x4f, 0xb1, 0xc9, 0x22, 0x5b,
0x10, 0x8e, 0xc7, 0x53, 0x35, 0xd3, 0x56, 0x77, 0xe6, 0x56, 0x79, 0xfc, 0x0f, 0x11, 0xd9, 0x95,
0x91, 0x5d, 0xcd, 0xb4, 0x77, 0x65, 0x64, 0x2f, 0x29, 0xce, 0x8f, 0x85, 0xff, 0x02, 0x00, 0x00,
0xff, 0xff, 0x23, 0x3e, 0xc9, 0x3d, 0x3e, 0x13, 0x00, 0x00,
// 1333 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x57, 0xcb, 0x8e, 0x1b, 0x45,
0x17, 0x4e, 0xdb, 0x63, 0x4f, 0x72, 0xfc, 0x67, 0x7e, 0xab, 0x32, 0xce, 0x38, 0x9d, 0x4c, 0x14,
0x5a, 0xca, 0x05, 0x11, 0xda, 0x9a, 0x0b, 0x41, 0x81, 0x10, 0x34, 0xf6, 0x38, 0x89, 0x45, 0xc6,
0xb6, 0x6a, 0x26, 0x41, 0xa0, 0x88, 0x56, 0xa7, 0x5d, 0xb6, 0x5b, 0x99, 0xbe, 0x4c, 0x57, 0x7b,
0xc8, 0x44, 0x20, 0x45, 0xdc, 0x24, 0x90, 0x58, 0xc0, 0x23, 0xb0, 0x60, 0xc1, 0x86, 0x3d, 0x1b,
0x24, 0x96, 0x48, 0x6c, 0xd8, 0xf2, 0x02, 0x48, 0xbc, 0x04, 0xaa, 0xea, 0x6a, 0xdb, 0x6d, 0xbb,
0x7d, 0x49, 0x22, 0x87, 0x5d, 0x77, 0x9d, 0xef, 0x9c, 0xfa, 0xaa, 0xce, 0x57, 0xe7, 0x54, 0xc1,
0x45, 0x83, 0x6e, 0x14, 0x68, 0x5b, 0xf7, 0x4c, 0xbb, 0x55, 0x70, 0x0c, 0xab, 0x70, 0xb8, 0xf6,
0x90, 0xf8, 0xfa, 0x1a, 0xfb, 0xd6, 0x74, 0xd7, 0x54, 0x5d, 0xcf, 0xf1, 0x1d, 0xb4, 0x62, 0xd0,
0x0d, 0x55, 0xc0, 0x54, 0xc7, 0xb0, 0x54, 0x01, 0x93, 0x5f, 0x65, 0xfe, 0x66, 0x83, 0xd8, 0xbe,
0xe9, 0x1f, 0x15, 0x3a, 0x94, 0x78, 0xdd, 0x08, 0x1e, 0xa1, 0x4e, 0xc7, 0x33, 0x08, 0x0d, 0x62,
0xc8, 0x57, 0x18, 0x94, 0x4d, 0xe1, 0x7a, 0xce, 0xa1, 0xd9, 0x18, 0x83, 0x3c, 0xc7, 0x90, 0x9e,
0x6b, 0x74, 0x01, 0xd4, 0xd7, 0xfd, 0x4e, 0x68, 0xbd, 0x1c, 0x47, 0x79, 0x30, 0xcc, 0x55, 0x0e,
0xf4, 0x1d, 0x4f, 0x6f, 0x91, 0xc9, 0x93, 0xae, 0x32, 0xb4, 0x7f, 0xe4, 0x12, 0xda, 0x85, 0xf0,
0x3f, 0x61, 0xbe, 0xd0, 0x72, 0x9c, 0xd6, 0x3e, 0x8f, 0xe3, 0x3b, 0x0f, 0x3b, 0xcd, 0x42, 0xd3,
0x24, 0xfb, 0x0d, 0xcd, 0xd2, 0xe9, 0xa3, 0x00, 0xa1, 0xfc, 0x96, 0x84, 0x5c, 0xc9, 0x23, 0xba,
0x4f, 0x6a, 0xa5, 0x9d, 0xdd, 0xb6, 0xee, 0x11, 0x4c, 0x0e, 0x3a, 0x84, 0xfa, 0x68, 0x0d, 0xd2,
0x8e, 0xab, 0x1f, 0x74, 0x48, 0x5e, 0xba, 0x20, 0x5d, 0xc9, 0xac, 0x9f, 0x51, 0xd9, 0x76, 0x06,
0xd1, 0xc5, 0x5c, 0x6a, 0x8d, 0x03, 0xb0, 0x00, 0xa2, 0x0a, 0x64, 0x42, 0x82, 0x9a, 0xd9, 0xc8,
0x27, 0xb8, 0xdf, 0x15, 0xee, 0x27, 0x56, 0xa4, 0x86, 0x2b, 0xea, 0x86, 0xc0, 0xc2, 0xa1, 0xd2,
0xc0, 0xe0, 0x75, 0xbf, 0xd1, 0xbb, 0xb0, 0xd8, 0xf2, 0x74, 0xdb, 0x27, 0x24, 0x9f, 0xe4, 0x61,
0x2e, 0x8e, 0x0f, 0x73, 0x3b, 0x00, 0xe3, 0xd0, 0x0b, 0x7d, 0x04, 0x2b, 0x1e, 0x31, 0x4c, 0xd7,
0x24, 0xb6, 0xaf, 0x59, 0x84, 0xb6, 0xb5, 0xd0, 0x27, 0xbf, 0xc0, 0x03, 0x5e, 0xe2, 0x01, 0x99,
0x2c, 0x86, 0x82, 0xd5, 0xc5, 0x40, 0xc5, 0x6e, 0x3a, 0x38, 0xd7, 0x0d, 0xb3, 0x43, 0x68, 0x3b,
0x34, 0xa1, 0xbb, 0xb0, 0xa4, 0x1b, 0x06, 0xa1, 0x54, 0xb3, 0x88, 0xdf, 0x76, 0x1a, 0x34, 0x9f,
0xba, 0x90, 0xec, 0xf1, 0x1c, 0x56, 0x9d, 0xba, 0xc5, 0xe1, 0x3b, 0x1c, 0x8d, 0x4f, 0xea, 0x7d,
0x7f, 0x14, 0xdd, 0x00, 0x20, 0x8f, 0x5d, 0xd3, 0xd3, 0x7d, 0xd3, 0xb1, 0xf3, 0x69, 0x4e, 0xf0,
0xdc, 0x88, 0x0d, 0xdf, 0x33, 0x2d, 0x42, 0x7d, 0xdd, 0x72, 0x71, 0x1f, 0x5e, 0xf9, 0x5b, 0x82,
0xd3, 0x83, 0x49, 0xa4, 0xae, 0x63, 0x53, 0x82, 0x0a, 0x90, 0x0e, 0x74, 0x28, 0xb2, 0xb8, 0xc2,
0x83, 0x7a, 0xae, 0xd1, 0x0d, 0xb9, 0xcb, 0xcd, 0x58, 0xc0, 0xfa, 0xd2, 0x9e, 0x98, 0x36, 0xed,
0x9b, 0x90, 0x62, 0xeb, 0x0d, 0x33, 0x75, 0x3e, 0x76, 0x07, 0x02, 0x6a, 0x01, 0x18, 0x6d, 0xc2,
0xe9, 0x5e, 0x82, 0x1a, 0x26, 0x75, 0xf7, 0xf5, 0x23, 0xcd, 0xd6, 0x2d, 0xc2, 0xf3, 0x73, 0x02,
0x2f, 0x77, 0xad, 0xdb, 0x81, 0xb1, 0xaa, 0x5b, 0x44, 0x79, 0x9a, 0x84, 0xdc, 0x3d, 0xb7, 0xf1,
0x62, 0xf4, 0x7a, 0x1d, 0x92, 0x1e, 0x69, 0x8a, 0x85, 0x5e, 0x9e, 0x40, 0x9b, 0x34, 0x89, 0x47,
0x6c, 0x83, 0x60, 0xe6, 0x83, 0xea, 0x90, 0xe2, 0x67, 0x29, 0x9f, 0xe4, 0x59, 0x7f, 0x2b, 0xd6,
0x79, 0x24, 0x59, 0x31, 0x7a, 0x8b, 0x45, 0xc0, 0x41, 0x20, 0xf9, 0x47, 0x09, 0x32, 0x7d, 0xc3,
0xe8, 0x66, 0x44, 0x12, 0xd2, 0x64, 0x49, 0xdc, 0x39, 0xd6, 0x2f, 0x0a, 0x54, 0x1d, 0x12, 0x68,
0xa2, 0xff, 0x20, 0x4d, 0x10, 0xe8, 0x9d, 0x63, 0x03, 0x12, 0x2d, 0x2e, 0x8a, 0x15, 0x2b, 0x9f,
0xc0, 0xe9, 0xc1, 0x45, 0xcd, 0x4f, 0x6c, 0xca, 0xf7, 0x29, 0x58, 0xbe, 0x6b, 0x52, 0x3f, 0x9c,
0x9c, 0x3e, 0x47, 0xfe, 0xab, 0xb0, 0xd8, 0x34, 0xf7, 0x7d, 0xe2, 0xb1, 0xbd, 0x61, 0x69, 0xdc,
0x8c, 0xdd, 0x9b, 0x51, 0x53, 0xaa, 0xb7, 0xb8, 0x33, 0x0e, 0x83, 0xa0, 0xb3, 0x70, 0xc2, 0xd5,
0x5b, 0x44, 0xa3, 0xe6, 0x93, 0xe0, 0x30, 0xa4, 0xf0, 0x71, 0x36, 0xb0, 0x6b, 0x3e, 0x21, 0x68,
0x15, 0x80, 0x1b, 0x7d, 0xe7, 0x11, 0xb1, 0x85, 0xc6, 0x39, 0x7c, 0x8f, 0x0d, 0xc8, 0xbf, 0x24,
0x21, 0x1d, 0xc4, 0x43, 0x3b, 0xb0, 0xc0, 0x68, 0xf3, 0x3d, 0x59, 0x5a, 0xbf, 0xfe, 0x2c, 0x9c,
0xd4, 0xbd, 0x23, 0x97, 0x60, 0x1e, 0x06, 0xbd, 0x17, 0xad, 0xca, 0xc9, 0xd9, 0xaa, 0x32, 0x53,
0x55, 0x5f, 0x5d, 0xbe, 0x0e, 0x29, 0xe7, 0x63, 0xbb, 0x5b, 0x44, 0x5f, 0xe1, 0x61, 0xc2, 0x56,
0xaa, 0xb2, 0x56, 0xda, 0x53, 0x3e, 0x25, 0x1e, 0xf7, 0x0f, 0x3c, 0xd0, 0x3b, 0xb0, 0x68, 0xb0,
0x22, 0xe5, 0x78, 0xf9, 0xd4, 0xf4, 0xce, 0xa1, 0x8f, 0xf2, 0x9d, 0x04, 0x0b, 0x6c, 0x55, 0x28,
0x0b, 0xff, 0xdb, 0xfb, 0xa0, 0x5e, 0xd6, 0x2a, 0xd5, 0xfb, 0x5b, 0x77, 0x2b, 0xdb, 0xd9, 0x63,
0x28, 0x03, 0x8b, 0x7c, 0xa4, 0x5a, 0xcb, 0x4a, 0x68, 0x19, 0xb2, 0xfc, 0x07, 0x97, 0x77, 0x6b,
0xf7, 0x70, 0xa9, 0xac, 0x55, 0xb6, 0xb3, 0x09, 0xb4, 0x04, 0xc0, 0x47, 0x6b, 0xef, 0x57, 0xcb,
0x38, 0x9b, 0xec, 0x06, 0x29, 0xe1, 0xf2, 0xd6, 0x5e, 0x0d, 0x67, 0x17, 0xd0, 0x0a, 0x9c, 0xea,
0x21, 0xb4, 0x3a, 0xae, 0xdd, 0xaf, 0x6c, 0x97, 0x71, 0x36, 0x85, 0xce, 0x40, 0xae, 0x1f, 0xda,
0x33, 0xa5, 0x8b, 0x69, 0x58, 0xf0, 0x89, 0x67, 0x29, 0x7f, 0x49, 0x90, 0x1b, 0xc8, 0xc6, 0x1c,
0xeb, 0xef, 0x35, 0x48, 0xf3, 0x92, 0x4a, 0x45, 0x31, 0x9a, 0x54, 0x80, 0x05, 0x1a, 0x5d, 0x82,
0xff, 0xdb, 0xe4, 0xb1, 0xaf, 0x0d, 0xc9, 0xf2, 0x24, 0x1b, 0xae, 0x87, 0xd2, 0x54, 0xbe, 0x94,
0x20, 0x87, 0x89, 0xe5, 0x1c, 0xbe, 0xdc, 0x9a, 0xcb, 0x0a, 0xcf, 0x20, 0x8d, 0x39, 0x16, 0x9e,
0xcf, 0x24, 0x40, 0xb7, 0x89, 0xff, 0x72, 0xb7, 0xe0, 0x67, 0x09, 0x4e, 0x45, 0x48, 0xfc, 0xd7,
0xdb, 0xbc, 0xb2, 0x06, 0x67, 0xfa, 0x08, 0x17, 0x8f, 0xb8, 0xa4, 0xc2, 0xcd, 0x5b, 0x86, 0x54,
0xa0, 0x3b, 0x89, 0xeb, 0x2e, 0xf8, 0x51, 0x3e, 0x97, 0x40, 0x1e, 0xe5, 0xf3, 0xac, 0x6b, 0xed,
0x12, 0x4f, 0xcc, 0x42, 0xfc, 0x5b, 0x09, 0xce, 0xb1, 0x33, 0x8d, 0x89, 0x41, 0xcc, 0x43, 0xd2,
0x78, 0x11, 0x0d, 0x27, 0xd2, 0x20, 0x12, 0x63, 0x1b, 0x44, 0x72, 0xa0, 0x41, 0x28, 0xff, 0x48,
0xb0, 0x1a, 0xc3, 0x67, 0x8e, 0x22, 0xb8, 0x39, 0x50, 0x6b, 0x2e, 0xc5, 0x6e, 0x66, 0xc8, 0xf3,
0xd9, 0x6a, 0xce, 0x1f, 0x12, 0xac, 0x06, 0xb7, 0x8c, 0xc1, 0xf5, 0x3e, 0xc7, 0xf6, 0xdf, 0x88,
0x0a, 0x61, 0x5a, 0xee, 0xe2, 0xc2, 0xfa, 0x36, 0x64, 0x3a, 0x9c, 0x11, 0x7f, 0x3f, 0x89, 0x53,
0x20, 0xab, 0xc1, 0x13, 0x4b, 0x0d, 0x9f, 0x58, 0x2a, 0xbf, 0xbd, 0xed, 0xe8, 0xf4, 0x11, 0x86,
0x00, 0xce, 0xbe, 0x95, 0x2f, 0x24, 0x38, 0x1f, 0xb7, 0x9e, 0x39, 0x16, 0xb1, 0x6f, 0x82, 0xa3,
0xf5, 0x02, 0xf7, 0xf4, 0x39, 0x8a, 0xd9, 0xaf, 0x12, 0x9c, 0x1d, 0x49, 0x66, 0x8e, 0x7a, 0xbe,
0x11, 0x2d, 0x6a, 0xb3, 0x49, 0x62, 0xfd, 0xcf, 0xe3, 0x90, 0xae, 0x19, 0xd6, 0x56, 0xbd, 0x82,
0x0e, 0x60, 0x29, 0xfa, 0x04, 0x43, 0x6a, 0x6c, 0xac, 0x91, 0x0f, 0x6e, 0xb9, 0x30, 0x35, 0x5e,
0xec, 0xcf, 0x01, 0x2c, 0x45, 0xfb, 0xe1, 0x98, 0x29, 0x47, 0xf6, 0xef, 0x31, 0x53, 0xc6, 0x34,
0xda, 0x36, 0x64, 0xfa, 0x2a, 0x33, 0x7a, 0x2d, 0xd6, 0x7f, 0xb8, 0x53, 0xca, 0x57, 0xa7, 0x03,
0x8b, 0x99, 0x3e, 0x8d, 0x74, 0x5b, 0xd1, 0x03, 0xd0, 0xfa, 0x34, 0x31, 0xa2, 0x4d, 0x46, 0xde,
0x98, 0xc9, 0x47, 0x4c, 0x6f, 0xc3, 0xc9, 0xc8, 0x85, 0x0e, 0xbd, 0x3e, 0xd3, 0x35, 0x5c, 0x56,
0xa7, 0x85, 0xf7, 0x72, 0x19, 0x7d, 0x54, 0x8d, 0xc9, 0xe5, 0xc8, 0x27, 0xe5, 0x98, 0x5c, 0xc6,
0xbc, 0xd6, 0xbe, 0x12, 0x97, 0xd6, 0xa1, 0x86, 0x82, 0xde, 0x18, 0x4b, 0x3e, 0xae, 0x21, 0xca,
0xd7, 0x66, 0x75, 0x13, 0x44, 0xbe, 0x96, 0xc2, 0x17, 0xe5, 0x20, 0x06, 0x5d, 0x9b, 0xb0, 0xa8,
0x98, 0x42, 0x26, 0xbf, 0x39, 0xb3, 0x9f, 0xe0, 0xf2, 0x34, 0xb8, 0x60, 0x0d, 0x11, 0x19, 0x2b,
0xa2, 0x38, 0x16, 0x9b, 0xb3, 0x39, 0x05, 0x14, 0x8a, 0x1e, 0x9c, 0x35, 0x1c, 0x2b, 0xce, 0xb5,
0x98, 0x61, 0x05, 0xc7, 0x35, 0xeb, 0xac, 0xdf, 0xd4, 0xa5, 0x0f, 0xc1, 0x31, 0x2c, 0x61, 0xfa,
0x21, 0x91, 0x2c, 0xed, 0xd6, 0x7e, 0x4a, 0xac, 0x94, 0xe8, 0x06, 0x2f, 0xb8, 0xcc, 0xb5, 0x66,
0x58, 0xea, 0xfd, 0xb5, 0x22, 0xb3, 0xff, 0xce, 0x2d, 0x0f, 0x84, 0xe5, 0x41, 0xcd, 0xb0, 0x1e,
0x08, 0xcb, 0xc3, 0x34, 0x6f, 0x5f, 0x1b, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0x14, 0xd1, 0x72,
0x91, 0x5a, 0x15, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@@ -1347,20 +1478,31 @@ type OcmAPIClient interface {
// MUST return CODE_NOT_FOUND if the resource reference does not exist.
// MUST return CODE_ALREADY_EXISTS if the share already exists for the 4-tuple consisting of
// (owner, shared_resource, grantee).
// New shares MUST be created in the state SHARE_STATE_PENDING.
// New shares MUST be created in the state SHARE_STATE_PENDING, and MUST be sent
// to the remote system using the OCM API at:
// https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1shares/post
CreateOCMShare(ctx context.Context, in *CreateOCMShareRequest, opts ...grpc.CallOption) (*CreateOCMShareResponse, error)
// Removes a share.
// MUST return CODE_NOT_FOUND if the share reference does not exist.
// This action SHALL be notified to the remote system
// using the OCM API at:
// https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1notifications/post
RemoveOCMShare(ctx context.Context, in *RemoveOCMShareRequest, opts ...grpc.CallOption) (*RemoveOCMShareResponse, error)
// Gets share information for a single share.
// MUST return CODE_NOT_FOUND if the share reference does not exist.
GetOCMShare(ctx context.Context, in *GetOCMShareRequest, opts ...grpc.CallOption) (*GetOCMShareResponse, error)
// Gets share information for a single share by its unlisted token.
// MUST return CODE_NOT_FOUND if the share does not exist.
GetOCMShareByToken(ctx context.Context, in *GetOCMShareByTokenRequest, opts ...grpc.CallOption) (*GetOCMShareByTokenResponse, error)
// List the shares the authenticated principal has created,
// both as owner and creator. If a filter is specified, only
// shares satisfying the filter MUST be returned.
ListOCMShares(ctx context.Context, in *ListOCMSharesRequest, opts ...grpc.CallOption) (*ListOCMSharesResponse, error)
// Updates a share.
// MUST return CODE_NOT_FOUND if the share reference does not exist.
// This action SHALL be notified to the remote system
// using the OCM API at:
// https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1notifications/post
UpdateOCMShare(ctx context.Context, in *UpdateOCMShareRequest, opts ...grpc.CallOption) (*UpdateOCMShareResponse, error)
// List all shares the authenticated principal has received.
ListReceivedOCMShares(ctx context.Context, in *ListReceivedOCMSharesRequest, opts ...grpc.CallOption) (*ListReceivedOCMSharesResponse, error)
@@ -1407,6 +1549,15 @@ func (c *ocmAPIClient) GetOCMShare(ctx context.Context, in *GetOCMShareRequest,
return out, nil
}
func (c *ocmAPIClient) GetOCMShareByToken(ctx context.Context, in *GetOCMShareByTokenRequest, opts ...grpc.CallOption) (*GetOCMShareByTokenResponse, error) {
out := new(GetOCMShareByTokenResponse)
err := c.cc.Invoke(ctx, "/cs3.sharing.ocm.v1beta1.OcmAPI/GetOCMShareByToken", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *ocmAPIClient) ListOCMShares(ctx context.Context, in *ListOCMSharesRequest, opts ...grpc.CallOption) (*ListOCMSharesResponse, error) {
out := new(ListOCMSharesResponse)
err := c.cc.Invoke(ctx, "/cs3.sharing.ocm.v1beta1.OcmAPI/ListOCMShares", in, out, opts...)
@@ -1458,20 +1609,31 @@ type OcmAPIServer interface {
// MUST return CODE_NOT_FOUND if the resource reference does not exist.
// MUST return CODE_ALREADY_EXISTS if the share already exists for the 4-tuple consisting of
// (owner, shared_resource, grantee).
// New shares MUST be created in the state SHARE_STATE_PENDING.
// New shares MUST be created in the state SHARE_STATE_PENDING, and MUST be sent
// to the remote system using the OCM API at:
// https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1shares/post
CreateOCMShare(context.Context, *CreateOCMShareRequest) (*CreateOCMShareResponse, error)
// Removes a share.
// MUST return CODE_NOT_FOUND if the share reference does not exist.
// This action SHALL be notified to the remote system
// using the OCM API at:
// https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1notifications/post
RemoveOCMShare(context.Context, *RemoveOCMShareRequest) (*RemoveOCMShareResponse, error)
// Gets share information for a single share.
// MUST return CODE_NOT_FOUND if the share reference does not exist.
GetOCMShare(context.Context, *GetOCMShareRequest) (*GetOCMShareResponse, error)
// Gets share information for a single share by its unlisted token.
// MUST return CODE_NOT_FOUND if the share does not exist.
GetOCMShareByToken(context.Context, *GetOCMShareByTokenRequest) (*GetOCMShareByTokenResponse, error)
// List the shares the authenticated principal has created,
// both as owner and creator. If a filter is specified, only
// shares satisfying the filter MUST be returned.
ListOCMShares(context.Context, *ListOCMSharesRequest) (*ListOCMSharesResponse, error)
// Updates a share.
// MUST return CODE_NOT_FOUND if the share reference does not exist.
// This action SHALL be notified to the remote system
// using the OCM API at:
// https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1notifications/post
UpdateOCMShare(context.Context, *UpdateOCMShareRequest) (*UpdateOCMShareResponse, error)
// List all shares the authenticated principal has received.
ListReceivedOCMShares(context.Context, *ListReceivedOCMSharesRequest) (*ListReceivedOCMSharesResponse, error)
@@ -1496,6 +1658,9 @@ func (*UnimplementedOcmAPIServer) RemoveOCMShare(ctx context.Context, req *Remov
func (*UnimplementedOcmAPIServer) GetOCMShare(ctx context.Context, req *GetOCMShareRequest) (*GetOCMShareResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetOCMShare not implemented")
}
func (*UnimplementedOcmAPIServer) GetOCMShareByToken(ctx context.Context, req *GetOCMShareByTokenRequest) (*GetOCMShareByTokenResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetOCMShareByToken not implemented")
}
func (*UnimplementedOcmAPIServer) ListOCMShares(ctx context.Context, req *ListOCMSharesRequest) (*ListOCMSharesResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListOCMShares not implemented")
}
@@ -1570,6 +1735,24 @@ func _OcmAPI_GetOCMShare_Handler(srv interface{}, ctx context.Context, dec func(
return interceptor(ctx, in, info, handler)
}
func _OcmAPI_GetOCMShareByToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetOCMShareByTokenRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(OcmAPIServer).GetOCMShareByToken(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/cs3.sharing.ocm.v1beta1.OcmAPI/GetOCMShareByToken",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(OcmAPIServer).GetOCMShareByToken(ctx, req.(*GetOCMShareByTokenRequest))
}
return interceptor(ctx, in, info, handler)
}
func _OcmAPI_ListOCMShares_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListOCMSharesRequest)
if err := dec(in); err != nil {
@@ -1676,6 +1859,10 @@ var _OcmAPI_serviceDesc = grpc.ServiceDesc{
MethodName: "GetOCMShare",
Handler: _OcmAPI_GetOCMShare_Handler,
},
{
MethodName: "GetOCMShareByToken",
Handler: _OcmAPI_GetOCMShareByToken_Handler,
},
{
MethodName: "ListOCMShares",
Handler: _OcmAPI_ListOCMShares_Handler,

View File

File diff suppressed because it is too large Load Diff

View File

@@ -2639,7 +2639,7 @@ type RestoreRecycleItemRequest struct {
// Opaque information.
Opaque *v1beta1.Opaque `protobuf:"bytes,1,opt,name=opaque,proto3" json:"opaque,omitempty"`
// REQUIRED.
// The reference to which the action should be performed.
// The reference to the user's home directory.
Ref *Reference `protobuf:"bytes,2,opt,name=ref,proto3" json:"ref,omitempty"`
// REQUIRED.
// The key for the recycle item to be restored.
@@ -4086,10 +4086,12 @@ func (m *UnlockResponse) GetOpaque() *v1beta1.Opaque {
type CreateHomeRequest struct {
// OPTIONAL.
// Opaque information.
Opaque *v1beta1.Opaque `protobuf:"bytes,1,opt,name=opaque,proto3" json:"opaque,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
Opaque *v1beta1.Opaque `protobuf:"bytes,1,opt,name=opaque,proto3" json:"opaque,omitempty"`
// OPTIONAL.
Quota *Quota `protobuf:"bytes,2,opt,name=quota,proto3" json:"quota,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *CreateHomeRequest) Reset() { *m = CreateHomeRequest{} }
@@ -4124,6 +4126,13 @@ func (m *CreateHomeRequest) GetOpaque() *v1beta1.Opaque {
return nil
}
func (m *CreateHomeRequest) GetQuota() *Quota {
if m != nil {
return m.Quota
}
return nil
}
type CreateHomeResponse struct {
// REQUIRED.
// The response status.
@@ -4900,179 +4909,179 @@ func init() {
}
var fileDescriptor_d1968a7258bd7add = []byte{
// 2745 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x5b, 0x5d, 0x6c, 0x1b, 0x59,
0xf5, 0xef, 0x75, 0x1c, 0x27, 0x39, 0xce, 0x87, 0x73, 0xdb, 0x6d, 0x9b, 0x69, 0xfb, 0x6f, 0xff,
0x46, 0x40, 0xb6, 0xb4, 0x4e, 0x9b, 0xd2, 0xed, 0x96, 0x5d, 0x76, 0x49, 0xd2, 0xb4, 0x89, 0x68,
0x53, 0xef, 0x24, 0xe9, 0x0a, 0xd4, 0x65, 0x34, 0xb5, 0xaf, 0xd3, 0x51, 0xec, 0x19, 0x77, 0xe6,
0x3a, 0xad, 0x8b, 0x58, 0x16, 0x54, 0xed, 0x0a, 0xb1, 0xf0, 0x82, 0x40, 0x42, 0x42, 0x42, 0x42,
0xf0, 0x82, 0xc4, 0x0b, 0x1f, 0x2b, 0x81, 0x04, 0x42, 0xe2, 0x6d, 0x9f, 0x40, 0x20, 0x1e, 0x90,
0xe0, 0x89, 0x95, 0x00, 0x09, 0x24, 0x1e, 0x78, 0xe1, 0x01, 0xa1, 0x7b, 0xe7, 0xce, 0x78, 0xc6,
0x1e, 0xfb, 0x8e, 0xe3, 0xd5, 0xb8, 0xdd, 0xe5, 0x6d, 0x66, 0xee, 0x3d, 0xe7, 0x9e, 0xf3, 0xbb,
0xe7, 0x9e, 0x39, 0x73, 0xce, 0x19, 0x58, 0x28, 0x39, 0x17, 0x16, 0x1c, 0x6a, 0xd9, 0xfa, 0x0e,
0x59, 0xa8, 0xdb, 0xd6, 0x9e, 0x51, 0x26, 0xf6, 0xc2, 0xde, 0xf9, 0x3b, 0x84, 0xea, 0xe7, 0xfd,
0x07, 0x9a, 0x5e, 0x37, 0x0a, 0x75, 0xdb, 0xa2, 0x16, 0x3e, 0x5e, 0x72, 0x2e, 0x14, 0x04, 0x41,
0xc1, 0x1b, 0x2f, 0x08, 0x02, 0xe5, 0x69, 0xc6, 0xce, 0x28, 0x13, 0x93, 0x1a, 0xb4, 0xb9, 0xd0,
0x70, 0x02, 0xbc, 0x6c, 0xe2, 0x58, 0x0d, 0xbb, 0x44, 0x1c, 0x97, 0x91, 0xc2, 0x18, 0x2d, 0xd8,
0xf5, 0x92, 0x3f, 0xc1, 0xa1, 0x3a, 0x6d, 0x78, 0xa3, 0x67, 0x7a, 0xca, 0xd5, 0xce, 0xeb, 0x04,
0x9b, 0x4d, 0x9b, 0x75, 0xe2, 0xf8, 0x53, 0xf8, 0x9d, 0x18, 0x3e, 0xb5, 0x63, 0x59, 0x3b, 0x55,
0xce, 0x87, 0x5a, 0x77, 0x1a, 0x95, 0x85, 0x8a, 0x41, 0xaa, 0x65, 0xad, 0xa6, 0x3b, 0xbb, 0xee,
0x8c, 0xfc, 0x0a, 0x4c, 0x5f, 0x23, 0x74, 0xcd, 0xaa, 0x11, 0x95, 0xdc, 0x6b, 0x10, 0x87, 0xe2,
0xf3, 0x90, 0xb1, 0xea, 0xfa, 0xbd, 0x06, 0x39, 0x8a, 0x4e, 0xa1, 0xf9, 0xec, 0xe2, 0x5c, 0x81,
0x29, 0xee, 0x72, 0x15, 0x6b, 0x14, 0x6e, 0xf2, 0x09, 0xaa, 0x98, 0x98, 0xff, 0x12, 0x82, 0x19,
0x9f, 0x8b, 0x53, 0xb7, 0x4c, 0x87, 0xe0, 0x05, 0xc8, 0xb8, 0x7a, 0x09, 0x36, 0x47, 0x38, 0x1b,
0xbb, 0x5e, 0xf2, 0x99, 0x6c, 0xf2, 0x61, 0x55, 0x4c, 0x0b, 0xac, 0x9b, 0x8a, 0xb9, 0x2e, 0xc6,
0x90, 0xae, 0xeb, 0xf4, 0xee, 0xd1, 0x91, 0x53, 0x68, 0x7e, 0x42, 0xe5, 0xd7, 0xf9, 0xdf, 0x22,
0x98, 0x59, 0x2a, 0x97, 0xaf, 0xd9, 0xba, 0x49, 0xf7, 0xaf, 0x12, 0xbe, 0x0c, 0x23, 0x36, 0xa9,
0x08, 0x51, 0x3e, 0x5c, 0xe8, 0xb5, 0xf7, 0x05, 0x95, 0x54, 0x88, 0x4d, 0xcc, 0x12, 0x51, 0x19,
0x0d, 0xbe, 0x0c, 0xa3, 0x3b, 0x6c, 0x75, 0x2e, 0x56, 0x76, 0xf1, 0x03, 0xbd, 0x89, 0x5d, 0x41,
0x5d, 0x0a, 0x7c, 0x04, 0xc6, 0xaa, 0x56, 0x69, 0x57, 0x33, 0xca, 0x47, 0xd3, 0x5c, 0xa7, 0x0c,
0xbb, 0x5d, 0x2f, 0xe7, 0xf7, 0x20, 0xd7, 0x52, 0x2a, 0x39, 0x84, 0xf3, 0x7f, 0x40, 0x90, 0xbb,
0x42, 0xcc, 0xe6, 0x10, 0xe1, 0x7c, 0x11, 0xc6, 0x38, 0x38, 0x84, 0x08, 0x40, 0x3f, 0x18, 0x03,
0x50, 0x42, 0x54, 0x8f, 0xaa, 0x3b, 0xa8, 0xf7, 0x61, 0x36, 0xa0, 0x5b, 0x82, 0xa8, 0xbe, 0x8e,
0xe0, 0xf0, 0x8a, 0x4d, 0x74, 0x4a, 0x56, 0x2c, 0x93, 0xea, 0x86, 0x49, 0xec, 0xa1, 0x60, 0x9b,
0xff, 0x1c, 0x1c, 0xe9, 0x90, 0x23, 0x41, 0x1c, 0x5e, 0x43, 0x90, 0xdb, 0xb2, 0x1a, 0xa5, 0xbb,
0x57, 0x8d, 0x2a, 0x19, 0x0e, 0x02, 0xf7, 0x61, 0x36, 0x20, 0x41, 0x82, 0xba, 0x7f, 0x03, 0xc1,
0xd4, 0x15, 0x52, 0x25, 0x74, 0x38, 0x8a, 0x07, 0x4f, 0xc5, 0x48, 0xe8, 0x54, 0x50, 0x98, 0xf6,
0xe4, 0x4a, 0x10, 0x8e, 0xaf, 0x22, 0xfe, 0x22, 0x2a, 0xea, 0xf4, 0xee, 0x00, 0x78, 0xac, 0x43,
0xd6, 0x7b, 0x43, 0x32, 0xc5, 0xdc, 0xd5, 0xe7, 0x65, 0xb8, 0xb8, 0x04, 0xeb, 0x65, 0x15, 0x6c,
0xff, 0xda, 0x7b, 0xa7, 0xb9, 0x02, 0x0d, 0xf9, 0x9d, 0xf6, 0x79, 0x2e, 0xca, 0x4b, 0x0d, 0x8b,
0xea, 0xc3, 0x39, 0x25, 0x6f, 0x21, 0xc8, 0xb5, 0x24, 0x48, 0x10, 0x8d, 0x93, 0x90, 0xa5, 0x16,
0xd5, 0xab, 0xda, 0x9d, 0x26, 0x25, 0x0e, 0x07, 0x25, 0xad, 0x02, 0x7f, 0xb4, 0xcc, 0x9e, 0xe0,
0x13, 0x00, 0x0d, 0x87, 0x94, 0xc5, 0x78, 0x9a, 0x8f, 0x4f, 0xb0, 0x27, 0x7c, 0x38, 0xff, 0x8b,
0x14, 0xcc, 0xad, 0x9b, 0x06, 0x35, 0x74, 0x4a, 0xd8, 0x11, 0xdf, 0xae, 0x57, 0x2d, 0xbd, 0x3c,
0x9c, 0x13, 0x97, 0x87, 0x49, 0xa3, 0xa2, 0x99, 0x16, 0xd5, 0xc8, 0x03, 0xc3, 0x71, 0xc3, 0x83,
0xf1, 0xb5, 0x03, 0x2a, 0x18, 0x95, 0x0d, 0x8b, 0xae, 0xb2, 0x67, 0xf8, 0x18, 0x8c, 0x1b, 0x15,
0xad, 0xa6, 0xd3, 0xd2, 0x5d, 0xf7, 0x65, 0xb5, 0x76, 0x40, 0x1d, 0x33, 0x2a, 0x37, 0xd8, 0x03,
0xbc, 0x01, 0x07, 0x8d, 0x8a, 0xd6, 0x30, 0x6b, 0x56, 0xd9, 0xa8, 0x18, 0xa4, 0xac, 0x39, 0x86,
0x59, 0x22, 0x47, 0x33, 0x5c, 0x96, 0xe3, 0x11, 0xb2, 0x6f, 0x19, 0x35, 0xe2, 0x50, 0xbd, 0x56,
0x5f, 0x3b, 0xa0, 0xce, 0x1a, 0x95, 0x6d, 0x9f, 0x72, 0x93, 0x11, 0x06, 0x5d, 0xc0, 0x68, 0xd0,
0x05, 0x2c, 0x4f, 0xc0, 0x98, 0x55, 0xa7, 0x86, 0x65, 0x3a, 0xf9, 0x5f, 0x23, 0x50, 0xa2, 0x00,
0x4c, 0xd0, 0x06, 0x36, 0x60, 0x82, 0xc7, 0xaa, 0x25, 0xab, 0xca, 0x2c, 0x60, 0x64, 0x3e, 0xbb,
0x78, 0xae, 0x37, 0xf0, 0x2d, 0x41, 0x8b, 0x82, 0x50, 0x6d, 0xb1, 0xc8, 0x7f, 0x17, 0xc1, 0xb1,
0xa0, 0x4a, 0x57, 0xac, 0xfb, 0xe6, 0xf0, 0xac, 0xa2, 0xab, 0x1f, 0xfe, 0x1d, 0x82, 0xe3, 0xd1,
0x62, 0x26, 0x88, 0x7d, 0xb1, 0x13, 0xfb, 0x45, 0x39, 0xf6, 0x9e, 0xa8, 0x51, 0xe8, 0xff, 0x1c,
0xc1, 0xec, 0x75, 0xc3, 0xa1, 0x3c, 0xea, 0x72, 0x86, 0x83, 0xf9, 0x31, 0x98, 0xa8, 0xeb, 0x3b,
0x44, 0x73, 0x8c, 0x87, 0x6e, 0x50, 0x39, 0xaa, 0x8e, 0xb3, 0x07, 0x9b, 0xc6, 0x43, 0xc2, 0x3c,
0x0a, 0x1f, 0xa4, 0xd6, 0x2e, 0x31, 0x45, 0xc4, 0xc8, 0xa7, 0x6f, 0xb1, 0x07, 0xf9, 0x3f, 0x22,
0xc0, 0x41, 0xf9, 0x13, 0xdc, 0x8c, 0xe7, 0x20, 0xc3, 0x63, 0x5a, 0x6f, 0x27, 0x62, 0x7d, 0x59,
0x08, 0x12, 0xfc, 0x21, 0x98, 0x31, 0xc9, 0x03, 0xaa, 0x75, 0xe8, 0x36, 0xc5, 0x1e, 0x17, 0x7d,
0xfd, 0x7e, 0x9a, 0x02, 0x85, 0xe9, 0xe7, 0x47, 0x84, 0x9b, 0xd4, 0x26, 0x7a, 0x6d, 0x38, 0x1b,
0xf5, 0x0c, 0x1c, 0xd1, 0xed, 0x3b, 0x06, 0xb5, 0x75, 0xbb, 0xa9, 0xd5, 0x08, 0xd5, 0xcb, 0x3a,
0xd5, 0xb5, 0x5d, 0xd2, 0x74, 0x21, 0x98, 0x50, 0x9f, 0xf2, 0x87, 0x6f, 0x88, 0xd1, 0x4f, 0x92,
0xa6, 0x83, 0x2f, 0x03, 0xb4, 0xbe, 0x74, 0xb9, 0x9e, 0xd9, 0x45, 0xa5, 0xe0, 0x7e, 0x0c, 0x17,
0xbc, 0x8f, 0xe1, 0xc2, 0x55, 0x36, 0xe5, 0x86, 0xee, 0xec, 0xaa, 0x13, 0x15, 0xef, 0x32, 0x6c,
0x1b, 0xa3, 0x3d, 0x6d, 0x23, 0xd3, 0x6e, 0x1b, 0x7f, 0x45, 0x70, 0x2c, 0x12, 0xbb, 0x04, 0x8d,
0xe4, 0x05, 0x48, 0x1b, 0x66, 0xc5, 0x12, 0xdf, 0x4a, 0xa7, 0x63, 0xc6, 0x3e, 0x66, 0xc5, 0x52,
0x39, 0x5d, 0x6c, 0x3b, 0xf9, 0x51, 0x0a, 0x0e, 0x85, 0x74, 0xfd, 0x9f, 0x85, 0xc4, 0xb0, 0x90,
0x77, 0x10, 0x3c, 0xd5, 0x86, 0x5a, 0x82, 0xb6, 0xf1, 0x09, 0x18, 0x65, 0x7b, 0xec, 0xf9, 0x8f,
0x7e, 0x8c, 0xc3, 0x25, 0x8c, 0x6d, 0x1d, 0xbf, 0x42, 0x70, 0x84, 0xe9, 0xc9, 0xde, 0x06, 0xb7,
0x88, 0xed, 0xb0, 0x58, 0xe2, 0xc9, 0xf3, 0xf5, 0x7f, 0x47, 0x70, 0xb4, 0x53, 0x8b, 0x04, 0x37,
0x6c, 0x15, 0xc6, 0xf7, 0xc4, 0xba, 0x62, 0xcf, 0x9e, 0x96, 0xbf, 0x7d, 0x85, 0xa4, 0xaa, 0x4f,
0x1a, 0x7b, 0xd7, 0x7e, 0x96, 0x72, 0xdf, 0x6d, 0x2a, 0x29, 0x35, 0x4b, 0x03, 0x7d, 0x91, 0x5f,
0x84, 0xb1, 0x8a, 0x6d, 0xd5, 0x34, 0xea, 0x08, 0x65, 0x7b, 0x86, 0xa7, 0x6a, 0x86, 0x4d, 0xde,
0x62, 0x10, 0x8d, 0x52, 0x4b, 0xa3, 0x8e, 0xf0, 0x5e, 0xbd, 0x89, 0xd2, 0xd4, 0xda, 0x72, 0x3c,
0xd3, 0x48, 0xef, 0xc3, 0x34, 0x72, 0x30, 0xb2, 0x4b, 0x9a, 0x22, 0xf6, 0x65, 0x97, 0x61, 0x63,
0xc9, 0xf4, 0x34, 0x96, 0xb1, 0x76, 0x63, 0xf9, 0x27, 0x82, 0x83, 0x21, 0xf0, 0x12, 0x0d, 0x91,
0xa7, 0x6c, 0x77, 0x59, 0xcd, 0xa0, 0xa4, 0x16, 0xd3, 0x58, 0x84, 0xa4, 0xeb, 0x94, 0xd4, 0xd4,
0x49, 0xbb, 0x75, 0x13, 0xdf, 0x60, 0x7e, 0x99, 0x72, 0x0f, 0x88, 0xe0, 0x34, 0x70, 0xa8, 0xf0,
0x3e, 0x34, 0x9b, 0x7f, 0x21, 0x98, 0x8b, 0x80, 0x30, 0x41, 0xe3, 0xb9, 0x0e, 0x93, 0x41, 0xe3,
0x11, 0x20, 0xf6, 0x61, 0x3b, 0xd9, 0x80, 0xed, 0xc4, 0x36, 0x9d, 0x77, 0x10, 0x64, 0x6f, 0x58,
0x7b, 0x83, 0x38, 0x99, 0x17, 0x21, 0xe3, 0xbe, 0xa1, 0xfa, 0x7d, 0x31, 0x08, 0x32, 0xbc, 0x0e,
0xd9, 0x32, 0x71, 0xa8, 0x61, 0xea, 0xec, 0x63, 0x57, 0x28, 0x1e, 0x9b, 0x4b, 0x90, 0xb6, 0x7b,
0x92, 0xd9, 0x86, 0x49, 0x57, 0xcd, 0x04, 0x93, 0x69, 0x5f, 0x47, 0x70, 0xb0, 0xd8, 0xb0, 0x77,
0xc8, 0xe0, 0x8e, 0x7c, 0x80, 0x37, 0xaf, 0x38, 0x27, 0x23, 0xfe, 0x39, 0xc9, 0x3f, 0x84, 0x43,
0x61, 0xb1, 0x12, 0xc4, 0xe4, 0xc7, 0x08, 0xe6, 0x54, 0xc2, 0x64, 0x27, 0xc1, 0x97, 0xe4, 0xe3,
0x81, 0x4c, 0x77, 0xf3, 0x79, 0x0d, 0x81, 0x12, 0x25, 0x76, 0x82, 0xc8, 0xfd, 0xa7, 0x85, 0x5c,
0xf0, 0xd4, 0x3f, 0x26, 0xc8, 0xad, 0xf1, 0x94, 0x2f, 0x13, 0x4e, 0xdb, 0x87, 0x43, 0x07, 0xdb,
0x53, 0xac, 0xd2, 0x35, 0x1d, 0x16, 0xdc, 0x83, 0x10, 0x00, 0x09, 0xee, 0xc1, 0xef, 0x11, 0x60,
0x95, 0xd4, 0xac, 0x3d, 0xf2, 0x1e, 0x2b, 0x6c, 0x36, 0xe1, 0x60, 0x48, 0xaf, 0x04, 0x31, 0xfd,
0x07, 0x82, 0x2c, 0xe3, 0xf2, 0x7e, 0xf9, 0x70, 0xcd, 0xff, 0x10, 0xc1, 0xa4, 0xab, 0xf0, 0x93,
0x93, 0x8f, 0xe0, 0x96, 0xbf, 0x5d, 0x2f, 0xeb, 0xf4, 0x3d, 0x68, 0xf9, 0x21, 0xbd, 0x12, 0xb4,
0xfc, 0x6f, 0x21, 0x38, 0xe4, 0xd6, 0x7d, 0x37, 0x9b, 0xb5, 0xaa, 0x61, 0xee, 0x0e, 0x07, 0xd5,
0xc3, 0x90, 0xa1, 0xba, 0xbd, 0x43, 0xa8, 0x97, 0xf9, 0x76, 0xef, 0xf2, 0x9f, 0x85, 0xa7, 0xda,
0xa4, 0x4b, 0x10, 0x9b, 0xef, 0xf9, 0xb5, 0xf9, 0x96, 0xb4, 0x43, 0x41, 0xe7, 0x04, 0x80, 0x8b,
0x87, 0xd6, 0xb0, 0x0d, 0x81, 0xd0, 0x84, 0xfb, 0x64, 0xdb, 0x36, 0x5a, 0xa5, 0xfb, 0x80, 0x98,
0x09, 0xc2, 0xf4, 0x28, 0x05, 0xc7, 0x36, 0x09, 0x5d, 0x6a, 0xf7, 0x51, 0xc3, 0xc1, 0xea, 0x33,
0x80, 0x3b, 0x9d, 0xa9, 0x38, 0xac, 0x0b, 0xbd, 0x39, 0x75, 0x6a, 0x30, 0xdb, 0xe1, 0x78, 0xbb,
0x1f, 0xe2, 0x2f, 0x22, 0x38, 0x1e, 0x0d, 0x43, 0x82, 0x7b, 0xf1, 0x27, 0x04, 0x27, 0xb6, 0x4d,
0xe7, 0xb1, 0xd9, 0x8d, 0xfd, 0xbe, 0xda, 0xba, 0xa2, 0xfc, 0x08, 0xc1, 0xff, 0x75, 0x53, 0x30,
0x41, 0x9c, 0xdf, 0x42, 0x30, 0xbd, 0x49, 0xe8, 0x75, 0xab, 0xb4, 0x3b, 0x2c, 0x60, 0xd3, 0x0c,
0x11, 0x61, 0xd8, 0xf9, 0xde, 0xb4, 0x5c, 0x4c, 0x3e, 0x3f, 0xdf, 0x80, 0x19, 0x5f, 0xee, 0x04,
0xf1, 0x7a, 0x95, 0xb7, 0x74, 0x0c, 0x0d, 0xae, 0xfc, 0x0f, 0xdc, 0x16, 0x8e, 0xa4, 0xf5, 0xde,
0xf7, 0x36, 0xfd, 0x99, 0x07, 0xf9, 0x15, 0x9b, 0x38, 0x77, 0x9f, 0x38, 0x1b, 0xc3, 0xf3, 0x90,
0xe3, 0x6d, 0x0d, 0x86, 0xb9, 0xa3, 0x85, 0x4f, 0xf1, 0xb4, 0xf7, 0xfc, 0x7a, 0x20, 0xe4, 0x0f,
0x68, 0x99, 0xa0, 0x45, 0xfe, 0x04, 0xc1, 0xd4, 0xb6, 0x59, 0x7d, 0xe2, 0x0e, 0x30, 0x85, 0x69,
0x4f, 0xec, 0x04, 0xd1, 0xba, 0x0a, 0xb3, 0x6e, 0x88, 0x31, 0x60, 0x7b, 0xf0, 0x03, 0xc0, 0x41,
0x3e, 0x09, 0x6a, 0xf0, 0x17, 0x04, 0x73, 0x22, 0x94, 0x74, 0x51, 0xde, 0xac, 0xeb, 0xa5, 0xc1,
0xea, 0x1a, 0xa3, 0xd6, 0x7d, 0x93, 0xd8, 0x42, 0x84, 0x93, 0x9c, 0xc2, 0x6b, 0xfb, 0x2e, 0x34,
0x9c, 0xc0, 0xf6, 0x6d, 0x3b, 0xc4, 0x56, 0xdd, 0xd9, 0x18, 0x43, 0x9a, 0xb1, 0xf5, 0x9a, 0xba,
0xd8, 0x35, 0x7b, 0x66, 0xea, 0x35, 0x22, 0x0e, 0x09, 0xbf, 0x66, 0xdf, 0x19, 0xf7, 0x1a, 0x16,
0xd5, 0x79, 0x02, 0x42, 0xfa, 0x9d, 0xe1, 0xb6, 0x63, 0xb9, 0x14, 0xf9, 0xdf, 0x20, 0x50, 0xa2,
0x54, 0x15, 0x68, 0xef, 0x43, 0xd7, 0xd6, 0x06, 0xa5, 0xe2, 0x6d, 0xd0, 0x4d, 0x98, 0x12, 0xb2,
0x6a, 0x0e, 0x5b, 0x3c, 0xde, 0x37, 0x5f, 0x48, 0xdc, 0x49, 0x27, 0x70, 0x97, 0xff, 0xdb, 0xa8,
0x5b, 0x5e, 0x08, 0x4e, 0x19, 0xa4, 0x8c, 0xf8, 0x32, 0x8c, 0x55, 0x8c, 0x2a, 0x25, 0x36, 0x53,
0x69, 0x64, 0x3e, 0xbb, 0xf8, 0x71, 0xc9, 0x09, 0xec, 0xb2, 0x76, 0xe1, 0x2a, 0xe7, 0xa2, 0x7a,
0xdc, 0xda, 0x3e, 0xca, 0x47, 0xf6, 0x5d, 0x4d, 0x4e, 0xf7, 0xac, 0x1d, 0x8c, 0xb6, 0xd5, 0x0e,
0x94, 0xb7, 0x47, 0x20, 0xe3, 0x8a, 0x82, 0x6f, 0x09, 0x0b, 0x63, 0x58, 0x4c, 0x2f, 0x2e, 0x0f,
0xa4, 0x57, 0x61, 0xab, 0x59, 0x27, 0xc2, 0x4a, 0x5f, 0x80, 0x94, 0xdf, 0x48, 0x79, 0x26, 0xfe,
0x46, 0xae, 0x97, 0xd7, 0x0e, 0xa8, 0x29, 0xa3, 0xcc, 0x2c, 0xda, 0x3d, 0x30, 0x2e, 0x28, 0xff,
0x2f, 0x39, 0x30, 0x9c, 0x4e, 0x1c, 0x9a, 0x93, 0x00, 0xdc, 0x8c, 0x34, 0xae, 0x98, 0xd7, 0x0d,
0x37, 0xc1, 0x9f, 0x31, 0x09, 0xf1, 0x21, 0xd1, 0x2a, 0x39, 0x2a, 0x86, 0xf8, 0x1d, 0xbe, 0x04,
0x69, 0xc6, 0x56, 0xb4, 0xc5, 0xc5, 0x5a, 0x90, 0x13, 0xe4, 0x1b, 0x90, 0xe6, 0x6c, 0x73, 0x30,
0xb9, 0xf5, 0xa9, 0xe2, 0xaa, 0xb6, 0xbe, 0x71, 0x6b, 0xe9, 0xfa, 0xfa, 0x95, 0xdc, 0x01, 0x9c,
0x85, 0x31, 0xfe, 0x64, 0xe3, 0x66, 0x0e, 0xf9, 0x37, 0xeb, 0x57, 0x72, 0x29, 0x3c, 0x0d, 0xc0,
0x6f, 0x6e, 0xbe, 0xbc, 0xb1, 0xaa, 0xe6, 0x46, 0xf0, 0x41, 0x98, 0xe1, 0xf7, 0x9b, 0xc5, 0xa5,
0x95, 0x55, 0x8d, 0x5d, 0xe6, 0xd2, 0x78, 0x0a, 0x26, 0xf8, 0xc3, 0xe2, 0xd2, 0xd6, 0x5a, 0x6e,
0xd4, 0xbf, 0xdd, 0xde, 0x5c, 0x55, 0x73, 0x99, 0xe5, 0x0c, 0xa4, 0x29, 0xb1, 0x6b, 0xf9, 0x7f,
0x8b, 0x42, 0x50, 0xdb, 0xc6, 0x24, 0x78, 0x7e, 0x5f, 0x82, 0xe9, 0xd0, 0xf9, 0x8d, 0xd9, 0x27,
0x10, 0x3a, 0xc0, 0x53, 0xc1, 0x03, 0x1c, 0xbf, 0x90, 0xf8, 0x6d, 0x04, 0x73, 0x6e, 0x36, 0xe4,
0x5d, 0x72, 0xd4, 0x1d, 0xbe, 0x28, 0x35, 0xa0, 0x2f, 0x62, 0xfe, 0x35, 0x4a, 0xc2, 0x27, 0xd9,
0xbf, 0xbe, 0x89, 0x60, 0xce, 0xed, 0xf5, 0x7e, 0x97, 0x50, 0x7f, 0x7e, 0xbf, 0xde, 0x82, 0xf9,
0x0a, 0x9e, 0x67, 0x8f, 0x12, 0x27, 0x39, 0x88, 0x17, 0xbf, 0x99, 0x87, 0x6c, 0x51, 0x88, 0xba,
0x54, 0x5c, 0xc7, 0x06, 0x8c, 0x7b, 0xff, 0xdd, 0xe0, 0xb3, 0x92, 0x44, 0x42, 0xf8, 0xa7, 0x23,
0xa5, 0x10, 0x77, 0xba, 0x50, 0xef, 0x55, 0x98, 0x69, 0xfb, 0x17, 0x03, 0x7f, 0xb4, 0x37, 0x8b,
0xe8, 0x5f, 0x48, 0x94, 0x8b, 0x7d, 0x52, 0x89, 0xf5, 0xab, 0x30, 0xe1, 0xff, 0x09, 0x81, 0x25,
0xc2, 0xb7, 0xff, 0xb4, 0xa1, 0x2c, 0xc4, 0x9e, 0x2f, 0x56, 0x2b, 0x41, 0xc6, 0xdd, 0x6a, 0xfc,
0x91, 0xde, 0xa4, 0xa1, 0x7f, 0x24, 0x94, 0x33, 0xf1, 0x26, 0xb7, 0x54, 0xf2, 0x7f, 0xf0, 0x91,
0xa9, 0xd4, 0xfe, 0x97, 0x93, 0x4c, 0xa5, 0xce, 0x3f, 0x87, 0x2a, 0x30, 0x26, 0x7e, 0x18, 0xc0,
0x12, 0x31, 0xc3, 0x3f, 0x3a, 0x28, 0x67, 0x63, 0xce, 0x16, 0xeb, 0x18, 0x30, 0xee, 0xf5, 0xe2,
0x63, 0x39, 0x69, 0xf0, 0xaf, 0x01, 0x99, 0x4d, 0x76, 0xb4, 0xf8, 0x7f, 0x05, 0xc1, 0xa1, 0xa8,
0x1e, 0x64, 0x7c, 0xb9, 0x37, 0xa3, 0x1e, 0xed, 0xd5, 0xca, 0xc7, 0xf6, 0x43, 0x2a, 0xe4, 0x79,
0x03, 0x01, 0xee, 0xec, 0x46, 0xc7, 0x97, 0xe2, 0xb3, 0x0c, 0xfd, 0x00, 0xa0, 0x3c, 0xdb, 0x3f,
0xa1, 0x90, 0xc4, 0x02, 0x68, 0x75, 0x01, 0xe3, 0x05, 0x79, 0xbc, 0x15, 0xea, 0x77, 0x56, 0xce,
0xc5, 0x27, 0x10, 0x0b, 0xbe, 0x29, 0xda, 0x8b, 0xda, 0x7a, 0x4b, 0xf1, 0xb3, 0x72, 0x4e, 0xd1,
0xad, 0xbc, 0xca, 0xe5, 0x7d, 0x50, 0xba, 0xc2, 0x9c, 0x43, 0xf8, 0x01, 0x4c, 0x85, 0x26, 0xe0,
0xc5, 0x3e, 0xb8, 0x79, 0x12, 0x5c, 0xe8, 0x8b, 0x46, 0x00, 0xf1, 0x05, 0x04, 0xb9, 0xf6, 0xa6,
0x3c, 0x7c, 0x51, 0xce, 0x29, 0xa2, 0x15, 0x51, 0x79, 0xa6, 0x5f, 0x32, 0x21, 0xc3, 0xeb, 0xa2,
0x89, 0x3d, 0xd4, 0xb4, 0x83, 0x63, 0x70, 0x8b, 0x6a, 0x94, 0x52, 0x2e, 0xf5, 0x4d, 0xe7, 0x6f,
0x83, 0x0d, 0xd9, 0xc0, 0x30, 0x3e, 0x17, 0x9b, 0x93, 0xb7, 0xf6, 0xf9, 0x3e, 0x28, 0x84, 0xf2,
0xaf, 0x40, 0xfa, 0x86, 0xb5, 0x47, 0xb0, 0xa4, 0x43, 0x28, 0xd0, 0xdc, 0xa3, 0x9c, 0x8e, 0x33,
0x55, 0xb0, 0xb7, 0x21, 0x1b, 0xa8, 0x08, 0xcb, 0x54, 0xea, 0x2c, 0x8a, 0xcb, 0x54, 0x8a, 0x2a,
0x37, 0x37, 0x60, 0x32, 0xd8, 0x98, 0x82, 0x25, 0x2c, 0x22, 0x7a, 0x6b, 0x94, 0xc5, 0x7e, 0x48,
0x02, 0xee, 0xac, 0xb3, 0xb9, 0x43, 0xe6, 0xce, 0xba, 0x76, 0xb1, 0xc8, 0xdc, 0x59, 0x8f, 0x3e,
0x92, 0x80, 0x24, 0x81, 0x16, 0x87, 0x98, 0x92, 0x74, 0x76, 0x85, 0xc4, 0x94, 0x24, 0xaa, 0x9b,
0xe2, 0x15, 0x48, 0xb3, 0x98, 0x4c, 0x66, 0x5d, 0x81, 0xc2, 0xbd, 0x72, 0x3a, 0xce, 0xd4, 0x96,
0x75, 0x05, 0xaa, 0xae, 0x32, 0xeb, 0xea, 0x2c, 0x3c, 0xcb, 0xac, 0x2b, 0xaa, 0xa4, 0xfb, 0x00,
0xa6, 0x42, 0xf5, 0x4c, 0x99, 0xaf, 0x8c, 0x2a, 0xcd, 0xca, 0x7c, 0x65, 0x74, 0xc1, 0xd4, 0x8f,
0x29, 0xfd, 0x3c, 0x64, 0xbc, 0x98, 0xb2, 0xbd, 0xf4, 0x19, 0x2f, 0xa6, 0xec, 0xac, 0x44, 0xb2,
0xf8, 0x21, 0xaa, 0x3c, 0x26, 0x8b, 0x1f, 0x7a, 0x54, 0x16, 0x65, 0xf1, 0x43, 0xcf, 0x6a, 0xdc,
0xd7, 0x10, 0x1c, 0x8e, 0x2e, 0x24, 0xe1, 0xe7, 0x24, 0xfb, 0xda, 0xab, 0xbe, 0xa6, 0x3c, 0xbf,
0x3f, 0xe2, 0x56, 0xe0, 0x28, 0xca, 0x33, 0xb2, 0xc0, 0x31, 0x5c, 0x7d, 0x92, 0x05, 0x8e, 0xed,
0x35, 0x1f, 0x37, 0x40, 0x8d, 0xb3, 0xce, 0xb5, 0xbe, 0xd6, 0x69, 0xaf, 0xb1, 0x70, 0x0f, 0xee,
0x27, 0xf8, 0xe5, 0x1e, 0xbc, 0xbd, 0xe2, 0x21, 0xf7, 0xe0, 0x9d, 0xd5, 0x83, 0x12, 0x64, 0xdc,
0x0c, 0xb9, 0xec, 0x7b, 0x22, 0x94, 0xfe, 0x97, 0x7d, 0x4f, 0xb4, 0x25, 0xdd, 0x2d, 0x80, 0x56,
0x22, 0x5b, 0x16, 0xf4, 0x75, 0xa4, 0xce, 0x65, 0x41, 0x5f, 0x44, 0x8e, 0xdc, 0xdd, 0x31, 0xbe,
0x9a, 0x7c, 0xc7, 0x82, 0x4b, 0x9d, 0x8d, 0x39, 0x3b, 0xe0, 0xfe, 0x3b, 0x93, 0xc7, 0x32, 0xf7,
0xdf, 0x35, 0xb3, 0x2e, 0x73, 0xff, 0x3d, 0xf2, 0xd4, 0x8f, 0x44, 0x64, 0x15, 0xca, 0x82, 0xc5,
0x89, 0xac, 0xa2, 0xf2, 0x99, 0x71, 0x22, 0xab, 0xe8, 0x74, 0xdb, 0x1b, 0x7e, 0xd7, 0x51, 0x3f,
0x80, 0x74, 0xcd, 0x60, 0xc9, 0x00, 0xe9, 0x91, 0x58, 0x62, 0x92, 0x74, 0x26, 0x45, 0x64, 0x92,
0x74, 0xcd, 0xea, 0xc8, 0x24, 0xe9, 0x9e, 0x7f, 0x59, 0xfe, 0x32, 0x82, 0x53, 0x25, 0xab, 0xd6,
0x93, 0x7e, 0x39, 0xe7, 0x67, 0x4f, 0xea, 0x06, 0xff, 0xfd, 0xb3, 0x88, 0x3e, 0x3d, 0xe3, 0xcd,
0x12, 0x93, 0xbe, 0x93, 0x1a, 0x59, 0xd9, 0x2c, 0x7e, 0x3f, 0x75, 0x7c, 0xc5, 0xb9, 0xe0, 0xe5,
0x81, 0x0a, 0x1e, 0x5d, 0xe1, 0xd6, 0xf9, 0x65, 0x36, 0xe9, 0x6d, 0x3e, 0x7c, 0x5b, 0x0c, 0xdf,
0xf6, 0x86, 0x6f, 0x8b, 0xe1, 0x3b, 0x19, 0x9e, 0x56, 0xbf, 0xf0, 0xdf, 0x00, 0x00, 0x00, 0xff,
0xff, 0xbd, 0x6f, 0xe6, 0xea, 0xc8, 0x47, 0x00, 0x00,
// 2749 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x5b, 0x5f, 0x6c, 0x1c, 0x47,
0x19, 0xcf, 0x9c, 0xef, 0xce, 0xf6, 0x77, 0xfe, 0x73, 0x9e, 0xa4, 0x4d, 0xbc, 0x49, 0x48, 0x38,
0x04, 0xb8, 0x21, 0x39, 0x27, 0x0e, 0x69, 0x1a, 0x5a, 0x5a, 0x6c, 0xc7, 0x89, 0x2d, 0x12, 0xe7,
0xba, 0xb6, 0x53, 0x81, 0x52, 0x56, 0x9b, 0xbb, 0x39, 0x67, 0xe5, 0xbb, 0xdd, 0xcb, 0xee, 0x9c,
0x93, 0x0b, 0xa2, 0xb4, 0x28, 0x6a, 0x85, 0x28, 0xbc, 0x20, 0x90, 0x90, 0x90, 0x90, 0x10, 0xbc,
0x20, 0xf1, 0xc2, 0x9f, 0x4a, 0x20, 0x81, 0x90, 0x78, 0xeb, 0x13, 0x08, 0xc4, 0x03, 0x12, 0x3c,
0x51, 0x09, 0x90, 0x40, 0xe2, 0x81, 0x17, 0x1e, 0x10, 0x9a, 0xd9, 0xd9, 0xbd, 0xdd, 0xbb, 0xbd,
0x9b, 0x3d, 0xbb, 0xda, 0x4b, 0x5a, 0xde, 0x76, 0x67, 0xe6, 0xfb, 0xe6, 0xfb, 0x7e, 0xf3, 0xcd,
0xb7, 0xdf, 0xce, 0xf7, 0x0d, 0xcc, 0x97, 0x9d, 0xf3, 0xf3, 0x0e, 0xb5, 0x6c, 0x7d, 0x9b, 0xcc,
0x37, 0x6c, 0x6b, 0xd7, 0xa8, 0x10, 0x7b, 0x7e, 0xf7, 0xdc, 0x6d, 0x42, 0xf5, 0x73, 0x7e, 0x83,
0xa6, 0x37, 0x8c, 0x62, 0xc3, 0xb6, 0xa8, 0x85, 0x8f, 0x95, 0x9d, 0xf3, 0x45, 0x41, 0x50, 0xf4,
0xfa, 0x8b, 0x82, 0x40, 0x79, 0x8a, 0xb1, 0x33, 0x2a, 0xc4, 0xa4, 0x06, 0x6d, 0xcd, 0x37, 0x9d,
0x00, 0x2f, 0x9b, 0x38, 0x56, 0xd3, 0x2e, 0x13, 0xc7, 0x65, 0xa4, 0x30, 0x46, 0xf3, 0x76, 0xa3,
0xec, 0x0f, 0x70, 0xa8, 0x4e, 0x9b, 0x5e, 0xef, 0xe9, 0xbe, 0x72, 0x75, 0xf2, 0x3a, 0xce, 0x46,
0xd3, 0x56, 0x83, 0x38, 0xfe, 0x10, 0xfe, 0x26, 0xba, 0x4f, 0x6e, 0x5b, 0xd6, 0x76, 0x8d, 0xf3,
0xa1, 0xd6, 0xed, 0x66, 0x75, 0xbe, 0x6a, 0x90, 0x5a, 0x45, 0xab, 0xeb, 0xce, 0x8e, 0x3b, 0xa2,
0xb0, 0x0c, 0x53, 0x57, 0x09, 0x5d, 0xb5, 0xea, 0x44, 0x25, 0x77, 0x9b, 0xc4, 0xa1, 0xf8, 0x1c,
0x64, 0xad, 0x86, 0x7e, 0xb7, 0x49, 0x8e, 0xa0, 0x93, 0x68, 0x2e, 0xb7, 0x30, 0x5b, 0x64, 0x8a,
0xbb, 0x5c, 0xc5, 0x1c, 0xc5, 0x1b, 0x7c, 0x80, 0x2a, 0x06, 0x16, 0xbe, 0x8c, 0x60, 0xda, 0xe7,
0xe2, 0x34, 0x2c, 0xd3, 0x21, 0x78, 0x1e, 0xb2, 0xae, 0x5e, 0x82, 0xcd, 0x61, 0xce, 0xc6, 0x6e,
0x94, 0x7d, 0x26, 0x1b, 0xbc, 0x5b, 0x15, 0xc3, 0x02, 0xf3, 0xa6, 0x62, 0xce, 0x8b, 0x31, 0xa4,
0x1b, 0x3a, 0xbd, 0x73, 0x64, 0xe4, 0x24, 0x9a, 0x1b, 0x57, 0xf9, 0x73, 0xe1, 0x77, 0x08, 0xa6,
0x17, 0x2b, 0x95, 0xab, 0xb6, 0x6e, 0xd2, 0xbd, 0xab, 0x84, 0x2f, 0xc1, 0x88, 0x4d, 0xaa, 0x42,
0x94, 0x8f, 0x16, 0xfb, 0xad, 0x7d, 0x51, 0x25, 0x55, 0x62, 0x13, 0xb3, 0x4c, 0x54, 0x46, 0x83,
0x2f, 0x41, 0x66, 0x9b, 0xcd, 0xce, 0xc5, 0xca, 0x2d, 0x7c, 0xa8, 0x3f, 0xb1, 0x2b, 0xa8, 0x4b,
0x81, 0x0f, 0xc3, 0x68, 0xcd, 0x2a, 0xef, 0x68, 0x46, 0xe5, 0x48, 0x9a, 0xeb, 0x94, 0x65, 0xaf,
0x6b, 0x95, 0xc2, 0x2e, 0xe4, 0xdb, 0x4a, 0x25, 0x87, 0x70, 0xe1, 0x8f, 0x08, 0xf2, 0x97, 0x89,
0xd9, 0x1a, 0x22, 0x9c, 0x2f, 0xc0, 0x28, 0x07, 0x87, 0x10, 0x01, 0xe8, 0x87, 0x63, 0x00, 0x4a,
0x88, 0xea, 0x51, 0xf5, 0x06, 0xf5, 0x1e, 0xcc, 0x04, 0x74, 0x4b, 0x10, 0xd5, 0xd7, 0x11, 0x3c,
0xb9, 0x6c, 0x13, 0x9d, 0x92, 0x65, 0xcb, 0xa4, 0xba, 0x61, 0x12, 0x7b, 0x28, 0xd8, 0x16, 0xbe,
0x00, 0x87, 0xbb, 0xe4, 0x48, 0x10, 0x87, 0x57, 0x11, 0xe4, 0x37, 0xad, 0x66, 0xf9, 0xce, 0x15,
0xa3, 0x46, 0x86, 0x83, 0xc0, 0x3d, 0x98, 0x09, 0x48, 0x90, 0xa0, 0xee, 0xdf, 0x44, 0x30, 0x79,
0x99, 0xd4, 0x08, 0x1d, 0x8e, 0xe2, 0xc1, 0x5d, 0x31, 0x12, 0xda, 0x15, 0x14, 0xa6, 0x3c, 0xb9,
0x12, 0x84, 0xe3, 0x6b, 0x88, 0x7f, 0x88, 0x4a, 0x3a, 0xbd, 0xb3, 0x0f, 0x3c, 0xd6, 0x20, 0xe7,
0x7d, 0x21, 0x99, 0x62, 0xee, 0xec, 0x73, 0x32, 0x5c, 0x5c, 0x82, 0xb5, 0x8a, 0x0a, 0xb6, 0xff,
0xec, 0x7d, 0xd3, 0x5c, 0x81, 0x86, 0xfc, 0x4d, 0xfb, 0x22, 0x17, 0xe5, 0xc5, 0xa6, 0x45, 0xf5,
0xe1, 0xec, 0x92, 0xb7, 0x10, 0xe4, 0xdb, 0x12, 0x24, 0x88, 0xc6, 0x09, 0xc8, 0x51, 0x8b, 0xea,
0x35, 0xed, 0x76, 0x8b, 0x12, 0x87, 0x83, 0x92, 0x56, 0x81, 0x37, 0x2d, 0xb1, 0x16, 0x7c, 0x1c,
0xa0, 0xe9, 0x90, 0x8a, 0xe8, 0x4f, 0xf3, 0xfe, 0x71, 0xd6, 0xc2, 0xbb, 0x0b, 0xbf, 0x4c, 0xc1,
0xec, 0x9a, 0x69, 0x50, 0x43, 0xa7, 0x84, 0x6d, 0xf1, 0xad, 0x46, 0xcd, 0xd2, 0x2b, 0xc3, 0xd9,
0x71, 0x05, 0x98, 0x30, 0xaa, 0x9a, 0x69, 0x51, 0x8d, 0xdc, 0x37, 0x1c, 0x37, 0x3c, 0x18, 0x5b,
0x3d, 0xa0, 0x82, 0x51, 0x5d, 0xb7, 0xe8, 0x0a, 0x6b, 0xc3, 0x47, 0x61, 0xcc, 0xa8, 0x6a, 0x75,
0x9d, 0x96, 0xef, 0xb8, 0x1f, 0xab, 0xd5, 0x03, 0xea, 0xa8, 0x51, 0xbd, 0xce, 0x1a, 0xf0, 0x3a,
0x1c, 0x34, 0xaa, 0x5a, 0xd3, 0xac, 0x5b, 0x15, 0xa3, 0x6a, 0x90, 0x8a, 0xe6, 0x18, 0x66, 0x99,
0x1c, 0xc9, 0x72, 0x59, 0x8e, 0x45, 0xc8, 0xbe, 0x69, 0xd4, 0x89, 0x43, 0xf5, 0x7a, 0x63, 0xf5,
0x80, 0x3a, 0x63, 0x54, 0xb7, 0x7c, 0xca, 0x0d, 0x46, 0x18, 0x74, 0x01, 0x99, 0xa0, 0x0b, 0x58,
0x1a, 0x87, 0x51, 0xab, 0x41, 0x0d, 0xcb, 0x74, 0x0a, 0xbf, 0x41, 0xa0, 0x44, 0x01, 0x98, 0xa0,
0x0d, 0xac, 0xc3, 0x38, 0x8f, 0x55, 0xcb, 0x56, 0x8d, 0x59, 0xc0, 0xc8, 0x5c, 0x6e, 0xe1, 0x6c,
0x7f, 0xe0, 0xdb, 0x82, 0x96, 0x04, 0xa1, 0xda, 0x66, 0x51, 0xf8, 0x1e, 0x82, 0xa3, 0x41, 0x95,
0x2e, 0x5b, 0xf7, 0xcc, 0xe1, 0x59, 0x45, 0x4f, 0x3f, 0xfc, 0x7b, 0x04, 0xc7, 0xa2, 0xc5, 0x4c,
0x10, 0xfb, 0x52, 0x37, 0xf6, 0x0b, 0x72, 0xec, 0x3d, 0x51, 0xa3, 0xd0, 0xff, 0x05, 0x82, 0x99,
0x6b, 0x86, 0x43, 0x79, 0xd4, 0xe5, 0x0c, 0x07, 0xf3, 0xa3, 0x30, 0xde, 0xd0, 0xb7, 0x89, 0xe6,
0x18, 0x0f, 0xdc, 0xa0, 0x32, 0xa3, 0x8e, 0xb1, 0x86, 0x0d, 0xe3, 0x01, 0x61, 0x1e, 0x85, 0x77,
0x52, 0x6b, 0x87, 0x98, 0x22, 0x62, 0xe4, 0xc3, 0x37, 0x59, 0x43, 0xe1, 0x4f, 0x08, 0x70, 0x50,
0xfe, 0x04, 0x17, 0xe3, 0x59, 0xc8, 0xf2, 0x98, 0xd6, 0x5b, 0x89, 0x58, 0x7f, 0x16, 0x82, 0x04,
0x7f, 0x04, 0xa6, 0x4d, 0x72, 0x9f, 0x6a, 0x5d, 0xba, 0x4d, 0xb2, 0xe6, 0x92, 0xaf, 0xdf, 0xcf,
0x52, 0xa0, 0x30, 0xfd, 0xfc, 0x88, 0x70, 0x83, 0xda, 0x44, 0xaf, 0x0f, 0x67, 0xa1, 0x9e, 0x86,
0xc3, 0xba, 0x7d, 0xdb, 0xa0, 0xb6, 0x6e, 0xb7, 0xb4, 0x3a, 0xa1, 0x7a, 0x45, 0xa7, 0xba, 0xb6,
0x43, 0x5a, 0x2e, 0x04, 0xe3, 0xea, 0x13, 0x7e, 0xf7, 0x75, 0xd1, 0xfb, 0x69, 0xd2, 0x72, 0xf0,
0x25, 0x80, 0xf6, 0x9f, 0x2e, 0xd7, 0x33, 0xb7, 0xa0, 0x14, 0xdd, 0x9f, 0xe1, 0xa2, 0xf7, 0x33,
0x5c, 0xbc, 0xc2, 0x86, 0x5c, 0xd7, 0x9d, 0x1d, 0x75, 0xbc, 0xea, 0x3d, 0x86, 0x6d, 0x23, 0xd3,
0xd7, 0x36, 0xb2, 0x9d, 0xb6, 0xf1, 0x37, 0x04, 0x47, 0x23, 0xb1, 0x4b, 0xd0, 0x48, 0x9e, 0x87,
0xb4, 0x61, 0x56, 0x2d, 0xf1, 0xaf, 0x74, 0x2a, 0x66, 0xec, 0x63, 0x56, 0x2d, 0x95, 0xd3, 0xc5,
0xb6, 0x93, 0x1f, 0xa7, 0xe0, 0x50, 0x48, 0xd7, 0xff, 0x5b, 0x48, 0x0c, 0x0b, 0x79, 0x07, 0xc1,
0x13, 0x1d, 0xa8, 0x25, 0x68, 0x1b, 0x9f, 0x82, 0x0c, 0x5b, 0x63, 0xcf, 0x7f, 0x0c, 0x62, 0x1c,
0x2e, 0x61, 0x6c, 0xeb, 0xf8, 0x35, 0x82, 0xc3, 0x4c, 0x4f, 0xf6, 0x35, 0xb8, 0x49, 0x6c, 0x87,
0xc5, 0x12, 0x8f, 0x9f, 0xaf, 0xff, 0x07, 0x82, 0x23, 0xdd, 0x5a, 0x24, 0xb8, 0x60, 0x2b, 0x30,
0xb6, 0x2b, 0xe6, 0x15, 0x6b, 0xf6, 0x94, 0xfc, 0xeb, 0x2b, 0x24, 0x55, 0x7d, 0xd2, 0xd8, 0xab,
0xf6, 0xf3, 0x94, 0xfb, 0x6d, 0x53, 0x49, 0xb9, 0x55, 0xde, 0xd7, 0x1f, 0xf9, 0x05, 0x18, 0xad,
0xda, 0x56, 0x5d, 0xa3, 0x8e, 0x50, 0xb6, 0x6f, 0x78, 0xaa, 0x66, 0xd9, 0xe0, 0x4d, 0x06, 0x51,
0x86, 0x5a, 0x1a, 0x75, 0x84, 0xf7, 0xea, 0x4f, 0x94, 0xa6, 0xd6, 0xa6, 0xe3, 0x99, 0x46, 0x7a,
0x0f, 0xa6, 0x91, 0x87, 0x91, 0x1d, 0xd2, 0x12, 0xb1, 0x2f, 0x7b, 0x0c, 0x1b, 0x4b, 0xb6, 0xaf,
0xb1, 0x8c, 0x76, 0x1a, 0xcb, 0xbf, 0x10, 0x1c, 0x0c, 0x81, 0x97, 0x68, 0x88, 0x3c, 0x69, 0xbb,
0xd3, 0x6a, 0x06, 0x25, 0xf5, 0x98, 0xc6, 0x22, 0x24, 0x5d, 0xa3, 0xa4, 0xae, 0x4e, 0xd8, 0xed,
0x97, 0xf8, 0x06, 0xf3, 0xab, 0x94, 0xbb, 0x41, 0x04, 0xa7, 0x7d, 0x87, 0x0a, 0xef, 0x43, 0xb3,
0xf9, 0x37, 0x82, 0xd9, 0x08, 0x08, 0x13, 0x34, 0x9e, 0x6b, 0x30, 0x11, 0x34, 0x1e, 0x01, 0xe2,
0x00, 0xb6, 0x93, 0x0b, 0xd8, 0x4e, 0x6c, 0xd3, 0x79, 0x07, 0x41, 0xee, 0xba, 0xb5, 0xbb, 0x1f,
0x27, 0xf3, 0x02, 0x64, 0xdd, 0x2f, 0xd4, 0xa0, 0x1f, 0x06, 0x41, 0x86, 0xd7, 0x20, 0x57, 0x21,
0x0e, 0x35, 0x4c, 0x9d, 0xfd, 0xec, 0x0a, 0xc5, 0x63, 0x73, 0x09, 0xd2, 0xf6, 0x3e, 0x64, 0xb6,
0x61, 0xc2, 0x55, 0x33, 0xc1, 0xc3, 0xb4, 0x6f, 0x20, 0x38, 0x58, 0x6a, 0xda, 0xdb, 0x64, 0xff,
0x8e, 0x7c, 0x1f, 0x5f, 0x5e, 0xb1, 0x4f, 0x46, 0xfc, 0x7d, 0x52, 0x78, 0x00, 0x87, 0xc2, 0x62,
0x25, 0x88, 0xc9, 0x4f, 0x10, 0xcc, 0xaa, 0x84, 0xc9, 0x4e, 0x82, 0x1f, 0xc9, 0x47, 0x03, 0x99,
0xde, 0xe6, 0xf3, 0x2a, 0x02, 0x25, 0x4a, 0xec, 0x04, 0x91, 0xfb, 0x6f, 0x1b, 0xb9, 0xe0, 0xae,
0x7f, 0x44, 0x90, 0x5b, 0xe5, 0x47, 0xbe, 0x4c, 0x38, 0x6d, 0x0f, 0x0e, 0x1d, 0x6c, 0x4f, 0xb1,
0x6a, 0xcf, 0xe3, 0xb0, 0xe0, 0x1a, 0x84, 0x00, 0x48, 0x70, 0x0d, 0xfe, 0x80, 0x00, 0xab, 0xa4,
0x6e, 0xed, 0x92, 0xf7, 0x58, 0x62, 0xb3, 0x05, 0x07, 0x43, 0x7a, 0x25, 0x88, 0xe9, 0x3f, 0x11,
0xe4, 0x18, 0x97, 0xf7, 0xcb, 0x8f, 0x6b, 0xe1, 0x47, 0x08, 0x26, 0x5c, 0x85, 0x1f, 0x9f, 0xf3,
0x08, 0x6e, 0xf9, 0x5b, 0x8d, 0x8a, 0x4e, 0xdf, 0x83, 0x96, 0x1f, 0xd2, 0x2b, 0x41, 0xcb, 0xff,
0x36, 0x82, 0x43, 0x6e, 0xde, 0x77, 0xa3, 0x55, 0xaf, 0x19, 0xe6, 0xce, 0x70, 0x50, 0x7d, 0x12,
0xb2, 0x54, 0xb7, 0xb7, 0x09, 0xf5, 0x4e, 0xbe, 0xdd, 0xb7, 0xc2, 0xe7, 0xe1, 0x89, 0x0e, 0xe9,
0x12, 0xc4, 0xe6, 0xfb, 0x7e, 0x6e, 0xbe, 0x2d, 0xed, 0x50, 0xd0, 0x39, 0x0e, 0xe0, 0xe2, 0xa1,
0x35, 0x6d, 0x43, 0x20, 0x34, 0xee, 0xb6, 0x6c, 0xd9, 0x46, 0x3b, 0x75, 0x1f, 0x10, 0x33, 0x41,
0x98, 0x1e, 0xa6, 0xe0, 0xe8, 0x06, 0xa1, 0x8b, 0x9d, 0x3e, 0x6a, 0x38, 0x58, 0x7d, 0x0e, 0x70,
0xb7, 0x33, 0x15, 0x9b, 0x75, 0xbe, 0x3f, 0xa7, 0x6e, 0x0d, 0x66, 0xba, 0x1c, 0x6f, 0xef, 0x4d,
0xfc, 0x25, 0x04, 0xc7, 0xa2, 0x61, 0x48, 0x70, 0x2d, 0xfe, 0x8c, 0xe0, 0xf8, 0x96, 0xe9, 0x3c,
0x32, 0xab, 0xb1, 0xd7, 0x4f, 0x5b, 0x4f, 0x94, 0x1f, 0x22, 0xf8, 0x40, 0x2f, 0x05, 0x13, 0xc4,
0xf9, 0x2d, 0x04, 0x53, 0x1b, 0x84, 0x5e, 0xb3, 0xca, 0x3b, 0xc3, 0x02, 0x36, 0xcd, 0x10, 0x11,
0x86, 0x5d, 0xe8, 0x4f, 0xcb, 0xc5, 0xe4, 0xe3, 0x0b, 0x4d, 0x98, 0xf6, 0xe5, 0x4e, 0x10, 0xaf,
0x57, 0x78, 0x49, 0xc7, 0xd0, 0xe0, 0x2a, 0xfc, 0xd0, 0x2d, 0xe1, 0x48, 0x5a, 0xef, 0x3d, 0x2f,
0xd3, 0x5f, 0x78, 0x90, 0x5f, 0xb5, 0x89, 0x73, 0xe7, 0xb1, 0xb3, 0x31, 0x3c, 0x07, 0x79, 0x5e,
0xd6, 0x60, 0x98, 0xdb, 0x5a, 0x78, 0x17, 0x4f, 0x79, 0xed, 0xd7, 0x02, 0x21, 0x7f, 0x40, 0xcb,
0x04, 0x2d, 0xf2, 0xa7, 0x08, 0x26, 0xb7, 0xcc, 0xda, 0x63, 0xb7, 0x81, 0x29, 0x4c, 0x79, 0x62,
0x27, 0x88, 0xd6, 0x6b, 0x08, 0x66, 0xdc, 0x18, 0x63, 0x7f, 0xf5, 0xc1, 0x2c, 0x7c, 0xbe, 0xdb,
0xb4, 0xa8, 0x2e, 0xa6, 0x96, 0x84, 0xcf, 0x6e, 0x95, 0x91, 0x4b, 0x51, 0xb8, 0x0f, 0x38, 0x28,
0x42, 0x82, 0xda, 0xff, 0x15, 0xc1, 0xac, 0x08, 0x43, 0x5d, 0x49, 0x37, 0x1a, 0x7a, 0x79, 0x7f,
0x39, 0x91, 0x8c, 0x75, 0xcf, 0x24, 0xb6, 0x10, 0xe1, 0x04, 0xa7, 0xf0, 0x4a, 0xc6, 0x8b, 0x4d,
0x27, 0x00, 0xc1, 0x96, 0x43, 0x6c, 0xd5, 0x1d, 0x8d, 0x31, 0xa4, 0x19, 0x5b, 0xaf, 0x20, 0x8c,
0x3d, 0xb3, 0x36, 0x53, 0xaf, 0x13, 0xb1, 0xc1, 0xf8, 0x73, 0x1b, 0xe4, 0xcc, 0xc0, 0x20, 0xff,
0x16, 0x81, 0x12, 0xa5, 0xaa, 0x40, 0x7b, 0x0f, 0xba, 0xb6, 0x17, 0x28, 0x15, 0x6f, 0x81, 0x6e,
0xc0, 0xa4, 0x90, 0x55, 0x73, 0xd8, 0xe4, 0xf1, 0xfe, 0x17, 0x43, 0xe2, 0x4e, 0x38, 0x81, 0xb7,
0xc2, 0xdf, 0x33, 0x6e, 0x6a, 0x22, 0x38, 0x64, 0x3f, 0x29, 0xc8, 0x97, 0x60, 0xb4, 0x6a, 0xd4,
0x28, 0xb1, 0x99, 0x4a, 0x23, 0x73, 0xb9, 0x85, 0x4f, 0x4a, 0x76, 0x6f, 0x8f, 0xb9, 0x8b, 0x57,
0x38, 0x17, 0xd5, 0xe3, 0xd6, 0xf1, 0x43, 0x3f, 0xb2, 0xe7, 0x4c, 0x74, 0xba, 0x6f, 0xde, 0x21,
0xd3, 0x91, 0x77, 0x50, 0xde, 0x1e, 0x81, 0xac, 0x2b, 0x0a, 0xbe, 0x29, 0x2c, 0x8c, 0x61, 0x31,
0xb5, 0xb0, 0xb4, 0x2f, 0xbd, 0x8a, 0x9b, 0xad, 0x06, 0x11, 0x56, 0xfa, 0x3c, 0xa4, 0xfc, 0x22,
0xcc, 0xd3, 0xf1, 0x17, 0x72, 0xad, 0xb2, 0x7a, 0x40, 0x4d, 0x19, 0x15, 0x66, 0xd1, 0xee, 0x86,
0x71, 0x41, 0xf9, 0xa0, 0x64, 0xc3, 0x70, 0x3a, 0xb1, 0x69, 0x4e, 0x00, 0x70, 0x33, 0xd2, 0xb8,
0x62, 0x5e, 0x25, 0xdd, 0x38, 0x6f, 0x63, 0x12, 0xe2, 0x43, 0xa2, 0xcc, 0x32, 0x23, 0xba, 0xf8,
0x1b, 0xbe, 0x08, 0x69, 0xc6, 0x56, 0x94, 0xd4, 0xc5, 0x9a, 0x90, 0x13, 0x14, 0x9a, 0x90, 0xe6,
0x6c, 0xf3, 0x30, 0xb1, 0xf9, 0x99, 0xd2, 0x8a, 0xb6, 0xb6, 0x7e, 0x73, 0xf1, 0xda, 0xda, 0xe5,
0xfc, 0x01, 0x9c, 0x83, 0x51, 0xde, 0xb2, 0x7e, 0x23, 0x8f, 0xfc, 0x97, 0xb5, 0xcb, 0xf9, 0x14,
0x9e, 0x02, 0xe0, 0x2f, 0x37, 0x5e, 0x5a, 0x5f, 0x51, 0xf3, 0x23, 0xf8, 0x20, 0x4c, 0xf3, 0xf7,
0x8d, 0xd2, 0xe2, 0xf2, 0x8a, 0xc6, 0x1e, 0xf3, 0x69, 0x3c, 0x09, 0xe3, 0xbc, 0xb1, 0xb4, 0xb8,
0xb9, 0x9a, 0xcf, 0xf8, 0xaf, 0x5b, 0x1b, 0x2b, 0x6a, 0x3e, 0xbb, 0x94, 0x85, 0x34, 0x25, 0x76,
0xbd, 0xf0, 0x1f, 0x91, 0x44, 0xea, 0x58, 0x98, 0x04, 0xf7, 0xef, 0x8b, 0x30, 0x15, 0xda, 0xbf,
0x31, 0x6b, 0x0c, 0x42, 0x1b, 0x78, 0x32, 0xb8, 0x81, 0xe3, 0x27, 0x21, 0xbf, 0x83, 0x60, 0xd6,
0x3d, 0x49, 0x79, 0x97, 0x1c, 0x75, 0x97, 0x2f, 0x4a, 0xed, 0xd3, 0x17, 0x31, 0xff, 0x1a, 0x25,
0xe1, 0xe3, 0xec, 0x5f, 0xdf, 0x44, 0x30, 0xeb, 0xd6, 0x89, 0xbf, 0x4b, 0xa8, 0x3f, 0xb7, 0x57,
0x6f, 0xc1, 0x7c, 0x05, 0x3f, 0xa3, 0x8f, 0x12, 0x27, 0x39, 0x88, 0x17, 0xbe, 0x55, 0x80, 0x5c,
0x49, 0x88, 0xba, 0x58, 0x5a, 0xc3, 0x06, 0x8c, 0x79, 0x77, 0x76, 0xf0, 0x19, 0xc9, 0x21, 0x44,
0xf8, 0xc2, 0x92, 0x52, 0x8c, 0x3b, 0x5c, 0xa8, 0xf7, 0x0a, 0x4c, 0x77, 0xdc, 0xe3, 0xc0, 0x1f,
0xef, 0xcf, 0x22, 0xfa, 0xfa, 0x89, 0x72, 0x61, 0x40, 0x2a, 0x31, 0x7f, 0x0d, 0xc6, 0xfd, 0x5b,
0x14, 0x58, 0x22, 0x7c, 0xe7, 0x85, 0x0f, 0x65, 0x3e, 0xf6, 0x78, 0x31, 0x5b, 0x19, 0xb2, 0xee,
0x52, 0xe3, 0x8f, 0xf5, 0x27, 0x0d, 0xdd, 0xaf, 0x50, 0x4e, 0xc7, 0x1b, 0xdc, 0x56, 0xc9, 0xbf,
0x1c, 0x24, 0x53, 0xa9, 0xf3, 0x86, 0x94, 0x4c, 0xa5, 0xee, 0x5b, 0x47, 0x55, 0x18, 0x15, 0x97,
0x0d, 0xb0, 0x44, 0xcc, 0xf0, 0x25, 0x09, 0xe5, 0x4c, 0xcc, 0xd1, 0x62, 0x1e, 0x03, 0xc6, 0xbc,
0x3a, 0x7e, 0x2c, 0x27, 0x0d, 0xde, 0x38, 0x90, 0xd9, 0x64, 0xd7, 0xf5, 0x80, 0xaf, 0x22, 0x38,
0x14, 0x55, 0xbf, 0x8c, 0x2f, 0xf5, 0x67, 0xd4, 0xa7, 0x34, 0x5b, 0xf9, 0xc4, 0x5e, 0x48, 0x85,
0x3c, 0x6f, 0x20, 0xc0, 0xdd, 0x95, 0xec, 0xf8, 0x62, 0x7c, 0x96, 0xa1, 0xcb, 0x03, 0xca, 0x33,
0x83, 0x13, 0x0a, 0x49, 0x2c, 0x80, 0x76, 0x05, 0x31, 0x9e, 0x97, 0xc7, 0x5b, 0xa1, 0x5a, 0x69,
0xe5, 0x6c, 0x7c, 0x02, 0x31, 0xe1, 0x9b, 0xa2, 0x34, 0xa9, 0xa3, 0x2e, 0x15, 0x3f, 0x23, 0xe7,
0x14, 0x5d, 0x06, 0xac, 0x5c, 0xda, 0x03, 0xa5, 0x2b, 0xcc, 0x59, 0x84, 0xef, 0xc3, 0x64, 0x68,
0x00, 0x5e, 0x18, 0x80, 0x9b, 0x27, 0xc1, 0xf9, 0x81, 0x68, 0x04, 0x10, 0xaf, 0x21, 0xc8, 0x77,
0x16, 0xf4, 0xe1, 0x0b, 0x72, 0x4e, 0x11, 0x65, 0x8c, 0xca, 0xd3, 0x83, 0x92, 0x09, 0x19, 0x5e,
0x17, 0x05, 0xf0, 0xa1, 0x82, 0x1f, 0x1c, 0x83, 0x5b, 0x54, 0x91, 0x95, 0x72, 0x71, 0x60, 0x3a,
0x7f, 0x19, 0x6c, 0xc8, 0x05, 0xba, 0xf1, 0xd9, 0xd8, 0x9c, 0xbc, 0xb9, 0xcf, 0x0d, 0x40, 0x21,
0x94, 0x7f, 0x19, 0xd2, 0xd7, 0xad, 0x5d, 0x82, 0x25, 0xd5, 0x45, 0x81, 0xc2, 0x20, 0xe5, 0x54,
0x9c, 0xa1, 0x82, 0xbd, 0x0d, 0xb9, 0x40, 0x36, 0x59, 0xa6, 0x52, 0x77, 0x42, 0x5d, 0xa6, 0x52,
0x54, 0xaa, 0xba, 0x09, 0x13, 0xc1, 0xa2, 0x16, 0x2c, 0x61, 0x11, 0x51, 0x97, 0xa3, 0x2c, 0x0c,
0x42, 0x12, 0x70, 0x67, 0xdd, 0x85, 0x21, 0x32, 0x77, 0xd6, 0xb3, 0x02, 0x46, 0xe6, 0xce, 0xfa,
0xd4, 0xa0, 0x04, 0x24, 0x09, 0x94, 0x47, 0xc4, 0x94, 0xa4, 0xbb, 0xa2, 0x24, 0xa6, 0x24, 0x51,
0x95, 0x18, 0x2f, 0x43, 0x9a, 0xc5, 0x64, 0x32, 0xeb, 0x0a, 0x24, 0xfd, 0x95, 0x53, 0x71, 0x86,
0xb6, 0xad, 0x2b, 0x90, 0xb1, 0x95, 0x59, 0x57, 0x77, 0xd2, 0x5a, 0x66, 0x5d, 0x51, 0xe9, 0xe0,
0xfb, 0x30, 0x19, 0xca, 0x85, 0xca, 0x7c, 0x65, 0x54, 0x5a, 0x57, 0xe6, 0x2b, 0xa3, 0x93, 0xad,
0x7e, 0x4c, 0xe9, 0x9f, 0x61, 0xc6, 0x8b, 0x29, 0x3b, 0xd3, 0xa6, 0xf1, 0x62, 0xca, 0xee, 0x2c,
0x26, 0x8b, 0x1f, 0xa2, 0x52, 0x6b, 0xb2, 0xf8, 0xa1, 0x4f, 0x56, 0x52, 0x16, 0x3f, 0xf4, 0xcd,
0xe4, 0x7d, 0x1d, 0xc1, 0x93, 0xd1, 0x49, 0x28, 0xfc, 0xac, 0x64, 0x5d, 0xfb, 0xe5, 0xe6, 0x94,
0xe7, 0xf6, 0x46, 0xdc, 0x0e, 0x1c, 0x45, 0x6a, 0x47, 0x16, 0x38, 0x86, 0x33, 0x57, 0xb2, 0xc0,
0xb1, 0x33, 0x5f, 0xe4, 0x06, 0xa8, 0x71, 0xe6, 0xb9, 0x3a, 0xd0, 0x3c, 0x9d, 0xf9, 0x19, 0xee,
0xc1, 0xfd, 0xe4, 0x80, 0xdc, 0x83, 0x77, 0x66, 0x4b, 0xe4, 0x1e, 0xbc, 0x3b, 0xf3, 0x50, 0x86,
0xac, 0x7b, 0xba, 0x2e, 0xfb, 0x9f, 0x08, 0xa5, 0x0e, 0x64, 0xff, 0x13, 0x1d, 0x07, 0xf6, 0x16,
0x40, 0xfb, 0x20, 0x5b, 0x16, 0xf4, 0x75, 0x9d, 0xba, 0xcb, 0x82, 0xbe, 0x88, 0x33, 0x72, 0x77,
0xc5, 0xf8, 0x6c, 0xf2, 0x15, 0x0b, 0x4e, 0x75, 0x26, 0xe6, 0xe8, 0x80, 0xfb, 0xef, 0x3e, 0x3c,
0x96, 0xb9, 0xff, 0x9e, 0x27, 0xeb, 0x32, 0xf7, 0xdf, 0xe7, 0x9c, 0xfa, 0xa1, 0x88, 0xac, 0x42,
0xa7, 0x60, 0x71, 0x22, 0xab, 0xa8, 0xf3, 0xcc, 0x38, 0x91, 0x55, 0xf4, 0x71, 0xdb, 0x1b, 0x7e,
0xc5, 0xd2, 0x20, 0x80, 0xf4, 0x3c, 0xc1, 0x92, 0x01, 0xd2, 0xe7, 0x60, 0x89, 0x49, 0xd2, 0x7d,
0x28, 0x22, 0x93, 0xa4, 0xe7, 0xa9, 0x8e, 0x4c, 0x92, 0xde, 0xe7, 0x2f, 0x4b, 0x5f, 0x41, 0x70,
0xb2, 0x6c, 0xd5, 0xfb, 0xd2, 0x2f, 0xe5, 0xfd, 0xd3, 0x93, 0x86, 0xc1, 0xaf, 0x8e, 0x96, 0xd0,
0x67, 0xa7, 0xbd, 0x51, 0x62, 0xd0, 0x77, 0x53, 0x23, 0xcb, 0x1b, 0xa5, 0x1f, 0xa4, 0x8e, 0x2d,
0x3b, 0xe7, 0xbd, 0x73, 0xa0, 0xa2, 0x47, 0x57, 0xbc, 0x79, 0x6e, 0x89, 0x0d, 0x7a, 0x9b, 0x77,
0xdf, 0x12, 0xdd, 0xb7, 0xbc, 0xee, 0x5b, 0xa2, 0xfb, 0x76, 0x96, 0x1f, 0xab, 0x9f, 0xff, 0x5f,
0x00, 0x00, 0x00, 0xff, 0xff, 0x58, 0x37, 0x60, 0xa0, 0x04, 0x48, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.

View File

@@ -36,9 +36,9 @@ import (
_ "github.com/cs3org/reva/v2/pkg/datatx/manager/loader"
_ "github.com/cs3org/reva/v2/pkg/group/manager/loader"
_ "github.com/cs3org/reva/v2/pkg/metrics/driver/loader"
_ "github.com/cs3org/reva/v2/pkg/ocm/invite/manager/loader"
_ "github.com/cs3org/reva/v2/pkg/ocm/invite/repository/loader"
_ "github.com/cs3org/reva/v2/pkg/ocm/provider/authorizer/loader"
_ "github.com/cs3org/reva/v2/pkg/ocm/share/manager/loader"
_ "github.com/cs3org/reva/v2/pkg/ocm/share/repository/loader"
_ "github.com/cs3org/reva/v2/pkg/permission/manager/loader"
_ "github.com/cs3org/reva/v2/pkg/preferences/loader"
_ "github.com/cs3org/reva/v2/pkg/publicshare/manager/loader"

View File

@@ -32,6 +32,7 @@ import (
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1"
ocmv1beta1 "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
registry "github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1"
"github.com/cs3org/reva/v2/pkg/appctx"
@@ -83,6 +84,10 @@ func expandAndVerifyScope(ctx context.Context, req interface{}, tokenScope map[s
if err = resolveLightweightScope(ctx, ref, tokenScope[k], user, client, mgr); err == nil {
return nil
}
case strings.HasPrefix(k, "ocmshare"):
if err = resolveOCMShare(ctx, ref, tokenScope[k], client, mgr); err == nil {
return nil
}
}
log.Err(err).Msgf("error resolving reference %s under scope %+v", ref.String(), k)
}
@@ -168,6 +173,21 @@ func resolvePublicShare(ctx context.Context, ref *provider.Reference, scope *aut
return checkRelativeReference(ctx, ref, share.ResourceId, client)
}
func resolveOCMShare(ctx context.Context, ref *provider.Reference, scope *authpb.Scope, client gateway.GatewayAPIClient, mgr token.Manager) error {
var share ocmv1beta1.Share
if err := utils.UnmarshalJSONToProtoV1(scope.Resource.Value, &share); err != nil {
return err
}
if err := checkCacheForNestedResource(ctx, ref, share.ResourceId, client, mgr); err == nil {
return nil
}
// Some services like wopi don't access the shared resource relative to the
// share root but instead relative to the shared resources parent.
return checkRelativeReference(ctx, ref, share.ResourceId, client)
}
// checkRelativeReference checks if the shared resource is being accessed via a relative reference
// e.g.:
// storage: abcd, space: efgh

View File

@@ -171,7 +171,7 @@ func (s *svc) openLocalResources(ctx context.Context, ri *storageprovider.Resour
appProviderReq := &providerpb.OpenInAppRequest{
ResourceInfo: ri,
ViewMode: providerpb.OpenInAppRequest_ViewMode(vm),
ViewMode: providerpb.ViewMode(vm),
AccessToken: accessToken,
Opaque: opaque,
}

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 CERN
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -42,3 +42,35 @@ func (s *svc) CreateOCMCoreShare(ctx context.Context, req *ocmcore.CreateOCMCore
return res, nil
}
func (s *svc) UpdateOCMCoreShare(ctx context.Context, req *ocmcore.UpdateOCMCoreShareRequest) (*ocmcore.UpdateOCMCoreShareResponse, error) {
c, err := pool.GetOCMCoreClient(s.c.OCMCoreEndpoint)
if err != nil {
return &ocmcore.UpdateOCMCoreShareResponse{
Status: status.NewInternal(ctx, "error getting ocm core client"),
}, nil
}
res, err := c.UpdateOCMCoreShare(ctx, req)
if err != nil {
return nil, errors.Wrap(err, "gateway: error calling UpdateOCMCoreShare")
}
return res, nil
}
func (s *svc) DeleteOCMCoreShare(ctx context.Context, req *ocmcore.DeleteOCMCoreShareRequest) (*ocmcore.DeleteOCMCoreShareResponse, error) {
c, err := pool.GetOCMCoreClient(s.c.OCMCoreEndpoint)
if err != nil {
return &ocmcore.DeleteOCMCoreShareResponse{
Status: status.NewInternal(ctx, "error getting ocm core client"),
}, nil
}
res, err := c.DeleteOCMCoreShare(ctx, req)
if err != nil {
return nil, errors.Wrap(err, "gateway: error calling UpdateOCMCoreShare")
}
return res, nil
}

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 CERN
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -43,6 +43,22 @@ func (s *svc) GenerateInviteToken(ctx context.Context, req *invitepb.GenerateInv
return res, nil
}
func (s *svc) ListInviteTokens(ctx context.Context, req *invitepb.ListInviteTokensRequest) (*invitepb.ListInviteTokensResponse, error) {
c, err := pool.GetOCMInviteManagerClient(s.c.OCMInviteManagerEndpoint)
if err != nil {
return &invitepb.ListInviteTokensResponse{
Status: status.NewInternal(ctx, "error getting user invite provider client"),
}, nil
}
res, err := c.ListInviteTokens(ctx, req)
if err != nil {
return nil, errors.Wrap(err, "gateway: error calling ListInviteTokens")
}
return res, nil
}
func (s *svc) ForwardInvite(ctx context.Context, req *invitepb.ForwardInviteRequest) (*invitepb.ForwardInviteResponse, error) {
c, err := pool.GetOCMInviteManagerClient(s.c.OCMInviteManagerEndpoint)
if err != nil {
@@ -106,3 +122,19 @@ func (s *svc) FindAcceptedUsers(ctx context.Context, req *invitepb.FindAcceptedU
return res, nil
}
func (s *svc) DeleteAcceptedUser(ctx context.Context, req *invitepb.DeleteAcceptedUserRequest) (*invitepb.DeleteAcceptedUserResponse, error) {
c, err := pool.GetOCMInviteManagerClient(s.c.OCMInviteManagerEndpoint)
if err != nil {
return &invitepb.DeleteAcceptedUserResponse{
Status: status.NewInternal(ctx, "error getting user invite provider client"),
}, nil
}
res, err := c.DeleteAcceptedUser(ctx, req)
if err != nil {
return nil, errors.Wrap(err, "gateway: error calling FindAcceptedUsers")
}
return res, nil
}

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 CERN
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 CERN
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -25,12 +25,10 @@ import (
"path"
"strings"
ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
datatx "github.com/cs3org/go-cs3apis/cs3/tx/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/v2/pkg/appctx"
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
"github.com/cs3org/reva/v2/pkg/errtypes"
@@ -53,16 +51,22 @@ func (s *svc) CreateOCMShare(ctx context.Context, req *ocm.CreateOCMShareRequest
return nil, errors.Wrap(err, "gateway: error calling CreateShare")
}
if s.c.CommitShareToStorageGrant {
addGrantStatus, err := s.addGrant(ctx, req.ResourceId, req.Grant.Grantee, req.Grant.Permissions.Permissions, nil, nil)
if err != nil {
return nil, errors.Wrap(err, "gateway: error adding OCM grant to storage")
}
if addGrantStatus.Code != rpc.Code_CODE_OK {
return &ocm.CreateOCMShareResponse{
Status: addGrantStatus,
}, err
}
status, err := s.addGrant(ctx, req.ResourceId, req.Grantee, req.AccessMethods[0].GetWebdavOptions().Permissions, req.Expiration, nil)
if err != nil {
appctx.GetLogger(ctx).Debug().Interface("status", status).Interface("req", req).Msg(err.Error())
return nil, errors.Wrap(err, "gateway: error adding grant to storage")
}
switch status.Code {
case rpc.Code_CODE_OK:
s.statCache.RemoveStatContext(ctx, ctxpkg.ContextMustGetUser(ctx).GetId(), req.ResourceId)
case rpc.Code_CODE_UNIMPLEMENTED:
appctx.GetLogger(ctx).Debug().Interface("status", status).Interface("req", req).Msg("storing grants not supported, ignoring")
default:
appctx.GetLogger(ctx).Debug().Interface("status", status).Interface("req", req).Msg("storing grants is not successful")
return &ocm.CreateOCMShareResponse{
Status: status,
}, err
}
return res, nil
@@ -76,44 +80,11 @@ func (s *svc) RemoveOCMShare(ctx context.Context, req *ocm.RemoveOCMShareRequest
}, nil
}
// if we need to commit the share, we need the resource it points to.
var share *ocm.Share
if s.c.CommitShareToStorageGrant {
getShareReq := &ocm.GetOCMShareRequest{
Ref: req.Ref,
}
getShareRes, err := c.GetOCMShare(ctx, getShareReq)
if err != nil {
return nil, errors.Wrap(err, "gateway: error calling GetShare")
}
if getShareRes.Status.Code != rpc.Code_CODE_OK {
res := &ocm.RemoveOCMShareResponse{
Status: status.NewInternal(ctx,
"error getting share when committing to the storage"),
}
return res, nil
}
share = getShareRes.Share
}
res, err := c.RemoveOCMShare(ctx, req)
if err != nil {
return nil, errors.Wrap(err, "gateway: error calling RemoveShare")
}
if s.c.CommitShareToStorageGrant {
removeGrantStatus, err := s.removeGrant(ctx, share.ResourceId, share.Grantee, share.Permissions.Permissions, nil)
if err != nil {
return nil, errors.Wrap(err, "gateway: error removing OCM grant from storage")
}
if removeGrantStatus.Code != rpc.Code_CODE_OK {
return &ocm.RemoveOCMShareResponse{
Status: removeGrantStatus,
}, err
}
}
return res, nil
}
@@ -127,6 +98,7 @@ func (s *svc) GetOCMShare(ctx context.Context, req *ocm.GetOCMShareRequest) (*oc
func (s *svc) getOCMShare(ctx context.Context, req *ocm.GetOCMShareRequest) (*ocm.GetOCMShareResponse, error) {
c, err := pool.GetOCMShareProviderClient(s.c.OCMShareProviderEndpoint)
if err != nil {
appctx.GetLogger(ctx).Error().Err(err).Msg("error calling GetOCMShareProviderClient")
return &ocm.GetOCMShareResponse{
Status: status.NewInternal(ctx, "error getting user share provider client"),
}, nil
@@ -140,10 +112,25 @@ func (s *svc) getOCMShare(ctx context.Context, req *ocm.GetOCMShareRequest) (*oc
return res, nil
}
func (s *svc) GetOCMShareByToken(ctx context.Context, req *ocm.GetOCMShareByTokenRequest) (*ocm.GetOCMShareByTokenResponse, error) {
c, err := pool.GetOCMShareProviderClient(s.c.OCMShareProviderEndpoint)
if err != nil {
return nil, errors.Wrap(err, "gateway: error calling GetOCMShareProviderClient")
}
res, err := c.GetOCMShareByToken(ctx, req)
if err != nil {
return nil, errors.Wrap(err, "gateway: error calling GetOCMShareByToken")
}
return res, nil
}
// TODO(labkode): read GetShare comment.
func (s *svc) ListOCMShares(ctx context.Context, req *ocm.ListOCMSharesRequest) (*ocm.ListOCMSharesResponse, error) {
c, err := pool.GetOCMShareProviderClient(s.c.OCMShareProviderEndpoint)
if err != nil {
appctx.GetLogger(ctx).Error().Err(err).Msg("error calling GetOCMShareProviderClient")
return &ocm.ListOCMSharesResponse{
Status: status.NewInternal(ctx, "error getting user share provider client"),
}, nil
@@ -160,6 +147,7 @@ func (s *svc) ListOCMShares(ctx context.Context, req *ocm.ListOCMSharesRequest)
func (s *svc) UpdateOCMShare(ctx context.Context, req *ocm.UpdateOCMShareRequest) (*ocm.UpdateOCMShareResponse, error) {
c, err := pool.GetOCMShareProviderClient(s.c.OCMShareProviderEndpoint)
if err != nil {
appctx.GetLogger(ctx).Error().Err(err).Msg("error calling GetOCMShareProviderClient")
return &ocm.UpdateOCMShareResponse{
Status: status.NewInternal(ctx, "error getting share provider client"),
}, nil
@@ -176,6 +164,7 @@ func (s *svc) UpdateOCMShare(ctx context.Context, req *ocm.UpdateOCMShareRequest
func (s *svc) ListReceivedOCMShares(ctx context.Context, req *ocm.ListReceivedOCMSharesRequest) (*ocm.ListReceivedOCMSharesResponse, error) {
c, err := pool.GetOCMShareProviderClient(s.c.OCMShareProviderEndpoint)
if err != nil {
appctx.GetLogger(ctx).Error().Err(err).Msg("error calling GetOCMShareProviderClient")
return &ocm.ListReceivedOCMSharesResponse{
Status: status.NewInternal(ctx, "error getting share provider client"),
}, nil
@@ -193,11 +182,49 @@ func (s *svc) UpdateReceivedOCMShare(ctx context.Context, req *ocm.UpdateReceive
log := appctx.GetLogger(ctx)
c, err := pool.GetOCMShareProviderClient(s.c.OCMShareProviderEndpoint)
if err != nil {
appctx.GetLogger(ctx).Error().Err(err).Msg("error calling GetOCMShareProviderClient")
return &ocm.UpdateReceivedOCMShareResponse{
Status: status.NewInternal(ctx, "error getting share provider client"),
}, nil
}
// retrieve the current received share
getShareReq := &ocm.GetReceivedOCMShareRequest{
Ref: &ocm.ShareReference{
Spec: &ocm.ShareReference_Id{
Id: req.Share.Id,
},
},
}
getShareRes, err := s.GetReceivedOCMShare(ctx, getShareReq)
if err != nil {
log.Error().Err(err).Msg("gateway: error calling GetReceivedOCMShare")
return &ocm.UpdateReceivedOCMShareResponse{
Status: &rpc.Status{
Code: rpc.Code_CODE_INTERNAL,
},
}, nil
}
if getShareRes.Status.Code != rpc.Code_CODE_OK {
log.Error().Msg("gateway: error calling GetReceivedOCMShare")
return &ocm.UpdateReceivedOCMShareResponse{
Status: &rpc.Status{
Code: rpc.Code_CODE_INTERNAL,
Message: "gateway: error calling GetReceivedOCMShare",
},
}, nil
}
share := getShareRes.Share
if share == nil {
log.Error().Err(err).Msg("gateway: got a nil share from GetReceivedOCMShare")
return &ocm.UpdateReceivedOCMShareResponse{
Status: &rpc.Status{
Code: rpc.Code_CODE_INTERNAL,
Message: "gateway: got a nil share from GetReceivedOCMShare",
},
}, nil
}
res, err := c.UpdateReceivedOCMShare(ctx, req)
if err != nil {
log.Err(err).Msg("gateway: error calling UpdateReceivedShare")
@@ -208,175 +235,17 @@ func (s *svc) UpdateReceivedOCMShare(ctx context.Context, req *ocm.UpdateReceive
}, nil
}
// if we don't need to create/delete references then we return early.
if !s.c.CommitShareToStorageGrant {
return res, nil
}
// properties are updated in the order they appear in the field mask
// when an error occurs the request ends and no further fields are updated
for i := range req.UpdateMask.Paths {
switch req.UpdateMask.Paths[i] {
case "state":
switch req.GetShare().GetState() {
case ocm.ShareState_SHARE_STATE_ACCEPTED:
getShareReq := &ocm.GetReceivedOCMShareRequest{
Ref: &ocm.ShareReference{
Spec: &ocm.ShareReference_Id{
Id: req.Share.Share.Id,
},
},
}
getShareRes, err := s.GetReceivedOCMShare(ctx, getShareReq)
if err != nil {
log.Err(err).Msg("gateway: error calling GetReceivedShare")
return &ocm.UpdateReceivedOCMShareResponse{
Status: &rpc.Status{
Code: rpc.Code_CODE_INTERNAL,
},
}, nil
}
if getShareRes.Status.Code != rpc.Code_CODE_OK {
log.Error().Msg("gateway: error calling GetReceivedShare")
return &ocm.UpdateReceivedOCMShareResponse{
Status: &rpc.Status{
Code: rpc.Code_CODE_INTERNAL,
},
}, nil
}
share := getShareRes.Share
if share == nil {
panic("gateway: error updating a received share: the share is nil")
}
if share.GetShare().ShareType == ocm.Share_SHARE_TYPE_TRANSFER {
srcIdp := share.GetShare().GetOwner().GetIdp()
meshProvider, err := s.GetInfoByDomain(ctx, &ocmprovider.GetInfoByDomainRequest{
Domain: srcIdp,
})
if err != nil {
log.Err(err).Msg("gateway: error calling GetInfoByDomain")
return &ocm.UpdateReceivedOCMShareResponse{
Status: &rpc.Status{Code: rpc.Code_CODE_INTERNAL},
}, nil
}
var srcEndpoint string
var srcEndpointBaseURI string
// target URI scheme will be the webdav endpoint scheme
var srcEndpointScheme string
for _, s := range meshProvider.ProviderInfo.Services {
if strings.ToLower(s.Endpoint.Type.Name) == "webdav" {
url, err := url.Parse(s.Endpoint.Path)
if err != nil {
log.Err(err).Msg("gateway: error calling UpdateReceivedShare: unable to parse webdav endpoint " + s.Endpoint.Path)
return &ocm.UpdateReceivedOCMShareResponse{
Status: &rpc.Status{Code: rpc.Code_CODE_INTERNAL},
}, nil
}
srcEndpoint = url.Host
srcEndpointBaseURI = url.Path
srcEndpointScheme = url.Scheme
break
}
}
var srcToken string
srcTokenOpaque, ok := share.GetShare().Grantee.Opaque.Map["token"]
if !ok {
return &ocm.UpdateReceivedOCMShareResponse{
Status: status.NewNotFound(ctx, "token not found"),
}, nil
}
switch srcTokenOpaque.Decoder {
case "plain":
srcToken = string(srcTokenOpaque.Value)
default:
return &ocm.UpdateReceivedOCMShareResponse{
Status: status.NewInternal(ctx, "error updating received share"),
}, nil
}
srcPath := path.Join(srcEndpointBaseURI, share.GetShare().Name)
srcTargetURI := fmt.Sprintf("%s://%s@%s?name=%s", srcEndpointScheme, srcToken, srcEndpoint, srcPath)
// get the webdav endpoint of the grantee's idp
var granteeIdp string
if share.GetShare().GetGrantee().Type == provider.GranteeType_GRANTEE_TYPE_USER {
granteeIdp = share.GetShare().GetGrantee().GetUserId().Idp
}
if share.GetShare().GetGrantee().Type == provider.GranteeType_GRANTEE_TYPE_GROUP {
granteeIdp = share.GetShare().GetGrantee().GetGroupId().Idp
}
destWebdavEndpoint, err := s.getWebdavEndpoint(ctx, granteeIdp)
if err != nil {
log.Err(err).Msg("gateway: error calling UpdateReceivedShare")
return &ocm.UpdateReceivedOCMShareResponse{
Status: &rpc.Status{Code: rpc.Code_CODE_INTERNAL},
}, nil
}
url, err := url.Parse(destWebdavEndpoint)
if err != nil {
log.Err(err).Msg("gateway: error calling UpdateReceivedShare: unable to parse webdav endpoint " + destWebdavEndpoint)
return &ocm.UpdateReceivedOCMShareResponse{
Status: &rpc.Status{Code: rpc.Code_CODE_INTERNAL},
}, nil
}
destEndpoint := url.Host
destEndpointBaseURI := url.Path
destEndpointScheme := url.Scheme
destToken := ctxpkg.ContextMustGetToken(ctx)
homeRes, err := s.GetHome(ctx, &provider.GetHomeRequest{})
if err != nil {
log.Err(err).Msg("gateway: error calling UpdateReceivedShare")
return &ocm.UpdateReceivedOCMShareResponse{
Status: &rpc.Status{Code: rpc.Code_CODE_INTERNAL},
}, nil
}
destPath := path.Join(destEndpointBaseURI, homeRes.Path, s.c.DataTransfersFolder, path.Base(share.GetShare().Name))
destTargetURI := fmt.Sprintf("%s://%s@%s?name=%s", destEndpointScheme, destToken, destEndpoint, destPath)
opaqueObj := &types.Opaque{
Map: map[string]*types.OpaqueEntry{
"shareId": {
Decoder: "plain",
Value: []byte(share.GetShare().GetId().OpaqueId),
},
},
}
req := &datatx.CreateTransferRequest{
SrcTargetUri: srcTargetURI,
DestTargetUri: destTargetURI,
Opaque: opaqueObj,
}
res, err := s.CreateTransfer(ctx, req)
if err != nil {
log.Err(err).Msg("gateway: error calling PullTransfer")
return &ocm.UpdateReceivedOCMShareResponse{
Status: &rpc.Status{
Code: rpc.Code_CODE_INTERNAL,
},
}, err
}
log.Info().Msgf("gateway: PullTransfer: %v", res.TxInfo)
// do not create an OCM reference, just return
return &ocm.UpdateReceivedOCMShareResponse{
Status: status.NewOK(ctx),
}, nil
}
createRefStatus, err := s.createOCMReference(ctx, share.Share)
return &ocm.UpdateReceivedOCMShareResponse{
Status: createRefStatus,
}, err
// for a transfer this is handled elsewhere
case ocm.ShareState_SHARE_STATE_PENDING:
// currently no consequences
case ocm.ShareState_SHARE_STATE_REJECTED:
return &ocm.UpdateReceivedOCMShareResponse{
Status: status.NewUnimplemented(ctx, err, "ocm share rejection not supported at the moment"),
}, nil
// TODO
return res, nil
}
case "mount_point":
// TODO(labkode): implementing updating mount point
@@ -388,12 +257,139 @@ func (s *svc) UpdateReceivedOCMShare(ctx context.Context, req *ocm.UpdateReceive
return nil, errtypes.NotSupported("updating " + req.UpdateMask.Paths[i] + " is not supported")
}
}
// handle transfer in case it has not already been accepted
if s.isTransferShare(share) && req.GetShare().State == ocm.ShareState_SHARE_STATE_ACCEPTED {
if share.State == ocm.ShareState_SHARE_STATE_ACCEPTED {
log.Err(err).Msg("gateway: error calling UpdateReceivedShare, share already accepted.")
return &ocm.UpdateReceivedOCMShareResponse{
Status: &rpc.Status{
Code: rpc.Code_CODE_FAILED_PRECONDITION,
Message: "Share already accepted.",
},
}, err
}
// get provided destination path
transferDestinationPath, err := s.getTransferDestinationPath(ctx, req)
if err != nil {
if err != nil {
log.Err(err).Msg("gateway: error calling UpdateReceivedShare")
return &ocm.UpdateReceivedOCMShareResponse{
Status: &rpc.Status{
Code: rpc.Code_CODE_INTERNAL,
},
}, err
}
}
error := s.handleTransfer(ctx, share, transferDestinationPath)
if error != nil {
log.Err(error).Msg("gateway: error handling transfer in UpdateReceivedShare")
return &ocm.UpdateReceivedOCMShareResponse{
Status: &rpc.Status{
Code: rpc.Code_CODE_INTERNAL,
},
}, error
}
}
return res, nil
}
func (s *svc) handleTransfer(ctx context.Context, share *ocm.ReceivedShare, transferDestinationPath string) error {
log := appctx.GetLogger(ctx)
protocol, ok := s.getTransferProtocol(share)
if !ok {
return errors.New("gateway: unable to retrieve transfer protocol")
}
sourceURI := protocol.SourceUri
// get the webdav endpoint of the grantee's idp
var granteeIdp string
if share.GetGrantee().Type == provider.GranteeType_GRANTEE_TYPE_USER {
granteeIdp = share.GetGrantee().GetUserId().Idp
}
if share.GetGrantee().Type == provider.GranteeType_GRANTEE_TYPE_GROUP {
granteeIdp = share.GetGrantee().GetGroupId().Idp
}
destWebdavEndpoint, err := s.getWebdavEndpoint(ctx, granteeIdp)
if err != nil {
log.Err(err).Msg("gateway: error calling UpdateReceivedShare")
return err
}
destWebdavEndpointURL, err := url.Parse(destWebdavEndpoint)
if err != nil {
log.Err(err).Msg("gateway: error calling UpdateReceivedShare: unable to parse webdav endpoint \"" + destWebdavEndpoint + "\" into URL structure")
return err
}
destWebdavHost, err := s.getWebdavHost(ctx, granteeIdp)
if err != nil {
log.Err(err).Msg("gateway: error calling UpdateReceivedShare")
return err
}
var dstWebdavURLString string
if strings.Contains(destWebdavHost, "://") {
dstWebdavURLString = destWebdavHost
} else {
dstWebdavURLString = "http://" + destWebdavHost
}
dstWebdavHostURL, err := url.Parse(dstWebdavURLString)
if err != nil {
log.Err(err).Msg("gateway: error calling UpdateReceivedShare: unable to parse webdav service host \"" + dstWebdavURLString + "\" into URL structure")
return err
}
destServiceHost := dstWebdavHostURL.Host + dstWebdavHostURL.Path
// optional prefix must only appear in target url path:
// http://...token...@reva.eu/prefix/?name=remote.php/webdav/home/...
destEndpointPath := strings.TrimPrefix(destWebdavEndpointURL.Path, dstWebdavHostURL.Path)
destEndpointScheme := destWebdavEndpointURL.Scheme
destToken := ctxpkg.ContextMustGetToken(ctx)
destPath := path.Join(destEndpointPath, transferDestinationPath, path.Base(share.Name))
destTargetURI := fmt.Sprintf("%s://%s@%s?name=%s", destEndpointScheme, destToken, destServiceHost, destPath)
// var destUri string
req := &datatx.CreateTransferRequest{
SrcTargetUri: sourceURI,
DestTargetUri: destTargetURI,
ShareId: share.Id,
}
res, err := s.CreateTransfer(ctx, req)
if err != nil {
return err
}
log.Info().Msgf("gateway: CreateTransfer: %v", res.TxInfo)
return nil
}
func (s *svc) isTransferShare(share *ocm.ReceivedShare) bool {
_, ok := s.getTransferProtocol(share)
return ok
}
func (s *svc) getTransferDestinationPath(ctx context.Context, req *ocm.UpdateReceivedOCMShareRequest) (string, error) {
log := appctx.GetLogger(ctx)
// the destination path is not part of any protocol, but an opaque field
destPathOpaque, ok := req.GetOpaque().GetMap()["transfer_destination_path"]
if ok {
switch destPathOpaque.Decoder {
case "plain":
if string(destPathOpaque.Value) != "" {
return string(destPathOpaque.Value), nil
}
default:
return "", errtypes.NotSupported("decoder of opaque entry 'transfer_destination_path' not recognized: " + destPathOpaque.Decoder)
}
}
log.Info().Msg("destination path not provided, trying default transfer destination folder")
if s.c.DataTransfersFolder == "" {
return "", errtypes.NotSupported("no destination path provided and default transfer destination folder is not set")
}
return s.c.DataTransfersFolder, nil
}
func (s *svc) GetReceivedOCMShare(ctx context.Context, req *ocm.GetReceivedOCMShareRequest) (*ocm.GetReceivedOCMShareResponse, error) {
c, err := pool.GetOCMShareProviderClient(s.c.OCMShareProviderEndpoint)
if err != nil {
appctx.GetLogger(ctx).Error().Err(err).Msg("error calling GetOCMShareProviderClient")
return &ocm.GetReceivedOCMShareResponse{
Status: status.NewInternal(ctx, "error getting share provider client"),
}, nil
@@ -407,96 +403,11 @@ func (s *svc) GetReceivedOCMShare(ctx context.Context, req *ocm.GetReceivedOCMSh
return res, nil
}
func (s *svc) createOCMReference(ctx context.Context, share *ocm.Share) (*rpc.Status, error) {
log := appctx.GetLogger(ctx)
var token string
tokenOpaque, ok := share.Grantee.Opaque.Map["token"]
if !ok {
log.Debug().Msg("createOCMReference: token not found in opaque map")
return status.NewNotFound(ctx, "token not found"), nil
}
switch tokenOpaque.Decoder {
case "plain":
token = string(tokenOpaque.Value)
default:
log.Error().Str("decoder", tokenOpaque.Decoder).Msg("createOCMReference: opaque entry decoder not recognized")
return status.NewInternal(ctx, "invalid opaque entry decoder"), nil
}
homeRes, err := s.GetHome(ctx, &provider.GetHomeRequest{})
if err != nil {
log.Error().Err(err).Msg("createOCMReference: error calling GetHome")
return status.NewInternal(ctx, "error updating received share"), nil
}
var refPath, targetURI string
if share.ShareType == ocm.Share_SHARE_TYPE_TRANSFER {
createTransferDir, err := s.CreateContainer(ctx, &provider.CreateContainerRequest{
Ref: &provider.Reference{
Path: path.Join(homeRes.Path, s.c.DataTransfersFolder),
},
})
if err != nil {
log.Error().Err(err).Msg("createOCMReference: error creating transfers directory")
return status.NewInternal(ctx, "error creating transfers directory"), nil
func (s *svc) getTransferProtocol(share *ocm.ReceivedShare) (*ocm.TransferProtocol, bool) {
for _, p := range share.Protocols {
if d, ok := p.Term.(*ocm.Protocol_TransferOptions); ok {
return d.TransferOptions, true
}
if createTransferDir.Status.Code != rpc.Code_CODE_OK && createTransferDir.Status.Code != rpc.Code_CODE_ALREADY_EXISTS {
log.Error().Interface("status", createTransferDir.Status).Msg("createOCMReference: error creating transfers directory")
return status.NewInternal(ctx, "error creating transfers directory"), nil
}
refPath = path.Join(homeRes.Path, s.c.DataTransfersFolder, path.Base(share.Name))
targetURI = fmt.Sprintf("datatx://%s@%s?name=%s", token, share.Creator.Idp, share.Name)
} else {
// reference path is the home path + some name on the corresponding
// mesh provider (/home/MyShares/x)
// It is the responsibility of the gateway to resolve these references and merge the response back
// from the main request.
refPath = path.Join(homeRes.Path, s.c.ShareFolder, path.Base(share.Name))
// webdav is the scheme, token@host the opaque part and the share name the query of the URL.
targetURI = fmt.Sprintf("webdav://%s@%s?name=%s", token, share.Creator.Idp, share.Name)
}
log.Info().Msg("mount path will be:" + refPath)
c, p, err := s.findByPath(ctx, refPath)
if err != nil {
log.Error().Err(err).Msg("createOCMReference: could not find storage provider")
if _, ok := err.(errtypes.IsNotFound); ok {
return status.NewNotFound(ctx, "storage provider not found"), nil
}
return status.NewInternal(ctx, "error finding storage provider"), nil
}
var (
root *provider.ResourceId
mountPath string
)
for _, space := range decodeSpaces(p) {
mountPath = decodePath(space)
root = space.Root
break // TODO can there be more than one space for a path?
}
pRef := unwrap(&provider.Reference{Path: refPath}, mountPath, root)
createRefReq := &provider.CreateReferenceRequest{
Ref: pRef,
TargetUri: targetURI,
}
createRefRes, err := c.CreateReference(ctx, createRefReq)
if err != nil {
log.Err(err).Msg("createOCMReference: error calling CreateReference")
return &rpc.Status{
Code: rpc.Code_CODE_INTERNAL,
}, nil
}
if createRefRes.Status.Code != rpc.Code_CODE_OK {
log.Error().Interface("status", createRefRes.Status).Msg("createOCMReference: error calling CreateReference")
return status.NewInternal(ctx, "error updating received share"), nil
}
return status.NewOK(ctx), nil
return nil, false
}

View File

@@ -1030,11 +1030,6 @@ func (s *svc) GetQuota(ctx context.Context, req *gateway.GetQuotaRequest) (*prov
return res, nil
}
func (s *svc) findByPath(ctx context.Context, path string) (provider.ProviderAPIClient, *registry.ProviderInfo, error) {
ref := &provider.Reference{Path: path}
return s.find(ctx, ref)
}
// find looks up the provider that is responsible for the given request
// It will return a client that the caller can use to make the call, as well as the ProviderInfo. It:
// - contains the provider path, which is the mount point of the provider

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 CERN
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -60,21 +60,6 @@ func (s *svc) extractEndpointInfo(ctx context.Context, targetURL string) (*webda
}, nil
}
func appendNameQuery(targetURL string, nameQueries ...string) (string, error) {
uri, err := url.Parse(targetURL)
if err != nil {
return "", err
}
q, err := url.ParseQuery(uri.RawQuery)
if err != nil {
return "", err
}
name := append([]string{q["name"][0]}, nameQueries...)
q.Set("name", path.Join(name...))
uri.RawQuery = q.Encode()
return uri.String(), nil
}
func (s *svc) getWebdavEndpoint(ctx context.Context, domain string) (string, error) {
meshProvider, err := s.GetInfoByDomain(ctx, &ocmprovider.GetInfoByDomainRequest{
Domain: domain,
@@ -89,3 +74,33 @@ func (s *svc) getWebdavEndpoint(ctx context.Context, domain string) (string, err
}
return "", errtypes.NotFound(domain)
}
func (s *svc) getWebdavHost(ctx context.Context, domain string) (string, error) {
meshProvider, err := s.GetInfoByDomain(ctx, &ocmprovider.GetInfoByDomainRequest{
Domain: domain,
})
if err != nil {
return "", errors.Wrap(err, "gateway: error calling GetInfoByDomain")
}
for _, s := range meshProvider.ProviderInfo.Services {
if strings.ToLower(s.Endpoint.Type.Name) == "webdav" {
return s.Host, nil
}
}
return "", errtypes.NotFound(domain)
}
func appendNameQuery(targetURL string, nameQueries ...string) (string, error) {
uri, err := url.Parse(targetURL)
if err != nil {
return "", err
}
q, err := url.ParseQuery(uri.RawQuery)
if err != nil {
return "", err
}
name := append([]string{q["name"][0]}, nameQueries...)
q.Set("name", path.Join(name...))
uri.RawQuery = q.Encode()
return uri.String(), nil
}

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 CERN
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -20,20 +20,19 @@ package ocmcore
import (
"context"
"encoding/json"
"fmt"
"time"
ocmcore "github.com/cs3org/go-cs3apis/cs3/ocm/core/v1beta1"
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
typespb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
providerpb "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/ocm/share"
"github.com/cs3org/reva/v2/pkg/ocm/share/manager/registry"
"github.com/cs3org/reva/v2/pkg/ocm/share/repository/registry"
"github.com/cs3org/reva/v2/pkg/rgrpc"
"github.com/cs3org/reva/v2/pkg/rgrpc/status"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
"github.com/cs3org/reva/v2/pkg/utils/cfg"
"google.golang.org/grpc"
)
@@ -48,10 +47,10 @@ type config struct {
type service struct {
conf *config
sm share.Manager
repo share.Repository
}
func (c *config) init() {
func (c *config) ApplyDefaults() {
if c.Driver == "" {
c.Driver = "json"
}
@@ -61,39 +60,28 @@ func (s *service) Register(ss *grpc.Server) {
ocmcore.RegisterOcmCoreAPIServer(ss, s)
}
func getShareManager(c *config) (share.Manager, error) {
func getShareRepository(c *config) (share.Repository, error) {
if f, ok := registry.NewFuncs[c.Driver]; ok {
return f(c.Drivers[c.Driver])
}
return nil, errtypes.NotFound(fmt.Sprintf("driver not found: %s", c.Driver))
}
func parseConfig(m map[string]interface{}) (*config, error) {
c := &config{}
if err := mapstructure.Decode(m, c); err != nil {
err = errors.Wrap(err, "error decoding conf")
return nil, err
}
return c, nil
}
// New creates a new ocm core svc
// New creates a new ocm core svc.
func New(m map[string]interface{}, ss *grpc.Server) (rgrpc.Service, error) {
c, err := parseConfig(m)
if err != nil {
var c config
if err := cfg.Decode(m, &c); err != nil {
return nil, err
}
c.init()
sm, err := getShareManager(c)
repo, err := getShareRepository(&c)
if err != nil {
return nil, err
}
service := &service{
conf: c,
sm: sm,
conf: &c,
repo: repo,
}
return service, nil
@@ -107,91 +95,53 @@ func (s *service) UnprotectedEndpoints() []string {
return []string{"/cs3.ocm.core.v1beta1.OcmCoreAPI/CreateOCMCoreShare"}
}
// CreateOCMCoreShare is called when an OCM request comes into this reva instance from
// CreateOCMCoreShare is called when an OCM request comes into this reva instance from.
func (s *service) CreateOCMCoreShare(ctx context.Context, req *ocmcore.CreateOCMCoreShareRequest) (*ocmcore.CreateOCMCoreShareResponse, error) {
resource := &provider.ResourceId{
StorageId: "remote",
OpaqueId: req.Name,
if req.ShareType != ocm.ShareType_SHARE_TYPE_USER {
return nil, errtypes.NotSupported("share type not supported")
}
var resourcePermissions *provider.ResourcePermissions
permOpaque, ok := req.Protocol.Opaque.Map["permissions"]
if !ok {
return &ocmcore.CreateOCMCoreShareResponse{
Status: status.NewInternal(ctx, "resource permissions not set"),
}, nil
}
switch permOpaque.Decoder {
case "json":
err := json.Unmarshal(permOpaque.Value, &resourcePermissions)
if err != nil {
return &ocmcore.CreateOCMCoreShareResponse{
Status: status.NewInternal(ctx, "error decoding resource permissions"),
}, nil
}
default:
return &ocmcore.CreateOCMCoreShareResponse{
Status: status.NewInternal(ctx, "invalid opaque entry decoder"),
}, nil
now := &typesv1beta1.Timestamp{
Seconds: uint64(time.Now().Unix()),
}
var token string
tokenOpaque, ok := req.Protocol.Opaque.Map["token"]
if !ok {
return &ocmcore.CreateOCMCoreShareResponse{
Status: status.NewInternal(ctx, "token not set"),
}, nil
}
switch tokenOpaque.Decoder {
case "plain":
token = string(tokenOpaque.Value)
default:
return &ocmcore.CreateOCMCoreShareResponse{
Status: status.NewInternal(ctx, "invalid opaque entry decoder"),
}, nil
}
grant := &ocm.ShareGrant{
Grantee: &provider.Grantee{
Type: provider.GranteeType_GRANTEE_TYPE_USER,
// For now, we only support user shares.
// TODO (ishank011): To be updated once this is decided.
Id: &provider.Grantee_UserId{UserId: req.ShareWith},
// passing this in grant.Grantee.Opaque because ShareGrant itself doesn't have a root opaque.
Opaque: &typespb.Opaque{
Map: map[string]*typespb.OpaqueEntry{
"remoteShareId": {
Decoder: "plain",
Value: []byte(req.ProviderId),
},
},
share, err := s.repo.StoreReceivedShare(ctx, &ocm.ReceivedShare{
RemoteShareId: req.ResourceId,
Name: req.Name,
Grantee: &providerpb.Grantee{
Type: providerpb.GranteeType_GRANTEE_TYPE_USER,
Id: &providerpb.Grantee_UserId{
UserId: req.ShareWith,
},
},
Permissions: &ocm.SharePermissions{
Permissions: resourcePermissions,
},
}
var shareType ocm.Share_ShareType
switch req.Protocol.Name {
case "datatx":
shareType = ocm.Share_SHARE_TYPE_TRANSFER
default:
shareType = ocm.Share_SHARE_TYPE_REGULAR
}
share, err := s.sm.Share(ctx, resource, grant, req.Name, nil, "", req.Owner, token, shareType)
ResourceType: req.ResourceType,
ShareType: req.ShareType,
Owner: req.Owner,
Creator: req.Sender,
Protocols: req.Protocols,
Ctime: now,
Mtime: now,
Expiration: req.Expiration,
State: ocm.ShareState_SHARE_STATE_PENDING,
})
if err != nil {
// TODO: identify errors
return &ocmcore.CreateOCMCoreShareResponse{
Status: status.NewInternal(ctx, "error creating ocm core share"),
Status: status.NewInternal(ctx, err.Error()),
}, nil
}
res := &ocmcore.CreateOCMCoreShareResponse{
return &ocmcore.CreateOCMCoreShareResponse{
Status: status.NewOK(ctx),
Id: share.Id.OpaqueId,
Created: share.Ctime,
}
return res, nil
}, nil
}
func (s *service) UpdateOCMCoreShare(ctx context.Context, req *ocmcore.UpdateOCMCoreShareRequest) (*ocmcore.UpdateOCMCoreShareResponse, error) {
return nil, errtypes.NotSupported("not implemented")
}
func (s *service) DeleteOCMCoreShare(ctx context.Context, req *ocmcore.DeleteOCMCoreShareRequest) (*ocmcore.DeleteOCMCoreShareResponse, error) {
return nil, errtypes.NotSupported("not implemented")
}

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 CERN
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -20,14 +20,24 @@ package ocminvitemanager
import (
"context"
"time"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
invitepb "github.com/cs3org/go-cs3apis/cs3/ocm/invite/v1beta1"
ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/ocm/client"
"github.com/cs3org/reva/v2/pkg/ocm/invite"
"github.com/cs3org/reva/v2/pkg/ocm/invite/manager/registry"
"github.com/cs3org/reva/v2/pkg/ocm/invite/repository/registry"
"github.com/cs3org/reva/v2/pkg/rgrpc"
"github.com/cs3org/reva/v2/pkg/rgrpc/status"
"github.com/mitchellh/mapstructure"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/v2/pkg/sharedconf"
"github.com/cs3org/reva/v2/pkg/utils"
"github.com/cs3org/reva/v2/pkg/utils/cfg"
"github.com/pkg/errors"
"google.golang.org/grpc"
)
@@ -37,58 +47,77 @@ func init() {
}
type config struct {
Driver string `mapstructure:"driver"`
Drivers map[string]map[string]interface{} `mapstructure:"drivers"`
Driver string `mapstructure:"driver"`
Drivers map[string]map[string]interface{} `mapstructure:"drivers"`
TokenExpiration string `mapstructure:"token_expiration"`
OCMClientTimeout int `mapstructure:"ocm_timeout"`
OCMClientInsecure bool `mapstructure:"ocm_insecure"`
GatewaySVC string `mapstructure:"gatewaysvc" validate:"required"`
ProviderDomain string `mapstructure:"provider_domain" validate:"required" docs:"The same domain registered in the provider authorizer"`
tokenExpiration time.Duration
}
type service struct {
conf *config
im invite.Manager
conf *config
repo invite.Repository
ocmClient *client.OCMClient
gatewaySelector *pool.Selector[gateway.GatewayAPIClient]
}
func (c *config) init() {
func (c *config) ApplyDefaults() {
if c.Driver == "" {
c.Driver = "json"
}
if c.TokenExpiration == "" {
c.TokenExpiration = "24h"
}
c.GatewaySVC = sharedconf.GetGatewaySVC(c.GatewaySVC)
}
func (s *service) Register(ss *grpc.Server) {
invitepb.RegisterInviteAPIServer(ss, s)
}
func getInviteManager(c *config) (invite.Manager, error) {
func getInviteRepository(c *config) (invite.Repository, error) {
if f, ok := registry.NewFuncs[c.Driver]; ok {
return f(c.Drivers[c.Driver])
}
return nil, errtypes.NotFound("driver not found: " + c.Driver)
}
func parseConfig(m map[string]interface{}) (*config, error) {
c := &config{}
if err := mapstructure.Decode(m, c); err != nil {
err = errors.Wrap(err, "error decoding conf")
// New creates a new OCM invite manager svc.
func New(m map[string]interface{}, ss *grpc.Server) (rgrpc.Service, error) {
var c config
if err := cfg.Decode(m, &c); err != nil {
return nil, err
}
return c, nil
}
// New creates a new OCM invite manager svc
func New(m map[string]interface{}, ss *grpc.Server) (rgrpc.Service, error) {
c, err := parseConfig(m)
p, err := time.ParseDuration(c.TokenExpiration)
if err != nil {
return nil, err
}
c.init()
c.tokenExpiration = p
im, err := getInviteManager(c)
repo, err := getInviteRepository(&c)
if err != nil {
return nil, err
}
gatewaySelector, err := pool.GatewaySelector(c.GatewaySVC)
if err != nil {
return nil, err
}
service := &service{
conf: c,
im: im,
conf: &c,
repo: repo,
ocmClient: client.New(&client.Config{
Timeout: time.Duration(c.OCMClientTimeout) * time.Second,
Insecure: c.OCMClientInsecure,
}),
gatewaySelector: gatewaySelector,
}
return service, nil
}
@@ -98,12 +127,14 @@ func (s *service) Close() error {
}
func (s *service) UnprotectedEndpoints() []string {
return []string{"/cs3.ocm.invite.v1beta1.InviteAPI/AcceptInvite"}
return []string{"/cs3.ocm.invite.v1beta1.InviteAPI/AcceptInvite", "/cs3.ocm.invite.v1beta1.InviteAPI/GetAcceptedUser"}
}
func (s *service) GenerateInviteToken(ctx context.Context, req *invitepb.GenerateInviteTokenRequest) (*invitepb.GenerateInviteTokenResponse, error) {
token, err := s.im.GenerateToken(ctx)
if err != nil {
user := ctxpkg.ContextMustGetUser(ctx)
token := CreateToken(s.conf.tokenExpiration, user.GetId(), req.Description)
if err := s.repo.AddToken(ctx, token); err != nil {
return &invitepb.GenerateInviteTokenResponse{
Status: status.NewInternal(ctx, "error generating invite token"),
}, nil
@@ -115,34 +146,175 @@ func (s *service) GenerateInviteToken(ctx context.Context, req *invitepb.Generat
}, nil
}
func (s *service) ForwardInvite(ctx context.Context, req *invitepb.ForwardInviteRequest) (*invitepb.ForwardInviteResponse, error) {
err := s.im.ForwardInvite(ctx, req.InviteToken, req.OriginSystemProvider)
func (s *service) ListInviteTokens(ctx context.Context, req *invitepb.ListInviteTokensRequest) (*invitepb.ListInviteTokensResponse, error) {
user := ctxpkg.ContextMustGetUser(ctx)
tokens, err := s.repo.ListTokens(ctx, user.Id)
if err != nil {
return &invitepb.ForwardInviteResponse{
Status: status.NewInternal(ctx, "error forwarding invite"),
return &invitepb.ListInviteTokensResponse{
Status: status.NewInternal(ctx, "error listing tokens"),
}, nil
}
return &invitepb.ForwardInviteResponse{
Status: status.NewOK(ctx),
return &invitepb.ListInviteTokensResponse{
Status: status.NewOK(ctx),
InviteTokens: tokens,
}, nil
}
func (s *service) ForwardInvite(ctx context.Context, req *invitepb.ForwardInviteRequest) (*invitepb.ForwardInviteResponse, error) {
user := ctxpkg.ContextMustGetUser(ctx)
ocmEndpoint, err := getOCMEndpoint(req.GetOriginSystemProvider())
if err != nil {
return nil, err
}
remoteUser, err := s.ocmClient.InviteAccepted(ctx, ocmEndpoint, &client.InviteAcceptedRequest{
Token: req.InviteToken.GetToken(),
RecipientProvider: s.conf.ProviderDomain,
UserID: user.GetId().GetOpaqueId(),
Email: user.GetMail(),
Name: user.GetDisplayName(),
})
if err != nil {
switch {
case errors.Is(err, client.ErrTokenInvalid):
return &invitepb.ForwardInviteResponse{
Status: status.NewInvalid(ctx, "token not valid"),
}, nil
case errors.Is(err, client.ErrTokenNotFound):
return &invitepb.ForwardInviteResponse{
Status: status.NewNotFound(ctx, "token not found"),
}, nil
case errors.Is(err, client.ErrUserAlreadyAccepted):
return &invitepb.ForwardInviteResponse{
Status: status.NewAlreadyExists(ctx, err, err.Error()),
}, nil
case errors.Is(err, client.ErrServiceNotTrusted):
return &invitepb.ForwardInviteResponse{
Status: status.NewPermissionDenied(ctx, err, err.Error()),
}, nil
default:
return &invitepb.ForwardInviteResponse{
Status: status.NewInternal(ctx, err.Error()),
}, nil
}
}
// create a link between the user that accepted the share (in ctx)
// and the remote one (the initiator), so at the end of the invitation workflow they
// know each other
remoteUserID := &userpb.UserId{
Type: userpb.UserType_USER_TYPE_FEDERATED,
Idp: req.GetOriginSystemProvider().Domain,
OpaqueId: remoteUser.UserID,
}
if err := s.repo.AddRemoteUser(ctx, user.Id, &userpb.User{
Id: remoteUserID,
Mail: remoteUser.Email,
DisplayName: remoteUser.Name,
}); err != nil {
if !errors.Is(err, invite.ErrUserAlreadyAccepted) {
// skip error if user was already accepted
return &invitepb.ForwardInviteResponse{
Status: status.NewInternal(ctx, err.Error()),
}, nil
}
}
return &invitepb.ForwardInviteResponse{
Status: status.NewOK(ctx),
UserId: remoteUserID,
Email: remoteUser.Email,
DisplayName: remoteUser.Name,
}, nil
}
func getOCMEndpoint(originProvider *ocmprovider.ProviderInfo) (string, error) {
for _, s := range originProvider.Services {
if s.Endpoint.Type.Name == "OCM" {
return s.Endpoint.Path, nil
}
}
return "", errors.New("ocm endpoint not specified for mesh provider")
}
func (s *service) AcceptInvite(ctx context.Context, req *invitepb.AcceptInviteRequest) (*invitepb.AcceptInviteResponse, error) {
err := s.im.AcceptInvite(ctx, req.InviteToken, req.RemoteUser)
token, err := s.repo.GetToken(ctx, req.InviteToken.Token)
if err != nil {
if errors.Is(err, invite.ErrTokenNotFound) {
return &invitepb.AcceptInviteResponse{
Status: status.NewNotFound(ctx, "token not found"),
}, nil
}
return &invitepb.AcceptInviteResponse{
Status: status.NewInternal(ctx, err.Error()),
}, nil
}
if !isTokenValid(token) {
return &invitepb.AcceptInviteResponse{
Status: status.NewInvalid(ctx, "token is not valid"),
}, nil
}
initiator, err := s.getUserInfo(ctx, token.UserId)
if err != nil {
return &invitepb.AcceptInviteResponse{
Status: status.NewInternal(ctx, "error accepting invite"),
Status: status.NewInternal(ctx, err.Error()),
}, nil
}
if err := s.repo.AddRemoteUser(ctx, token.GetUserId(), req.GetRemoteUser()); err != nil {
if errors.Is(err, invite.ErrUserAlreadyAccepted) {
return &invitepb.AcceptInviteResponse{
Status: status.NewAlreadyExists(ctx, err, err.Error()),
}, nil
}
return &invitepb.AcceptInviteResponse{
Status: status.NewInternal(ctx, err.Error()),
}, nil
}
return &invitepb.AcceptInviteResponse{
Status: status.NewOK(ctx),
Status: status.NewOK(ctx),
UserId: initiator.GetId(),
Email: initiator.Mail,
DisplayName: initiator.DisplayName,
}, nil
}
func (s *service) getUserInfo(ctx context.Context, id *userpb.UserId) (*userpb.User, error) {
gw, err := s.gatewaySelector.Next()
if err != nil {
return nil, nil
}
res, err := gw.GetUser(ctx, &userpb.GetUserRequest{
UserId: id,
})
if err != nil {
return nil, err
}
if res.Status.Code != rpcv1beta1.Code_CODE_OK {
return nil, errors.New(res.Status.Message)
}
return res.User, nil
}
func isTokenValid(token *invitepb.InviteToken) bool {
return time.Now().Unix() < int64(token.Expiration.Seconds)
}
func (s *service) GetAcceptedUser(ctx context.Context, req *invitepb.GetAcceptedUserRequest) (*invitepb.GetAcceptedUserResponse, error) {
remoteUser, err := s.im.GetAcceptedUser(ctx, req.RemoteUserId)
user, ok := getUserFilter(ctx, req)
if !ok {
return &invitepb.GetAcceptedUserResponse{
Status: status.NewInvalidArg(ctx, "user not found"),
}, nil
}
remoteUser, err := s.repo.GetRemoteUser(ctx, user.GetId(), req.GetRemoteUserId())
if err != nil {
return &invitepb.GetAcceptedUserResponse{
Status: status.NewInternal(ctx, "error fetching remote user details"),
@@ -155,11 +327,34 @@ func (s *service) GetAcceptedUser(ctx context.Context, req *invitepb.GetAccepted
}, nil
}
func getUserFilter(ctx context.Context, req *invitepb.GetAcceptedUserRequest) (*userpb.User, bool) {
user, ok := ctxpkg.ContextGetUser(ctx)
if ok {
return user, true
}
if req.Opaque == nil || req.Opaque.Map == nil {
return nil, false
}
v, ok := req.Opaque.Map["user-filter"]
if !ok {
return nil, false
}
var u userpb.UserId
if err := utils.UnmarshalJSONToProtoV1(v.Value, &u); err != nil {
return nil, false
}
return &userpb.User{Id: &u}, true
}
func (s *service) FindAcceptedUsers(ctx context.Context, req *invitepb.FindAcceptedUsersRequest) (*invitepb.FindAcceptedUsersResponse, error) {
acceptedUsers, err := s.im.FindAcceptedUsers(ctx, req.Filter)
user := ctxpkg.ContextMustGetUser(ctx)
acceptedUsers, err := s.repo.FindRemoteUsers(ctx, user.GetId(), req.GetFilter())
if err != nil {
return &invitepb.FindAcceptedUsersResponse{
Status: status.NewInternal(ctx, "error finding remote users"),
Status: status.NewInternal(ctx, "error finding remote users: "+err.Error()),
}, nil
}
@@ -168,3 +363,16 @@ func (s *service) FindAcceptedUsers(ctx context.Context, req *invitepb.FindAccep
AcceptedUsers: acceptedUsers,
}, nil
}
func (s *service) DeleteAcceptedUser(ctx context.Context, req *invitepb.DeleteAcceptedUserRequest) (*invitepb.DeleteAcceptedUserResponse, error) {
user := ctxpkg.ContextMustGetUser(ctx)
if err := s.repo.DeleteRemoteUser(ctx, user.Id, req.RemoteUserId); err != nil {
return &invitepb.DeleteAcceptedUserResponse{
Status: status.NewInternal(ctx, "error deleting remote users: "+err.Error()),
}, nil
}
return &invitepb.DeleteAcceptedUserResponse{
Status: status.NewOK(ctx),
}, nil
}

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 CERN
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.
package token
package ocminvitemanager
import (
"time"
@@ -25,33 +25,21 @@ import (
invitepb "github.com/cs3org/go-cs3apis/cs3/ocm/invite/v1beta1"
typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/google/uuid"
"github.com/pkg/errors"
)
// DefaultExpirationTime is the expiration time to be used when unspecified in the config.
const DefaultExpirationTime = "24h"
// CreateToken creates a InviteToken object for the userID indicated by userID.
func CreateToken(expiration string, userID *userpb.UserId) (*invitepb.InviteToken, error) {
// Parse time of expiration
duration, err := time.ParseDuration(expiration)
if err != nil {
return nil, errors.Wrap(err, "error parsing time of expiration")
}
func CreateToken(expiration time.Duration, userID *userpb.UserId, description string) *invitepb.InviteToken {
tokenID := uuid.New().String()
now := time.Now()
expirationTime := now.Add(duration)
expirationTime := now.Add(expiration)
token := invitepb.InviteToken{
return &invitepb.InviteToken{
Token: tokenID,
UserId: userID,
Expiration: &typesv1beta1.Timestamp{
Seconds: uint64(expirationTime.Unix()),
Nanos: 0,
},
Description: description,
}
return &token, nil
}

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 CERN
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -20,14 +20,33 @@ package ocmshareprovider
import (
"context"
"fmt"
"net/url"
"path/filepath"
"strings"
"text/template"
"time"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
providerpb "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
typespb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/v2/internal/http/services/ocmd"
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/ocm/client"
"github.com/cs3org/reva/v2/pkg/ocm/share"
"github.com/cs3org/reva/v2/pkg/ocm/share/manager/registry"
"github.com/cs3org/reva/v2/pkg/ocm/share/repository/registry"
"github.com/cs3org/reva/v2/pkg/rgrpc"
"github.com/cs3org/reva/v2/pkg/rgrpc/status"
"github.com/mitchellh/mapstructure"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/v2/pkg/sharedconf"
"github.com/cs3org/reva/v2/pkg/storage/utils/walker"
"github.com/cs3org/reva/v2/pkg/utils"
"github.com/cs3org/reva/v2/pkg/utils/cfg"
"github.com/pkg/errors"
"google.golang.org/grpc"
)
@@ -37,58 +56,85 @@ func init() {
}
type config struct {
Driver string `mapstructure:"driver"`
Drivers map[string]map[string]interface{} `mapstructure:"drivers"`
Driver string `mapstructure:"driver"`
Drivers map[string]map[string]interface{} `mapstructure:"drivers"`
ClientTimeout int `mapstructure:"client_timeout"`
ClientInsecure bool `mapstructure:"client_insecure"`
GatewaySVC string `mapstructure:"gatewaysvc" validate:"required"`
ProviderDomain string `mapstructure:"provider_domain" validate:"required" docs:"The same domain registered in the provider authorizer"`
WebDAVEndpoint string `mapstructure:"webdav_endpoint" validate:"required"`
WebappTemplate string `mapstructure:"webapp_template"`
}
type service struct {
conf *config
sm share.Manager
conf *config
repo share.Repository
client *client.OCMClient
gatewaySelector *pool.Selector[gateway.GatewayAPIClient]
webappTmpl *template.Template
walker walker.Walker
}
func (c *config) init() {
func (c *config) ApplyDefaults() {
if c.Driver == "" {
c.Driver = "json"
}
if c.ClientTimeout == 0 {
c.ClientTimeout = 10
}
if c.WebappTemplate == "" {
c.WebappTemplate = "https://cernbox.cern.ch/external/sciencemesh/{{.Token}}{relative-path-to-shared-resource}"
}
c.GatewaySVC = sharedconf.GetGatewaySVC(c.GatewaySVC)
}
func (s *service) Register(ss *grpc.Server) {
ocm.RegisterOcmAPIServer(ss, s)
}
func getShareManager(c *config) (share.Manager, error) {
func getShareRepository(c *config) (share.Repository, error) {
if f, ok := registry.NewFuncs[c.Driver]; ok {
return f(c.Drivers[c.Driver])
}
return nil, errtypes.NotFound("driver not found: " + c.Driver)
}
func parseConfig(m map[string]interface{}) (*config, error) {
c := &config{}
if err := mapstructure.Decode(m, c); err != nil {
err = errors.Wrap(err, "error decoding conf")
return nil, err
}
return c, nil
}
// New creates a new ocm share provider svc
// New creates a new ocm share provider svc.
func New(m map[string]interface{}, ss *grpc.Server) (rgrpc.Service, error) {
var c config
if err := cfg.Decode(m, &c); err != nil {
return nil, err
}
c, err := parseConfig(m)
repo, err := getShareRepository(&c)
if err != nil {
return nil, err
}
c.init()
sm, err := getShareManager(c)
client := client.New(&client.Config{
Timeout: time.Duration(c.ClientTimeout) * time.Second,
Insecure: c.ClientInsecure,
})
gatewaySelector, err := pool.GatewaySelector(c.GatewaySVC)
if err != nil {
return nil, err
}
tpl, err := template.New("webapp_template").Parse(c.WebappTemplate)
if err != nil {
return nil, err
}
walker := walker.NewWalker(gatewaySelector)
service := &service{
conf: c,
sm: sm,
conf: &c,
repo: repo,
client: client,
gatewaySelector: gatewaySelector,
webappTmpl: tpl,
walker: walker,
}
return service, nil
@@ -99,98 +145,240 @@ func (s *service) Close() error {
}
func (s *service) UnprotectedEndpoints() []string {
return []string{}
return []string{"/cs3.sharing.ocm.v1beta1.OcmAPI/GetOCMShareByToken"}
}
func getOCMEndpoint(originProvider *ocmprovider.ProviderInfo) (string, error) {
for _, s := range originProvider.Services {
if s.Endpoint.Type.Name == "OCM" {
return s.Endpoint.Path, nil
}
}
return "", errors.New("ocm endpoint not specified for mesh provider")
}
func formatOCMUser(u *userpb.UserId) string {
return fmt.Sprintf("%s@%s", u.OpaqueId, u.Idp)
}
func getResourceType(info *providerpb.ResourceInfo) string {
switch info.Type {
case providerpb.ResourceType_RESOURCE_TYPE_FILE:
return "file"
case providerpb.ResourceType_RESOURCE_TYPE_CONTAINER:
return "folder"
}
return "unknown"
}
func (s *service) webdavURL(ctx context.Context, share *ocm.Share) string {
// the url is in the form of https://cernbox.cern.ch/remote.php/dav/ocm/token
p, _ := url.JoinPath(s.conf.WebDAVEndpoint, "/dav/ocm", share.Token)
return p
}
func (s *service) getWebdavProtocol(ctx context.Context, share *ocm.Share, m *ocm.AccessMethod_WebdavOptions) *ocmd.WebDAV {
var perms []string
if m.WebdavOptions.Permissions.InitiateFileDownload {
perms = append(perms, "read")
}
if m.WebdavOptions.Permissions.InitiateFileUpload {
perms = append(perms, "write")
}
return &ocmd.WebDAV{
Permissions: perms,
URL: s.webdavURL(ctx, share),
SharedSecret: share.Token,
}
}
func (s *service) getWebappProtocol(share *ocm.Share) *ocmd.Webapp {
var b strings.Builder
if err := s.webappTmpl.Execute(&b, share); err != nil {
return nil
}
return &ocmd.Webapp{
URITemplate: b.String(),
}
}
func (s *service) getDataTransferProtocol(ctx context.Context, share *ocm.Share) *ocmd.Datatx {
var size uint64
gatewayClient, err := s.gatewaySelector.Next()
if err != nil {
return nil
}
// get the path of the share
statRes, err := gatewayClient.Stat(ctx, &providerpb.StatRequest{
Ref: &providerpb.Reference{
ResourceId: share.ResourceId,
},
})
if err != nil {
return nil
}
err = s.walker.Walk(ctx, statRes.GetInfo().GetId(), func(path string, info *providerpb.ResourceInfo, err error) error {
if info.Type == providerpb.ResourceType_RESOURCE_TYPE_FILE {
size += info.Size
}
return nil
})
if err != nil {
return nil
}
return &ocmd.Datatx{
SourceURI: s.webdavURL(ctx, share),
Size: size,
}
}
func (s *service) getProtocols(ctx context.Context, share *ocm.Share) ocmd.Protocols {
var p ocmd.Protocols
for _, m := range share.AccessMethods {
var newProtocol ocmd.Protocol
switch t := m.Term.(type) {
case *ocm.AccessMethod_WebdavOptions:
newProtocol = s.getWebdavProtocol(ctx, share, t)
case *ocm.AccessMethod_WebappOptions:
newProtocol = s.getWebappProtocol(share)
case *ocm.AccessMethod_TransferOptions:
newProtocol = s.getDataTransferProtocol(ctx, share)
}
if newProtocol != nil {
p = append(p, newProtocol)
}
}
return p
}
// Note: this is for outgoing OCM shares
// This function is used when you for instance
// call `ocm-share-create` in reva-cli.
// For incoming OCM shares from internal/http/services/ocmd/shares.go
// there is the very similar but slightly different function
// CreateOCMCoreShare (the "Core" somehow means "incoming").
// So make sure to keep in mind the difference between this file for outgoing:
// internal/grpc/services/ocmshareprovider/ocmshareprovider.go
// and the other one for incoming:
// internal/grpc/service/ocmcore/ocmcore.go
// Both functions end up calling the same s.sm.Share function
// on the OCM share manager:
// pkg/ocm/share/manager/{json|nextcloud|...}
func (s *service) CreateOCMShare(ctx context.Context, req *ocm.CreateOCMShareRequest) (*ocm.CreateOCMShareResponse, error) {
if req.Opaque == nil {
return &ocm.CreateOCMShareResponse{
Status: status.NewInternal(ctx, "can't find resource permissions"),
}, nil
gatewayClient, err := s.gatewaySelector.Next()
if err != nil {
return nil, err
}
statRes, err := gatewayClient.Stat(ctx, &providerpb.StatRequest{
Ref: &providerpb.Reference{
ResourceId: req.ResourceId,
},
})
if err != nil {
return nil, err
}
var permissions string
permOpaque, ok := req.Opaque.Map["permissions"]
if !ok {
return &ocm.CreateOCMShareResponse{
Status: status.NewInternal(ctx, "resource permissions not set"),
}, nil
}
switch permOpaque.Decoder {
case "plain":
permissions = string(permOpaque.Value)
default:
return &ocm.CreateOCMShareResponse{
Status: status.NewInternal(ctx, "invalid opaque entry decoder"),
}, nil
}
var name string
nameOpaque, ok := req.Opaque.Map["name"]
if !ok {
return &ocm.CreateOCMShareResponse{
Status: status.NewInternal(ctx, "resource name not set"),
}, nil
}
switch nameOpaque.Decoder {
case "plain":
name = string(nameOpaque.Value)
default:
return &ocm.CreateOCMShareResponse{
Status: status.NewInternal(ctx, "invalid opaque entry decoder"),
}, nil
}
// discover share type
sharetype := ocm.Share_SHARE_TYPE_REGULAR
// FIXME: https://github.com/cs3org/reva/issues/2402
protocol, ok := req.Opaque.Map["protocol"]
if ok {
switch protocol.Decoder {
case "plain":
if string(protocol.Value) == "datatx" {
sharetype = ocm.Share_SHARE_TYPE_TRANSFER
}
default:
if statRes.Status.Code != rpc.Code_CODE_OK {
if statRes.Status.Code == rpc.Code_CODE_NOT_FOUND {
return &ocm.CreateOCMShareResponse{
Status: status.NewInternal(ctx, "error creating share"),
Status: status.NewNotFound(ctx, statRes.Status.Message),
}, nil
}
// token = protocol FIXME!
return &ocm.CreateOCMShareResponse{
Status: status.NewInternal(ctx, statRes.Status.Message),
}, nil
}
var sharedSecret string
share, err := s.sm.Share(ctx, req.ResourceId, req.Grant, name, req.RecipientMeshProvider, permissions, nil, sharedSecret, sharetype)
info := statRes.Info
user := ctxpkg.ContextMustGetUser(ctx)
tkn := utils.RandString(32)
now := time.Now().UnixNano()
ts := &typespb.Timestamp{
Seconds: uint64(now / 1000000000),
Nanos: uint32(now % 1000000000),
}
ocmshare := &ocm.Share{
Token: tkn,
Name: filepath.Base(info.Path),
ResourceId: req.ResourceId,
Grantee: req.Grantee,
ShareType: ocm.ShareType_SHARE_TYPE_USER,
Owner: info.Owner,
Creator: user.Id,
Ctime: ts,
Mtime: ts,
Expiration: req.Expiration,
AccessMethods: req.AccessMethods,
}
ocmshare, err = s.repo.StoreShare(ctx, ocmshare)
if err != nil {
if errors.Is(err, share.ErrShareAlreadyExisting) {
return &ocm.CreateOCMShareResponse{
Status: status.NewAlreadyExists(ctx, err, "share already exists"),
}, nil
}
return &ocm.CreateOCMShareResponse{
Status: status.NewInternal(ctx, err.Error()),
}, nil
}
ocmEndpoint, err := getOCMEndpoint(req.RecipientMeshProvider)
if err != nil {
return &ocm.CreateOCMShareResponse{
Status: status.NewInternal(ctx, "error creating share"),
Status: status.NewInvalidArg(ctx, "the selected provider does not have an OCM endpoint"),
}, nil
}
newShareReq := &client.NewShareRequest{
ShareWith: formatOCMUser(req.Grantee.GetUserId()),
Name: ocmshare.Name,
ProviderID: ocmshare.Id.OpaqueId,
Owner: formatOCMUser(&userpb.UserId{
OpaqueId: info.Owner.OpaqueId,
Idp: s.conf.ProviderDomain, // FIXME: this is not generally true in case of resharing
}),
Sender: formatOCMUser(&userpb.UserId{
OpaqueId: user.Id.OpaqueId,
Idp: s.conf.ProviderDomain,
}),
SenderDisplayName: user.DisplayName,
ShareType: "user",
ResourceType: getResourceType(info),
Protocols: s.getProtocols(ctx, ocmshare),
}
if req.Expiration != nil {
newShareReq.Expiration = req.Expiration.Seconds
}
newShareRes, err := s.client.NewShare(ctx, ocmEndpoint, newShareReq)
if err != nil {
switch {
case errors.Is(err, client.ErrInvalidParameters):
return &ocm.CreateOCMShareResponse{
Status: status.NewInvalidArg(ctx, err.Error()),
}, nil
case errors.Is(err, client.ErrServiceNotTrusted):
return &ocm.CreateOCMShareResponse{
Status: status.NewInvalidArg(ctx, err.Error()),
}, nil
default:
return &ocm.CreateOCMShareResponse{
Status: status.NewInternal(ctx, err.Error()),
}, nil
}
}
res := &ocm.CreateOCMShareResponse{
Status: status.NewOK(ctx),
Share: share,
Status: status.NewOK(ctx),
Share: ocmshare,
RecipientDisplayName: newShareRes.RecipientDisplayName,
}
return res, nil
}
func (s *service) RemoveOCMShare(ctx context.Context, req *ocm.RemoveOCMShareRequest) (*ocm.RemoveOCMShareResponse, error) {
err := s.sm.Unshare(ctx, req.Ref)
if err != nil {
// TODO (gdelmont): notify the remote provider using the /notification ocm endpoint
// https://cs3org.github.io/OCM-API/docs.html?branch=develop&repo=OCM-API&user=cs3org#/paths/~1notifications/post
user := ctxpkg.ContextMustGetUser(ctx)
if err := s.repo.DeleteShare(ctx, user, req.Ref); err != nil {
if errors.Is(err, share.ErrShareNotFound) {
return &ocm.RemoveOCMShareResponse{
Status: status.NewNotFound(ctx, "share does not exist"),
}, nil
}
return &ocm.RemoveOCMShareResponse{
Status: status.NewInternal(ctx, "error removing share"),
}, nil
@@ -202,8 +390,18 @@ func (s *service) RemoveOCMShare(ctx context.Context, req *ocm.RemoveOCMShareReq
}
func (s *service) GetOCMShare(ctx context.Context, req *ocm.GetOCMShareRequest) (*ocm.GetOCMShareResponse, error) {
share, err := s.sm.GetShare(ctx, req.Ref)
// if the request is by token, the user does not need to be in the ctx
var user *userpb.User
if req.Ref.GetToken() == "" {
user = ctxpkg.ContextMustGetUser(ctx)
}
ocmshare, err := s.repo.GetShare(ctx, user, req.Ref)
if err != nil {
if errors.Is(err, share.ErrShareNotFound) {
return &ocm.GetOCMShareResponse{
Status: status.NewNotFound(ctx, "share does not exist"),
}, nil
}
return &ocm.GetOCMShareResponse{
Status: status.NewInternal(ctx, "error getting share"),
}, nil
@@ -211,12 +409,36 @@ func (s *service) GetOCMShare(ctx context.Context, req *ocm.GetOCMShareRequest)
return &ocm.GetOCMShareResponse{
Status: status.NewOK(ctx),
Share: share,
Share: ocmshare,
}, nil
}
func (s *service) GetOCMShareByToken(ctx context.Context, req *ocm.GetOCMShareByTokenRequest) (*ocm.GetOCMShareByTokenResponse, error) {
ocmshare, err := s.repo.GetShare(ctx, nil, &ocm.ShareReference{
Spec: &ocm.ShareReference_Token{
Token: req.Token,
},
})
if err != nil {
if errors.Is(err, share.ErrShareNotFound) {
return &ocm.GetOCMShareByTokenResponse{
Status: status.NewNotFound(ctx, "share does not exist"),
}, nil
}
return &ocm.GetOCMShareByTokenResponse{
Status: status.NewInternal(ctx, "error getting share"),
}, nil
}
return &ocm.GetOCMShareByTokenResponse{
Status: status.NewOK(ctx),
Share: ocmshare,
}, nil
}
func (s *service) ListOCMShares(ctx context.Context, req *ocm.ListOCMSharesRequest) (*ocm.ListOCMSharesResponse, error) {
shares, err := s.sm.ListShares(ctx, req.Filters) // TODO(labkode): add filter to share manager
user := ctxpkg.ContextMustGetUser(ctx)
shares, err := s.repo.ListShares(ctx, user, req.Filters)
if err != nil {
return &ocm.ListOCMSharesResponse{
Status: status.NewInternal(ctx, "error listing shares"),
@@ -231,8 +453,19 @@ func (s *service) ListOCMShares(ctx context.Context, req *ocm.ListOCMSharesReque
}
func (s *service) UpdateOCMShare(ctx context.Context, req *ocm.UpdateOCMShareRequest) (*ocm.UpdateOCMShareResponse, error) {
_, err := s.sm.UpdateShare(ctx, req.Ref, req.Field.GetPermissions()) // TODO(labkode): check what to update
user := ctxpkg.ContextMustGetUser(ctx)
if len(req.Field) == 0 {
return &ocm.UpdateOCMShareResponse{
Status: status.NewOK(ctx),
}, nil
}
_, err := s.repo.UpdateShare(ctx, user, req.Ref, req.Field...)
if err != nil {
if errors.Is(err, share.ErrShareNotFound) {
return &ocm.UpdateOCMShareResponse{
Status: status.NewNotFound(ctx, "share does not exist"),
}, nil
}
return &ocm.UpdateOCMShareResponse{
Status: status.NewInternal(ctx, "error updating share"),
}, nil
@@ -245,7 +478,8 @@ func (s *service) UpdateOCMShare(ctx context.Context, req *ocm.UpdateOCMShareReq
}
func (s *service) ListReceivedOCMShares(ctx context.Context, req *ocm.ListReceivedOCMSharesRequest) (*ocm.ListReceivedOCMSharesResponse, error) {
shares, err := s.sm.ListReceivedShares(ctx)
user := ctxpkg.ContextMustGetUser(ctx)
shares, err := s.repo.ListReceivedShares(ctx, user)
if err != nil {
return &ocm.ListReceivedOCMSharesResponse{
Status: status.NewInternal(ctx, "error listing received shares"),
@@ -260,8 +494,14 @@ func (s *service) ListReceivedOCMShares(ctx context.Context, req *ocm.ListReceiv
}
func (s *service) UpdateReceivedOCMShare(ctx context.Context, req *ocm.UpdateReceivedOCMShareRequest) (*ocm.UpdateReceivedOCMShareResponse, error) {
_, err := s.sm.UpdateReceivedShare(ctx, req.Share, req.UpdateMask) // TODO(labkode): check what to update
user := ctxpkg.ContextMustGetUser(ctx)
_, err := s.repo.UpdateReceivedShare(ctx, user, req.Share, req.UpdateMask)
if err != nil {
if errors.Is(err, share.ErrShareNotFound) {
return &ocm.UpdateReceivedOCMShareResponse{
Status: status.NewNotFound(ctx, "share does not exist"),
}, nil
}
return &ocm.UpdateReceivedOCMShareResponse{
Status: status.NewInternal(ctx, "error updating received share"),
}, nil
@@ -274,8 +514,14 @@ func (s *service) UpdateReceivedOCMShare(ctx context.Context, req *ocm.UpdateRec
}
func (s *service) GetReceivedOCMShare(ctx context.Context, req *ocm.GetReceivedOCMShareRequest) (*ocm.GetReceivedOCMShareResponse, error) {
share, err := s.sm.GetReceivedShare(ctx, req.Ref)
user := ctxpkg.ContextMustGetUser(ctx)
ocmshare, err := s.repo.GetReceivedShare(ctx, user, req.Ref)
if err != nil {
if errors.Is(err, share.ErrShareNotFound) {
return &ocm.GetReceivedOCMShareResponse{
Status: status.NewNotFound(ctx, "share does not exist"),
}, nil
}
return &ocm.GetReceivedOCMShareResponse{
Status: status.NewInternal(ctx, "error getting received share"),
}, nil
@@ -283,7 +529,7 @@ func (s *service) GetReceivedOCMShare(ctx context.Context, req *ocm.GetReceivedO
res := &ocm.GetReceivedOCMShareResponse{
Status: status.NewOK(ctx),
Share: share,
Share: ocmshare,
}
return res, nil
}

View File

@@ -30,10 +30,12 @@ import (
userv1beta1 "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"
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/v2/pkg/appctx"
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/rgrpc"
"github.com/cs3org/reva/v2/pkg/rgrpc/status"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
@@ -105,13 +107,10 @@ func New(m map[string]interface{}, ss *grpc.Server) (rgrpc.Service, error) {
}
func (s *service) SetArbitraryMetadata(ctx context.Context, req *provider.SetArbitraryMetadataRequest) (*provider.SetArbitraryMetadataResponse, error) {
ref, _, _, st, err := s.translatePublicRefToCS3Ref(ctx, req.Ref)
switch {
case err != nil:
return nil, err
case st != nil:
ref, _, _, err := s.translatePublicRefToCS3Ref(ctx, req.Ref)
if err != nil {
return &provider.SetArbitraryMetadataResponse{
Status: st,
Status: status.NewStatusFromErrType(ctx, "failed to resolve reference", err),
}, nil
}
gatewayClient, err := s.gatewaySelector.Next()
@@ -127,13 +126,10 @@ func (s *service) UnsetArbitraryMetadata(ctx context.Context, req *provider.Unse
// SetLock puts a lock on the given reference
func (s *service) SetLock(ctx context.Context, req *provider.SetLockRequest) (*provider.SetLockResponse, error) {
ref, _, _, st, err := s.translatePublicRefToCS3Ref(ctx, req.Ref)
switch {
case err != nil:
return nil, err
case st != nil:
ref, _, _, err := s.translatePublicRefToCS3Ref(ctx, req.Ref)
if err != nil {
return &provider.SetLockResponse{
Status: st,
Status: status.NewStatusFromErrType(ctx, "failed to resolve reference", err),
}, nil
}
gatewayClient, err := s.gatewaySelector.Next()
@@ -145,13 +141,10 @@ func (s *service) SetLock(ctx context.Context, req *provider.SetLockRequest) (*p
// GetLock returns an existing lock on the given reference
func (s *service) GetLock(ctx context.Context, req *provider.GetLockRequest) (*provider.GetLockResponse, error) {
ref, _, _, st, err := s.translatePublicRefToCS3Ref(ctx, req.Ref)
switch {
case err != nil:
return nil, err
case st != nil:
ref, _, _, err := s.translatePublicRefToCS3Ref(ctx, req.Ref)
if err != nil {
return &provider.GetLockResponse{
Status: st,
Status: status.NewStatusFromErrType(ctx, "failed to resolve reference", err),
}, nil
}
gatewayClient, err := s.gatewaySelector.Next()
@@ -163,13 +156,10 @@ func (s *service) GetLock(ctx context.Context, req *provider.GetLockRequest) (*p
// RefreshLock refreshes an existing lock on the given reference
func (s *service) RefreshLock(ctx context.Context, req *provider.RefreshLockRequest) (*provider.RefreshLockResponse, error) {
ref, _, _, st, err := s.translatePublicRefToCS3Ref(ctx, req.Ref)
switch {
case err != nil:
return nil, err
case st != nil:
ref, _, _, err := s.translatePublicRefToCS3Ref(ctx, req.Ref)
if err != nil {
return &provider.RefreshLockResponse{
Status: st,
Status: status.NewStatusFromErrType(ctx, "failed to resolve reference", err),
}, nil
}
gatewayClient, err := s.gatewaySelector.Next()
@@ -181,13 +171,10 @@ func (s *service) RefreshLock(ctx context.Context, req *provider.RefreshLockRequ
// Unlock removes an existing lock from the given reference
func (s *service) Unlock(ctx context.Context, req *provider.UnlockRequest) (*provider.UnlockResponse, error) {
ref, _, _, st, err := s.translatePublicRefToCS3Ref(ctx, req.Ref)
switch {
case err != nil:
return nil, err
case st != nil:
ref, _, _, err := s.translatePublicRefToCS3Ref(ctx, req.Ref)
if err != nil {
return &provider.UnlockResponse{
Status: st,
Status: status.NewStatusFromErrType(ctx, "failed to resolve reference", err),
}, nil
}
gatewayClient, err := s.gatewaySelector.Next()
@@ -220,26 +207,16 @@ func (s *service) InitiateFileDownload(ctx context.Context, req *provider.Initia
return s.initiateFileDownload(ctx, req)
}
func (s *service) translatePublicRefToCS3Ref(ctx context.Context, ref *provider.Reference) (*provider.Reference, string, *link.PublicShare, *rpc.Status, error) {
func (s *service) translatePublicRefToCS3Ref(ctx context.Context, ref *provider.Reference) (*provider.Reference, *provider.ResourceInfo, string, error) {
log := appctx.GetLogger(ctx)
share, ok := extractLinkFromScope(ctx)
if !ok {
return nil, "", nil, nil, gstatus.Errorf(codes.NotFound, "share or token not found")
}
// the share is minimally populated, we need more than the token
// look up complete share
ls, shareInfo, st, err := s.resolveToken(ctx, share.Token)
switch {
case err != nil:
return nil, "", nil, nil, err
case st != nil:
return nil, "", nil, st, nil
info, _, _, token, err := s.extractLinkFromScope(ctx)
if err != nil {
return nil, nil, "", err
}
var path string
switch shareInfo.Type {
switch info.Type {
case provider.ResourceType_RESOURCE_TYPE_CONTAINER:
// folders point to the folder -> path needs to be added
path = utils.MakeRelativePath(ref.Path)
@@ -252,37 +229,34 @@ func (s *service) translatePublicRefToCS3Ref(ctx context.Context, ref *provider.
}
cs3Ref := &provider.Reference{
ResourceId: shareInfo.Id,
ResourceId: info.Id,
Path: path,
}
log.Debug().
Interface("sourceRef", ref).
Interface("cs3Ref", cs3Ref).
Interface("share", ls).
Str("tkn", share.Token).
Str("originalPath", shareInfo.Path).
Str("tkn", token).
Str("originalPath", info.Path).
Str("relativePath", path).
Msg("translatePublicRefToCS3Ref")
return cs3Ref, share.Token, ls, nil, nil
return cs3Ref, info, token, nil
}
func (s *service) initiateFileDownload(ctx context.Context, req *provider.InitiateFileDownloadRequest) (*provider.InitiateFileDownloadResponse, error) {
cs3Ref, _, ls, st, err := s.translatePublicRefToCS3Ref(ctx, req.Ref)
ref, info, _, err := s.translatePublicRefToCS3Ref(ctx, req.Ref)
switch {
case err != nil:
return nil, err
case st != nil:
return &provider.InitiateFileDownloadResponse{
Status: st,
Status: status.NewStatusFromErrType(ctx, "failed to resolve reference", err),
}, nil
case ls.GetPermissions() == nil || !ls.GetPermissions().Permissions.InitiateFileDownload:
case info.PermissionSet == nil || !info.PermissionSet.InitiateFileDownload:
return &provider.InitiateFileDownloadResponse{
Status: status.NewPermissionDenied(ctx, nil, "share does not grant InitiateFileDownload permission"),
}, nil
}
dReq := &provider.InitiateFileDownloadRequest{
Ref: cs3Ref,
Ref: ref,
}
gatewayClient, err := s.gatewaySelector.Next()
@@ -325,15 +299,13 @@ func (s *service) initiateFileDownload(ctx context.Context, req *provider.Initia
}
func (s *service) InitiateFileUpload(ctx context.Context, req *provider.InitiateFileUploadRequest) (*provider.InitiateFileUploadResponse, error) {
cs3Ref, _, ls, st, err := s.translatePublicRefToCS3Ref(ctx, req.Ref)
cs3Ref, info, _, err := s.translatePublicRefToCS3Ref(ctx, req.Ref)
switch {
case err != nil:
return nil, err
case st != nil:
return &provider.InitiateFileUploadResponse{
Status: st,
Status: status.NewStatusFromErrType(ctx, "failed to resolve reference", err),
}, nil
case ls.GetPermissions() == nil || !ls.GetPermissions().Permissions.InitiateFileUpload:
case info.PermissionSet == nil || !info.PermissionSet.InitiateFileUpload:
return &provider.InitiateFileUploadResponse{
Status: status.NewPermissionDenied(ctx, nil, "share does not grant InitiateFileUpload permission"),
}, nil
@@ -443,12 +415,19 @@ func (s *service) ListStorageSpaces(ctx context.Context, req *provider.ListStora
}
}
// if there is no public scope there are no publicstorage spaces
share, ok := extractLinkFromScope(ctx)
if !ok {
return &provider.ListStorageSpacesResponse{
Status: &rpc.Status{Code: rpc.Code_CODE_OK},
}, nil
info, _, grantee, token, err := s.extractLinkFromScope(ctx)
if err != nil {
switch err.(type) {
case errtypes.NotFound:
// if there is no public scope there are no publicstorage spaces
return &provider.ListStorageSpacesResponse{
Status: &rpc.Status{Code: rpc.Code_CODE_OK},
}, nil
default:
return &provider.ListStorageSpacesResponse{
Status: &rpc.Status{Code: rpc.Code_CODE_INTERNAL},
}, nil
}
}
if len(spaceTypes) == 0 {
@@ -466,7 +445,7 @@ func (s *service) ListStorageSpaces(ctx context.Context, req *provider.ListStora
case "grant":
// when a list storage space with the resourceid of an external
// resource is made we may have a grant for it
root := share.ResourceId
root := info.Id
if spaceID != nil && !utils.ResourceIDEqual(spaceID, root) {
// none of our business
continue
@@ -477,7 +456,7 @@ func (s *service) ListStorageSpaces(ctx context.Context, req *provider.ListStora
OpaqueId: storagespace.FormatResourceID(*root),
},
SpaceType: "grant",
Owner: &userv1beta1.User{Id: share.Owner},
Owner: &userv1beta1.User{Id: grantee},
// the publicstorageprovider keeps track of mount points
Root: root,
}
@@ -487,15 +466,15 @@ func (s *service) ListStorageSpaces(ctx context.Context, req *provider.ListStora
root := &provider.ResourceId{
StorageId: utils.PublicStorageProviderID,
SpaceId: utils.PublicStorageSpaceID,
OpaqueId: share.Token, // the link share has no id, only the token
OpaqueId: token, // the link share has no id, only the token
}
if spaceID != nil {
switch {
case utils.ResourceIDEqual(spaceID, root):
// we have a virtual node
case utils.ResourceIDEqual(spaceID, share.ResourceId):
case utils.ResourceIDEqual(spaceID, info.Id):
// we have a mount point
root = share.ResourceId
root = info.Id
default:
// none of our business
continue
@@ -506,7 +485,7 @@ func (s *service) ListStorageSpaces(ctx context.Context, req *provider.ListStora
OpaqueId: storagespace.FormatResourceID(*root),
},
SpaceType: "mountpoint",
Owner: &userv1beta1.User{Id: share.Owner}, // FIXME actually, the mount point belongs to no one?
Owner: &userv1beta1.User{Id: grantee}, // FIXME actually, the mount point belongs to no one?
// the publicstorageprovider keeps track of mount points
Root: root,
}
@@ -517,27 +496,44 @@ func (s *service) ListStorageSpaces(ctx context.Context, req *provider.ListStora
return res, nil
}
func extractLinkFromScope(ctx context.Context) (*link.PublicShare, bool) {
func (s *service) extractLinkFromScope(ctx context.Context) (*provider.ResourceInfo, interface{}, *userv1beta1.UserId, string, error) {
scopes, ok := ctxpkg.ContextGetScopes(ctx)
if !ok {
return nil, false
return nil, nil, nil, "", errtypes.NotFound("No scopes found in context")
}
var share *link.PublicShare
for k, v := range scopes {
if strings.HasPrefix(k, "publicshare:") && v.Resource.Decoder == "json" {
share = &link.PublicShare{}
if strings.HasPrefix(k, "ocmshare:") && v.Resource.Decoder == "json" {
share := &ocm.Share{}
err := utils.UnmarshalJSONToProtoV1(v.Resource.Value, share)
if err != nil {
continue
return nil, nil, nil, "", errtypes.InternalError("failed to unmarshal public share")
}
// the share is minimally populated, we need more than the token
// look up complete share
info, resolvedShare, err := s.resolveToken(ctx, share)
if err != nil {
return nil, nil, nil, "", err
}
return info, resolvedShare, share.Owner, share.Token, nil
} else if strings.HasPrefix(k, "publicshare:") && v.Resource.Decoder == "json" {
share := &link.PublicShare{}
err := utils.UnmarshalJSONToProtoV1(v.Resource.Value, share)
if err != nil {
return nil, nil, nil, "", errtypes.InternalError("failed to unmarshal public share")
}
// the share is minimally populated, we need more than the token
// look up complete share
info, resolvedShare, err := s.resolveToken(ctx, share)
if err != nil {
return nil, nil, nil, "", err
}
return info, resolvedShare, share.Owner, share.Token, nil
}
}
if share == nil {
return nil, false
}
return share, true
return nil, nil, nil, "", errtypes.NotFound("No public storage info found in scopes")
}
func (s *service) UpdateStorageSpace(ctx context.Context, req *provider.UpdateStorageSpaceRequest) (*provider.UpdateStorageSpaceResponse, error) {
return nil, gstatus.Errorf(codes.Unimplemented, "method not implemented")
}
@@ -555,15 +551,13 @@ func (s *service) CreateContainer(ctx context.Context, req *provider.CreateConta
Value: attribute.StringValue(req.Ref.String()),
})
cs3Ref, _, ls, st, err := s.translatePublicRefToCS3Ref(ctx, req.Ref)
cs3Ref, info, _, err := s.translatePublicRefToCS3Ref(ctx, req.Ref)
switch {
case err != nil:
return nil, err
case st != nil:
return &provider.CreateContainerResponse{
Status: st,
Status: status.NewStatusFromErrType(ctx, "failed to resolve reference", err),
}, nil
case ls.GetPermissions() == nil || !ls.GetPermissions().Permissions.CreateContainer:
case info.PermissionSet == nil || !info.PermissionSet.CreateContainer:
return &provider.CreateContainerResponse{
Status: status.NewPermissionDenied(ctx, nil, "share does not grant CreateContainer permission"),
}, nil
@@ -591,13 +585,10 @@ func (s *service) CreateContainer(ctx context.Context, req *provider.CreateConta
}
func (s *service) TouchFile(ctx context.Context, req *provider.TouchFileRequest) (*provider.TouchFileResponse, error) {
ref, _, _, st, err := s.translatePublicRefToCS3Ref(ctx, req.Ref)
switch {
case err != nil:
return nil, err
case st != nil:
ref, _, _, err := s.translatePublicRefToCS3Ref(ctx, req.Ref)
if err != nil {
return &provider.TouchFileResponse{
Status: st,
Status: status.NewStatusFromErrType(ctx, "failed to resolve reference", err),
}, nil
}
gatewayClient, err := s.gatewaySelector.Next()
@@ -616,15 +607,13 @@ func (s *service) Delete(ctx context.Context, req *provider.DeleteRequest) (*pro
Value: attribute.StringValue(req.Ref.String()),
})
cs3Ref, _, ls, st, err := s.translatePublicRefToCS3Ref(ctx, req.Ref)
cs3Ref, info, _, err := s.translatePublicRefToCS3Ref(ctx, req.Ref)
switch {
case err != nil:
return nil, err
case st != nil:
return &provider.DeleteResponse{
Status: st,
Status: status.NewStatusFromErrType(ctx, "failed to resolve reference", err),
}, nil
case ls.GetPermissions() == nil || !ls.GetPermissions().Permissions.Delete:
case info.PermissionSet == nil || !info.PermissionSet.Delete:
return &provider.DeleteResponse{
Status: status.NewPermissionDenied(ctx, nil, "share does not grant Delete permission"),
}, nil
@@ -666,27 +655,22 @@ func (s *service) Move(ctx context.Context, req *provider.MoveRequest) (*provide
},
)
cs3RefSource, tknSource, ls, st, err := s.translatePublicRefToCS3Ref(ctx, req.Source)
cs3RefSource, info, tknSource, err := s.translatePublicRefToCS3Ref(ctx, req.Source)
switch {
case err != nil:
return nil, err
case st != nil:
return &provider.MoveResponse{
Status: st,
Status: status.NewStatusFromErrType(ctx, "failed to resolve source reference", err),
}, nil
case ls.GetPermissions() == nil || !ls.GetPermissions().Permissions.Move:
case info.PermissionSet == nil || !info.PermissionSet.Move:
return &provider.MoveResponse{
Status: status.NewPermissionDenied(ctx, nil, "share does not grant Move permission"),
}, nil
}
// FIXME: maybe there's a shortcut possible here using the source path
cs3RefDestination, tknDest, _, st, err := s.translatePublicRefToCS3Ref(ctx, req.Destination)
switch {
case err != nil:
return nil, err
case st != nil:
cs3RefDestination, _, tknDest, err := s.translatePublicRefToCS3Ref(ctx, req.Destination)
if err != nil {
return &provider.MoveResponse{
Status: st,
Status: status.NewStatusFromErrType(ctx, "failed to resolve destination reference", err),
}, nil
}
@@ -728,40 +712,31 @@ func (s *service) Stat(ctx context.Context, req *provider.StatRequest) (*provide
Value: attribute.StringValue(req.Ref.String()),
})
share, ok := extractLinkFromScope(ctx)
if !ok {
return &provider.StatResponse{
Status: status.NewNotFound(ctx, "share or token not found"),
}, nil
info, share, _, token, err := s.extractLinkFromScope(ctx)
if err != nil {
switch err.(type) {
case errtypes.NotFound:
return &provider.StatResponse{
Status: status.NewNotFound(ctx, "share or token not found"),
}, nil
default:
return &provider.StatResponse{
Status: status.NewInternal(ctx, "share or token not found"),
}, nil
}
}
// the share is minimally populated, we need more than the token
// look up complete share
share, shareInfo, st, err := s.resolveToken(ctx, share.Token)
switch {
case err != nil:
return nil, err
case st != nil:
return &provider.StatResponse{
Status: st,
}, nil
case share.GetPermissions() == nil || !share.GetPermissions().Permissions.Stat:
return &provider.StatResponse{
Status: status.NewPermissionDenied(ctx, nil, "share does not grant Stat permission"),
}, nil
}
if shareInfo.Type == provider.ResourceType_RESOURCE_TYPE_FILE || req.Ref.Path == "" {
if info.Type == provider.ResourceType_RESOURCE_TYPE_FILE || req.Ref.Path == "" {
res := &provider.StatResponse{
Status: status.NewOK(ctx),
Info: shareInfo,
Info: info,
}
s.augmentStatResponse(ctx, res, shareInfo, share, share.Token)
s.augmentStatResponse(ctx, res.Info, info, share, token)
return res, nil
}
ref := &provider.Reference{
ResourceId: share.ResourceId,
ResourceId: info.Id,
Path: utils.MakeRelativePath(req.Ref.Path),
}
@@ -776,38 +751,38 @@ func (s *service) Stat(ctx context.Context, req *provider.StatRequest) (*provide
}, nil
}
s.augmentStatResponse(ctx, statResponse, shareInfo, share, share.Token)
s.augmentStatResponse(ctx, statResponse.Info, info, share, token)
return statResponse, nil
}
func (s *service) augmentStatResponse(ctx context.Context, res *provider.StatResponse, shareInfo *provider.ResourceInfo, share *link.PublicShare, tkn string) {
func (s *service) augmentStatResponse(ctx context.Context, statInfo *provider.ResourceInfo, shareInfo *provider.ResourceInfo, share interface{}, tkn string) {
// prevent leaking internal paths
if res.Info != nil {
if err := addShare(res.Info, share); err != nil {
appctx.GetLogger(ctx).Error().Err(err).Interface("share", share).Interface("info", res.Info).Msg("error when adding share")
if statInfo != nil {
if err := addShare(statInfo, share); err != nil {
appctx.GetLogger(ctx).Error().Err(err).Interface("share", share).Interface("info", statInfo).Msg("error when adding share")
}
var sharePath string
if shareInfo.Type == provider.ResourceType_RESOURCE_TYPE_FILE {
sharePath = path.Base(shareInfo.Path)
} else {
sharePath = strings.TrimPrefix(res.Info.Path, shareInfo.Path)
sharePath = strings.TrimPrefix(statInfo.Path, shareInfo.Path)
}
res.Info.Path = path.Join("/", sharePath)
filterPermissions(res.Info.PermissionSet, share.GetPermissions().Permissions)
statInfo.Path = path.Join("/", sharePath)
filterPermissions(statInfo.PermissionSet, shareInfo.PermissionSet)
}
}
func addShare(i *provider.ResourceInfo, ls *link.PublicShare) error {
func addShare(i *provider.ResourceInfo, share interface{}) error {
if i.Opaque == nil {
i.Opaque = &typesv1beta1.Opaque{}
}
if i.Opaque.Map == nil {
i.Opaque.Map = map[string]*typesv1beta1.OpaqueEntry{}
}
val, err := json.Marshal(ls)
val, err := json.Marshal(share)
if err != nil {
return err
}
@@ -820,25 +795,20 @@ func (s *service) ListContainerStream(req *provider.ListContainerStreamRequest,
}
func (s *service) ListContainer(ctx context.Context, req *provider.ListContainerRequest) (*provider.ListContainerResponse, error) {
share, ok := extractLinkFromScope(ctx)
if !ok {
return &provider.ListContainerResponse{
Status: status.NewNotFound(ctx, "share or token not found"),
}, nil
info, share, _, _, err := s.extractLinkFromScope(ctx)
if err != nil {
switch err.(type) {
case errtypes.NotFound:
return &provider.ListContainerResponse{
Status: status.NewNotFound(ctx, "share or token not found"),
}, nil
default:
return &provider.ListContainerResponse{
Status: status.NewInternal(ctx, "share or token not found"),
}, nil
}
}
// the share is minimally populated, we need more than the token
// look up complete share
share, _, st, err := s.resolveToken(ctx, share.Token)
switch {
case err != nil:
return nil, err
case st != nil:
return &provider.ListContainerResponse{
Status: st,
}, nil
}
if share.GetPermissions() == nil || !share.GetPermissions().Permissions.ListContainer {
if info.PermissionSet == nil || !info.PermissionSet.ListContainer {
return &provider.ListContainerResponse{
Status: status.NewPermissionDenied(ctx, nil, "share does not grant ListContainer permission"),
}, nil
@@ -852,7 +822,7 @@ func (s *service) ListContainer(ctx context.Context, req *provider.ListContainer
ctx,
&provider.ListContainerRequest{
Ref: &provider.Reference{
ResourceId: share.ResourceId,
ResourceId: info.Id,
// prefix relative path with './' to make it a CS3 relative path
Path: utils.MakeRelativePath(req.Ref.Path),
},
@@ -867,7 +837,7 @@ func (s *service) ListContainer(ctx context.Context, req *provider.ListContainer
for i := range listContainerR.Infos {
// FIXME how do we reduce permissions to what is granted by the public link?
// only a problem for id based access -> middleware
filterPermissions(listContainerR.Infos[i].PermissionSet, share.GetPermissions().Permissions)
filterPermissions(listContainerR.Infos[i].PermissionSet, info.PermissionSet)
if err := addShare(listContainerR.Infos[i], share); err != nil {
appctx.GetLogger(ctx).Error().Err(err).Interface("share", share).Interface("info", listContainerR.Infos[i]).Msg("error when adding share")
}
@@ -953,45 +923,70 @@ func (s *service) GetQuota(ctx context.Context, req *provider.GetQuotaRequest) (
return nil, gstatus.Errorf(codes.Unimplemented, "method not implemented")
}
// resolveToken returns the path and share for the publicly shared resource.
func (s *service) resolveToken(ctx context.Context, token string) (*link.PublicShare, *provider.ResourceInfo, *rpc.Status, error) {
driver, err := pool.GetGatewayServiceClient(s.conf.GatewayAddr)
if err != nil {
return nil, nil, nil, err
}
publicShareResponse, err := driver.GetPublicShare(
ctx,
&link.GetPublicShareRequest{
Ref: &link.PublicShareReference{
Spec: &link.PublicShareReference_Token{
Token: token,
},
},
Sign: true,
},
)
switch {
case err != nil:
return nil, nil, nil, err
case publicShareResponse.Status.Code != rpc.Code_CODE_OK:
return nil, nil, publicShareResponse.Status, nil
}
// resolveToken returns the resource info for the publicly shared resource.
func (s *service) resolveToken(ctx context.Context, share interface{}) (*provider.ResourceInfo, interface{}, error) {
gatewayClient, err := s.gatewaySelector.Next()
if err != nil {
return nil, nil, nil, err
return nil, nil, err
}
resourceID := &provider.ResourceId{}
perms := &provider.ResourcePermissions{}
var resolvedShare interface{}
switch v := share.(type) {
case *link.PublicShare:
publicShareResponse, err := gatewayClient.GetPublicShare(
ctx,
&link.GetPublicShareRequest{
Ref: &link.PublicShareReference{
Spec: &link.PublicShareReference_Token{
Token: v.Token,
},
},
Sign: true,
},
)
switch {
case err != nil:
return nil, nil, err
case publicShareResponse.Status.Code != rpc.Code_CODE_OK:
return nil, nil, errtypes.NewErrtypeFromStatus(publicShareResponse.Status)
}
resolvedShare = publicShareResponse.GetShare()
resourceID = publicShareResponse.GetShare().GetResourceId()
perms = publicShareResponse.GetShare().GetPermissions().GetPermissions()
case *ocm.Share:
gsr, err := gatewayClient.GetOCMShareByToken(ctx, &ocm.GetOCMShareByTokenRequest{
Token: v.Token,
})
switch {
case err != nil:
return nil, nil, err
case gsr.Status.Code != rpc.Code_CODE_OK:
return nil, nil, errtypes.NewErrtypeFromStatus(gsr.Status)
}
accessMethods := gsr.GetShare().GetAccessMethods()
if len(accessMethods) == 0 {
return nil, nil, errtypes.PermissionDenied("failed to get access to the requested resource")
}
resolvedShare = gsr.GetShare()
resourceID = gsr.GetShare().GetResourceId()
perms = accessMethods[0].GetWebdavOptions().Permissions
}
sRes, err := gatewayClient.Stat(ctx, &provider.StatRequest{
Ref: &provider.Reference{
ResourceId: publicShareResponse.GetShare().GetResourceId(),
ResourceId: resourceID,
},
})
switch {
case err != nil:
return nil, nil, nil, err
return nil, nil, err
case sRes.Status.Code != rpc.Code_CODE_OK:
return nil, nil, sRes.Status, nil
return nil, nil, errtypes.NewErrtypeFromStatus(sRes.Status)
}
return publicShareResponse.GetShare(), sRes.Info, nil, nil
// Set permissions
sRes.Info.PermissionSet = perms
return sRes.Info, resolvedShare, nil
}

View File

@@ -246,7 +246,10 @@ func (s *service) ListReceivedShares(ctx context.Context, req *collaboration.Lis
if !foundExclude {
req.Filters = append(req.Filters, &collaboration.Filter{Type: collaboration.Filter_TYPE_EXCLUDE_DENIALS})
}
shares, err := s.sm.ListReceivedShares(ctx, req.Filters) // TODO(labkode): check what to update
var uid userpb.UserId
_ = utils.ReadJSONFromOpaque(req.Opaque, "userid", &uid)
shares, err := s.sm.ListReceivedShares(ctx, req.Filters, &uid) // TODO(labkode): check what to update
if err != nil {
return &collaboration.ListReceivedSharesResponse{
Status: status.NewInternal(ctx, "error listing received shares"),

View File

@@ -27,6 +27,7 @@ import (
"time"
"github.com/bluele/gcache"
authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
@@ -69,7 +70,7 @@ type config struct {
CredentialsByUserAgent map[string]string `mapstructure:"credentials_by_user_agent"`
CredentialChain []string `mapstructure:"credential_chain"`
CredentialStrategies map[string]map[string]interface{} `mapstructure:"credential_strategies"`
TokenStrategy string `mapstructure:"token_strategy"`
TokenStrategyChain []string `mapstructure:"token_strategy_chain"`
TokenStrategies map[string]map[string]interface{} `mapstructure:"token_strategies"`
TokenManager string `mapstructure:"token_manager"`
TokenManagers map[string]map[string]interface{} `mapstructure:"token_managers"`
@@ -97,8 +98,8 @@ func New(m map[string]interface{}, unprotected []string, tp trace.TracerProvider
conf.GatewaySvc = sharedconf.GetGatewaySVC(conf.GatewaySvc)
// set defaults
if conf.TokenStrategy == "" {
conf.TokenStrategy = "header"
if len(conf.TokenStrategyChain) == 0 {
conf.TokenStrategyChain = []string{"header"}
}
if conf.TokenWriter == "" {
@@ -109,10 +110,6 @@ func New(m map[string]interface{}, unprotected []string, tp trace.TracerProvider
conf.TokenManager = "jwt"
}
if len(conf.CredentialChain) == 0 {
conf.CredentialChain = []string{"basic", "bearer"}
}
if conf.CredentialsByUserAgent == nil {
conf.CredentialsByUserAgent = map[string]string{}
}
@@ -139,19 +136,22 @@ func New(m map[string]interface{}, unprotected []string, tp trace.TracerProvider
credChain[key] = credStrategy
}
g, ok := tokenregistry.NewTokenFuncs[conf.TokenStrategy]
if !ok {
return nil, fmt.Errorf("token strategy not found: %s", conf.TokenStrategy)
}
tokenStrategy, err := g(conf.TokenStrategies[conf.TokenStrategy])
if err != nil {
return nil, err
tokenStrategyChain := make([]auth.TokenStrategy, 0, len(conf.TokenStrategyChain))
for _, strategy := range conf.TokenStrategyChain {
g, ok := tokenregistry.NewTokenFuncs[strategy]
if !ok {
return nil, fmt.Errorf("token strategy not found: %s", strategy)
}
tokenStrategy, err := g(conf.TokenStrategies[strategy])
if err != nil {
return nil, err
}
tokenStrategyChain = append(tokenStrategyChain, tokenStrategy)
}
h, ok := tokenmgr.NewFuncs[conf.TokenManager]
if !ok {
return nil, fmt.Errorf("token manager not found: %s", conf.TokenStrategy)
return nil, fmt.Errorf("token manager not found: %s", conf.TokenManager)
}
tokenManager, err := h(conf.TokenManagers[conf.TokenManager])
@@ -196,7 +196,7 @@ func New(m map[string]interface{}, unprotected []string, tp trace.TracerProvider
isUnprotectedEndpoint = true
}
ctx, err := authenticateUser(w, r, conf, tokenStrategy, tokenManager, tokenWriter, credChain, isUnprotectedEndpoint)
ctx, err := authenticateUser(w, r, conf, tokenStrategyChain, tokenManager, tokenWriter, credChain, isUnprotectedEndpoint)
if err != nil {
if !isUnprotectedEndpoint {
return
@@ -216,7 +216,7 @@ func New(m map[string]interface{}, unprotected []string, tp trace.TracerProvider
return chain, nil
}
func authenticateUser(w http.ResponseWriter, r *http.Request, conf *config, tokenStrategy auth.TokenStrategy, tokenManager token.Manager, tokenWriter auth.TokenWriter, credChain map[string]auth.CredentialStrategy, isUnprotectedEndpoint bool) (context.Context, error) {
func authenticateUser(w http.ResponseWriter, r *http.Request, conf *config, tokenStrategies []auth.TokenStrategy, tokenManager token.Manager, tokenWriter auth.TokenWriter, credChain map[string]auth.CredentialStrategy, isUnprotectedEndpoint bool) (context.Context, error) {
ctx := r.Context()
log := appctx.GetLogger(ctx)
@@ -229,71 +229,85 @@ func authenticateUser(w http.ResponseWriter, r *http.Request, conf *config, toke
return nil, err
}
tkn := tokenStrategy.GetToken(r)
if tkn == "" {
log.Warn().Msg("core access token not set")
userAgentCredKeys := getCredsForUserAgent(r.UserAgent(), conf.CredentialsByUserAgent, conf.CredentialChain)
// obtain credentials (basic auth, bearer token, ...) based on user agent
var creds *auth.Credentials
for _, k := range userAgentCredKeys {
creds, err = credChain[k].GetCredentials(w, r)
if err != nil {
log.Debug().Err(err).Msg("error retrieving credentials")
}
if creds != nil {
log.Debug().Msgf("credentials obtained from credential strategy: type: %s, client_id: %s", creds.Type, creds.ClientID)
break
}
}
// if no credentials are found, reply with authentication challenge depending on user agent
if creds == nil {
if !isUnprotectedEndpoint {
for _, key := range userAgentCredKeys {
if cred, ok := credChain[key]; ok {
cred.AddWWWAuthenticate(w, r, conf.Realm)
} else {
panic("auth credential strategy: " + key + "must have been loaded in init method")
}
// reva token or auth token can be passed using the same technique (for example bearer)
// before validating it against an auth provider, we can check directly if it's a reva
// token and if not try to use it for authenticating the user.
for _, tokenStrategy := range tokenStrategies {
token := tokenStrategy.GetToken(r)
if token != "" {
if user, tokenScope, ok := isTokenValid(r, tokenManager, token); ok {
if err := insertGroupsInUser(ctx, userGroupsCache, client, user); err != nil {
logError(isUnprotectedEndpoint, log, err, "got an error retrieving groups for user "+user.Username, http.StatusInternalServerError, w)
return nil, err
}
w.WriteHeader(http.StatusUnauthorized)
return ctxWithUserInfo(ctx, r, user, token, tokenScope), nil
}
return nil, errtypes.PermissionDenied("no credentials found")
}
req := &gateway.AuthenticateRequest{
Type: creds.Type,
ClientId: creds.ClientID,
ClientSecret: creds.ClientSecret,
}
log.Debug().Msgf("AuthenticateRequest: type: %s, client_id: %s against %s", req.Type, req.ClientId, conf.GatewaySvc)
res, err := client.Authenticate(ctx, req)
if err != nil {
logError(isUnprotectedEndpoint, log, err, "error calling Authenticate", http.StatusUnauthorized, w)
return nil, err
}
if res.Status.Code != rpc.Code_CODE_OK {
err := status.NewErrorFromCode(res.Status.Code, "auth")
logError(isUnprotectedEndpoint, log, err, "error generating access token from credentials", http.StatusUnauthorized, w)
return nil, err
}
log.Info().Msg("core access token generated")
// write token to response
tkn = res.Token
tokenWriter.WriteToken(tkn, w)
} else {
log.Debug().Msg("access token is already provided")
}
log.Warn().Msg("core access token not set")
userAgentCredKeys := getCredsForUserAgent(r.UserAgent(), conf.CredentialsByUserAgent, conf.CredentialChain)
// obtain credentials (basic auth, bearer token, ...) based on user agent
var creds *auth.Credentials
for _, k := range userAgentCredKeys {
creds, err = credChain[k].GetCredentials(w, r)
if err != nil {
log.Debug().Err(err).Msg("error retrieving credentials")
}
if creds != nil {
log.Debug().Msgf("credentials obtained from credential strategy: type: %s, client_id: %s", creds.Type, creds.ClientID)
break
}
}
// if no credentials are found, reply with authentication challenge depending on user agent
if creds == nil {
if !isUnprotectedEndpoint {
for _, key := range userAgentCredKeys {
if cred, ok := credChain[key]; ok {
cred.AddWWWAuthenticate(w, r, conf.Realm)
} else {
log.Error().Msg("auth credential strategy: " + key + "must have been loaded in init method")
w.WriteHeader(http.StatusInternalServerError)
return nil, errtypes.InternalError("no credentials found")
}
}
w.WriteHeader(http.StatusUnauthorized)
}
return nil, errtypes.PermissionDenied("no credentials found")
}
req := &gateway.AuthenticateRequest{
Type: creds.Type,
ClientId: creds.ClientID,
ClientSecret: creds.ClientSecret,
}
log.Debug().Msgf("AuthenticateRequest: type: %s, client_id: %s against %s", req.Type, req.ClientId, conf.GatewaySvc)
res, err := client.Authenticate(ctx, req)
if err != nil {
logError(isUnprotectedEndpoint, log, err, "error calling Authenticate", http.StatusUnauthorized, w)
return nil, err
}
if res.Status.Code != rpc.Code_CODE_OK {
err := status.NewErrorFromCode(res.Status.Code, "auth")
logError(isUnprotectedEndpoint, log, err, "error generating access token from credentials", http.StatusUnauthorized, w)
return nil, err
}
log.Info().Msg("core access token generated") // write token to response
// write token to response
token := res.Token
tokenWriter.WriteToken(token, w)
// validate token
u, tokenScope, err := tokenManager.DismantleToken(r.Context(), tkn)
u, tokenScope, err := tokenManager.DismantleToken(r.Context(), token)
if err != nil {
logError(isUnprotectedEndpoint, log, err, "error dismantling token", http.StatusUnauthorized, w)
return nil, err
@@ -329,15 +343,59 @@ func authenticateUser(w http.ResponseWriter, r *http.Request, conf *config, toke
// store user and core access token in context.
ctx = ctxpkg.ContextSetUser(ctx, u)
ctx = ctxpkg.ContextSetToken(ctx, tkn)
ctx = metadata.AppendToOutgoingContext(ctx, ctxpkg.TokenHeader, tkn) // TODO(jfd): hardcoded metadata key. use PerRPCCredentials?
ctx = ctxpkg.ContextSetToken(ctx, token)
ctx = metadata.AppendToOutgoingContext(ctx, ctxpkg.TokenHeader, token) // TODO(jfd): hardcoded metadata key. use PerRPCCredentials?
ctx = metadata.AppendToOutgoingContext(ctx, ctxpkg.UserAgentHeader, r.UserAgent())
// store scopes in context
ctx = ctxpkg.ContextSetScopes(ctx, tokenScope)
return ctx, nil
return ctxWithUserInfo(ctx, r, u, token, tokenScope), nil
}
func ctxWithUserInfo(ctx context.Context, r *http.Request, user *userpb.User, token string, tokenScope map[string]*authpb.Scope) context.Context {
ctx = ctxpkg.ContextSetUser(ctx, user)
ctx = ctxpkg.ContextSetToken(ctx, token)
ctx = metadata.AppendToOutgoingContext(ctx, ctxpkg.TokenHeader, token)
ctx = metadata.AppendToOutgoingContext(ctx, ctxpkg.UserAgentHeader, r.UserAgent())
ctx = ctxpkg.ContextSetScopes(ctx, tokenScope)
return ctx
}
func insertGroupsInUser(ctx context.Context, userGroupsCache gcache.Cache, client gateway.GatewayAPIClient, user *userpb.User) error {
if sharedconf.SkipUserGroupsInToken() {
var groups []string
if groupsIf, err := userGroupsCache.Get(user.Id.OpaqueId); err == nil {
groups = groupsIf.([]string)
} else {
groupsRes, err := client.GetUserGroups(ctx, &userpb.GetUserGroupsRequest{UserId: user.Id})
if err != nil {
return err
}
groups = groupsRes.Groups
_ = userGroupsCache.SetWithExpire(user.Id.OpaqueId, groupsRes.Groups, 3600*time.Second)
}
user.Groups = groups
}
return nil
}
func isTokenValid(r *http.Request, tokenManager token.Manager, token string) (*userpb.User, map[string]*authpb.Scope, bool) {
ctx := r.Context()
u, tokenScope, err := tokenManager.DismantleToken(ctx, token)
if err != nil {
return nil, nil, false
}
// ensure access to the resource is allowed
ok, err := scope.VerifyScope(ctx, tokenScope, r.URL.Path)
if err != nil {
return nil, nil, false
}
return u, tokenScope, ok
}
func logError(isUnprotectedEndpoint bool, log *zerolog.Logger, err error, msg string, status int, w http.ResponseWriter) {

View File

@@ -22,5 +22,6 @@ import (
// Load core authentication strategies.
_ "github.com/cs3org/reva/v2/internal/http/interceptors/auth/credential/strategy/basic"
_ "github.com/cs3org/reva/v2/internal/http/interceptors/auth/credential/strategy/bearer"
_ "github.com/cs3org/reva/v2/internal/http/interceptors/auth/credential/strategy/ocmshares"
// Add your own here.
)

View File

@@ -0,0 +1,58 @@
// Copyright 2018-2023 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 ocmshares
import (
"fmt"
"net/http"
"github.com/cs3org/reva/v2/internal/http/interceptors/auth/credential/registry"
"github.com/cs3org/reva/v2/pkg/auth"
)
func init() {
registry.Register("ocmshares", New)
}
const (
headerShareToken = "ocm-token"
)
type strategy struct{}
// New returns a new auth strategy that handles public share verification.
func New(m map[string]interface{}) (auth.CredentialStrategy, error) {
return &strategy{}, nil
}
func (s *strategy) GetCredentials(w http.ResponseWriter, r *http.Request) (*auth.Credentials, error) {
token := r.Header.Get(headerShareToken)
if token == "" {
token = r.URL.Query().Get(headerShareToken)
}
if token == "" {
return nil, fmt.Errorf("no ocm token provided")
}
return &auth.Credentials{Type: "ocmshares", ClientID: token}, nil
}
func (s *strategy) AddWWWAuthenticate(w http.ResponseWriter, r *http.Request, realm string) {
// TODO read realm from forwarded header?
}

View File

@@ -20,6 +20,7 @@ package loader
import (
// Load core token strategies.
_ "github.com/cs3org/reva/v2/internal/http/interceptors/auth/token/strategy/bearer"
_ "github.com/cs3org/reva/v2/internal/http/interceptors/auth/token/strategy/header"
// Add your own here.
)

View File

@@ -0,0 +1,84 @@
// Copyright 2018-2023 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 header
import (
"mime"
"net/http"
"strings"
"github.com/cs3org/reva/v2/internal/http/interceptors/auth/token/registry"
"github.com/cs3org/reva/v2/pkg/auth"
)
func init() {
registry.Register("bearer", New)
}
type b struct{}
// New returns a new auth strategy that checks for bearer auth.
func New(m map[string]interface{}) (auth.TokenStrategy, error) {
return b{}, nil
}
func (b) GetToken(r *http.Request) string {
// Authorization Request Header Field: https://www.rfc-editor.org/rfc/rfc6750#section-2.1
if tkn, ok := getFromAuthorizationHeader(r); ok {
return tkn
}
// Form-Encoded Body Parameter: https://www.rfc-editor.org/rfc/rfc6750#section-2.2
if tkn, ok := getFromBody(r); ok {
return tkn
}
// URI Query Parameter: https://www.rfc-editor.org/rfc/rfc6750#section-2.3
if tkn, ok := getFromQueryParam(r); ok {
return tkn
}
return ""
}
func getFromAuthorizationHeader(r *http.Request) (string, bool) {
auth := r.Header.Get("Authorization")
tkn := strings.TrimPrefix(auth, "Bearer ")
return tkn, tkn != ""
}
func getFromBody(r *http.Request) (string, bool) {
mediatype, _, err := mime.ParseMediaType(r.Header.Get("content-type"))
if err != nil {
return "", false
}
if mediatype != "application/x-www-form-urlencoded" {
return "", false
}
if err = r.ParseForm(); err != nil {
return "", false
}
tkn := r.Form.Get("access-token")
return tkn, tkn != ""
}
func getFromQueryParam(r *http.Request) (string, bool) {
tkn := r.URL.Query().Get("access_token")
return tkn, tkn != ""
}

View File

@@ -44,7 +44,7 @@ import (
var tracer trace.Tracer
func init() {
tracer = otel.Tracer("github.com/cs3org/reva/pkg/storage/utils/decomposedfs/tree")
tracer = otel.Tracer("github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/tree")
}
const (
@@ -324,6 +324,7 @@ func (s *svc) doPut(w http.ResponseWriter, r *http.Request) {
return
}
httpReq.Header = r.Header
httpReq.ContentLength = r.ContentLength
httpRes, err := httpClient.Do(httpReq)
if err != nil {

View File

@@ -26,7 +26,6 @@ import (
_ "github.com/cs3org/reva/v2/internal/http/services/dataprovider"
_ "github.com/cs3org/reva/v2/internal/http/services/helloworld"
_ "github.com/cs3org/reva/v2/internal/http/services/mentix"
_ "github.com/cs3org/reva/v2/internal/http/services/meshdirectory"
_ "github.com/cs3org/reva/v2/internal/http/services/metrics"
_ "github.com/cs3org/reva/v2/internal/http/services/ocmd"
_ "github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav"
@@ -34,6 +33,7 @@ import (
_ "github.com/cs3org/reva/v2/internal/http/services/preferences"
_ "github.com/cs3org/reva/v2/internal/http/services/prometheus"
_ "github.com/cs3org/reva/v2/internal/http/services/reverseproxy"
_ "github.com/cs3org/reva/v2/internal/http/services/sciencemesh"
_ "github.com/cs3org/reva/v2/internal/http/services/siteacc"
_ "github.com/cs3org/reva/v2/internal/http/services/sysinfo"
_ "github.com/cs3org/reva/v2/internal/http/services/wellknown"

View File

@@ -1,155 +0,0 @@
// Copyright 2018-2021 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 meshdirectory
import (
"encoding/json"
"fmt"
"net/http"
meshdirectoryweb "github.com/sciencemesh/meshdirectory-web"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
providerv1beta1 "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
"github.com/cs3org/reva/v2/internal/http/services/ocmd"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/v2/pkg/rhttp/router"
"github.com/cs3org/reva/v2/pkg/sharedconf"
"github.com/pkg/errors"
"github.com/rs/zerolog"
"github.com/cs3org/reva/v2/pkg/rhttp/global"
"github.com/mitchellh/mapstructure"
)
func init() {
global.Register("meshdirectory", New)
}
type config struct {
Prefix string `mapstructure:"prefix"`
GatewaySvc string `mapstructure:"gatewaysvc"`
}
func (c *config) init() {
c.GatewaySvc = sharedconf.GetGatewaySVC(c.GatewaySvc)
if c.Prefix == "" {
c.Prefix = "meshdir"
}
}
type svc struct {
conf *config
}
func parseConfig(m map[string]interface{}) (*config, error) {
c := &config{}
if err := mapstructure.Decode(m, c); err != nil {
err = errors.Wrap(err, "error decoding conf")
return nil, err
}
return c, nil
}
// New returns a new Mesh Directory HTTP service
func New(m map[string]interface{}, log *zerolog.Logger) (global.Service, error) {
c, err := parseConfig(m)
if err != nil {
return nil, err
}
c.init()
service := &svc{
conf: c,
}
return service, nil
}
// Service prefix
func (s *svc) Prefix() string {
return s.conf.Prefix
}
// Unprotected endpoints
func (s *svc) Unprotected() []string {
return []string{"/"}
}
// Close performs cleanup.
func (s *svc) Close() error {
return nil
}
func (s *svc) getClient() (gateway.GatewayAPIClient, error) {
return pool.GetGatewayServiceClient(s.conf.GatewaySvc)
}
func (s *svc) serveJSON(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
ctx := r.Context()
gatewayClient, err := s.getClient()
if err != nil {
ocmd.WriteError(w, r, ocmd.APIErrorServerError,
fmt.Sprintf("error getting grpc client on addr: %v", s.conf.GatewaySvc), err)
return
}
providers, err := gatewayClient.ListAllProviders(ctx, &providerv1beta1.ListAllProvidersRequest{})
if err != nil {
ocmd.WriteError(w, r, ocmd.APIErrorServerError, "error listing all providers", err)
return
}
jsonResponse, err := json.Marshal(providers.Providers)
if err != nil {
ocmd.WriteError(w, r, ocmd.APIErrorServerError, "error marshalling providers data", err)
return
}
// Write response
_, err = w.Write(jsonResponse)
if err != nil {
ocmd.WriteError(w, r, ocmd.APIErrorServerError, "error writing providers data", err)
return
}
w.WriteHeader(http.StatusOK)
}
// HTTP service handler
func (s *svc) Handler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var head string
head, r.URL.Path = router.ShiftPath(r.URL.Path)
switch head {
case "providers":
s.serveJSON(w, r)
return
default:
r.URL.Path = head + r.URL.Path
meshdirectoryweb.ServeMeshDirectorySPA(w, r)
return
}
})
}

View File

@@ -1,90 +0,0 @@
// Copyright 2018-2021 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 ocmd
import (
"encoding/json"
"fmt"
"net/http"
"github.com/cs3org/reva/v2/pkg/appctx"
)
type configData struct {
Enabled bool `json:"enabled" xml:"enabled"`
APIVersion string `json:"apiVersion" xml:"apiVersion"`
Host string `json:"host" xml:"host"`
Endpoint string `json:"endPoint" xml:"endPoint"`
Provider string `json:"provider" xml:"provider"`
ResourceTypes []resourceTypes `json:"resourceTypes" xml:"resourceTypes"`
}
type resourceTypes struct {
Name string `json:"name"`
ShareTypes []string `json:"shareTypes"`
Protocols resourceTypesProtocols `json:"protocols"`
}
type resourceTypesProtocols struct {
Webdav string `json:"webdav"`
}
type configHandler struct {
c configData
}
func (h *configHandler) init(c *Config) {
h.c = c.Config
if h.c.APIVersion == "" {
h.c.APIVersion = "1.0-proposal1"
}
if h.c.Host == "" {
h.c.Host = "localhost"
}
if h.c.Provider == "" {
h.c.Provider = "cernbox"
}
h.c.Enabled = true
if len(c.Prefix) > 0 {
h.c.Endpoint = fmt.Sprintf("https://%s/%s", h.c.Host, c.Prefix)
} else {
h.c.Endpoint = fmt.Sprintf("https://%s", h.c.Host)
}
h.c.ResourceTypes = []resourceTypes{{
Name: "file",
ShareTypes: []string{"user"},
Protocols: resourceTypesProtocols{
Webdav: fmt.Sprintf("/%s/ocm_webdav", h.c.Provider),
},
}}
}
func (h *configHandler) Handler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log := appctx.GetLogger(r.Context())
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
indentedConf, _ := json.MarshalIndent(h.c, "", " ")
if _, err := w.Write(indentedConf); err != nil {
log.Err(err).Msg("Error writing to ResponseWriter")
}
})
}

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 CERN
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -22,323 +22,158 @@ import (
"encoding/json"
"errors"
"fmt"
"io"
"mime"
"net/http"
"net/url"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
invitepb "github.com/cs3org/go-cs3apis/cs3/ocm/invite/v1beta1"
ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
"github.com/cs3org/reva/v2/internal/http/services/reqres"
"github.com/cs3org/reva/v2/pkg/appctx"
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/v2/pkg/rhttp/router"
"github.com/cs3org/reva/v2/pkg/smtpclient"
"github.com/cs3org/reva/v2/pkg/utils"
)
type invitesHandler struct {
smtpCredentials *smtpclient.SMTPCredentials
gatewayAddr string
meshDirectoryURL string
gatewaySelector *pool.Selector[gateway.GatewayAPIClient]
}
func (h *invitesHandler) init(c *Config) {
h.gatewayAddr = c.GatewaySvc
if c.SMTPCredentials != nil {
h.smtpCredentials = smtpclient.NewSMTPCredentials(c.SMTPCredentials)
func (h *invitesHandler) init(c *config) error {
var err error
gatewaySelector, err := pool.GatewaySelector(c.GatewaySvc)
if err != nil {
return err
}
h.meshDirectoryURL = c.MeshDirectoryURL
h.gatewaySelector = gatewaySelector
return nil
}
func (h *invitesHandler) Handler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log := appctx.GetLogger(r.Context())
var head string
head, r.URL.Path = router.ShiftPath(r.URL.Path)
log.Debug().Str("head", head).Str("tail", r.URL.Path).Msg("http routing")
switch head {
case "":
h.generateInviteToken(w, r)
case "forward":
h.forwardInvite(w, r)
case "accept":
h.acceptInvite(w, r)
case "find-accepted-users":
h.findAcceptedUsers(w, r)
case "generate":
h.generate(w, r)
default:
w.WriteHeader(http.StatusNotFound)
}
})
type acceptInviteRequest struct {
Token string `json:"token"`
UserID string `json:"userID"`
RecipientProvider string `json:"recipientProvider"`
Name string `json:"name"`
Email string `json:"email"`
}
func (h *invitesHandler) generateInviteToken(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
gatewayClient, err := pool.GetGatewayServiceClient(h.gatewayAddr)
if err != nil {
WriteError(w, r, APIErrorServerError, "error getting gateway grpc client", err)
return
}
token, err := gatewayClient.GenerateInviteToken(ctx, &invitepb.GenerateInviteTokenRequest{})
if err != nil {
WriteError(w, r, APIErrorServerError, "error generating token", err)
return
}
if r.FormValue("recipient") != "" && h.smtpCredentials != nil {
usr := ctxpkg.ContextMustGetUser(ctx)
// TODO: the message body needs to point to the meshdirectory service
subject := fmt.Sprintf("ScienceMesh: %s wants to collaborate with you", usr.DisplayName)
body := "Hi,\n\n" +
usr.DisplayName + " (" + usr.Mail + ") wants to start sharing OCM resources with you. " +
"To accept the invite, please visit the following URL:\n" +
h.meshDirectoryURL + "?token=" + token.InviteToken.Token + "&providerDomain=" + usr.Id.Idp + "\n\n" +
"Alternatively, you can visit your mesh provider and use the following details:\n" +
"Token: " + token.InviteToken.Token + "\n" +
"ProviderDomain: " + usr.Id.Idp + "\n\n" +
"Best,\nThe ScienceMesh team"
err = h.smtpCredentials.SendMail(r.FormValue("recipient"), subject, body)
if err != nil {
WriteError(w, r, APIErrorServerError, "error sending token by mail", err)
return
}
}
jsonResponse, err := json.Marshal(token.InviteToken)
if err != nil {
WriteError(w, r, APIErrorServerError, "error marshalling token data", err)
return
}
// Write response
_, err = w.Write(jsonResponse)
if err != nil {
WriteError(w, r, APIErrorServerError, "error writing token data", err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
}
func (h *invitesHandler) forwardInvite(w http.ResponseWriter, r *http.Request) {
// 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) {
ctx := r.Context()
log := appctx.GetLogger(ctx)
contentType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
var token, providerDomain string
if err == nil && contentType == "application/json" {
defer r.Body.Close()
reqBody, err := io.ReadAll(r.Body)
if err == nil {
reqMap := make(map[string]string)
err = json.Unmarshal(reqBody, &reqMap)
if err == nil {
token, providerDomain = reqMap["token"], reqMap["providerDomain"]
}
}
} else {
token, providerDomain = r.FormValue("token"), r.FormValue("providerDomain")
}
if token == "" || providerDomain == "" {
WriteError(w, r, APIErrorInvalidParameter, "token and providerDomain must not be null", nil)
return
}
gatewayClient, err := pool.GetGatewayServiceClient(h.gatewayAddr)
req, err := getAcceptInviteRequest(r)
if err != nil {
WriteError(w, r, APIErrorServerError, "error getting gateway grpc client", err)
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "missing parameters in request", err)
return
}
inviteToken := &invitepb.InviteToken{
Token: token,
}
providerInfo, err := gatewayClient.GetInfoByDomain(ctx, &ocmprovider.GetInfoByDomainRequest{
Domain: providerDomain,
})
if err != nil {
WriteError(w, r, APIErrorServerError, "error sending a grpc get invite by domain info request", err)
return
}
if providerInfo.Status.Code != rpc.Code_CODE_OK {
WriteError(w, r, APIErrorServerError, "grpc forward invite request failed", errors.New(providerInfo.Status.Message))
return
}
forwardInviteReq := &invitepb.ForwardInviteRequest{
InviteToken: inviteToken,
OriginSystemProvider: providerInfo.ProviderInfo,
}
forwardInviteResponse, err := gatewayClient.ForwardInvite(ctx, forwardInviteReq)
if err != nil {
WriteError(w, r, APIErrorServerError, "error sending a grpc forward invite request", err)
return
}
if forwardInviteResponse.Status.Code != rpc.Code_CODE_OK {
WriteError(w, r, APIErrorServerError, "grpc forward invite request failed", errors.New(forwardInviteResponse.Status.Message))
return
}
_, err = w.Write([]byte("Accepted invite from: " + providerDomain))
if err != nil {
WriteError(w, r, APIErrorServerError, "error writing token data", err)
return
}
w.WriteHeader(http.StatusOK)
log.Info().Msgf("Invite forwarded to: %s", providerDomain)
}
func (h *invitesHandler) acceptInvite(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
log := appctx.GetLogger(ctx)
contentType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
var token, userID, recipientProvider, name, email string
if err == nil && contentType == "application/json" {
defer r.Body.Close()
reqBody, err := io.ReadAll(r.Body)
if err == nil {
reqMap := make(map[string]string)
err = json.Unmarshal(reqBody, &reqMap)
if err == nil {
token, userID, recipientProvider = reqMap["token"], reqMap["userID"], reqMap["recipientProvider"]
name, email = reqMap["name"], reqMap["email"]
}
}
} else {
token, userID, recipientProvider = r.FormValue("token"), r.FormValue("userID"), r.FormValue("recipientProvider")
name, email = r.FormValue("name"), r.FormValue("email")
}
if token == "" || userID == "" || recipientProvider == "" {
WriteError(w, r, APIErrorInvalidParameter, "missing parameters in request", nil)
return
}
gatewayClient, err := pool.GetGatewayServiceClient(h.gatewayAddr)
if err != nil {
WriteError(w, r, APIErrorServerError, "error getting gateway grpc client", err)
if req.Token == "" || req.UserID == "" || req.RecipientProvider == "" {
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "token, userID and recipiendProvider must not be null", nil)
return
}
clientIP, err := utils.GetClientIP(r)
if err != nil {
WriteError(w, r, APIErrorServerError, fmt.Sprintf("error retrieving client IP from request: %s", r.RemoteAddr), err)
return
}
recipientProviderURL, err := url.Parse(recipientProvider)
if err != nil {
WriteError(w, r, APIErrorServerError, fmt.Sprintf("error parseing recipientProvider URL: %s", recipientProvider), err)
reqres.WriteError(w, r, reqres.APIErrorServerError, fmt.Sprintf("error retrieving client IP from request: %s", r.RemoteAddr), err)
return
}
providerInfo := ocmprovider.ProviderInfo{
Domain: recipientProviderURL.Hostname(),
Domain: req.RecipientProvider,
Services: []*ocmprovider.Service{
{
Host: clientIP,
},
},
}
gatewayClient, err := h.gatewaySelector.Next()
if err != nil {
reqres.WriteError(w, r, reqres.APIErrorServerError, "error getting gateway client", err)
return
}
providerAllowedResp, err := gatewayClient.IsProviderAllowed(ctx, &ocmprovider.IsProviderAllowedRequest{
Provider: &providerInfo,
})
if err != nil {
WriteError(w, r, APIErrorServerError, "error sending a grpc is provider allowed request", err)
reqres.WriteError(w, r, reqres.APIErrorServerError, "error sending a grpc is provider allowed request", err)
return
}
if providerAllowedResp.Status.Code != rpc.Code_CODE_OK {
WriteError(w, r, APIErrorUnauthenticated, "provider not authorized", errors.New(providerAllowedResp.Status.Message))
reqres.WriteError(w, r, reqres.APIErrorUntrustedService, "provider not trusted", errors.New(providerAllowedResp.Status.Message))
return
}
userObj := &userpb.User{
Id: &userpb.UserId{
OpaqueId: userID,
Idp: recipientProvider,
Type: userpb.UserType_USER_TYPE_PRIMARY,
OpaqueId: req.UserID,
Idp: req.RecipientProvider,
Type: userpb.UserType_USER_TYPE_FEDERATED,
},
Mail: email,
DisplayName: name,
Mail: req.Email,
DisplayName: req.Name,
}
acceptInviteRequest := &invitepb.AcceptInviteRequest{
InviteToken: &invitepb.InviteToken{
Token: token,
Token: req.Token,
},
RemoteUser: userObj,
}
acceptInviteResponse, err := gatewayClient.AcceptInvite(ctx, acceptInviteRequest)
if err != nil {
WriteError(w, r, APIErrorServerError, "error sending a grpc accept invite request", err)
reqres.WriteError(w, r, reqres.APIErrorServerError, "error sending a grpc accept invite request", err)
return
}
if acceptInviteResponse.Status.Code != rpc.Code_CODE_OK {
WriteError(w, r, APIErrorServerError, "grpc accept invite request failed", errors.New(acceptInviteResponse.Status.Message))
return
switch acceptInviteResponse.Status.Code {
case rpc.Code_CODE_NOT_FOUND:
reqres.WriteError(w, r, reqres.APIErrorNotFound, "token not found", nil)
return
case rpc.Code_CODE_INVALID_ARGUMENT:
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "token has expired", nil)
return
case rpc.Code_CODE_ALREADY_EXISTS:
reqres.WriteError(w, r, reqres.APIErrorAlreadyExist, "user already known", nil)
return
default:
reqres.WriteError(w, r, reqres.APIErrorServerError, "unexpected error: "+acceptInviteResponse.Status.Message, errors.New(acceptInviteResponse.Status.Message))
return
}
}
log.Info().Msgf("User: %+v added to accepted users.", userObj)
}
func (h *invitesHandler) findAcceptedUsers(w http.ResponseWriter, r *http.Request) {
log := appctx.GetLogger(r.Context())
ctx := r.Context()
gatewayClient, err := pool.GetGatewayServiceClient(h.gatewayAddr)
if err != nil {
WriteError(w, r, APIErrorServerError, "error getting gateway grpc client", err)
if err := json.NewEncoder(w).Encode(&user{
UserID: acceptInviteResponse.UserId.OpaqueId,
Email: acceptInviteResponse.Email,
Name: acceptInviteResponse.DisplayName,
}); err != nil {
reqres.WriteError(w, r, reqres.APIErrorServerError, "error encoding response", err)
return
}
response, err := gatewayClient.FindAcceptedUsers(ctx, &invitepb.FindAcceptedUsersRequest{
Filter: "",
})
if err != nil {
WriteError(w, r, APIErrorServerError, "error sending a grpc find accepted users request", err)
return
}
indentedResponse, _ := json.MarshalIndent(response, "", " ")
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
if _, err := w.Write(indentedResponse); err != nil {
log.Err(err).Msg("Error writing to ResponseWriter")
}
}
func (h *invitesHandler) generate(w http.ResponseWriter, r *http.Request) {
log := appctx.GetLogger(r.Context())
ctx := r.Context()
gatewayClient, err := pool.GetGatewayServiceClient(h.gatewayAddr)
if err != nil {
WriteError(w, r, APIErrorServerError, "error getting gateway grpc client", err)
return
}
response, err := gatewayClient.GenerateInviteToken(ctx, &invitepb.GenerateInviteTokenRequest{})
if err != nil {
WriteError(w, r, APIErrorServerError, "error sending a grpc generate invite token request", err)
return
}
indentedResponse, _ := json.MarshalIndent(response, "", " ")
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
if _, err := w.Write(indentedResponse); err != nil {
log.Err(err).Msg("Error writing to ResponseWriter")
}
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
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
}
} else {
req.Token, req.UserID, req.RecipientProvider = r.FormValue("token"), r.FormValue("userID"), r.FormValue("recipientProvider")
req.Name, req.Email = r.FormValue("name"), r.FormValue("email")
}
return &req, nil
}

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 CERN
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -19,27 +19,48 @@
package ocmd
import (
"io"
"mime"
"net/http"
"github.com/cs3org/reva/v2/internal/http/services/reqres"
"github.com/cs3org/reva/v2/pkg/appctx"
"github.com/cs3org/reva/v2/pkg/rhttp/router"
)
type notificationsHandler struct {
// var validate = validator.New()
type notifHandler struct {
}
func (h *notificationsHandler) init(c *Config) {
func (h *notifHandler) init(c *config) error {
return nil
}
func (h *notificationsHandler) Handler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log := appctx.GetLogger(r.Context())
// Notifications dispatches any notifications received from remote OCM sites
// according to the specifications at:
// https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1notifications/post
func (h *notifHandler) Notifications(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
log := appctx.GetLogger(ctx)
req, err := getNotification(r)
if err != nil {
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, err.Error(), nil)
return
}
var head string
head, r.URL.Path = router.ShiftPath(r.URL.Path)
// TODO(lopresti) this is all to be implemented. For now we just log what we got
log.Debug().Msgf("Received OCM notification: %+v", req)
log.Debug().Str("head", head).Str("tail", r.URL.Path).Msg("http routing")
w.WriteHeader(http.StatusOK)
})
// this is to please Nextcloud
w.WriteHeader(http.StatusCreated)
}
func getNotification(r *http.Request) (string, error) {
// var req notificationRequest
contentType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err == nil && contentType == "application/json" {
bytes, _ := io.ReadAll(r.Body)
return string(bytes), nil
}
return "", nil
}

View File

@@ -0,0 +1,118 @@
// Copyright 2018-2023 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 ocmd
import (
"net/http"
"github.com/cs3org/reva/v2/pkg/appctx"
"github.com/cs3org/reva/v2/pkg/rhttp/global"
"github.com/cs3org/reva/v2/pkg/sharedconf"
"github.com/cs3org/reva/v2/pkg/utils/cfg"
"github.com/go-chi/chi/v5"
"github.com/rs/zerolog"
)
func init() {
global.Register("ocmd", New)
}
type config struct {
Prefix string `mapstructure:"prefix"`
GatewaySvc string `mapstructure:"gatewaysvc" validate:"required"`
ExposeRecipientDisplayName bool `mapstructure:"expose_recipient_display_name"`
}
func (c *config) ApplyDefaults() {
c.GatewaySvc = sharedconf.GetGatewaySVC(c.GatewaySvc)
if c.Prefix == "" {
c.Prefix = "ocm"
}
}
type svc struct {
Conf *config
router chi.Router
}
// New returns a new ocmd object, that implements
// the OCM APIs specified in https://cs3org.github.io/OCM-API/docs.html
func New(m map[string]interface{}, log *zerolog.Logger) (global.Service, error) {
var c config
if err := cfg.Decode(m, &c); err != nil {
return nil, err
}
r := chi.NewRouter()
s := &svc{
Conf: &c,
router: r,
}
if err := s.routerInit(); err != nil {
return nil, err
}
return s, nil
}
func (s *svc) routerInit() error {
sharesHandler := new(sharesHandler)
invitesHandler := new(invitesHandler)
notifHandler := new(notifHandler)
if err := sharesHandler.init(s.Conf); err != nil {
return err
}
if err := invitesHandler.init(s.Conf); err != nil {
return err
}
if err := notifHandler.init(s.Conf); err != nil {
return err
}
s.router.Post("/shares", sharesHandler.CreateShare)
s.router.Post("/invite-accepted", invitesHandler.AcceptInvite)
s.router.Post("/notifications", notifHandler.Notifications)
return nil
}
// Close performs cleanup.
func (s *svc) Close() error {
return nil
}
func (s *svc) Prefix() string {
return s.Conf.Prefix
}
func (s *svc) Unprotected() []string {
return []string{"/invite-accepted", "/shares", "/notifications"}
}
func (s *svc) Handler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log := appctx.GetLogger(r.Context())
log.Debug().Str("path", r.URL.Path).Msg("ocm routing")
// unset raw path, otherwise chi uses it to route and then fails to match percent encoded path segments
r.URL.RawPath = ""
s.router.ServeHTTP(w, r)
})
}

View File

@@ -1,135 +0,0 @@
// Copyright 2018-2021 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 ocmd
import (
"net/http"
"github.com/cs3org/reva/v2/pkg/appctx"
"github.com/cs3org/reva/v2/pkg/rhttp/global"
"github.com/cs3org/reva/v2/pkg/rhttp/router"
"github.com/cs3org/reva/v2/pkg/sharedconf"
"github.com/cs3org/reva/v2/pkg/smtpclient"
"github.com/mitchellh/mapstructure"
"github.com/rs/zerolog"
)
func init() {
global.Register("ocmd", New)
}
// Config holds the config options that need to be passed down to all ocdav handlers
type Config struct {
SMTPCredentials *smtpclient.SMTPCredentials `mapstructure:"smtp_credentials"`
Prefix string `mapstructure:"prefix"`
Host string `mapstructure:"host"`
GatewaySvc string `mapstructure:"gatewaysvc"`
MeshDirectoryURL string `mapstructure:"mesh_directory_url"`
Config configData `mapstructure:"config"`
}
func (c *Config) init() {
c.GatewaySvc = sharedconf.GetGatewaySVC(c.GatewaySvc)
// if c.Prefix == "" {
// c.Prefix = "ocm"
// }
}
type svc struct {
Conf *Config
SharesHandler *sharesHandler
NotificationsHandler *notificationsHandler
ConfigHandler *configHandler
InvitesHandler *invitesHandler
SendHandler *sendHandler
}
// New returns a new ocmd object
func New(m map[string]interface{}, log *zerolog.Logger) (global.Service, error) {
conf := &Config{}
if err := mapstructure.Decode(m, conf); err != nil {
return nil, err
}
conf.init()
s := &svc{
Conf: conf,
}
s.SharesHandler = new(sharesHandler)
s.NotificationsHandler = new(notificationsHandler)
s.ConfigHandler = new(configHandler)
s.InvitesHandler = new(invitesHandler)
s.SendHandler = new(sendHandler)
s.SharesHandler.init(s.Conf)
s.NotificationsHandler.init(s.Conf)
log.Debug().Str("initializing ConfigHandler Host", s.Conf.Host)
s.ConfigHandler.init(s.Conf)
s.InvitesHandler.init(s.Conf)
s.SendHandler.init(s.Conf)
return s, nil
}
// Close performs cleanup.
func (s *svc) Close() error {
return nil
}
func (s *svc) Prefix() string {
return s.Conf.Prefix
}
func (s *svc) Unprotected() []string {
return []string{"/invites/accept", "/shares", "/ocm-provider", "/notifications"}
}
func (s *svc) Handler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
log := appctx.GetLogger(ctx)
var head string
head, r.URL.Path = router.ShiftPath(r.URL.Path)
log.Debug().Str("head", head).Str("tail", r.URL.Path).Msg("http routing")
switch head {
case "ocm-provider":
s.ConfigHandler.Handler().ServeHTTP(w, r)
return
case "shares":
s.SharesHandler.Handler().ServeHTTP(w, r)
return
case "notifications":
s.NotificationsHandler.Handler().ServeHTTP(w, r)
return
case "invites":
s.InvitesHandler.Handler().ServeHTTP(w, r)
return
case "send":
s.SendHandler.Handler().ServeHTTP(w, r)
}
log.Warn().Msg("request not handled")
w.WriteHeader(http.StatusNotFound)
})
}

View File

@@ -0,0 +1,160 @@
// Copyright 2018-2023 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 ocmd
import (
"encoding/json"
"errors"
"fmt"
"reflect"
"strings"
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
providerv1beta1 "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
ocmshare "github.com/cs3org/reva/v2/pkg/ocm/share"
utils "github.com/cs3org/reva/v2/pkg/utils"
)
// Protocols is the list of 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() *ocm.Protocol
}
// protocols supported by the OCM API
// WebDAV contains the parameters for the WebDAV protocol.
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"`
}
// ToOCMProtocol convert the protocol to a ocm Protocol struct.
func (w *WebDAV) ToOCMProtocol() *ocm.Protocol {
perms := &ocm.SharePermissions{
Permissions: &providerv1beta1.ResourcePermissions{},
}
for _, p := range w.Permissions {
switch p {
case "read":
perms.Permissions.GetPath = true
perms.Permissions.InitiateFileDownload = true
perms.Permissions.ListContainer = true
perms.Permissions.Stat = true
case "write":
perms.Permissions.InitiateFileUpload = true
case "share":
perms.Reshare = true
}
}
return ocmshare.NewWebDAVProtocol(w.URL, w.SharedSecret, perms)
}
// 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"`
}
// ToOCMProtocol convert the protocol to a ocm Protocol struct.
func (w *Webapp) ToOCMProtocol() *ocm.Protocol {
return ocmshare.NewWebappProtocol(w.URITemplate, utils.GetAppViewMode(w.ViewMode))
}
// Datatx contains the parameters for the Datatx protocol.
type Datatx struct {
SharedSecret string `json:"sharedSecret" validate:"required"`
SourceURI string `json:"srcUri" validate:"required"`
Size uint64 `json:"size" validate:"required"`
}
// ToOCMProtocol convert the protocol to a ocm Protocol struct.
func (w *Datatx) ToOCMProtocol() *ocm.Protocol {
return ocmshare.NewTransferProtocol(w.SourceURI, w.SharedSecret, w.Size)
}
var protocolImpl = map[string]reflect.Type{
"webdav": reflect.TypeOf(WebDAV{}),
"webapp": reflect.TypeOf(Webapp{}),
"datatx": reflect.TypeOf(Datatx{}),
}
// UnmarshalJSON implements the Unmarshaler interface.
func (p *Protocols) UnmarshalJSON(data []byte) error {
var prot map[string]json.RawMessage
if err := json.Unmarshal(data, &prot); err != nil {
return err
}
*p = []Protocol{}
for name, d := range prot {
var res Protocol
// we do not support the OCM v1.0 properties for now, therefore just skip or bail out
if name == "name" {
continue
}
if name == "options" {
var opt map[string]any
if err := json.Unmarshal(d, &opt); err != nil || len(opt) > 0 {
return fmt.Errorf("protocol options not supported: %s", string(d))
}
continue
}
ctype, ok := protocolImpl[name]
if !ok {
return fmt.Errorf("protocol %s not recognised", name)
}
res = reflect.New(ctype).Interface().(Protocol)
if err := json.Unmarshal(d, &res); err != nil {
return err
}
*p = append(*p, res)
}
return nil
}
// MarshalJSON implements the Marshaler interface.
func (p Protocols) MarshalJSON() ([]byte, error) {
if len(p) == 0 {
return nil, errors.New("no protocol defined")
}
d := make(map[string]any)
for _, prot := range p {
d[getProtocolName(prot)] = prot
}
// fill in the OCM v1.0 properties
d["name"] = "multi"
d["options"] = map[string]any{}
return json.Marshal(d)
}
func getProtocolName(p Protocol) string {
n := reflect.TypeOf(p).String()
s := strings.Split(n, ".")
return strings.ToLower(s[len(s)-1])
}

View File

@@ -1,200 +0,0 @@
// Copyright 2018-2021 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 ocmd
import (
"context"
"encoding/json"
"errors"
"io"
"net/http"
"strconv"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/v2/pkg/appctx"
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
"google.golang.org/grpc/metadata"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
)
type sendHandler struct {
GatewaySvc string
}
func (h *sendHandler) init(c *Config) {
h.GatewaySvc = c.GatewaySvc
}
func (h *sendHandler) Handler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log := appctx.GetLogger(r.Context())
defer r.Body.Close()
reqBody, err := io.ReadAll(r.Body)
if err != nil {
log.Error().Msg("cannot read POST body!")
w.WriteHeader(http.StatusInternalServerError)
return
}
reqMap := make(map[string]string)
err = json.Unmarshal(reqBody, &reqMap)
if err != nil {
log.Error().Msg("cannot parse POST body!")
w.WriteHeader(http.StatusInternalServerError)
return
}
sourcePath, targetPath, sharedSecret := reqMap["sourcePath"], reqMap["targetPath"], reqMap["sharedSecret"]
recipientUsername, recipientHost := reqMap["recipientUsername"], reqMap["recipientHost"]
loginType, loginUsername, loginPassword := reqMap["loginType"], reqMap["loginUsername"], reqMap["loginPassword"]
// "sourcePath": "other",
// "targetPath": "sciencemesh\/other",
// "type": "dir", (unused)
// "recipientUsername": "marie",
// "recipientHost": "revanc2.docker",
// "loginType": "basic",
// "loginUsername": "einstein",
// "loginPassword": "Ny4Nv6WLoC1o70kVgrVOZLZ2vRgPjuej"
gatewayAddr := h.GatewaySvc
gatewayClient, err := pool.GetGatewayServiceClient(gatewayAddr)
if err != nil {
log.Error().Msg("cannot get grpc client!")
w.WriteHeader(http.StatusInternalServerError)
return
}
loginReq := &gateway.AuthenticateRequest{
Type: loginType,
ClientId: loginUsername,
ClientSecret: loginPassword,
}
loginCtx := context.Background()
res, err := gatewayClient.Authenticate(loginCtx, loginReq)
if err != nil {
log.Error().Msg("error logging in")
w.WriteHeader(http.StatusInternalServerError)
return
}
authCtx := context.Background()
authCtx = ctxpkg.ContextSetToken(authCtx, res.Token)
authCtx = metadata.AppendToOutgoingContext(authCtx, ctxpkg.TokenHeader, res.Token)
// copied from cmd/reva/public-share-create.go:
ref := &provider.Reference{Path: sourcePath}
req := &provider.StatRequest{Ref: ref}
res2, err := gatewayClient.Stat(authCtx, req)
if err != nil {
log.Error().Msg("error sending: stat file/folder to share")
w.WriteHeader(http.StatusInternalServerError)
return
}
if res2.Status.Code != rpc.Code_CODE_OK {
log.Error().Msg("error returned: stat file/folder to share")
w.WriteHeader(http.StatusInternalServerError)
return
}
// see cmd/reva/share-creat.go:getSharePerm
readerPermission := &provider.ResourcePermissions{
GetPath: true,
InitiateFileDownload: true,
ListFileVersions: true,
ListContainer: true,
Stat: true,
}
grant := &ocm.ShareGrant{
Permissions: &ocm.SharePermissions{
Permissions: readerPermission,
},
Grantee: &provider.Grantee{
Type: provider.GranteeType_GRANTEE_TYPE_USER,
Id: &provider.Grantee_UserId{
UserId: &userpb.UserId{
Idp: recipientHost,
OpaqueId: recipientUsername,
},
},
},
}
recipientProviderInfo, err := gatewayClient.GetInfoByDomain(authCtx, &ocmprovider.GetInfoByDomainRequest{
Domain: recipientHost,
})
if err != nil {
WriteError(w, r, APIErrorServerError, "error sending a grpc get invite by domain info request", err)
return
}
if recipientProviderInfo.Status.Code != rpc.Code_CODE_OK {
WriteError(w, r, APIErrorServerError, "grpc forward invite request failed", errors.New(recipientProviderInfo.Status.Message))
return
}
shareRequest := &ocm.CreateOCMShareRequest{
Opaque: &types.Opaque{
Map: map[string]*types.OpaqueEntry{
"permissions": {
Decoder: "plain",
Value: []byte(strconv.Itoa(0)),
},
"name": {
Decoder: "plain",
Value: []byte(targetPath),
},
"protocol": {
Decoder: "plain",
Value: []byte("webdav"), // TODO: support datatx too
},
"token": {
Decoder: "plain",
Value: []byte(sharedSecret),
},
},
},
ResourceId: res2.Info.Id,
Grant: grant,
RecipientMeshProvider: recipientProviderInfo.ProviderInfo,
}
shareRes, err := gatewayClient.CreateOCMShare(authCtx, shareRequest)
if err != nil {
log.Error().Msg("error sending: CreateShare")
w.WriteHeader(http.StatusInternalServerError)
return
}
if shareRes.Status.Code != rpc.Code_CODE_OK {
log.Error().Msg("error returned: CreateShare")
w.WriteHeader(http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
})
}

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 CERN
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -22,102 +22,83 @@ import (
"encoding/json"
"errors"
"fmt"
"io"
"math"
"mime"
"net/http"
"reflect"
"strings"
"time"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
providerpb "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
ocmcore "github.com/cs3org/go-cs3apis/cs3/ocm/core/v1beta1"
ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/conversions"
"github.com/cs3org/reva/v2/internal/http/services/reqres"
"github.com/cs3org/reva/v2/pkg/appctx"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/v2/pkg/utils"
"github.com/go-playground/validator/v10"
)
var validate = validator.New()
type sharesHandler struct {
gatewayAddr string
gatewaySelector *pool.Selector[gateway.GatewayAPIClient]
exposeRecipientDisplayName bool
}
func (h *sharesHandler) init(c *Config) {
h.gatewayAddr = c.GatewaySvc
func (h *sharesHandler) init(c *config) error {
var err error
gatewaySelector, err := pool.GatewaySelector(c.GatewaySvc)
if err != nil {
return err
}
h.gatewaySelector = gatewaySelector
h.exposeRecipientDisplayName = c.ExposeRecipientDisplayName
return nil
}
func (h *sharesHandler) Handler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodPost:
h.createShare(w, r)
default:
WriteError(w, r, APIErrorInvalidParameter, "Only POST method is allowed", 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"`
}
func (h *sharesHandler) createShare(w http.ResponseWriter, r *http.Request) {
// CreateShare sends all the informations to the consumer needed to start
// synchronization between the two services.
func (h *sharesHandler) CreateShare(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
log := appctx.GetLogger(ctx)
contentType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
var shareWith, meshProvider, resource, providerID, owner string
var protocol map[string]interface{}
if err == nil && contentType == "application/json" {
defer r.Body.Close()
reqBody, err := io.ReadAll(r.Body)
if err == nil {
reqMap := make(map[string]interface{})
err = json.Unmarshal(reqBody, &reqMap)
if err == nil {
meshProvider = reqMap["meshProvider"].(string) // FIXME: get this from sharedBy string?
shareWith, protocol = reqMap["shareWith"].(string), reqMap["protocol"].(map[string]interface{})
resource, owner = reqMap["name"].(string), reqMap["owner"].(string)
// Note that if an OCM request were to go directly from a Nextcloud server
// to a Reva server, it will (incorrectly) sends an integer provider_id instead a string one.
// This doesn't happen when using the sciencemesh-nextcloud app, but in order to make the OCM
// test suite pass, this code works around that:
if reflect.ValueOf(reqMap["providerId"]).Kind() == reflect.Float64 {
providerID = fmt.Sprintf("%d", int(math.Round(reqMap["providerId"].(float64))))
} else {
providerID = reqMap["providerId"].(string)
}
} else {
WriteError(w, r, APIErrorInvalidParameter, "could not parse json request body", nil)
}
}
} else {
var protocolJSON string
shareWith, protocolJSON, meshProvider = r.FormValue("shareWith"), r.FormValue("protocol"), r.FormValue("meshProvider")
resource, providerID, owner = r.FormValue("name"), r.FormValue("providerId"), r.FormValue("owner")
err = json.Unmarshal([]byte(protocolJSON), &protocol)
if err != nil {
WriteError(w, r, APIErrorInvalidParameter, "invalid protocol parameters", nil)
}
}
if resource == "" || providerID == "" || owner == "" {
WriteError(w, r, APIErrorInvalidParameter, "missing details about resource to be shared", nil)
return
}
if shareWith == "" || protocol["name"] == "" || meshProvider == "" {
WriteError(w, r, APIErrorInvalidParameter, "missing request parameters", nil)
return
}
gatewayClient, err := pool.GetGatewayServiceClient(h.gatewayAddr)
req, err := getCreateShareRequest(r)
if err != nil {
WriteError(w, r, APIErrorServerError, "error getting storage grpc client", err)
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, err.Error(), nil)
return
}
_, meshProvider, err := getIDAndMeshProvider(req.Sender)
log.Debug().Msgf("Determined Mesh Provider '%s' from req.Sender '%s'", meshProvider, req.Sender)
if err != nil {
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, err.Error(), nil)
return
}
clientIP, err := utils.GetClientIP(r)
if err != nil {
WriteError(w, r, APIErrorServerError, fmt.Sprintf("error retrieving client IP from request: %s", r.RemoteAddr), err)
reqres.WriteError(w, r, reqres.APIErrorServerError, fmt.Sprintf("error retrieving client IP from request: %s", r.RemoteAddr), err)
return
}
providerInfo := ocmprovider.ProviderInfo{
@@ -128,128 +109,154 @@ func (h *sharesHandler) createShare(w http.ResponseWriter, r *http.Request) {
},
},
}
gatewayClient, err := h.gatewaySelector.Next()
if err != nil {
reqres.WriteError(w, r, reqres.APIErrorServerError, "error getting gateway client", err)
return
}
providerAllowedResp, err := gatewayClient.IsProviderAllowed(ctx, &ocmprovider.IsProviderAllowedRequest{
Provider: &providerInfo,
})
if err != nil {
WriteError(w, r, APIErrorServerError, "error sending a grpc is provider allowed request", err)
reqres.WriteError(w, r, reqres.APIErrorServerError, "error sending a grpc is provider allowed request", err)
return
}
if providerAllowedResp.Status.Code != rpc.Code_CODE_OK {
WriteError(w, r, APIErrorUnauthenticated, "provider not authorized", errors.New(providerAllowedResp.Status.Message))
reqres.WriteError(w, r, reqres.APIErrorUnauthenticated, "provider not authorized", errors.New(providerAllowedResp.Status.Message))
return
}
shareWith, _, err := getIDAndMeshProvider(req.ShareWith)
if err != nil {
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, err.Error(), nil)
return
}
shareWithParts := strings.Split(shareWith, "@")
userRes, err := gatewayClient.GetUser(ctx, &userpb.GetUserRequest{
UserId: &userpb.UserId{OpaqueId: shareWithParts[0]}, SkipFetchingUserGroups: true,
UserId: &userpb.UserId{OpaqueId: shareWith}, SkipFetchingUserGroups: true,
})
if err != nil {
WriteError(w, r, APIErrorServerError, "error searching recipient", err)
reqres.WriteError(w, r, reqres.APIErrorServerError, "error searching recipient", err)
return
}
if userRes.Status.Code != rpc.Code_CODE_OK {
WriteError(w, r, APIErrorNotFound, "user not found", errors.New(userRes.Status.Message))
reqres.WriteError(w, r, reqres.APIErrorNotFound, "user not found", errors.New(userRes.Status.Message))
return
}
var permissions conversions.Permissions
var token string
options, ok := protocol["options"].(map[string]interface{})
if !ok {
WriteError(w, r, APIErrorInvalidParameter, "protocol: webdav token not provided", nil)
return
}
token, ok = options["sharedSecret"].(string)
if !ok {
token, ok = options["token"].(string)
if !ok {
WriteError(w, r, APIErrorInvalidParameter, "protocol: webdav token not provided", nil)
return
}
}
var role *conversions.Role
pval, ok := options["permissions"].(int)
if !ok {
WriteError(w, r, APIErrorInvalidParameter, "permissions not provided", nil)
return
}
permissions, err = conversions.NewPermissions(pval)
owner, err := getUserIDFromOCMUser(req.Owner)
if err != nil {
WriteError(w, r, APIErrorInvalidParameter, err.Error(), nil)
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, err.Error(), nil)
return
}
role = conversions.RoleFromOCSPermissions(permissions)
val, err := json.Marshal(role.CS3ResourcePermissions())
sender, err := getUserIDFromOCMUser(req.Sender)
if err != nil {
WriteError(w, r, APIErrorServerError, "could not encode role", nil)
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, err.Error(), nil)
return
}
ownerID := &userpb.UserId{
OpaqueId: owner,
Idp: meshProvider,
Type: userpb.UserType_USER_TYPE_PRIMARY,
}
createShareReq := &ocmcore.CreateOCMCoreShareRequest{
Name: resource,
ProviderId: providerID,
Owner: ownerID,
ShareWith: userRes.User.GetId(),
Protocol: &ocmcore.Protocol{
Name: protocol["name"].(string),
Opaque: &types.Opaque{
Map: map[string]*types.OpaqueEntry{
"permissions": {
Decoder: "json",
Value: val,
},
"token": {
Decoder: "plain",
Value: []byte(token),
},
},
},
},
Description: req.Description,
Name: req.Name,
ResourceId: req.ProviderID,
Owner: owner,
Sender: sender,
ShareWith: userRes.User.Id,
ResourceType: getResourceTypeFromOCMRequest(req.ResourceType),
ShareType: getOCMShareType(req.ShareType),
Protocols: getProtocols(req.Protocols),
}
createShareResponse, err := gatewayClient.CreateOCMCoreShare(ctx, createShareReq)
if err != nil {
WriteError(w, r, APIErrorServerError, "error sending a grpc create ocm core share request", err)
return
}
if createShareResponse.Status.Code != rpc.Code_CODE_OK {
if createShareResponse.Status.Code == rpc.Code_CODE_NOT_FOUND {
WriteError(w, r, APIErrorNotFound, "not found", nil)
return
if req.Expiration != 0 {
createShareReq.Expiration = &types.Timestamp{
Seconds: req.Expiration,
}
WriteError(w, r, APIErrorServerError, "grpc create ocm core share request failed", errors.New(createShareResponse.Status.Message))
return
}
timeCreated := createShareResponse.Created
jsonOut, err := json.Marshal(
map[string]string{
"id": createShareResponse.Id,
"createdAt": time.Unix(int64(timeCreated.Seconds), int64(timeCreated.Nanos)).String(),
},
)
createShareResp, err := gatewayClient.CreateOCMCoreShare(ctx, createShareReq)
if err != nil {
WriteError(w, r, APIErrorServerError, "error marshalling share data", err)
reqres.WriteError(w, r, reqres.APIErrorServerError, "error creating ocm share", err)
return
}
if userRes.Status.Code != rpc.Code_CODE_OK {
// TODO: define errors in the cs3apis
reqres.WriteError(w, r, reqres.APIErrorServerError, "error creating ocm share", errors.New(createShareResp.Status.Message))
return
}
response := map[string]any{}
if h.exposeRecipientDisplayName {
response["recipientDisplayName"] = userRes.User.DisplayName
}
_ = json.NewEncoder(w).Encode(response)
w.WriteHeader(http.StatusCreated)
w.Header().Set("Content-Type", "application/json")
_, err = w.Write(jsonOut)
if err != nil {
WriteError(w, r, APIErrorServerError, "error writing shares data", err)
return
}
log.Info().Msg("Share created.")
}
func getUserIDFromOCMUser(user string) (*userpb.UserId, error) {
id, idp, err := getIDAndMeshProvider(user)
if err != nil {
return nil, err
}
return &userpb.UserId{
OpaqueId: id,
Idp: idp,
// the remote user is a federated account for the local reva
Type: userpb.UserType_USER_TYPE_FEDERATED,
}, nil
}
func getIDAndMeshProvider(user string) (string, string, error) {
// the user is in the form of dimitri@apiwise.nl
split := strings.Split(user, "@")
if len(split) < 2 {
return "", "", errors.New("not in the form <id>@<provider>")
}
return strings.Join(split[:len(split)-1], "@"), split[len(split)-1], nil
}
func getCreateShareRequest(r *http.Request) (*createShareRequest, error) {
var req createShareRequest
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
}
} else {
return nil, errors.New("body request not recognised")
}
// validate the request
if err := validate.Struct(req); err != nil {
return nil, err
}
return &req, nil
}
func getResourceTypeFromOCMRequest(t string) providerpb.ResourceType {
switch t {
case "file":
return providerpb.ResourceType_RESOURCE_TYPE_FILE
case "folder":
return providerpb.ResourceType_RESOURCE_TYPE_CONTAINER
default:
return providerpb.ResourceType_RESOURCE_TYPE_INVALID
}
}
func getOCMShareType(t string) ocm.ShareType {
if t == "user" {
return ocm.ShareType_SHARE_TYPE_USER
}
return ocm.ShareType_SHARE_TYPE_GROUP
}
func getProtocols(p Protocols) []*ocm.Protocol {
prot := make([]*ocm.Protocol, 0, len(p))
for _, data := range p {
prot = append(prot, data.ToOCMProtocol())
}
return prot
}

View File

@@ -16,6 +16,7 @@ type Config struct {
// /users/<first char of username>/<username>/docs
WebdavNamespace string `mapstructure:"webdav_namespace"`
SharesNamespace string `mapstructure:"shares_namespace"`
OCMNamespace string `mapstructure:"ocm_namespace"`
GatewaySvc string `mapstructure:"gatewaysvc"`
Timeout int64 `mapstructure:"timeout"`
Insecure bool `mapstructure:"insecure"`

View File

@@ -22,6 +22,7 @@ import (
"context"
"net/http"
"path"
"path/filepath"
"strings"
gatewayv1beta1 "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
@@ -56,6 +57,7 @@ type DavHandler struct {
PublicFolderHandler *WebDavHandler
PublicFileHandler *PublicFileHandler
SharesHandler *WebDavHandler
OCMSharesHandler *WebDavHandler
}
func (h *DavHandler) init(c *config.Config) error {
@@ -95,6 +97,11 @@ func (h *DavHandler) init(c *config.Config) error {
return err
}
h.OCMSharesHandler = new(WebDavHandler)
if err := h.OCMSharesHandler.init(c.OCMNamespace, true); err != nil {
return err
}
return nil
}
@@ -170,6 +177,60 @@ func (h *DavHandler) Handler(s *svc) http.Handler {
ctx = context.WithValue(ctx, net.CtxKeyBaseURI, base)
r = r.WithContext(ctx)
h.MetaHandler.Handler(s).ServeHTTP(w, r)
case "ocm":
base := path.Join(ctx.Value(net.CtxKeyBaseURI).(string), "ocm")
ctx := context.WithValue(ctx, net.CtxKeyBaseURI, base)
c, err := s.gatewaySelector.Next()
if err != nil {
w.WriteHeader(http.StatusNotFound)
return
}
// OC10 and Nextcloud (OCM 1.0) are using basic auth for carrying the
// shared token.
var token string
username, _, ok := r.BasicAuth()
if ok {
// OCM 1.0
token = username
r.URL.Path = filepath.Join("/", token, r.URL.Path)
ctx = context.WithValue(ctx, net.CtxOCM10, true)
} else {
token, _ = router.ShiftPath(r.URL.Path)
ctx = context.WithValue(ctx, net.CtxOCM10, false)
}
authRes, err := handleOCMAuth(ctx, c, token)
switch {
case err != nil:
log.Error().Err(err).Msg("error during ocm authentication")
w.WriteHeader(http.StatusInternalServerError)
return
case authRes.Status.Code == rpc.Code_CODE_PERMISSION_DENIED:
log.Debug().Str("token", token).Msg("permission denied")
fallthrough
case authRes.Status.Code == rpc.Code_CODE_UNAUTHENTICATED:
log.Debug().Str("token", token).Msg("unauthorized")
w.WriteHeader(http.StatusUnauthorized)
return
case authRes.Status.Code == rpc.Code_CODE_NOT_FOUND:
log.Debug().Str("token", token).Msg("not found")
w.WriteHeader(http.StatusNotFound)
return
case authRes.Status.Code != rpc.Code_CODE_OK:
log.Error().Str("token", token).Interface("status", authRes.Status).Msg("grpc auth request failed")
w.WriteHeader(http.StatusInternalServerError)
return
}
ctx = ctxpkg.ContextSetToken(ctx, authRes.Token)
ctx = ctxpkg.ContextSetUser(ctx, authRes.User)
ctx = metadata.AppendToOutgoingContext(ctx, ctxpkg.TokenHeader, authRes.Token)
log.Debug().Str("token", token).Interface("user", authRes.User).Msg("OCM user authenticated")
r = r.WithContext(ctx)
h.OCMSharesHandler.Handler(s).ServeHTTP(w, r)
case "trash-bin":
base := path.Join(ctx.Value(net.CtxKeyBaseURI).(string), "trash-bin")
ctx := context.WithValue(ctx, net.CtxKeyBaseURI, base)
@@ -315,3 +376,10 @@ func handleSignatureAuth(ctx context.Context, selector pool.Selectable[gatewayv1
return c.Authenticate(ctx, &authenticateRequest)
}
func handleOCMAuth(ctx context.Context, c gatewayv1beta1.GatewayAPIClient, token string) (*gatewayv1beta1.AuthenticateResponse, error) {
return c.Authenticate(ctx, &gatewayv1beta1.AuthenticateRequest{
Type: "ocmshares",
ClientId: token,
})
}

View File

@@ -35,6 +35,7 @@ type ctxKey int
const (
// CtxKeyBaseURI is the key of the base URI context field
CtxKeyBaseURI ctxKey = iota
CtxOCM10
// NsDav is the Dav ns
NsDav = "DAV:"

View File

@@ -157,7 +157,7 @@ func (s *svc) Close() error {
}
func (s *svc) Unprotected() []string {
return []string{"/status.php", "/status", "/remote.php/dav/public-files/", "/apps/files/", "/index.php/f/", "/index.php/s/"}
return []string{"/status.php", "/status", "/remote.php/dav/public-files/", "/apps/files/", "/index.php/f/", "/index.php/s/", "/remote.php/dav/ocm/", "/dav/ocm/"}
}
func (s *svc) Handler() http.Handler {

View File

@@ -47,6 +47,9 @@ type Config struct {
MachineAuthAPIKey string `mapstructure:"machine_auth_apikey"`
SkipUpdatingExistingSharesMountpoints bool `mapstructure:"skip_updating_existing_shares_mountpoint"`
EnableDenials bool `mapstructure:"enable_denials"`
OCMMountPoint string `mapstructure:"ocm_mount_point"`
ListOCMShares bool `mapstructure:"list_ocm_shares"`
Notifications map[string]interface{} `mapstructure:"notifications"`
}
// Init sets sane defaults

View File

@@ -26,6 +26,8 @@ import (
"path"
"time"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/mime"
"github.com/cs3org/reva/v2/pkg/publicshare"
"github.com/cs3org/reva/v2/pkg/user"
@@ -33,6 +35,7 @@ import (
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1"
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
publicsharemgr "github.com/cs3org/reva/v2/pkg/publicshare/manager/registry"
@@ -303,6 +306,82 @@ func PublicShare2ShareData(share *link.PublicShare, r *http.Request, publicURL s
return sd
}
func formatRemoteUser(u *userpb.UserId) string {
return fmt.Sprintf("%s@%s", u.OpaqueId, u.Idp)
}
func webdavInfo(protocols []*ocm.Protocol) (*ocm.WebDAVProtocol, bool) {
for _, p := range protocols {
if opt, ok := p.Term.(*ocm.Protocol_WebdavOptions); ok {
return opt.WebdavOptions, true
}
}
return nil, false
}
// ReceivedOCMShare2ShareData converts a cs3 ocm received share into a share data model.
func ReceivedOCMShare2ShareData(share *ocm.ReceivedShare, path string) (*ShareData, error) {
webdav, ok := webdavInfo(share.Protocols)
if !ok {
return nil, errtypes.InternalError("webdav endpoint not in share")
}
s := &ShareData{
ID: share.Id.OpaqueId,
UIDOwner: formatRemoteUser(share.Creator),
UIDFileOwner: formatRemoteUser(share.Owner),
ShareWith: share.Grantee.GetUserId().OpaqueId,
Permissions: RoleFromResourcePermissions(webdav.GetPermissions().GetPermissions(), false).OCSPermissions(),
ShareType: ShareTypeFederatedCloudShare,
Path: path,
FileTarget: path,
MimeType: mime.Detect(share.ResourceType == provider.ResourceType_RESOURCE_TYPE_CONTAINER, share.Name),
ItemType: ResourceType(share.ResourceType).String(),
ItemSource: path,
STime: share.Ctime.Seconds,
Name: share.Name,
}
if share.Expiration != nil {
s.Expiration = timestampToExpiration(share.Expiration)
}
return s, nil
}
func webdavAMInfo(methods []*ocm.AccessMethod) (*ocm.WebDAVAccessMethod, bool) {
for _, a := range methods {
if opt, ok := a.Term.(*ocm.AccessMethod_WebdavOptions); ok {
return opt.WebdavOptions, true
}
}
return nil, false
}
// OCMShare2ShareData converts a cs3 ocm share into a share data model.
func OCMShare2ShareData(share *ocm.Share) (*ShareData, error) {
webdav, ok := webdavAMInfo(share.AccessMethods)
if !ok {
return nil, errtypes.InternalError("webdav endpoint not in share")
}
s := &ShareData{
ID: share.Id.OpaqueId,
UIDOwner: share.Creator.OpaqueId,
UIDFileOwner: share.Owner.OpaqueId,
ShareWith: formatRemoteUser(share.Grantee.GetUserId()),
Permissions: RoleFromResourcePermissions(webdav.GetPermissions(), false).OCSPermissions(),
ShareType: ShareTypeFederatedCloudShare,
STime: share.Ctime.Seconds,
Name: share.Name,
}
if share.Expiration != nil {
s.Expiration = timestampToExpiration(share.Expiration)
}
return s, nil
}
// LocalUserIDToString transforms a cs3api user id into an ocs data model without domain name
// TODO ocs uses user names ... so an additional lookup is needed. see mapUserIds()
func LocalUserIDToString(userID *userpb.UserId) string {

View File

@@ -45,6 +45,8 @@ const (
RoleSpaceEditor = "spaceeditor"
// RoleFileEditor grants editor permission on a single file.
RoleFileEditor = "file-editor"
// RoleCoowner grants co-owner permissions on a resource.
RoleCoowner = "coowner"
// RoleUploader grants uploader permission to upload onto a resource.
RoleUploader = "uploader"
// RoleManager grants manager permissions on a resource. Semantically equivalent to co-owner.
@@ -286,6 +288,34 @@ func NewFileEditorRole() *Role {
}
}
// NewCoownerRole creates a coowner role.
func NewCoownerRole() *Role {
return &Role{
Name: RoleCoowner,
cS3ResourcePermissions: &provider.ResourcePermissions{
GetPath: true,
GetQuota: true,
InitiateFileDownload: true,
ListGrants: true,
ListContainer: true,
ListFileVersions: true,
ListRecycle: true,
Stat: true,
InitiateFileUpload: true,
RestoreFileVersion: true,
RestoreRecycleItem: true,
CreateContainer: true,
Delete: true,
Move: true,
PurgeRecycle: true,
AddGrant: true,
UpdateGrant: true,
RemoveGrant: true,
},
ocsPermissions: PermissionAll,
}
}
// NewUploaderRole creates an uploader role
func NewUploaderRole() *Role {
return &Role{

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 CERN
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -19,24 +19,28 @@
package shares
import (
"context"
"net/http"
"strconv"
"path/filepath"
"strings"
providerv1beta1 "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1"
gatewayv1beta1 "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
invitepb "github.com/cs3org/go-cs3apis/cs3/ocm/invite/v1beta1"
ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
providerpb "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/go-chi/chi/v5"
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/conversions"
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/response"
"github.com/cs3org/reva/v2/pkg/ocm/share"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/go-chi/chi/v5"
"github.com/pkg/errors"
)
func (h *Handler) createFederatedCloudShare(w http.ResponseWriter, r *http.Request, statInfo *provider.ResourceInfo, role *conversions.Role, roleVal []byte) {
func (h *Handler) createFederatedCloudShare(w http.ResponseWriter, r *http.Request, resource *provider.ResourceInfo, role *conversions.Role, roleVal []byte) {
ctx := r.Context()
c, err := pool.GetGatewayServiceClient(h.gatewayAddr)
@@ -51,7 +55,7 @@ func (h *Handler) createFederatedCloudShare(w http.ResponseWriter, r *http.Reque
return
}
providerInfoResp, err := c.GetInfoByDomain(ctx, &ocmprovider.GetInfoByDomainRequest{
providerInfoResp, err := c.GetInfoByDomain(ctx, &providerpb.GetInfoByDomainRequest{
Domain: shareWithProvider,
})
if err != nil {
@@ -59,8 +63,14 @@ func (h *Handler) createFederatedCloudShare(w http.ResponseWriter, r *http.Reque
return
}
if providerInfoResp.Status.Code != rpc.Code_CODE_OK {
// return proper error
response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error from provider info response", errors.New(providerInfoResp.Status.Message))
return
}
remoteUserRes, err := c.GetAcceptedUser(ctx, &invitepb.GetAcceptedUserRequest{
RemoteUserId: &userpb.UserId{OpaqueId: shareWithUser, Idp: shareWithProvider, Type: userpb.UserType_USER_TYPE_PRIMARY},
RemoteUserId: &userpb.UserId{OpaqueId: shareWithUser, Idp: shareWithProvider, Type: userpb.UserType_USER_TYPE_FEDERATED},
})
if err != nil {
response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error searching recipient", err)
@@ -71,39 +81,20 @@ func (h *Handler) createFederatedCloudShare(w http.ResponseWriter, r *http.Reque
return
}
createShareReq := &ocm.CreateOCMShareRequest{
Opaque: &types.Opaque{
Map: map[string]*types.OpaqueEntry{
/* TODO extend the spec with role names?
"role": {
Decoder: "plain",
Value: []byte(role.Name),
},
*/
"permissions": {
Decoder: "plain",
Value: []byte(strconv.Itoa(int(role.OCSPermissions()))),
},
"name": {
Decoder: "plain",
Value: []byte(statInfo.Path),
},
},
},
ResourceId: statInfo.Id,
Grant: &ocm.ShareGrant{
Grantee: &provider.Grantee{
Type: provider.GranteeType_GRANTEE_TYPE_USER,
Id: &provider.Grantee_UserId{UserId: remoteUserRes.RemoteUser.GetId()},
},
Permissions: &ocm.SharePermissions{
Permissions: role.CS3ResourcePermissions(),
createShareResponse, err := c.CreateOCMShare(ctx, &ocm.CreateOCMShareRequest{
ResourceId: resource.Id,
Grantee: &provider.Grantee{
Type: provider.GranteeType_GRANTEE_TYPE_USER,
Id: &provider.Grantee_UserId{
UserId: remoteUserRes.RemoteUser.Id,
},
},
RecipientMeshProvider: providerInfoResp.ProviderInfo,
}
createShareResponse, err := c.CreateOCMShare(ctx, createShareReq)
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(role.CS3ResourcePermissions()),
share.NewWebappAccessMethod(getViewModeFromRole(role)),
},
})
if err != nil {
response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error sending a grpc create ocm share request", err)
return
@@ -117,12 +108,41 @@ func (h *Handler) createFederatedCloudShare(w http.ResponseWriter, r *http.Reque
return
}
response.WriteOCSSuccess(w, r, "OCM Share created")
s := createShareResponse.Share
data, err := conversions.OCMShare2ShareData(s)
if err != nil {
response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error converting share", err)
return
}
h.mapUserIdsFederatedShare(ctx, c, data)
info, status, err := h.getResourceInfoByID(ctx, c, s.ResourceId)
if err != nil {
response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error statting resource id", err)
return
}
if status.Code != rpc.Code_CODE_OK {
response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error statting resource id", errors.New(status.Message))
return
}
h.addFileInfo(ctx, data, info)
response.WriteOCSSuccess(w, r, data)
}
// GetFederatedShare handles GET requests on /apps/files_sharing/api/v1/shares/remote_shares/{shareid}
func (h *Handler) GetFederatedShare(w http.ResponseWriter, r *http.Request) {
func getViewModeFromRole(role *conversions.Role) providerv1beta1.ViewMode {
switch role.Name {
case conversions.RoleViewer:
return providerv1beta1.ViewMode_VIEW_MODE_READ_ONLY
case conversions.RoleEditor:
return providerv1beta1.ViewMode_VIEW_MODE_READ_WRITE
}
return providerv1beta1.ViewMode_VIEW_MODE_INVALID
}
// GetFederatedShare handles GET requests on /apps/files_sharing/api/v1/shares/remote_shares/{shareid}.
func (h *Handler) GetFederatedShare(w http.ResponseWriter, r *http.Request) {
// TODO: Implement response with HAL schemating
ctx := r.Context()
@@ -156,28 +176,125 @@ func (h *Handler) GetFederatedShare(w http.ResponseWriter, r *http.Request) {
response.WriteOCSSuccess(w, r, share)
}
// ListFederatedShares handles GET requests on /apps/files_sharing/api/v1/shares/remote_shares
// ListFederatedShares handles GET requests on /apps/files_sharing/api/v1/shares/remote_shares.
func (h *Handler) ListFederatedShares(w http.ResponseWriter, r *http.Request) {
// TODO Implement pagination.
// TODO Implement response with HAL schemating
ctx := r.Context()
gatewayClient, err := pool.GetGatewayServiceClient(h.gatewayAddr)
if err != nil {
response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error getting grpc gateway client", err)
return
}
listOCMSharesResponse, err := gatewayClient.ListOCMShares(ctx, &ocm.ListOCMSharesRequest{})
if err != nil {
response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error sending a grpc list ocm share request", err)
return
}
shares := listOCMSharesResponse.GetShares()
if shares == nil {
shares = make([]*ocm.Share, 0)
}
response.WriteOCSSuccess(w, r, shares)
}
func (h *Handler) listReceivedFederatedShares(ctx context.Context, gw gatewayv1beta1.GatewayAPIClient, state ocm.ShareState) ([]*conversions.ShareData, error) {
listRes, err := gw.ListReceivedOCMShares(ctx, &ocm.ListReceivedOCMSharesRequest{})
if err != nil {
return nil, err
}
shares := []*conversions.ShareData{}
for _, s := range listRes.Shares {
if state != ocsStateUnknown && s.State != state {
continue
}
sd, err := conversions.ReceivedOCMShare2ShareData(s, h.ocmLocalMount(s))
if err != nil {
continue
}
h.mapUserIdsReceivedFederatedShare(ctx, gw, sd)
sd.State = mapOCMState(s.State)
shares = append(shares, sd)
}
return shares, nil
}
func (h *Handler) ocmLocalMount(share *ocm.ReceivedShare) string {
return filepath.Join("/", h.ocmMountPoint, share.Id.OpaqueId)
}
func (h *Handler) mapUserIdsReceivedFederatedShare(ctx context.Context, gw gatewayv1beta1.GatewayAPIClient, sd *conversions.ShareData) {
if sd.ShareWith != "" {
user := h.mustGetIdentifiers(ctx, gw, sd.ShareWith, false)
sd.ShareWith = user.Username
sd.ShareWithDisplayname = user.DisplayName
}
if sd.UIDOwner != "" {
user := h.mustGetRemoteUser(ctx, gw, sd.UIDOwner)
sd.DisplaynameOwner = user.DisplayName
}
if sd.UIDFileOwner != "" {
user := h.mustGetRemoteUser(ctx, gw, sd.UIDFileOwner)
sd.DisplaynameFileOwner = user.DisplayName
}
}
func (h *Handler) mapUserIdsFederatedShare(ctx context.Context, gw gatewayv1beta1.GatewayAPIClient, sd *conversions.ShareData) {
if sd.ShareWith != "" {
user := h.mustGetRemoteUser(ctx, gw, sd.ShareWith)
sd.ShareWith = user.Username
sd.ShareWithDisplayname = user.DisplayName
}
if sd.UIDOwner != "" {
user := h.mustGetIdentifiers(ctx, gw, sd.UIDOwner, false)
sd.DisplaynameOwner = user.DisplayName
}
if sd.UIDFileOwner != "" {
user := h.mustGetIdentifiers(ctx, gw, sd.UIDFileOwner, false)
sd.DisplaynameFileOwner = user.DisplayName
}
}
func (h *Handler) mustGetRemoteUser(ctx context.Context, gw gatewayv1beta1.GatewayAPIClient, id string) *userIdentifiers {
s := strings.SplitN(id, "@", 2)
opaqueID, idp := s[0], s[1]
userRes, err := gw.GetAcceptedUser(ctx, &invitepb.GetAcceptedUserRequest{
RemoteUserId: &userpb.UserId{
Idp: idp,
OpaqueId: opaqueID,
},
})
if err != nil {
return &userIdentifiers{}
}
if userRes.Status.Code != rpc.Code_CODE_OK {
return &userIdentifiers{}
}
user := userRes.RemoteUser
return &userIdentifiers{
DisplayName: user.DisplayName,
Username: user.Username,
Mail: user.Mail,
}
}
func (h *Handler) listOutcomingFederatedShares(ctx context.Context, gw gatewayv1beta1.GatewayAPIClient, filters []*ocm.ListOCMSharesRequest_Filter) ([]*conversions.ShareData, error) {
listRes, err := gw.ListOCMShares(ctx, &ocm.ListOCMSharesRequest{
Filters: filters,
})
if err != nil {
return nil, err
}
shares := []*conversions.ShareData{}
for _, s := range listRes.Shares {
sd, err := conversions.OCMShare2ShareData(s)
if err != nil {
continue
}
h.mapUserIdsFederatedShare(ctx, gw, sd)
info, status, err := h.getResourceInfoByID(ctx, gw, s.ResourceId)
if err != nil {
return nil, err
}
if status.Code != rpc.Code_CODE_OK {
return nil, err
}
h.addFileInfo(ctx, sd, info)
shares = append(shares, sd)
}
return shares, nil
}

View File

@@ -46,6 +46,7 @@ import (
"google.golang.org/grpc/metadata"
"google.golang.org/protobuf/types/known/fieldmaskpb"
ocmv1beta1 "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/config"
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/conversions"
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/response"
@@ -82,6 +83,8 @@ type Handler struct {
publicURL string
sharePrefix string
homeNamespace string
ocmMountPoint string
listOCMShares bool
skipUpdatingExistingSharesMountpoints bool
additionalInfoTemplate *template.Template
userIdentifierCache *ttlcache.Cache
@@ -132,6 +135,8 @@ func (h *Handler) Init(c *config.Config) error {
h.publicURL = c.Config.Host
h.sharePrefix = c.SharePrefix
h.homeNamespace = c.HomeNamespace
h.ocmMountPoint = c.OCMMountPoint
h.listOCMShares = c.ListOCMShares
h.skipUpdatingExistingSharesMountpoints = c.SkipUpdatingExistingSharesMountpoints
h.additionalInfoTemplate, _ = template.New("additionalInfo").Parse(c.AdditionalInfoAttribute)
@@ -861,7 +866,8 @@ const (
func (h *Handler) listSharesWithMe(w http.ResponseWriter, r *http.Request) {
// which pending state to list
stateFilter := getStateFilter(r.FormValue("state"))
state := r.FormValue("state")
stateFilter := getStateFilter(state)
showHidden, _ := strconv.ParseBool(r.URL.Query().Get("show_hidden"))
@@ -1037,6 +1043,18 @@ func (h *Handler) listSharesWithMe(w http.ResponseWriter, r *http.Request) {
sublog.Debug().Msgf("share: %+v", *data)
}
if h.listOCMShares {
// include ocm shares in the response
stateFilter := getOCMStateFilter(state)
lst, err := h.listReceivedFederatedShares(ctx, client, stateFilter)
if err != nil {
sublog.Err(err).Msg("error listing received ocm shares")
response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error listing received ocm shares", err)
return
}
shares = append(shares, lst...)
}
response.WriteOCSSuccess(w, r, shares)
}
@@ -1520,6 +1538,19 @@ func mapState(state collaboration.ShareState) int {
return mapped
}
func mapOCMState(state ocmv1beta1.ShareState) int {
switch state {
case ocmv1beta1.ShareState_SHARE_STATE_PENDING:
return ocsStatePending
case ocmv1beta1.ShareState_SHARE_STATE_ACCEPTED:
return ocsStateAccepted
case ocmv1beta1.ShareState_SHARE_STATE_REJECTED:
return ocsStateRejected
default:
return ocsStateUnknown
}
}
func getStateFilter(s string) collaboration.ShareState {
var stateFilter collaboration.ShareState
switch s {
@@ -1537,6 +1568,21 @@ func getStateFilter(s string) collaboration.ShareState {
return stateFilter
}
func getOCMStateFilter(s string) ocmv1beta1.ShareState {
switch s {
case "all":
return ocsStateUnknown // no filter
case "0": // accepted
return ocmv1beta1.ShareState_SHARE_STATE_ACCEPTED
case "1": // pending
return ocmv1beta1.ShareState_SHARE_STATE_PENDING
case "2": // rejected
return ocmv1beta1.ShareState_SHARE_STATE_REJECTED
default:
return ocmv1beta1.ShareState_SHARE_STATE_ACCEPTED
}
}
func (h *Handler) getPoolClient() (gateway.GatewayAPIClient, error) {
return pool.GetGatewayServiceClient(h.gatewayAddr)
}

View File

@@ -25,6 +25,7 @@ import (
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
ocmpb "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/conversions"
@@ -252,7 +253,46 @@ func (h *Handler) listUserShares(r *http.Request, filters []*collaboration.Filte
log.Debug().Interface("share", s).Interface("info", info).Interface("shareData", data).Msg("mapped")
ocsDataPayload = append(ocsDataPayload, data)
}
if h.listOCMShares {
// include the ocm shares
ocmShares, err := h.listOutcomingFederatedShares(ctx, client, convertToOCMFilters(filters))
if err != nil {
return nil, nil, err
}
ocsDataPayload = append(ocsDataPayload, ocmShares...)
}
}
return ocsDataPayload, nil, nil
}
func convertToOCMFilters(filters []*collaboration.Filter) []*ocmpb.ListOCMSharesRequest_Filter {
ocmfilters := []*ocmpb.ListOCMSharesRequest_Filter{}
for _, f := range filters {
switch v := f.Term.(type) {
case *collaboration.Filter_ResourceId:
ocmfilters = append(ocmfilters, &ocmpb.ListOCMSharesRequest_Filter{
Type: ocmpb.ListOCMSharesRequest_Filter_TYPE_RESOURCE_ID,
Term: &ocmpb.ListOCMSharesRequest_Filter_ResourceId{
ResourceId: v.ResourceId,
},
})
case *collaboration.Filter_Creator:
ocmfilters = append(ocmfilters, &ocmpb.ListOCMSharesRequest_Filter{
Type: ocmpb.ListOCMSharesRequest_Filter_TYPE_CREATOR,
Term: &ocmpb.ListOCMSharesRequest_Filter_Creator{
Creator: v.Creator,
},
})
case *collaboration.Filter_Owner:
ocmfilters = append(ocmfilters, &ocmpb.ListOCMSharesRequest_Filter{
Type: ocmpb.ListOCMSharesRequest_Filter_TYPE_OWNER,
Term: &ocmpb.ListOCMSharesRequest_Filter_Owner{
Owner: v.Owner,
},
})
}
}
return ocmfilters
}

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 CERN
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.
package ocmd
package reqres
import (
"encoding/json"
@@ -25,10 +25,10 @@ import (
"github.com/cs3org/reva/v2/pkg/appctx"
)
// APIErrorCode stores the type of error encountered
// APIErrorCode stores the type of error encountered.
type APIErrorCode string
// The various types of errors that can be expected to occur
// The various types of errors that can be expected to occur.
const (
APIErrorNotFound APIErrorCode = "RESOURCE_NOT_FOUND"
APIErrorUnauthenticated APIErrorCode = "UNAUTHENTICATED"
@@ -36,10 +36,11 @@ const (
APIErrorUnimplemented APIErrorCode = "FUNCTION_NOT_IMPLEMENTED"
APIErrorInvalidParameter APIErrorCode = "INVALID_PARAMETER"
APIErrorProviderError APIErrorCode = "PROVIDER_ERROR"
APIErrorAlreadyExist APIErrorCode = "ALREADY_EXIST"
APIErrorServerError APIErrorCode = "SERVER_ERROR"
)
// APIErrorCodeMapping stores the HTTP error code mapping for various APIErrorCodes
// APIErrorCodeMapping stores the HTTP error code mapping for various APIErrorCodes.
var APIErrorCodeMapping = map[APIErrorCode]int{
APIErrorNotFound: http.StatusNotFound,
APIErrorUnauthenticated: http.StatusUnauthorized,
@@ -47,16 +48,17 @@ var APIErrorCodeMapping = map[APIErrorCode]int{
APIErrorUnimplemented: http.StatusNotImplemented,
APIErrorInvalidParameter: http.StatusBadRequest,
APIErrorProviderError: http.StatusBadGateway,
APIErrorAlreadyExist: http.StatusConflict,
APIErrorServerError: http.StatusInternalServerError,
}
// APIError encompasses the error type and message
// APIError encompasses the error type and message.
type APIError struct {
Code APIErrorCode `json:"code"`
Message string `json:"message"`
}
// WriteError handles writing error responses
// 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)

View File

@@ -0,0 +1,139 @@
// Copyright 2018-2023 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 sciencemesh
import (
"context"
"encoding/json"
"errors"
"net/http"
"strings"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
ocmpb "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
"github.com/cs3org/reva/v2/internal/http/services/reqres"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/v2/pkg/rhttp/router"
)
type appsHandler struct {
gatewayClient gateway.GatewayAPIClient
ocmMountPoint string
}
func (h *appsHandler) init(c *config) error {
var err error
h.gatewayClient, err = pool.GetGatewayServiceClient(c.GatewaySvc)
if err != nil {
return err
}
h.ocmMountPoint = c.OCMMountPoint
return nil
}
func (h *appsHandler) shareInfo(p string) (*ocmpb.ShareId, string) {
p = strings.TrimPrefix(p, h.ocmMountPoint)
shareID, rel := router.ShiftPath(p)
if len(rel) > 0 {
rel = rel[1:]
}
return &ocmpb.ShareId{OpaqueId: shareID}, rel
}
func (h *appsHandler) OpenInApp(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
if err := r.ParseForm(); err != nil {
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "parameters could not be parsed", nil)
return
}
path := r.Form.Get("file")
if path == "" {
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "missing file", nil)
return
}
shareID, rel := h.shareInfo(path)
template, err := h.webappTemplate(ctx, shareID)
if err != nil {
var e errtypes.NotFound
if errors.As(err, &e) {
reqres.WriteError(w, r, reqres.APIErrorNotFound, e.Error(), nil)
}
reqres.WriteError(w, r, reqres.APIErrorServerError, err.Error(), err)
return
}
url := resolveTemplate(template, rel)
if err := json.NewEncoder(w).Encode(map[string]any{
"app_url": url,
}); err != nil {
reqres.WriteError(w, r, reqres.APIErrorServerError, "error marshalling JSON response", err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
}
func (h *appsHandler) webappTemplate(ctx context.Context, id *ocmpb.ShareId) (string, error) {
res, err := h.gatewayClient.GetReceivedOCMShare(ctx, &ocmpb.GetReceivedOCMShareRequest{
Ref: &ocmpb.ShareReference{
Spec: &ocmpb.ShareReference_Id{
Id: id,
},
},
})
if err != nil {
return "", err
}
if res.Status.Code != rpcv1beta1.Code_CODE_OK {
if res.Status.Code == rpcv1beta1.Code_CODE_NOT_FOUND {
return "", errtypes.NotFound(res.Status.Message)
}
return "", errtypes.InternalError(res.Status.Message)
}
webapp, ok := getWebappProtocol(res.Share.Protocols)
if !ok {
return "", errtypes.BadRequest("share does not contain webapp protocol")
}
return webapp.UriTemplate, nil
}
func getWebappProtocol(protocols []*ocmpb.Protocol) (*ocmpb.WebappProtocol, bool) {
for _, p := range protocols {
if t, ok := p.Term.(*ocmpb.Protocol_WebappOptions); ok {
return t.WebappOptions, true
}
}
return nil, false
}
func resolveTemplate(template string, rel string) string {
// the template is of type "https://open-cloud-mesh.org/s/share-hash/{relative-path-to-shared-resource}"
return strings.Replace(template, "{relative-path-to-shared-resource}", rel, 1)
}

View File

@@ -0,0 +1,119 @@
// Copyright 2018-2023 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 sciencemesh
import (
"bytes"
"html/template"
"io"
"os"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
)
type emailParams struct {
User *userpb.User
Token string
MeshDirectoryURL string
InviteLink string
}
const defaultSubject = `ScienceMesh: {{.User.DisplayName}} wants to collaborate with you`
const defaultBody = `Hi
{{.User.DisplayName}} ({{.User.Mail}}) wants to start sharing OCM resources with you.
To accept the invite, please visit the following URL:
{{.InviteLink}}
Alternatively, you can visit your mesh provider and use the following details:
Token: {{.Token}}
ProviderDomain: {{.User.Id.Idp}}
Best,
The ScienceMesh team`
func (h *tokenHandler) sendEmail(recipient string, obj *emailParams) error {
subj, err := h.generateEmailSubject(obj)
if err != nil {
return err
}
body, err := h.generateEmailBody(obj)
if err != nil {
return err
}
return h.smtpCredentials.SendMail(recipient, subj, body)
}
func (h *tokenHandler) generateEmailSubject(obj *emailParams) (string, error) {
var buf bytes.Buffer
err := h.tplSubj.Execute(&buf, obj)
return buf.String(), err
}
func (h *tokenHandler) generateEmailBody(obj *emailParams) (string, error) {
var buf bytes.Buffer
err := h.tplBody.Execute(&buf, obj)
return buf.String(), err
}
func (h *tokenHandler) initBodyTemplate(bodyTemplPath string) error {
var body string
if bodyTemplPath == "" {
body = defaultBody
} else {
f, err := os.Open(bodyTemplPath)
if err != nil {
return err
}
defer f.Close()
data, err := io.ReadAll(f)
if err != nil {
return err
}
body = string(data)
}
tpl, err := template.New("tpl_body").Parse(body)
if err != nil {
return err
}
h.tplBody = tpl
return nil
}
func (h *tokenHandler) initSubjectTemplate(subjTempl string) error {
var subj string
if subjTempl == "" {
subj = defaultSubject
} else {
subj = subjTempl
}
tpl, err := template.New("tpl_subj").Parse(subj)
if err != nil {
return err
}
h.tplSubj = tpl
return nil
}

View File

@@ -0,0 +1,87 @@
// Copyright 2018-2023 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 sciencemesh
import (
"encoding/json"
"errors"
"net/http"
"strings"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
providerpb "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
"github.com/cs3org/reva/v2/internal/http/services/reqres"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
)
type providersHandler struct {
gatewayClient gateway.GatewayAPIClient
}
func (h *providersHandler) init(c *config) error {
var err error
h.gatewayClient, err = pool.GetGatewayServiceClient(c.GatewaySvc)
if err != nil {
return err
}
return nil
}
type provider struct {
FullName string `json:"full_name"`
Domain string `json:"domain"`
}
// ListProviders lists all the providers filtering by the `search` query parameter.
func (h *providersHandler) ListProviders(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
term := strings.ToLower(r.URL.Query().Get("search"))
listRes, err := h.gatewayClient.ListAllProviders(ctx, &providerpb.ListAllProvidersRequest{})
if err != nil {
reqres.WriteError(w, r, reqres.APIErrorServerError, "error listing all providers", err)
return
}
if listRes.Status.Code != rpc.Code_CODE_OK {
reqres.WriteError(w, r, reqres.APIErrorServerError, listRes.Status.Message, errors.New(listRes.Status.Message))
return
}
filtered := []*provider{}
for _, p := range listRes.Providers {
if strings.Contains(strings.ToLower(p.FullName), term) ||
strings.Contains(strings.ToLower(p.Domain), term) {
filtered = append(filtered, &provider{
FullName: p.FullName,
Domain: p.Domain,
})
}
}
if err := json.NewEncoder(w).Encode(filtered); err != nil {
reqres.WriteError(w, r, reqres.APIErrorServerError, "error encoding response in json", err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
}

View File

@@ -0,0 +1,136 @@
// Copyright 2018-2023 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 sciencemesh
import (
"net/http"
"github.com/cs3org/reva/v2/pkg/appctx"
"github.com/cs3org/reva/v2/pkg/rhttp/global"
"github.com/cs3org/reva/v2/pkg/sharedconf"
"github.com/cs3org/reva/v2/pkg/smtpclient"
"github.com/cs3org/reva/v2/pkg/utils/cfg"
"github.com/go-chi/chi/v5"
"github.com/rs/zerolog"
)
func init() {
global.Register("sciencemesh", New)
}
// New returns a new sciencemesh service.
func New(m map[string]interface{}, _ *zerolog.Logger) (global.Service, error) {
var c config
if err := cfg.Decode(m, &c); err != nil {
return nil, err
}
r := chi.NewRouter()
s := &svc{
conf: &c,
router: r,
}
if err := s.routerInit(); err != nil {
return nil, err
}
return s, nil
}
// Close performs cleanup.
func (s *svc) Close() error {
return nil
}
type config struct {
Prefix string `mapstructure:"prefix"`
SMTPCredentials *smtpclient.SMTPCredentials `mapstructure:"smtp_credentials" validate:"required"`
GatewaySvc string `mapstructure:"gatewaysvc" validate:"required"`
MeshDirectoryURL string `mapstructure:"mesh_directory_url" validate:"required"`
ProviderDomain string `mapstructure:"provider_domain" validate:"required"`
SubjectTemplate string `mapstructure:"subject_template"`
BodyTemplatePath string `mapstructure:"body_template_path"`
OCMMountPoint string `mapstructure:"ocm_mount_point"`
}
func (c *config) ApplyDefaults() {
if c.Prefix == "" {
c.Prefix = "sciencemesh"
}
if c.OCMMountPoint == "" {
c.OCMMountPoint = "/ocm"
}
c.GatewaySvc = sharedconf.GetGatewaySVC(c.GatewaySvc)
}
type svc struct {
conf *config
router chi.Router
}
func (s *svc) routerInit() error {
tokenHandler := new(tokenHandler)
if err := tokenHandler.init(s.conf); err != nil {
return err
}
providersHandler := new(providersHandler)
if err := providersHandler.init(s.conf); err != nil {
return err
}
sharesHandler := new(sharesHandler)
if err := sharesHandler.init(s.conf); err != nil {
return err
}
appsHandler := new(appsHandler)
if err := appsHandler.init(s.conf); err != nil {
return err
}
s.router.Get("/generate-invite", tokenHandler.Generate)
s.router.Get("/list-invite", tokenHandler.ListInvite)
s.router.Post("/accept-invite", tokenHandler.AcceptInvite)
s.router.Get("/find-accepted-users", tokenHandler.FindAccepted)
s.router.Delete("/delete-accepted-user", tokenHandler.DeleteAccepted)
s.router.Get("/list-providers", providersHandler.ListProviders)
s.router.Post("/create-share", sharesHandler.CreateShare)
s.router.Post("/open-in-app", appsHandler.OpenInApp)
return nil
}
func (s *svc) Prefix() string {
return s.conf.Prefix
}
func (s *svc) Unprotected() []string {
return nil
}
func (s *svc) Handler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log := appctx.GetLogger(r.Context())
log.Debug().Str("path", r.URL.Path).Msg("sciencemesh routing")
// unset raw path, otherwise chi uses it to route and then fails to match percent encoded path segments
r.URL.RawPath = ""
s.router.ServeHTTP(w, r)
})
}

View File

@@ -0,0 +1,179 @@
// Copyright 2018-2023 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 sciencemesh
import (
"encoding/json"
"errors"
"mime"
"net/http"
appprovider "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
providerpb "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/conversions"
"github.com/cs3org/reva/v2/internal/http/services/reqres"
"github.com/cs3org/reva/v2/pkg/appctx"
"github.com/cs3org/reva/v2/pkg/ocm/share"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/go-playground/validator/v10"
)
var validate = validator.New()
type sharesHandler struct {
gatewayClient gateway.GatewayAPIClient
}
func (h *sharesHandler) init(c *config) error {
var err error
h.gatewayClient, err = pool.GetGatewayServiceClient(c.GatewaySvc)
return err
}
type createShareRequest struct {
SourcePath string `json:"sourcePath" validate:"required"`
TargetPath string `json:"targetPath" validate:"required"`
Type string `json:"type"`
Role string `json:"role" validate:"oneof=viewer editor"`
RecipientUsername string `json:"recipientUsername" validate:"required"`
RecipientHost string `json:"recipientHost" validate:"required"`
}
// CreateShare creates an OCM share.
func (h *sharesHandler) CreateShare(w http.ResponseWriter, r *http.Request) {
log := appctx.GetLogger(r.Context())
req, err := getCreateShareRequest(r)
if err != nil {
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "invalid parameters", err)
return
}
ctx := r.Context()
statRes, err := h.gatewayClient.Stat(ctx, &providerpb.StatRequest{
Ref: &providerpb.Reference{
Path: req.SourcePath,
},
})
switch {
case err != nil:
reqres.WriteError(w, r, reqres.APIErrorServerError, "unexpected error", err)
return
case statRes.Status.Code == rpc.Code_CODE_NOT_FOUND:
reqres.WriteError(w, r, reqres.APIErrorNotFound, statRes.Status.Message, nil)
return
case statRes.Status.Code != rpc.Code_CODE_OK:
reqres.WriteError(w, r, reqres.APIErrorServerError, statRes.Status.Message, errors.New(statRes.Status.Message))
return
}
recipientProviderInfo, err := h.gatewayClient.GetInfoByDomain(ctx, &ocmprovider.GetInfoByDomainRequest{
Domain: req.RecipientHost,
})
if err != nil {
reqres.WriteError(w, r, reqres.APIErrorServerError, "error sending a grpc get invite by domain info request", err)
return
}
if recipientProviderInfo.Status.Code != rpc.Code_CODE_OK {
reqres.WriteError(w, r, reqres.APIErrorNotFound, recipientProviderInfo.Status.Message, errors.New(recipientProviderInfo.Status.Message))
return
}
perm, viewMode := getPermissionsByRole(req.Role)
log.Debug().Msg("calling gatewayClient.CreateOCMShare from sciencemesh/share.go")
shareRes, err := h.gatewayClient.CreateOCMShare(ctx, &ocm.CreateOCMShareRequest{
ResourceId: statRes.Info.Id,
Grantee: &providerpb.Grantee{
Type: providerpb.GranteeType_GRANTEE_TYPE_USER,
Id: &providerpb.Grantee_UserId{
UserId: &userpb.UserId{
Idp: req.RecipientHost,
OpaqueId: req.RecipientUsername,
},
},
},
RecipientMeshProvider: recipientProviderInfo.ProviderInfo,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(perm),
share.NewWebappAccessMethod(viewMode),
},
})
log.Debug().Msg("called gatewayClient.CreateOCMShare from sciencemesh/share.go")
switch {
case err != nil:
reqres.WriteError(w, r, reqres.APIErrorServerError, "error sending a grpc CreateOCMShare", err)
return
case shareRes.Status.Code == rpc.Code_CODE_NOT_FOUND:
reqres.WriteError(w, r, reqres.APIErrorNotFound, shareRes.Status.Message, nil)
return
case shareRes.Status.Code == rpc.Code_CODE_ALREADY_EXISTS:
reqres.WriteError(w, r, reqres.APIErrorAlreadyExist, shareRes.Status.Message, nil)
return
case shareRes.Status.Code != rpc.Code_CODE_OK:
reqres.WriteError(w, r, reqres.APIErrorAlreadyExist, shareRes.Status.Message, errors.New(shareRes.Status.Message))
return
}
if err := json.NewEncoder(w).Encode(shareRes); err != nil {
log.Error().Err(err).Msg("error encoding response")
w.WriteHeader(http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
}
func getPermissionsByRole(role string) (*providerpb.ResourcePermissions, appprovider.ViewMode) {
switch role {
case "viewer":
return conversions.NewViewerRole(false).CS3ResourcePermissions(), appprovider.ViewMode_VIEW_MODE_READ_ONLY
case "editor":
return conversions.NewEditorRole(false).CS3ResourcePermissions(), appprovider.ViewMode_VIEW_MODE_READ_WRITE
}
return nil, 0
}
func getCreateShareRequest(r *http.Request) (*createShareRequest, error) {
var req createShareRequest
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
}
} else {
return nil, errors.New("body request not recognised")
}
// set defaults
if req.Type == "" {
req.Type = "viewer"
}
// validate the request
if err := validate.Struct(req); err != nil {
return nil, err
}
return &req, nil
}

View File

@@ -0,0 +1,324 @@
// Copyright 2018-2023 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 sciencemesh
import (
"encoding/json"
"errors"
"html/template"
"mime"
"net/http"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
invitepb "github.com/cs3org/go-cs3apis/cs3/ocm/invite/v1beta1"
ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
"github.com/cs3org/reva/v2/internal/http/services/reqres"
"github.com/cs3org/reva/v2/pkg/appctx"
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/v2/pkg/smtpclient"
"github.com/cs3org/reva/v2/pkg/utils/list"
)
type tokenHandler struct {
gatewayClient gateway.GatewayAPIClient
smtpCredentials *smtpclient.SMTPCredentials
meshDirectoryURL string
providerDomain string
tplSubj *template.Template
tplBody *template.Template
}
func (h *tokenHandler) init(c *config) error {
var err error
h.gatewayClient, err = pool.GetGatewayServiceClient(c.GatewaySvc)
if err != nil {
return err
}
if c.SMTPCredentials != nil {
h.smtpCredentials = smtpclient.NewSMTPCredentials(c.SMTPCredentials)
}
h.meshDirectoryURL = c.MeshDirectoryURL
h.providerDomain = c.ProviderDomain
if err := h.initSubjectTemplate(c.SubjectTemplate); err != nil {
return err
}
if err := h.initBodyTemplate(c.BodyTemplatePath); err != nil {
return err
}
return nil
}
type token struct {
Token string `json:"token"`
Description string `json:"description,omitempty"`
Expiration uint64 `json:"expiration,omitempty"`
InviteLink string `json:"invite_link"`
}
// Generate generates an invitation token and if a recipient is specified,
// will send an email containing the link the user will use to accept the
// invitation.
func (h *tokenHandler) Generate(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
query := r.URL.Query()
token, err := h.gatewayClient.GenerateInviteToken(ctx, &invitepb.GenerateInviteTokenRequest{
Description: query.Get("description"),
})
if err != nil {
reqres.WriteError(w, r, reqres.APIErrorServerError, "error generating token", err)
return
}
user := ctxpkg.ContextMustGetUser(ctx)
recipient := query.Get("recipient")
if recipient != "" && h.smtpCredentials != nil {
templObj := &emailParams{
User: user,
Token: token.InviteToken.Token,
MeshDirectoryURL: h.meshDirectoryURL,
}
if err := h.sendEmail(recipient, templObj); err != nil {
reqres.WriteError(w, r, reqres.APIErrorServerError, "error sending token by mail", err)
return
}
}
tknRes := h.prepareGenerateTokenResponse(token.InviteToken)
if err := json.NewEncoder(w).Encode(tknRes); err != nil {
reqres.WriteError(w, r, reqres.APIErrorServerError, "error marshalling token data", err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
}
func (h *tokenHandler) prepareGenerateTokenResponse(tkn *invitepb.InviteToken) *token {
res := &token{
Token: tkn.Token,
Description: tkn.Description,
InviteLink: h.meshDirectoryURL + "?token=" + tkn.Token + "&providerDomain=" + h.providerDomain,
}
if tkn.Expiration != nil {
res.Expiration = tkn.Expiration.Seconds
}
return res
}
type acceptInviteRequest struct {
Token string `json:"token"`
ProviderDomain string `json:"providerDomain"`
}
// AcceptInvite accepts an invitation from the user in the remote provider.
func (h *tokenHandler) AcceptInvite(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
log := appctx.GetLogger(ctx)
req, err := getAcceptInviteRequest(r)
if err != nil {
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "missing parameters in request", err)
return
}
if req.Token == "" || req.ProviderDomain == "" {
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "token and providerDomain must not be null", nil)
return
}
providerInfo, err := h.gatewayClient.GetInfoByDomain(ctx, &ocmprovider.GetInfoByDomainRequest{
Domain: req.ProviderDomain,
})
if err != nil {
reqres.WriteError(w, r, reqres.APIErrorServerError, "error sending a grpc get invite by domain info request", err)
return
}
if providerInfo.Status.Code != rpc.Code_CODE_OK {
reqres.WriteError(w, r, reqres.APIErrorServerError, "grpc forward invite request failed", errors.New(providerInfo.Status.Message))
return
}
forwardInviteReq := &invitepb.ForwardInviteRequest{
InviteToken: &invitepb.InviteToken{
Token: req.Token,
},
OriginSystemProvider: providerInfo.ProviderInfo,
}
forwardInviteResponse, err := h.gatewayClient.ForwardInvite(ctx, forwardInviteReq)
if err != nil {
reqres.WriteError(w, r, reqres.APIErrorServerError, "error sending a grpc forward invite request", err)
return
}
if forwardInviteResponse.Status.Code != rpc.Code_CODE_OK {
switch forwardInviteResponse.Status.Code {
case rpc.Code_CODE_NOT_FOUND:
reqres.WriteError(w, r, reqres.APIErrorNotFound, "token not found", nil)
return
case rpc.Code_CODE_INVALID_ARGUMENT:
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "token has expired", nil)
return
case rpc.Code_CODE_ALREADY_EXISTS:
reqres.WriteError(w, r, reqres.APIErrorAlreadyExist, "user already known", nil)
return
case rpc.Code_CODE_PERMISSION_DENIED:
reqres.WriteError(w, r, reqres.APIErrorUnauthenticated, "remove service not trusted", nil)
return
default:
reqres.WriteError(w, r, reqres.APIErrorServerError, "unexpected error: "+forwardInviteResponse.Status.Message, errors.New(forwardInviteResponse.Status.Message))
return
}
}
w.WriteHeader(http.StatusOK)
log.Info().Str("token", req.Token).Str("provider", req.ProviderDomain).Msgf("invite forwarded")
}
func getAcceptInviteRequest(r *http.Request) (*acceptInviteRequest, error) {
var req acceptInviteRequest
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
}
} else {
req.Token, req.ProviderDomain = r.FormValue("token"), r.FormValue("providerDomain")
}
return &req, nil
}
type remoteUser struct {
DisplayName string `json:"display_name"`
Idp string `json:"idp"`
UserID string `json:"user_id"`
Mail string `json:"mail"`
}
// FindAccepted returns the list of all the users that accepted the invitation
// to the authenticated user.
func (h *tokenHandler) FindAccepted(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
res, err := h.gatewayClient.FindAcceptedUsers(ctx, &invitepb.FindAcceptedUsersRequest{})
if err != nil {
reqres.WriteError(w, r, reqres.APIErrorServerError, "error sending a grpc find accepted users request", err)
return
}
users := list.Map(res.AcceptedUsers, func(u *userpb.User) *remoteUser {
return &remoteUser{
DisplayName: u.DisplayName,
Idp: u.Id.Idp,
UserID: u.Id.OpaqueId,
Mail: u.Mail,
}
})
if err := json.NewEncoder(w).Encode(users); err != nil {
reqres.WriteError(w, r, reqres.APIErrorServerError, "error marshalling token data", err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
}
// DeleteAccepted deletes the given user from the list of the accepted users.
func (h *tokenHandler) DeleteAccepted(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
req, err := getDeleteAcceptedRequest(r)
if err != nil {
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "missing parameters in request", err)
return
}
res, err := h.gatewayClient.DeleteAcceptedUser(ctx, &invitepb.DeleteAcceptedUserRequest{
RemoteUserId: &userpb.UserId{
Idp: req.Idp,
OpaqueId: req.UserID,
Type: userpb.UserType_USER_TYPE_FEDERATED,
},
})
if err != nil {
reqres.WriteError(w, r, reqres.APIErrorServerError, "error sending a grpc get invite by domain info request", err)
return
}
if res.Status.Code != rpc.Code_CODE_OK {
reqres.WriteError(w, r, reqres.APIErrorServerError, "grpc forward invite request failed", errors.New(res.Status.Message))
return
}
w.WriteHeader(http.StatusOK)
}
type deleteAcceptedRequest struct {
Idp string `json:"idp"`
UserID string `json:"user_id"`
}
func getDeleteAcceptedRequest(r *http.Request) (*deleteAcceptedRequest, error) {
var req deleteAcceptedRequest
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
}
} else {
req.Idp, req.UserID = r.FormValue("idp"), r.FormValue("user_id")
}
return &req, nil
}
func (h *tokenHandler) ListInvite(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
res, err := h.gatewayClient.ListInviteTokens(ctx, &invitepb.ListInviteTokensRequest{})
if err != nil {
reqres.WriteError(w, r, reqres.APIErrorServerError, "error listing tokens", err)
return
}
if res.Status.Code != rpc.Code_CODE_OK {
reqres.WriteError(w, r, reqres.APIErrorServerError, res.Status.Message, errors.New(res.Status.Message))
return
}
tokens := make([]*token, 0, len(res.InviteTokens))
for _, tkn := range res.InviteTokens {
tokens = append(tokens, h.prepareGenerateTokenResponse(tkn))
}
if err := json.NewEncoder(w).Encode(tokens); err != nil {
reqres.WriteError(w, r, reqres.APIErrorServerError, "error marshalling token data", err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
}

View File

@@ -40,6 +40,6 @@ type Registry interface {
// Provider is the interface that application providers implement
// for interacting with external apps that serve the requested resource.
type Provider interface {
GetAppURL(ctx context.Context, resource *provider.ResourceInfo, viewMode appprovider.OpenInAppRequest_ViewMode, token, language string) (*appprovider.OpenInAppURL, error)
GetAppURL(ctx context.Context, resource *provider.ResourceInfo, viewMode appprovider.ViewMode, token, language string) (*appprovider.OpenInAppURL, error)
GetAppProviderInfo(ctx context.Context) (*registry.ProviderInfo, error)
}

View File

@@ -39,7 +39,7 @@ type demoProvider struct {
iframeUIProvider string
}
func (p *demoProvider) GetAppURL(ctx context.Context, resource *provider.ResourceInfo, viewMode appprovider.OpenInAppRequest_ViewMode, token, language string) (*appprovider.OpenInAppURL, error) {
func (p *demoProvider) GetAppURL(ctx context.Context, resource *provider.ResourceInfo, viewMode appprovider.ViewMode, token, language string) (*appprovider.OpenInAppURL, error) {
url := fmt.Sprintf("<iframe src=%s/open/%s?view-mode=%s&access-token=%s />", p.iframeUIProvider, storagespace.FormatResourceID(*resource.Id), viewMode.String(), token)
return &appprovider.OpenInAppURL{
AppUrl: url,

View File

@@ -122,7 +122,7 @@ func New(m map[string]interface{}) (app.Provider, error) {
}, nil
}
func (p *wopiProvider) GetAppURL(ctx context.Context, resource *provider.ResourceInfo, viewMode appprovider.OpenInAppRequest_ViewMode, token, language string) (*appprovider.OpenInAppURL, error) {
func (p *wopiProvider) GetAppURL(ctx context.Context, resource *provider.ResourceInfo, viewMode appprovider.ViewMode, token, language string) (*appprovider.OpenInAppURL, error) {
log := appctx.GetLogger(ctx)
ext := path.Ext(resource.Path)

View File

@@ -27,6 +27,7 @@ import (
_ "github.com/cs3org/reva/v2/pkg/auth/manager/ldap"
_ "github.com/cs3org/reva/v2/pkg/auth/manager/machine"
_ "github.com/cs3org/reva/v2/pkg/auth/manager/nextcloud"
_ "github.com/cs3org/reva/v2/pkg/auth/manager/ocmshares"
_ "github.com/cs3org/reva/v2/pkg/auth/manager/oidc"
_ "github.com/cs3org/reva/v2/pkg/auth/manager/owncloudsql"
_ "github.com/cs3org/reva/v2/pkg/auth/manager/publicshares"

View File

@@ -0,0 +1,187 @@
// Copyright 2018-2023 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 ocmshares
import (
"context"
provider "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1"
authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
ocminvite "github.com/cs3org/go-cs3apis/cs3/ocm/invite/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/v2/pkg/appctx"
"github.com/cs3org/reva/v2/pkg/auth"
"github.com/cs3org/reva/v2/pkg/auth/manager/registry"
"github.com/cs3org/reva/v2/pkg/auth/scope"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/v2/pkg/sharedconf"
"github.com/cs3org/reva/v2/pkg/utils"
"github.com/cs3org/reva/v2/pkg/utils/cfg"
"github.com/pkg/errors"
)
func init() {
registry.Register("ocmshares", New)
}
type manager struct {
c *config
gw gateway.GatewayAPIClient
}
type config struct {
GatewayAddr string `mapstructure:"gatewaysvc"`
}
func (c *config) ApplyDefaults() {
c.GatewayAddr = sharedconf.GetGatewaySVC(c.GatewayAddr)
}
// New creates a new ocmshares authentication manager.
func New(m map[string]interface{}) (auth.Manager, error) {
var mgr manager
if err := mgr.Configure(m); err != nil {
return nil, err
}
gw, err := pool.GetGatewayServiceClient(mgr.c.GatewayAddr)
if err != nil {
return nil, err
}
mgr.gw = gw
return &mgr, nil
}
func (m *manager) Configure(ml map[string]interface{}) error {
var c config
if err := cfg.Decode(ml, &c); err != nil {
return errors.Wrap(err, "ocmshares: error decoding config")
}
m.c = &c
return nil
}
func (m *manager) Authenticate(ctx context.Context, token, _ string) (*userpb.User, map[string]*authpb.Scope, error) {
log := appctx.GetLogger(ctx).With().Str("token", token).Logger()
shareRes, err := m.gw.GetOCMShareByToken(ctx, &ocm.GetOCMShareByTokenRequest{
Token: token,
})
switch {
case err != nil:
log.Error().Err(err).Msg("error getting ocm share by token")
return nil, nil, err
case shareRes.Status.Code == rpc.Code_CODE_NOT_FOUND:
log.Debug().Msg("ocm share not found")
return nil, nil, errtypes.NotFound(shareRes.Status.Message)
case shareRes.Status.Code == rpc.Code_CODE_PERMISSION_DENIED:
log.Debug().Msg("permission denied")
return nil, nil, errtypes.InvalidCredentials(shareRes.Status.Message)
case shareRes.Status.Code != rpc.Code_CODE_OK:
log.Error().Interface("status", shareRes.Status).Msg("got unexpected error in the grpc call to GetOCMShare")
return nil, nil, errtypes.InternalError(shareRes.Status.Message)
}
// the user authenticated using the ocmshares authentication method
// is the recipient of the share
u := shareRes.Share.Grantee.GetUserId()
d, err := utils.MarshalProtoV1ToJSON(shareRes.GetShare().Creator)
if err != nil {
return nil, nil, err
}
o := &types.Opaque{
Map: map[string]*types.OpaqueEntry{
"user-filter": {
Decoder: "json",
Value: d,
},
},
}
userRes, err := m.gw.GetAcceptedUser(ctx, &ocminvite.GetAcceptedUserRequest{
RemoteUserId: u,
Opaque: o,
})
switch {
case err != nil:
return nil, nil, err
case userRes.Status.Code == rpc.Code_CODE_NOT_FOUND:
return nil, nil, errtypes.NotFound(shareRes.Status.Message)
case userRes.Status.Code != rpc.Code_CODE_OK:
return nil, nil, errtypes.InternalError(userRes.Status.Message)
}
role, roleStr := getRole(shareRes.Share)
scope, err := scope.AddOCMShareScope(shareRes.Share, role, nil)
if err != nil {
return nil, nil, err
}
user := userRes.RemoteUser
user.Opaque = &types.Opaque{
Map: map[string]*types.OpaqueEntry{
"ocm-share-role": {
Decoder: "plain",
Value: []byte(roleStr),
},
},
}
return user, scope, nil
}
func getRole(s *ocm.Share) (authpb.Role, string) {
// TODO: consider to somehow merge the permissions from all the access methods?
// it's not clear infact which should be the role when webdav is editor role while
// webapp is only view mode for example
// this implementation considers only the simple case in which when a client creates
// a share with multiple access methods, the permissions are matching in all of them.
for _, m := range s.AccessMethods {
switch v := m.Term.(type) {
case *ocm.AccessMethod_WebdavOptions:
p := v.WebdavOptions.Permissions
if p.InitiateFileUpload {
return authpb.Role_ROLE_EDITOR, "editor"
}
if p.InitiateFileDownload {
return authpb.Role_ROLE_VIEWER, "viewer"
}
case *ocm.AccessMethod_WebappOptions:
viewMode := v.WebappOptions.ViewMode
if viewMode == provider.ViewMode_VIEW_MODE_VIEW_ONLY ||
viewMode == provider.ViewMode_VIEW_MODE_READ_ONLY ||
viewMode == provider.ViewMode_VIEW_MODE_PREVIEW {
return authpb.Role_ROLE_VIEWER, "viewer"
}
if viewMode == provider.ViewMode_VIEW_MODE_READ_WRITE {
return authpb.Role_ROLE_EDITOR, "editor"
}
}
}
return authpb.Role_ROLE_INVALID, "invalid"
}

View File

@@ -0,0 +1,193 @@
// Copyright 2018-2023 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 scope
import (
"context"
"path/filepath"
"strings"
appprovider "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1"
appregistry "github.com/cs3org/go-cs3apis/cs3/app/registry/v1beta1"
authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
ocmv1beta1 "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
registry "github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/utils"
"github.com/rs/zerolog"
)
// FIXME: the namespace here is hardcoded
// find a way to pass it from the config.
const ocmNamespace = "/ocm"
func ocmShareScope(_ context.Context, scope *authpb.Scope, resource interface{}, _ *zerolog.Logger) (bool, error) {
var share ocmv1beta1.Share
if err := utils.UnmarshalJSONToProtoV1(scope.Resource.Value, &share); err != nil {
return false, err
}
switch v := resource.(type) {
// viewer role
case *registry.ListStorageProvidersRequest:
ref := &provider.Reference{}
if v.Opaque != nil && v.Opaque.Map != nil {
if e, ok := v.Opaque.Map["storage_id"]; ok {
if ref.ResourceId == nil {
ref.ResourceId = &provider.ResourceId{}
}
ref.ResourceId.StorageId = string(e.Value)
}
if e, ok := v.Opaque.Map["space_id"]; ok {
if ref.ResourceId == nil {
ref.ResourceId = &provider.ResourceId{}
}
ref.ResourceId.SpaceId = string(e.Value)
}
if e, ok := v.Opaque.Map["opaque_id"]; ok {
if ref.ResourceId == nil {
ref.ResourceId = &provider.ResourceId{}
}
ref.ResourceId.OpaqueId = string(e.Value)
}
if e, ok := v.Opaque.Map["path"]; ok {
ref.Path = string(e.Value)
}
}
return checkStorageRefForOCMShare(&share, ref, ocmNamespace), nil
case *registry.GetStorageProvidersRequest:
return checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
case *provider.StatRequest:
return checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
case *provider.ListContainerRequest:
return checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
case *provider.InitiateFileDownloadRequest:
return checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
case *appprovider.OpenInAppRequest:
return checkStorageRefForOCMShare(&share, &provider.Reference{ResourceId: v.ResourceInfo.Id}, ocmNamespace), nil
case *gateway.OpenInAppRequest:
return checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
case *provider.GetLockRequest:
return checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
// editor role
case *provider.CreateContainerRequest:
return hasRoleEditor(*scope) && checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
case *provider.TouchFileRequest:
return hasRoleEditor(*scope) && checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
case *provider.DeleteRequest:
return hasRoleEditor(*scope) && checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
case *provider.MoveRequest:
return hasRoleEditor(*scope) && checkStorageRefForOCMShare(&share, v.GetSource(), ocmNamespace) && checkStorageRefForOCMShare(&share, v.GetDestination(), ocmNamespace), nil
case *provider.InitiateFileUploadRequest:
return hasRoleEditor(*scope) && checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
case *provider.SetArbitraryMetadataRequest:
return hasRoleEditor(*scope) && checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
case *provider.UnsetArbitraryMetadataRequest:
return hasRoleEditor(*scope) && checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
case *provider.SetLockRequest:
return hasRoleEditor(*scope) && checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
case *provider.RefreshLockRequest:
return hasRoleEditor(*scope) && checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
case *provider.UnlockRequest:
return hasRoleEditor(*scope) && checkStorageRefForOCMShare(&share, v.GetRef(), ocmNamespace), nil
// App provider requests
case *appregistry.GetDefaultAppProviderForMimeTypeRequest:
return true, nil
case *appregistry.GetAppProvidersRequest:
return true, nil
case *userv1beta1.GetUserByClaimRequest:
return true, nil
case *userv1beta1.GetUserRequest:
return true, nil
case *provider.ListStorageSpacesRequest:
return true, nil
case *ocmv1beta1.GetOCMShareRequest:
return checkOCMShareRef(&share, v.GetRef()), nil
case *ocmv1beta1.GetOCMShareByTokenRequest:
return share.Token == v.GetToken(), nil
case string:
return checkResourcePath(v), nil
}
return false, nil
}
func checkStorageRefForOCMShare(s *ocmv1beta1.Share, r *provider.Reference, ns string) bool {
if r.ResourceId != nil {
return utils.ResourceIDEqual(s.ResourceId, r.GetResourceId()) || strings.HasPrefix(r.ResourceId.OpaqueId, s.Token)
}
// FIXME: the paths here are hardcoded
if strings.HasPrefix(r.GetPath(), "/public/"+s.Token) {
return true
}
return strings.HasPrefix(r.GetPath(), filepath.Join(ns, s.Token))
}
func checkOCMShareRef(s *ocmv1beta1.Share, ref *ocmv1beta1.ShareReference) bool {
return ref.GetToken() == s.Token
}
// AddOCMShareScope adds the scope to allow access to an OCM share and the share resource.
func AddOCMShareScope(share *ocmv1beta1.Share, role authpb.Role, scopes map[string]*authpb.Scope) (map[string]*authpb.Scope, error) {
// Create a new "scope share" to only expose the required fields `ResourceId` and `Token` to the scope.
scopeShare := ocmv1beta1.Share{ResourceId: share.ResourceId, Token: share.Token}
val, err := utils.MarshalProtoV1ToJSON(&scopeShare)
if err != nil {
return nil, err
}
if scopes == nil {
scopes = make(map[string]*authpb.Scope)
}
scopes["ocmshare:"+share.Id.OpaqueId] = &authpb.Scope{
Resource: &types.OpaqueEntry{
Decoder: "json",
Value: val,
},
Role: role,
}
return scopes, nil
}
// GetOCMSharesFromScopes returns all OCM shares in the given scope.
func GetOCMSharesFromScopes(scopes map[string]*authpb.Scope) ([]*ocmv1beta1.Share, error) {
var shares []*ocmv1beta1.Share
for k, s := range scopes {
if strings.HasPrefix(k, "ocmshare:") {
res := s.Resource
if res.Decoder != "json" {
return nil, errtypes.InternalError("resource should be json encoded")
}
var share ocmv1beta1.Share
err := utils.UnmarshalJSONToProtoV1(res.Value, &share)
if err != nil {
return nil, err
}
shares = append(shares, &share)
}
}
return shares, nil
}

View File

@@ -37,6 +37,7 @@ var supportedScopes = map[string]Verifier{
"share": shareScope,
"receivedshare": receivedShareScope,
"lightweight": lightweightAccountScope,
"ocmshare": ocmShareScope,
}
// VerifyScope is the function to be called when dismantling tokens to check if

View File

@@ -31,6 +31,7 @@ import (
"golang.org/x/crypto/bcrypt"
gatewayv1beta1 "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
@@ -39,6 +40,7 @@ import (
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/publicshare"
"github.com/cs3org/reva/v2/pkg/publicshare/manager/registry"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/v2/pkg/utils"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
@@ -59,11 +61,13 @@ type config struct {
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
c *config
db *sql.DB
client gatewayv1beta1.GatewayAPIClient
}
func (c *config) init() {
@@ -107,9 +111,15 @@ func New(m map[string]interface{}) (publicshare.Manager, error) {
return nil, err
}
gw, err := pool.GetGatewayServiceClient(c.GatewaySvc)
if err != nil {
return nil, err
}
mgr := manager{
c: c,
db: db,
c: c,
db: db,
client: gw,
}
go mgr.startJanitorRun()
@@ -259,7 +269,11 @@ func (m *manager) getByToken(ctx context.Context, token string, u *user.User) (*
}
return nil, "", err
}
return conversions.ConvertToCS3PublicShare(s), s.ShareWith, nil
share, err := conversions.ConvertToCS3PublicShare(ctx, m.client, s)
if err != nil {
return nil, "", err
}
return share, s.ShareWith, nil
}
func (m *manager) getByID(ctx context.Context, id *link.PublicShareId, u *user.User) (*link.PublicShare, string, error) {
@@ -272,7 +286,11 @@ func (m *manager) getByID(ctx context.Context, id *link.PublicShareId, u *user.U
}
return nil, "", err
}
return conversions.ConvertToCS3PublicShare(s), s.ShareWith, nil
share, err := conversions.ConvertToCS3PublicShare(ctx, m.client, s)
if err != nil {
return nil, "", err
}
return share, s.ShareWith, nil
}
func (m *manager) GetPublicShare(ctx context.Context, u *user.User, ref *link.PublicShareReference, sign bool) (*link.PublicShare, error) {
@@ -362,7 +380,10 @@ func (m *manager) ListPublicShares(ctx context.Context, u *user.User, filters []
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); err != nil {
continue
}
cs3Share := conversions.ConvertToCS3PublicShare(s)
cs3Share, err := conversions.ConvertToCS3PublicShare(ctx, m.client, s)
if err != nil {
return nil, err
}
if expired(cs3Share) {
_ = m.cleanupExpiredShares()
} else {
@@ -425,7 +446,10 @@ func (m *manager) GetPublicShareByToken(ctx context.Context, token string, auth
}
return nil, err
}
cs3Share := conversions.ConvertToCS3PublicShare(s)
cs3Share, err := conversions.ConvertToCS3PublicShare(ctx, m.client, s)
if err != nil {
return nil, err
}
if s.ShareWith != "" {
if !authenticate(cs3Share, s.ShareWith, auth) {
// if check := checkPasswordHash(auth.Password, s.ShareWith); !check {

View File

@@ -27,6 +27,7 @@ import (
"strings"
"time"
gatewayv1beta1 "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
@@ -34,6 +35,7 @@ import (
conversions "github.com/cs3org/reva/v2/pkg/cbox/utils"
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/v2/pkg/share"
"github.com/cs3org/reva/v2/pkg/share/manager/registry"
"github.com/cs3org/reva/v2/pkg/utils"
@@ -60,11 +62,13 @@ type config struct {
DbHost string `mapstructure:"db_host"`
DbPort int `mapstructure:"db_port"`
DbName string `mapstructure:"db_name"`
GatewaySvc string `mapstructure:"gatewaysvc"`
}
type mgr struct {
c *config
db *sql.DB
c *config
db *sql.DB
client gatewayv1beta1.GatewayAPIClient
}
// New returns a new share manager.
@@ -80,9 +84,15 @@ func New(m map[string]interface{}) (share.Manager, error) {
return nil, err
}
gw, err := pool.GetGatewayServiceClient(c.GatewaySvc)
if err != nil {
return nil, err
}
return &mgr{
c: c,
db: db,
c: c,
db: db,
client: gw,
}, nil
}
@@ -175,7 +185,11 @@ func (m *mgr) getByID(ctx context.Context, id *collaboration.ShareId) (*collabor
}
return nil, err
}
return conversions.ConvertToCS3Share(s), nil
share, err := conversions.ConvertToCS3Share(ctx, m.client, s)
if err != nil {
return nil, err
}
return share, nil
}
func (m *mgr) getByKey(ctx context.Context, key *collaboration.ShareKey) (*collaboration.Share, error) {
@@ -191,7 +205,11 @@ func (m *mgr) getByKey(ctx context.Context, key *collaboration.ShareKey) (*colla
}
return nil, err
}
return conversions.ConvertToCS3Share(s), nil
share, err := conversions.ConvertToCS3Share(ctx, m.client, s)
if err != nil {
return nil, err
}
return share, nil
}
func (m *mgr) GetShare(ctx context.Context, ref *collaboration.ShareReference) (*collaboration.Share, error) {
@@ -313,7 +331,11 @@ func (m *mgr) ListShares(ctx context.Context, filters []*collaboration.Filter) (
if err := rows.Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.Prefix, &s.ItemSource, &s.ItemType, &s.ID, &s.STime, &s.Permissions, &s.ShareType); err != nil {
continue
}
shares = append(shares, conversions.ConvertToCS3Share(s))
share, err := conversions.ConvertToCS3Share(ctx, m.client, s)
if err != nil {
continue
}
shares = append(shares, share)
}
if err = rows.Err(); err != nil {
return nil, err
@@ -323,7 +345,7 @@ func (m *mgr) ListShares(ctx context.Context, filters []*collaboration.Filter) (
}
// we list the shares that are targeted to the user in context or to the user groups.
func (m *mgr) ListReceivedShares(ctx context.Context, filters []*collaboration.Filter) ([]*collaboration.ReceivedShare, error) {
func (m *mgr) ListReceivedShares(ctx context.Context, filters []*collaboration.Filter, _ *userpb.UserId) ([]*collaboration.ReceivedShare, error) {
user := ctxpkg.ContextMustGetUser(ctx)
uid := conversions.FormatUserID(user.Id)
@@ -365,7 +387,11 @@ func (m *mgr) ListReceivedShares(ctx context.Context, filters []*collaboration.F
if err := rows.Scan(&s.UIDOwner, &s.UIDInitiator, &s.ShareWith, &s.Prefix, &s.ItemSource, &s.ItemType, &s.FileTarget, &s.ID, &s.STime, &s.Permissions, &s.ShareType, &s.State); err != nil {
continue
}
shares = append(shares, conversions.ConvertToCS3ReceivedShare(s))
share, err := conversions.ConvertToCS3ReceivedShare(ctx, m.client, s)
if err != nil {
continue
}
shares = append(shares, share)
}
if err = rows.Err(); err != nil {
return nil, err
@@ -400,7 +426,11 @@ func (m *mgr) getReceivedByID(ctx context.Context, id *collaboration.ShareId) (*
}
return nil, err
}
return conversions.ConvertToCS3ReceivedShare(s), nil
share, err := conversions.ConvertToCS3ReceivedShare(ctx, m.client, s)
if err != nil {
return nil, err
}
return share, nil
}
func (m *mgr) getReceivedByKey(ctx context.Context, key *collaboration.ShareKey) (*collaboration.ReceivedShare, error) {
@@ -431,7 +461,11 @@ func (m *mgr) getReceivedByKey(ctx context.Context, key *collaboration.ShareKey)
}
return nil, err
}
return conversions.ConvertToCS3ReceivedShare(s), nil
share, err := conversions.ConvertToCS3ReceivedShare(ctx, m.client, s)
if err != nil {
return nil, err
}
return share, nil
}
func (m *mgr) GetReceivedShare(ctx context.Context, ref *collaboration.ShareReference) (*collaboration.ReceivedShare, error) {

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 CERN
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -19,11 +19,14 @@
package utils
import (
"strings"
"context"
"errors"
"time"
gatewayv1beta1 "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
grouppb "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
@@ -33,24 +36,28 @@ import (
// DBShare stores information about user and public shares.
type DBShare struct {
ID string
UIDOwner string
UIDInitiator string
Prefix string
ItemSource string
ItemType string
ShareWith string
Token string
Expiration string
Permissions int
ShareType int
ShareName string
STime int
FileTarget string
State int
ID string
UIDOwner string
UIDInitiator string
Prefix string
ItemSource string
ItemType string
ShareWith string
Token string
Expiration string
Permissions int
ShareType int
ShareName string
STime int
FileTarget string
State int
Quicklink bool
Description string
NotifyUploads bool
NotifyUploadsExtraRecipients string
}
// FormatGrantee formats a CS3API grantee to a string
// FormatGrantee formats a CS3API grantee to a string.
func FormatGrantee(g *provider.Grantee) (int, string) {
var granteeType int
var formattedID string
@@ -67,23 +74,31 @@ func FormatGrantee(g *provider.Grantee) (int, string) {
return granteeType, formattedID
}
// ExtractGrantee retrieves the CS3API grantee from a formatted string
func ExtractGrantee(t int, g string) *provider.Grantee {
// ExtractGrantee retrieves the CS3API grantee from a formatted string.
func ExtractGrantee(ctx context.Context, gateway gatewayv1beta1.GatewayAPIClient, t int, g string) (*provider.Grantee, error) {
var grantee provider.Grantee
switch t {
case 0:
grantee.Type = provider.GranteeType_GRANTEE_TYPE_USER
grantee.Id = &provider.Grantee_UserId{UserId: ExtractUserID(g)}
user, err := ExtractUserID(ctx, gateway, g)
if err != nil {
return nil, err
}
grantee.Id = &provider.Grantee_UserId{UserId: user}
case 1:
grantee.Type = provider.GranteeType_GRANTEE_TYPE_GROUP
grantee.Id = &provider.Grantee_GroupId{GroupId: ExtractGroupID(g)}
group, err := ExtractGroupID(ctx, gateway, g)
if err != nil {
return nil, err
}
grantee.Id = &provider.Grantee_GroupId{GroupId: group}
default:
grantee.Type = provider.GranteeType_GRANTEE_TYPE_INVALID
}
return &grantee
return &grantee, nil
}
// ResourceTypeToItem maps a resource type to a string
// ResourceTypeToItem maps a resource type to a string.
func ResourceTypeToItem(r provider.ResourceType) string {
switch r {
case provider.ResourceType_RESOURCE_TYPE_FILE:
@@ -99,7 +114,7 @@ func ResourceTypeToItem(r provider.ResourceType) string {
}
}
// ResourceTypeToItemInt maps a resource type to an integer
// ResourceTypeToItemInt maps a resource type to an integer.
func ResourceTypeToItemInt(r provider.ResourceType) int {
switch r {
case provider.ResourceType_RESOURCE_TYPE_CONTAINER:
@@ -111,7 +126,7 @@ func ResourceTypeToItemInt(r provider.ResourceType) int {
}
}
// SharePermToInt maps read/write permissions to an integer
// SharePermToInt maps read/write permissions to an integer.
func SharePermToInt(p *provider.ResourcePermissions) int {
var perm int
switch {
@@ -126,13 +141,25 @@ func SharePermToInt(p *provider.ResourcePermissions) int {
return perm
}
// IntTosharePerm retrieves read/write permissions from an integer
// IntTosharePerm retrieves read/write permissions from an integer.
func IntTosharePerm(p int, itemType string) *provider.ResourcePermissions {
perms, _ := conversions.NewPermissions(p)
return conversions.RoleFromOCSPermissions(perms).CS3ResourcePermissions()
switch p {
case 1:
return conversions.NewViewerRole(false).CS3ResourcePermissions()
case 15:
if itemType == "folder" {
return conversions.NewEditorRole(false).CS3ResourcePermissions()
}
return conversions.NewFileEditorRole().CS3ResourcePermissions()
case 4:
return conversions.NewUploaderRole().CS3ResourcePermissions()
default:
// TODO we may have other options, for now this is a denial
return &provider.ResourcePermissions{}
}
}
// IntToShareState retrieves the received share state from an integer
// IntToShareState retrieves the received share state from an integer.
func IntToShareState(g int) collaboration.ShareState {
switch g {
case 0:
@@ -146,66 +173,95 @@ func IntToShareState(g int) collaboration.ShareState {
}
}
// FormatUserID formats a CS3API user ID to a string
// FormatUserID formats a CS3API user ID to a string.
func FormatUserID(u *userpb.UserId) string {
return u.OpaqueId
}
// ExtractUserID retrieves a CS3API user ID from a string
func ExtractUserID(u string) *userpb.UserId {
t := userpb.UserType_USER_TYPE_PRIMARY
if strings.HasPrefix(u, "guest:") {
t = userpb.UserType_USER_TYPE_LIGHTWEIGHT
} else if strings.Contains(u, "@") {
t = userpb.UserType_USER_TYPE_FEDERATED
// ExtractUserID retrieves a CS3API user ID from a string.
func ExtractUserID(ctx context.Context, gateway gatewayv1beta1.GatewayAPIClient, u string) (*userpb.UserId, error) {
userRes, err := gateway.GetUser(ctx, &userpb.GetUserRequest{
UserId: &userpb.UserId{OpaqueId: u},
})
if err != nil {
return nil, err
}
return &userpb.UserId{OpaqueId: u, Type: t}
if userRes.Status.Code != rpcv1beta1.Code_CODE_OK {
return nil, errors.New(userRes.Status.Message)
}
return userRes.User.Id, nil
}
// FormatGroupID formats a CS3API group ID to a string
// FormatGroupID formats a CS3API group ID to a string.
func FormatGroupID(u *grouppb.GroupId) string {
return u.OpaqueId
}
// ExtractGroupID retrieves a CS3API group ID from a string
func ExtractGroupID(u string) *grouppb.GroupId {
return &grouppb.GroupId{OpaqueId: u}
// ExtractGroupID retrieves a CS3API group ID from a string.
func ExtractGroupID(ctx context.Context, gateway gatewayv1beta1.GatewayAPIClient, u string) (*grouppb.GroupId, error) {
groupRes, err := gateway.GetGroup(ctx, &grouppb.GetGroupRequest{
GroupId: &grouppb.GroupId{OpaqueId: u},
})
if err != nil {
return nil, err
}
if groupRes.Status.Code != rpcv1beta1.Code_CODE_OK {
return nil, errors.New(groupRes.Status.Message)
}
return groupRes.Group.Id, nil
}
// ConvertToCS3Share converts a DBShare to a CS3API collaboration share
func ConvertToCS3Share(s DBShare) *collaboration.Share {
// ConvertToCS3Share converts a DBShare to a CS3API collaboration share.
func ConvertToCS3Share(ctx context.Context, gateway gatewayv1beta1.GatewayAPIClient, s DBShare) (*collaboration.Share, error) {
ts := &typespb.Timestamp{
Seconds: uint64(s.STime),
}
owner, err := ExtractUserID(ctx, gateway, s.UIDOwner)
if err != nil {
return nil, err
}
creator, err := ExtractUserID(ctx, gateway, s.UIDInitiator)
if err != nil {
return nil, err
}
grantee, err := ExtractGrantee(ctx, gateway, s.ShareType, s.ShareWith)
if err != nil {
return nil, err
}
return &collaboration.Share{
Id: &collaboration.ShareId{
OpaqueId: s.ID,
},
//ResourceId: &provider.Reference{StorageId: s.Prefix, NodeId: s.ItemSource},
ResourceId: &provider.ResourceId{
SpaceId: s.Prefix,
OpaqueId: s.ItemSource,
StorageId: s.Prefix,
OpaqueId: s.ItemSource,
},
Permissions: &collaboration.SharePermissions{Permissions: IntTosharePerm(s.Permissions, s.ItemType)},
Grantee: ExtractGrantee(s.ShareType, s.ShareWith),
Owner: ExtractUserID(s.UIDOwner),
Creator: ExtractUserID(s.UIDInitiator),
Grantee: grantee,
Owner: owner,
Creator: creator,
Ctime: ts,
Mtime: ts,
}
}, nil
}
// ConvertToCS3ReceivedShare converts a DBShare to a CS3API collaboration received share
func ConvertToCS3ReceivedShare(s DBShare) *collaboration.ReceivedShare {
// ConvertToCS3ReceivedShare converts a DBShare to a CS3API collaboration received share.
func ConvertToCS3ReceivedShare(ctx context.Context, gateway gatewayv1beta1.GatewayAPIClient, s DBShare) (*collaboration.ReceivedShare, error) {
share, err := ConvertToCS3Share(ctx, gateway, s)
if err != nil {
return nil, err
}
return &collaboration.ReceivedShare{
Share: ConvertToCS3Share(s),
State: IntToShareState(s.State),
MountPoint: &provider.Reference{Path: strings.TrimLeft(s.FileTarget, "/")},
}
Share: share,
State: IntToShareState(s.State),
}, nil
}
// ConvertToCS3PublicShare converts a DBShare to a CS3API public share
func ConvertToCS3PublicShare(s DBShare) *link.PublicShare {
// ConvertToCS3PublicShare converts a DBShare to a CS3API public share.
func ConvertToCS3PublicShare(ctx context.Context, gateway gatewayv1beta1.GatewayAPIClient, s DBShare) (*link.PublicShare, error) {
ts := &typespb.Timestamp{
Seconds: uint64(s.STime),
}
@@ -222,22 +278,34 @@ func ConvertToCS3PublicShare(s DBShare) *link.PublicShare {
}
}
}
owner, err := ExtractUserID(ctx, gateway, s.UIDOwner)
if err != nil {
return nil, err
}
creator, err := ExtractUserID(ctx, gateway, s.UIDInitiator)
if err != nil {
return nil, err
}
return &link.PublicShare{
Id: &link.PublicShareId{
OpaqueId: s.ID,
},
ResourceId: &provider.ResourceId{
SpaceId: s.Prefix,
OpaqueId: s.ItemSource,
StorageId: s.Prefix,
OpaqueId: s.ItemSource,
},
Permissions: &link.PublicSharePermissions{Permissions: IntTosharePerm(s.Permissions, s.ItemType)},
Owner: ExtractUserID(s.UIDOwner),
Creator: ExtractUserID(s.UIDInitiator),
Token: s.Token,
DisplayName: s.ShareName,
PasswordProtected: pwd,
Expiration: expires,
Ctime: ts,
Mtime: ts,
}
Permissions: &link.PublicSharePermissions{Permissions: IntTosharePerm(s.Permissions, s.ItemType)},
Owner: owner,
Creator: creator,
Token: s.Token,
DisplayName: s.ShareName,
PasswordProtected: pwd,
Expiration: expires,
Ctime: ts,
Mtime: ts,
Quicklink: s.Quicklink,
Description: s.Description,
NotifyUploads: s.NotifyUploads,
NotifyUploadsExtraRecipients: s.NotifyUploadsExtraRecipients,
}, nil
}

View File

@@ -173,6 +173,13 @@ func SharesNamespace(val string) Option {
}
}
// OCMNamespace provides a function to set the OCMNamespace config option.
func OCMNamespace(val string) Option {
return func(o *Options) {
o.config.OCMNamespace = val
}
}
// GatewaySvc provides a function to set the GatewaySvc config option.
func GatewaySvc(val string) Option {
return func(o *Options) {

View File

@@ -0,0 +1,280 @@
// Copyright 2018-2023 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 client
import (
"bytes"
"context"
"encoding/json"
"io"
"net/http"
"net/url"
"time"
"github.com/cs3org/reva/v2/internal/http/services/ocmd"
"github.com/cs3org/reva/v2/pkg/appctx"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/rhttp"
"github.com/pkg/errors"
)
// ErrTokenInvalid is the error returned by the invite-accepted
// endpoint when the token is not valid.
var ErrTokenInvalid = errors.New("the invitation token is invalid")
// ErrServiceNotTrusted is the error returned by the invite-accepted
// endpoint when the service is not trusted to accept invitations.
var ErrServiceNotTrusted = errors.New("service is not trusted to accept invitations")
// ErrUserAlreadyAccepted is the error returned by the invite-accepted
// endpoint when a user is already know by the remote cloud.
var ErrUserAlreadyAccepted = errors.New("user already accepted an invitation token")
// ErrTokenNotFound is the error returned by the invite-accepted
// endpoint when the request is done using a not existing token.
var ErrTokenNotFound = errors.New("token not found")
// ErrInvalidParameters is the error returned by the shares endpoint
// when the request does not contain required properties.
var ErrInvalidParameters = errors.New("invalid parameters")
// OCMClient is the client for an OCM provider.
type OCMClient struct {
client *http.Client
}
// Config is the configuration to be used for the OCMClient.
type Config struct {
Timeout time.Duration
Insecure bool
}
// New returns a new OCMClient.
func New(c *Config) *OCMClient {
return &OCMClient{
client: rhttp.GetHTTPClient(
rhttp.Timeout(c.Timeout),
rhttp.Insecure(c.Insecure),
),
}
}
// 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
// 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) {
url, err := url.JoinPath(endpoint, "invite-accepted")
if err != nil {
return nil, err
}
body, err := r.toJSON()
if err != nil {
return nil, err
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, body)
if err != nil {
return nil, errors.Wrap(err, "error creating request")
}
req.Header.Set("Content-Type", "application/json")
resp, err := c.client.Do(req)
if err != nil {
return nil, errors.Wrap(err, "error doing request")
}
defer resp.Body.Close()
return c.parseInviteAcceptedResponse(resp)
}
func (c *OCMClient) parseInviteAcceptedResponse(r *http.Response) (*User, error) {
switch r.StatusCode {
case http.StatusOK:
var u User
if err := json.NewDecoder(r.Body).Decode(&u); err != nil {
return nil, errors.Wrap(err, "error decoding response body")
}
return &u, nil
case http.StatusBadRequest:
return nil, ErrTokenInvalid
case http.StatusNotFound:
return nil, ErrTokenNotFound
case http.StatusConflict:
return nil, ErrUserAlreadyAccepted
case http.StatusForbidden:
return nil, ErrServiceNotTrusted
}
body, err := io.ReadAll(r.Body)
if err != nil {
return nil, errors.Wrap(err, "error decoding response body")
}
return nil, errtypes.InternalError(string(body))
}
// 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 ocmd.Protocols `json:"protocol"`
}
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"`
}
// NewShare creates a new share.
// https://github.com/cs3org/OCM-API/blob/develop/spec.yaml
func (c *OCMClient) NewShare(ctx context.Context, endpoint string, r *NewShareRequest) (*NewShareResponse, error) {
url, err := url.JoinPath(endpoint, "shares")
if err != nil {
return nil, err
}
body, err := r.toJSON()
if err != nil {
return nil, err
}
log := appctx.GetLogger(ctx)
log.Debug().Msgf("Sending OCM /shares POST to %s: %s", url, body)
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, body)
if err != nil {
return nil, errors.Wrap(err, "error creating request")
}
req.Header.Set("Content-Type", "application/json")
resp, err := c.client.Do(req)
if err != nil {
return nil, errors.Wrap(err, "error doing request")
}
defer resp.Body.Close()
return c.parseNewShareResponse(resp)
}
func (c *OCMClient) parseNewShareResponse(r *http.Response) (*NewShareResponse, error) {
switch r.StatusCode {
case http.StatusOK, http.StatusCreated:
var res NewShareResponse
err := json.NewDecoder(r.Body).Decode(&res)
return &res, err
case http.StatusBadRequest:
return nil, ErrInvalidParameters
case http.StatusUnauthorized, http.StatusForbidden:
return nil, ErrServiceNotTrusted
}
body, err := io.ReadAll(r.Body)
if err != nil {
return nil, errors.Wrap(err, "error decoding response body")
}
return nil, errtypes.InternalError(string(body))
}
// Capabilities contains a set of properties exposed by
// a remote cloud storage.
type Capabilities struct {
Enabled bool `json:"enabled"`
APIVersion string `json:"apiVersion"`
EndPoint string `json:"endPoint"`
Provider string `json:"provider"`
ResourceTypes []struct {
Name string `json:"name"`
ShareTypes []string `json:"shareTypes"`
Protocols struct {
Webdav *string `json:"webdav"`
Webapp *string `json:"webapp"`
Datatx *string `json:"datatx"`
} `json:"protocols"`
} `json:"resourceTypes"`
Capabilities []string `json:"capabilities"`
}
// Discovery 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) Discovery(ctx context.Context, endpoint string) (*Capabilities, error) {
url, err := url.JoinPath(endpoint, "shares")
if err != nil {
return nil, err
}
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")
resp, err := c.client.Do(req)
if err != nil {
return nil, errors.Wrap(err, "error doing request")
}
defer resp.Body.Close()
var cap Capabilities
if err := json.NewDecoder(resp.Body).Decode(&c); err != nil {
return nil, err
}
return &cap, nil
}

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 CERN
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -20,26 +20,39 @@ package invite
import (
"context"
"errors"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
invitepb "github.com/cs3org/go-cs3apis/cs3/ocm/invite/v1beta1"
ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
)
// Manager is the interface that is used to perform operations to invites.
type Manager interface {
// GenerateToken creates a new token for the user with a specified validity.
GenerateToken(ctx context.Context) (*invitepb.InviteToken, error)
// Repository is the interfaces used to store the tokens and the invited users.
type Repository interface {
// AddToken stores the token in the repository.
AddToken(ctx context.Context, token *invitepb.InviteToken) error
// ForwardInvite forwards a received invite to the sync'n'share system provider.
ForwardInvite(ctx context.Context, invite *invitepb.InviteToken, originProvider *ocmprovider.ProviderInfo) error
// GetToken gets the token from the repository.
GetToken(ctx context.Context, token string) (*invitepb.InviteToken, error)
// AcceptInvite completes an invitation acceptance.
AcceptInvite(ctx context.Context, invite *invitepb.InviteToken, remoteUser *userpb.User) error
// ListTokens gets the valid tokens from the repository (i.e. not expired).
ListTokens(ctx context.Context, initiator *userpb.UserId) ([]*invitepb.InviteToken, error)
// GetAcceptedUser retrieves details about a remote user who has accepted an invite to share.
GetAcceptedUser(ctx context.Context, remoteUserID *userpb.UserId) (*userpb.User, error)
// AddRemoteUser stores the remote user.
AddRemoteUser(ctx context.Context, initiator *userpb.UserId, remoteUser *userpb.User) error
// FindAcceptedUsers finds remote users who have accepted invites based on their attributes.
FindAcceptedUsers(ctx context.Context, query string) ([]*userpb.User, error)
// GetRemoteUser retrieves details about a remote user who has accepted an invite to share.
GetRemoteUser(ctx context.Context, initiator *userpb.UserId, remoteUserID *userpb.UserId) (*userpb.User, error)
// FindRemoteUsers finds remote users who have accepted invites based on their attributes.
FindRemoteUsers(ctx context.Context, initiator *userpb.UserId, query string) ([]*userpb.User, error)
// DeleteRemoteUser removes from the remote user from the initiator's list.
DeleteRemoteUser(ctx context.Context, initiator *userpb.UserId, remoteUser *userpb.UserId) error
}
// ErrTokenNotFound is the error returned when the token does not exist.
var ErrTokenNotFound = errors.New("token not found")
// ErrUserAlreadyAccepted is the error returned when the user was
// already added to the accepted users list.
var ErrUserAlreadyAccepted = errors.New("user already added to accepted users")

View File

@@ -1,325 +0,0 @@
// Copyright 2018-2021 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 json
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"os"
"path"
"strings"
"sync"
"time"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
invitepb "github.com/cs3org/go-cs3apis/cs3/ocm/invite/v1beta1"
ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/ocm/invite"
"github.com/cs3org/reva/v2/pkg/ocm/invite/manager/registry"
"github.com/cs3org/reva/v2/pkg/ocm/invite/token"
"github.com/cs3org/reva/v2/pkg/rhttp"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
)
const acceptInviteEndpoint = "invites/accept"
type inviteModel struct {
File string
Invites map[string]*invitepb.InviteToken `json:"invites"`
AcceptedUsers map[string][]*userpb.User `json:"accepted_users"`
}
type manager struct {
config *config
sync.Mutex // concurrent access to the file
model *inviteModel
client *http.Client
}
type config struct {
File string `mapstructure:"file"`
Expiration string `mapstructure:"expiration"`
InsecureConnections bool `mapstructure:"insecure_connections"`
}
func init() {
registry.Register("json", New)
}
func (c *config) init() error {
if c.File == "" {
c.File = "/var/tmp/reva/ocm-invites.json"
}
if c.Expiration == "" {
c.Expiration = token.DefaultExpirationTime
}
return nil
}
// New returns a new invite manager object.
func New(m map[string]interface{}) (invite.Manager, error) {
config, err := parseConfig(m)
if err != nil {
err = errors.Wrap(err, "error parsing config for json invite manager")
return nil, err
}
err = config.init()
if err != nil {
err = errors.Wrap(err, "error setting config defaults for json invite manager")
return nil, err
}
// load or create file
model, err := loadOrCreate(config.File)
if err != nil {
err = errors.Wrap(err, "error loading the file containing the invites")
return nil, err
}
manager := &manager{
config: config,
model: model,
client: rhttp.GetHTTPClient(
rhttp.Timeout(5*time.Second),
rhttp.Insecure(config.InsecureConnections),
),
}
return manager, nil
}
func parseConfig(m map[string]interface{}) (*config, error) {
c := &config{}
if err := mapstructure.Decode(m, c); err != nil {
return nil, err
}
return c, nil
}
func loadOrCreate(file string) (*inviteModel, error) {
_, err := os.Stat(file)
if os.IsNotExist(err) {
if err := os.WriteFile(file, []byte("{}"), 0700); err != nil {
err = errors.Wrap(err, "error creating the invite storage file: "+file)
return nil, err
}
}
fd, err := os.OpenFile(file, os.O_CREATE, 0644)
if err != nil {
err = errors.Wrap(err, "error opening the invite storage file: "+file)
return nil, err
}
defer fd.Close()
data, err := io.ReadAll(fd)
if err != nil {
err = errors.Wrap(err, "error reading the data")
return nil, err
}
model := &inviteModel{}
if err := json.Unmarshal(data, model); err != nil {
err = errors.Wrap(err, "error decoding invite data to json")
return nil, err
}
if model.Invites == nil {
model.Invites = make(map[string]*invitepb.InviteToken)
}
if model.AcceptedUsers == nil {
model.AcceptedUsers = make(map[string][]*userpb.User)
}
model.File = file
return model, nil
}
func (model *inviteModel) Save() error {
data, err := json.Marshal(model)
if err != nil {
err = errors.Wrap(err, "error encoding invite data to json")
return err
}
if err := os.WriteFile(model.File, data, 0644); err != nil {
err = errors.Wrap(err, "error writing invite data to file: "+model.File)
return err
}
return nil
}
func (m *manager) GenerateToken(ctx context.Context) (*invitepb.InviteToken, error) {
contexUser := ctxpkg.ContextMustGetUser(ctx)
inviteToken, err := token.CreateToken(m.config.Expiration, contexUser.GetId())
if err != nil {
return nil, err
}
// Store token data
m.Lock()
defer m.Unlock()
m.model.Invites[inviteToken.GetToken()] = inviteToken
if err := m.model.Save(); err != nil {
err = errors.Wrap(err, "error saving model")
return nil, err
}
return inviteToken, nil
}
func (m *manager) ForwardInvite(ctx context.Context, invite *invitepb.InviteToken, originProvider *ocmprovider.ProviderInfo) error {
contextUser := ctxpkg.ContextMustGetUser(ctx)
recipientProvider := contextUser.GetId().GetIdp()
requestBody := url.Values{
"token": {invite.GetToken()},
"userID": {contextUser.GetId().GetOpaqueId()},
"recipientProvider": {recipientProvider},
"email": {contextUser.GetMail()},
"name": {contextUser.GetDisplayName()},
}
ocmEndpoint, err := getOCMEndpoint(originProvider)
if err != nil {
return err
}
u, err := url.Parse(ocmEndpoint)
if err != nil {
return err
}
u.Path = path.Join(u.Path, acceptInviteEndpoint)
recipientURL := u.String()
req, err := http.NewRequest("POST", recipientURL, strings.NewReader(requestBody.Encode()))
if err != nil {
return errors.Wrap(err, "json: error framing post request")
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
resp, err := m.client.Do(req)
if err != nil {
err = errors.Wrap(err, "json: error sending post request")
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
respBody, e := io.ReadAll(resp.Body)
if e != nil {
return errors.Wrap(e, "json: error reading request body")
}
return errors.Wrap(fmt.Errorf("%s: %s", resp.Status, string(respBody)), "json: error sending accept post request")
}
return nil
}
func (m *manager) AcceptInvite(ctx context.Context, invite *invitepb.InviteToken, remoteUser *userpb.User) error {
m.Lock()
defer m.Unlock()
inviteToken, err := m.getTokenIfValid(invite)
if err != nil {
return err
}
currUser := inviteToken.GetUserId()
// do not allow the user who created the token to accept it
if remoteUser.Id.Idp == currUser.Idp && remoteUser.Id.OpaqueId == currUser.OpaqueId {
return errors.New("json: token creator and recipient are the same")
}
for _, acceptedUser := range m.model.AcceptedUsers[currUser.GetOpaqueId()] {
if acceptedUser.Id.GetOpaqueId() == remoteUser.Id.OpaqueId && acceptedUser.Id.GetIdp() == remoteUser.Id.Idp {
return errors.New("json: user already added to accepted users")
}
}
m.model.AcceptedUsers[currUser.GetOpaqueId()] = append(m.model.AcceptedUsers[currUser.GetOpaqueId()], remoteUser)
if err := m.model.Save(); err != nil {
err = errors.Wrap(err, "json: error saving model")
return err
}
return nil
}
func (m *manager) GetAcceptedUser(ctx context.Context, remoteUserID *userpb.UserId) (*userpb.User, error) {
userKey := ctxpkg.ContextMustGetUser(ctx).GetId().GetOpaqueId()
for _, acceptedUser := range m.model.AcceptedUsers[userKey] {
if (acceptedUser.Id.GetOpaqueId() == remoteUserID.OpaqueId) && (remoteUserID.Idp == "" || acceptedUser.Id.GetIdp() == remoteUserID.Idp) {
return acceptedUser, nil
}
}
return nil, errtypes.NotFound(remoteUserID.OpaqueId)
}
func (m *manager) FindAcceptedUsers(ctx context.Context, query string) ([]*userpb.User, error) {
users := []*userpb.User{}
userKey := ctxpkg.ContextMustGetUser(ctx).GetId().GetOpaqueId()
for _, acceptedUser := range m.model.AcceptedUsers[userKey] {
if query == "" || userContains(acceptedUser, query) {
users = append(users, acceptedUser)
}
}
return users, nil
}
func userContains(u *userpb.User, query string) bool {
query = strings.ToLower(query)
return strings.Contains(strings.ToLower(u.Username), query) || strings.Contains(strings.ToLower(u.DisplayName), query) ||
strings.Contains(strings.ToLower(u.Mail), query) || strings.Contains(strings.ToLower(u.Id.OpaqueId), query)
}
func (m *manager) getTokenIfValid(token *invitepb.InviteToken) (*invitepb.InviteToken, error) {
inviteToken, ok := m.model.Invites[token.GetToken()]
if !ok {
return nil, errors.New("json: invalid token")
}
if uint64(time.Now().Unix()) > inviteToken.Expiration.Seconds {
return nil, errors.New("json: token expired")
}
return inviteToken, nil
}
func getOCMEndpoint(originProvider *ocmprovider.ProviderInfo) (string, error) {
for _, s := range originProvider.Services {
if s.Endpoint.Type.Name == "OCM" {
return s.Endpoint.Path, nil
}
}
return "", errors.New("json: ocm endpoint not specified for mesh provider")
}

View File

@@ -1,233 +0,0 @@
// Copyright 2018-2021 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 memory
import (
"context"
"net/http"
"net/url"
"path"
"strings"
"sync"
"time"
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
"github.com/cs3org/reva/v2/pkg/errtypes"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
invitepb "github.com/cs3org/go-cs3apis/cs3/ocm/invite/v1beta1"
ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
"github.com/cs3org/reva/v2/pkg/ocm/invite"
"github.com/cs3org/reva/v2/pkg/ocm/invite/manager/registry"
"github.com/cs3org/reva/v2/pkg/ocm/invite/token"
"github.com/cs3org/reva/v2/pkg/rhttp"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
)
const acceptInviteEndpoint = "invites/accept"
func init() {
registry.Register("memory", New)
}
func (c *config) init() {
if c.Expiration == "" {
c.Expiration = token.DefaultExpirationTime
}
}
// New returns a new invite manager.
func New(m map[string]interface{}) (invite.Manager, error) {
c := &config{}
if err := mapstructure.Decode(m, c); err != nil {
err = errors.Wrap(err, "error creating a new manager")
return nil, err
}
c.init()
return &manager{
Invites: sync.Map{},
AcceptedUsers: sync.Map{},
Config: c,
Client: rhttp.GetHTTPClient(
rhttp.Timeout(5*time.Second),
rhttp.Insecure(c.InsecureConnections),
),
}, nil
}
type manager struct {
Invites sync.Map
AcceptedUsers sync.Map
Client *http.Client
Config *config
}
type config struct {
Expiration string `mapstructure:"expiration"`
InsecureConnections bool `mapstructure:"insecure_connections"`
}
func (m *manager) GenerateToken(ctx context.Context) (*invitepb.InviteToken, error) {
ctxUser := ctxpkg.ContextMustGetUser(ctx)
inviteToken, err := token.CreateToken(m.Config.Expiration, ctxUser.GetId())
if err != nil {
return nil, errors.Wrap(err, "memory: error creating token")
}
m.Invites.Store(inviteToken.GetToken(), inviteToken)
return inviteToken, nil
}
func (m *manager) ForwardInvite(ctx context.Context, invite *invitepb.InviteToken, originProvider *ocmprovider.ProviderInfo) error {
contextUser := ctxpkg.ContextMustGetUser(ctx)
requestBody := url.Values{
"token": {invite.GetToken()},
"userID": {contextUser.GetId().GetOpaqueId()},
"recipientProvider": {contextUser.GetId().GetIdp()},
"email": {contextUser.GetMail()},
"name": {contextUser.GetDisplayName()},
}
ocmEndpoint, err := getOCMEndpoint(originProvider)
if err != nil {
return err
}
u, err := url.Parse(ocmEndpoint)
if err != nil {
return err
}
u.Path = path.Join(u.Path, acceptInviteEndpoint)
recipientURL := u.String()
req, err := http.NewRequest("POST", recipientURL, strings.NewReader(requestBody.Encode()))
if err != nil {
return errors.Wrap(err, "json: error framing post request")
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
resp, err := m.Client.Do(req)
if err != nil {
err = errors.Wrap(err, "memory: error sending post request")
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
err = errors.Wrap(errors.New(resp.Status), "memory: error sending accept post request")
return err
}
return nil
}
func (m *manager) AcceptInvite(ctx context.Context, invite *invitepb.InviteToken, remoteUser *userpb.User) error {
inviteToken, err := m.getTokenIfValid(invite)
if err != nil {
return err
}
currUser := inviteToken.GetUserId()
// do not allow the user who created the token to accept it
if remoteUser.Id.Idp == currUser.Idp && remoteUser.Id.OpaqueId == currUser.OpaqueId {
return errors.New("memory: token creator and recipient are the same")
}
usersList, ok := m.AcceptedUsers.Load(currUser)
acceptedUsers := usersList.([]*userpb.User)
if ok {
for _, acceptedUser := range acceptedUsers {
if acceptedUser.Id.GetOpaqueId() == remoteUser.Id.OpaqueId && acceptedUser.Id.GetIdp() == remoteUser.Id.Idp {
return errors.New("memory: user already added to accepted users")
}
}
acceptedUsers = append(acceptedUsers, remoteUser)
m.AcceptedUsers.Store(currUser.GetOpaqueId(), acceptedUsers)
} else {
acceptedUsers := []*userpb.User{remoteUser}
m.AcceptedUsers.Store(currUser.GetOpaqueId(), acceptedUsers)
}
return nil
}
func (m *manager) GetAcceptedUser(ctx context.Context, remoteUserID *userpb.UserId) (*userpb.User, error) {
currUser := ctxpkg.ContextMustGetUser(ctx).GetId().GetOpaqueId()
usersList, ok := m.AcceptedUsers.Load(currUser)
if !ok {
return nil, errtypes.NotFound(remoteUserID.OpaqueId)
}
acceptedUsers := usersList.([]*userpb.User)
for _, acceptedUser := range acceptedUsers {
if (acceptedUser.Id.GetOpaqueId() == remoteUserID.OpaqueId) && (remoteUserID.Idp == "" || acceptedUser.Id.GetIdp() == remoteUserID.Idp) {
return acceptedUser, nil
}
}
return nil, errtypes.NotFound(remoteUserID.OpaqueId)
}
func (m *manager) FindAcceptedUsers(ctx context.Context, query string) ([]*userpb.User, error) {
currUser := ctxpkg.ContextMustGetUser(ctx).GetId().GetOpaqueId()
usersList, ok := m.AcceptedUsers.Load(currUser)
if !ok {
return []*userpb.User{}, nil
}
users := []*userpb.User{}
acceptedUsers := usersList.([]*userpb.User)
for _, acceptedUser := range acceptedUsers {
if query == "" || userContains(acceptedUser, query) {
users = append(users, acceptedUser)
}
}
return users, nil
}
func userContains(u *userpb.User, query string) bool {
query = strings.ToLower(query)
return strings.Contains(strings.ToLower(u.Username), query) || strings.Contains(strings.ToLower(u.DisplayName), query) ||
strings.Contains(strings.ToLower(u.Mail), query) || strings.Contains(strings.ToLower(u.Id.OpaqueId), query)
}
func (m *manager) getTokenIfValid(token *invitepb.InviteToken) (*invitepb.InviteToken, error) {
tokenInterface, ok := m.Invites.Load(token.GetToken())
if !ok {
return nil, errors.New("memory: invalid token")
}
inviteToken := tokenInterface.(*invitepb.InviteToken)
if uint64(time.Now().Unix()) > inviteToken.Expiration.Seconds {
return nil, errors.New("memory: token expired")
}
return inviteToken, nil
}
func getOCMEndpoint(originProvider *ocmprovider.ProviderInfo) (string, error) {
for _, s := range originProvider.Services {
if s.Endpoint.Type.Name == "OCM" {
return s.Endpoint.Path, nil
}
}
return "", errors.New("json: ocm endpoint not specified for mesh provider")
}

View File

@@ -0,0 +1,248 @@
// Copyright 2018-2023 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 json
import (
"context"
"encoding/json"
"io"
"os"
"strings"
"sync"
"time"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
invitepb "github.com/cs3org/go-cs3apis/cs3/ocm/invite/v1beta1"
"github.com/cs3org/reva/v2/pkg/appctx"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/ocm/invite"
"github.com/cs3org/reva/v2/pkg/ocm/invite/repository/registry"
"github.com/cs3org/reva/v2/pkg/utils"
"github.com/cs3org/reva/v2/pkg/utils/cfg"
"github.com/cs3org/reva/v2/pkg/utils/list"
"github.com/pkg/errors"
)
type inviteModel struct {
File string
Invites map[string]*invitepb.InviteToken `json:"invites"`
AcceptedUsers map[string][]*userpb.User `json:"accepted_users"`
}
type manager struct {
config *config
sync.RWMutex // concurrent access to the file
model *inviteModel
}
type config struct {
File string `mapstructure:"file"`
}
func init() {
registry.Register("json", New)
}
func (c *config) ApplyDefaults() {
if c.File == "" {
c.File = "/var/tmp/reva/ocm-invites.json"
}
}
// New returns a new invite manager object.
func New(m map[string]interface{}) (invite.Repository, error) {
var c config
if err := cfg.Decode(m, &c); err != nil {
return nil, err
}
// load or create file
model, err := loadOrCreate(c.File)
if err != nil {
return nil, errors.Wrap(err, "error loading the file containing the invites")
}
manager := &manager{
config: &c,
model: model,
}
return manager, nil
}
func loadOrCreate(file string) (*inviteModel, error) {
_, err := os.Stat(file)
if os.IsNotExist(err) {
if err := os.WriteFile(file, []byte("{}"), 0700); err != nil {
return nil, errors.Wrap(err, "error creating the invite storage file: "+file)
}
}
fd, err := os.OpenFile(file, os.O_CREATE, 0644)
if err != nil {
return nil, errors.Wrap(err, "error opening the invite storage file: "+file)
}
defer fd.Close()
data, err := io.ReadAll(fd)
if err != nil {
return nil, errors.Wrap(err, "error reading the data")
}
model := &inviteModel{}
if err := json.Unmarshal(data, model); err != nil {
return nil, errors.Wrap(err, "error decoding invite data to json")
}
if model.Invites == nil {
model.Invites = make(map[string]*invitepb.InviteToken)
}
if model.AcceptedUsers == nil {
model.AcceptedUsers = make(map[string][]*userpb.User)
}
model.File = file
return model, nil
}
func (model *inviteModel) save() error {
data, err := json.Marshal(model)
if err != nil {
return errors.Wrap(err, "error encoding invite data to json")
}
if err := os.WriteFile(model.File, data, 0644); err != nil {
return errors.Wrap(err, "error writing invite data to file: "+model.File)
}
return nil
}
func (m *manager) AddToken(ctx context.Context, token *invitepb.InviteToken) error {
m.Lock()
defer m.Unlock()
m.model.Invites[token.GetToken()] = token
if err := m.model.save(); err != nil {
return errors.Wrap(err, "json: error saving model")
}
return nil
}
func (m *manager) GetToken(ctx context.Context, token string) (*invitepb.InviteToken, error) {
m.RLock()
defer m.RUnlock()
if tkn, ok := m.model.Invites[token]; ok {
return tkn, nil
}
return nil, invite.ErrTokenNotFound
}
func (m *manager) ListTokens(ctx context.Context, initiator *userpb.UserId) ([]*invitepb.InviteToken, error) {
m.RLock()
defer m.RUnlock()
tokens := []*invitepb.InviteToken{}
for _, token := range m.model.Invites {
if utils.UserEqual(token.UserId, initiator) && !tokenIsExpired(token) {
tokens = append(tokens, token)
}
}
return tokens, nil
}
func tokenIsExpired(token *invitepb.InviteToken) bool {
return token.Expiration != nil && token.Expiration.Seconds > uint64(time.Now().Unix())
}
func (m *manager) AddRemoteUser(ctx context.Context, initiator *userpb.UserId, remoteUser *userpb.User) error {
m.Lock()
defer m.Unlock()
for _, acceptedUser := range m.model.AcceptedUsers[initiator.GetOpaqueId()] {
if acceptedUser.Id.GetOpaqueId() == remoteUser.Id.OpaqueId && acceptedUser.Id.GetIdp() == remoteUser.Id.Idp {
return invite.ErrUserAlreadyAccepted
}
}
m.model.AcceptedUsers[initiator.GetOpaqueId()] = append(m.model.AcceptedUsers[initiator.GetOpaqueId()], remoteUser)
if err := m.model.save(); err != nil {
return errors.Wrap(err, "json: error saving model")
}
return nil
}
func (m *manager) GetRemoteUser(ctx context.Context, initiator *userpb.UserId, remoteUserID *userpb.UserId) (*userpb.User, error) {
m.RLock()
defer m.RUnlock()
log := appctx.GetLogger(ctx)
for _, acceptedUser := range m.model.AcceptedUsers[initiator.GetOpaqueId()] {
log.Info().Msgf("looking for '%s' at '%s' - considering '%s' at '%s'",
remoteUserID.OpaqueId,
remoteUserID.Idp,
acceptedUser.Id.GetOpaqueId(),
acceptedUser.Id.GetIdp(),
)
if (acceptedUser.Id.GetOpaqueId() == remoteUserID.OpaqueId) && (remoteUserID.Idp == "" || acceptedUser.Id.GetIdp() == remoteUserID.Idp) {
return acceptedUser, nil
}
}
return nil, errtypes.NotFound(remoteUserID.OpaqueId)
}
func (m *manager) FindRemoteUsers(ctx context.Context, initiator *userpb.UserId, query string) ([]*userpb.User, error) {
m.RLock()
defer m.RUnlock()
users := []*userpb.User{}
for _, acceptedUser := range m.model.AcceptedUsers[initiator.GetOpaqueId()] {
if query == "" || userContains(acceptedUser, query) {
users = append(users, acceptedUser)
}
}
return users, nil
}
func userContains(u *userpb.User, query string) bool {
query = strings.ToLower(query)
return strings.Contains(strings.ToLower(u.Username), query) || strings.Contains(strings.ToLower(u.DisplayName), query) ||
strings.Contains(strings.ToLower(u.Mail), query) || strings.Contains(strings.ToLower(u.Id.OpaqueId), query)
}
func (m *manager) DeleteRemoteUser(ctx context.Context, initiator *userpb.UserId, remoteUser *userpb.UserId) error {
m.Lock()
defer m.Unlock()
acceptedUsers, ok := m.model.AcceptedUsers[initiator.GetOpaqueId()]
if !ok {
return nil
}
for i, user := range acceptedUsers {
if (user.Id.GetOpaqueId() == remoteUser.OpaqueId) && (remoteUser.Idp == "" || user.Id.GetIdp() == remoteUser.Idp) {
acceptedUsers = list.Remove(acceptedUsers, i)
m.model.AcceptedUsers[initiator.GetOpaqueId()] = acceptedUsers
_ = m.model.save()
return nil
}
}
return nil
}

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 CERN
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -20,7 +20,8 @@ package loader
import (
// Load core share manager drivers.
_ "github.com/cs3org/reva/v2/pkg/ocm/share/manager/json"
_ "github.com/cs3org/reva/v2/pkg/ocm/share/manager/nextcloud"
// Add your own here
_ "github.com/cs3org/reva/v2/pkg/ocm/invite/repository/json"
_ "github.com/cs3org/reva/v2/pkg/ocm/invite/repository/memory"
_ "github.com/cs3org/reva/v2/pkg/ocm/invite/repository/sql"
// Add your own here.
)

View File

@@ -0,0 +1,146 @@
// Copyright 2018-2023 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 memory
import (
"context"
"strings"
"sync"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
invitepb "github.com/cs3org/go-cs3apis/cs3/ocm/invite/v1beta1"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/ocm/invite"
"github.com/cs3org/reva/v2/pkg/ocm/invite/repository/registry"
"github.com/cs3org/reva/v2/pkg/utils"
"github.com/cs3org/reva/v2/pkg/utils/list"
)
func init() {
registry.Register("memory", New)
}
// New returns a new invite manager.
func New(m map[string]interface{}) (invite.Repository, error) {
return &manager{
Invites: sync.Map{},
AcceptedUsers: sync.Map{},
}, nil
}
type manager struct {
Invites sync.Map
AcceptedUsers sync.Map
}
func (m *manager) AddToken(ctx context.Context, token *invitepb.InviteToken) error {
m.Invites.Store(token.GetToken(), token)
return nil
}
func (m *manager) GetToken(ctx context.Context, token string) (*invitepb.InviteToken, error) {
if v, ok := m.Invites.Load(token); ok {
return v.(*invitepb.InviteToken), nil
}
return nil, invite.ErrTokenNotFound
}
func (m *manager) ListTokens(ctx context.Context, initiator *userpb.UserId) ([]*invitepb.InviteToken, error) {
tokens := []*invitepb.InviteToken{}
m.Invites.Range(func(_, value any) bool {
token := value.(*invitepb.InviteToken)
if utils.UserEqual(token.UserId, initiator) {
tokens = append(tokens, token)
}
return true
})
return tokens, nil
}
func (m *manager) AddRemoteUser(ctx context.Context, initiator *userpb.UserId, remoteUser *userpb.User) error {
usersList, ok := m.AcceptedUsers.Load(initiator)
acceptedUsers := usersList.([]*userpb.User)
if ok {
for _, acceptedUser := range acceptedUsers {
if acceptedUser.Id.GetOpaqueId() == remoteUser.Id.OpaqueId && acceptedUser.Id.GetIdp() == remoteUser.Id.Idp {
return invite.ErrUserAlreadyAccepted
}
}
acceptedUsers = append(acceptedUsers, remoteUser)
m.AcceptedUsers.Store(initiator.GetOpaqueId(), acceptedUsers)
} else {
acceptedUsers := []*userpb.User{remoteUser}
m.AcceptedUsers.Store(initiator.GetOpaqueId(), acceptedUsers)
}
return nil
}
func (m *manager) GetRemoteUser(ctx context.Context, initiator *userpb.UserId, remoteUserID *userpb.UserId) (*userpb.User, error) {
usersList, ok := m.AcceptedUsers.Load(initiator)
if !ok {
return nil, errtypes.NotFound(remoteUserID.OpaqueId)
}
acceptedUsers := usersList.([]*userpb.User)
for _, acceptedUser := range acceptedUsers {
if (acceptedUser.Id.GetOpaqueId() == remoteUserID.OpaqueId) && (remoteUserID.Idp == "" || acceptedUser.Id.GetIdp() == remoteUserID.Idp) {
return acceptedUser, nil
}
}
return nil, errtypes.NotFound(remoteUserID.OpaqueId)
}
func (m *manager) FindRemoteUsers(ctx context.Context, initiator *userpb.UserId, query string) ([]*userpb.User, error) {
usersList, ok := m.AcceptedUsers.Load(initiator)
if !ok {
return []*userpb.User{}, nil
}
users := []*userpb.User{}
acceptedUsers := usersList.([]*userpb.User)
for _, acceptedUser := range acceptedUsers {
if query == "" || userContains(acceptedUser, query) {
users = append(users, acceptedUser)
}
}
return users, nil
}
func userContains(u *userpb.User, query string) bool {
query = strings.ToLower(query)
return strings.Contains(strings.ToLower(u.Username), query) || strings.Contains(strings.ToLower(u.DisplayName), query) ||
strings.Contains(strings.ToLower(u.Mail), query) || strings.Contains(strings.ToLower(u.Id.OpaqueId), query)
}
func (m *manager) DeleteRemoteUser(ctx context.Context, initiator *userpb.UserId, remoteUser *userpb.UserId) error {
usersList, ok := m.AcceptedUsers.Load(initiator)
if !ok {
return nil
}
acceptedUsers := usersList.([]*userpb.User)
for i, user := range acceptedUsers {
if (user.Id.GetOpaqueId() == remoteUser.OpaqueId) && (remoteUser.Idp == "" || user.Id.GetIdp() == remoteUser.Idp) {
m.AcceptedUsers.Store(initiator, list.Remove(acceptedUsers, i))
return nil
}
}
return nil
}

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 CERN
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -18,16 +18,18 @@
package registry
import "github.com/cs3org/reva/v2/pkg/ocm/share"
import (
"github.com/cs3org/reva/v2/pkg/ocm/invite"
)
// NewFunc is the function that share managers
// NewFunc is the function that invite repositories
// should register at init time.
type NewFunc func(map[string]interface{}) (share.Manager, error)
type NewFunc func(map[string]interface{}) (invite.Repository, error)
// NewFuncs is a map containing all the registered share managers.
// NewFuncs is a map containing all the registered invite repositories.
var NewFuncs = map[string]NewFunc{}
// Register registers a new share manager new function.
// Register registers a new invite repository new function.
// Not safe for concurrent use. Safe for use from package init.
func Register(name string, f NewFunc) {
NewFuncs[name] = f

View File

@@ -0,0 +1,251 @@
// Copyright 2018-2023 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"
"time"
gatewayv1beta1 "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
invitepb "github.com/cs3org/go-cs3apis/cs3/ocm/invite/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
conversions "github.com/cs3org/reva/v2/pkg/cbox/utils"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/ocm/invite"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/v2/pkg/utils/cfg"
"github.com/go-sql-driver/mysql"
"github.com/cs3org/reva/v2/pkg/ocm/invite/repository/registry"
"github.com/cs3org/reva/v2/pkg/sharedconf"
"github.com/pkg/errors"
)
// This module implement the invite.Repository interface as a mysql driver.
//
// The OCM Invitation tokens are saved in the table:
// ocm_tokens(*token*, initiator, expiration, description)
//
// The OCM remote user are saved in the table:
// ocm_remote_users(*initiator*, *opaque_user_id*, *idp*, email, display_name)
func init() {
registry.Register("sql", New)
}
type mgr struct {
c *config
db *sql.DB
client gatewayv1beta1.GatewayAPIClient
}
type config struct {
DBUsername string `mapstructure:"db_username"`
DBPassword string `mapstructure:"db_password"`
DBAddress string `mapstructure:"db_address"`
DBName string `mapstructure:"db_name"`
GatewaySvc string `mapstructure:"gatewaysvc"`
}
func (c *config) ApplyDefaults() {
c.GatewaySvc = sharedconf.GetGatewaySVC(c.GatewaySvc)
}
// New creates a sql repository for ocm tokens and users.
func New(m map[string]interface{}) (invite.Repository, 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)/%s?parseTime=true", c.DBUsername, c.DBPassword, c.DBAddress, c.DBName))
if err != nil {
return nil, errors.Wrap(err, "sql: error opening connection to mysql database")
}
gw, err := pool.GetGatewayServiceClient(c.GatewaySvc)
if err != nil {
return nil, err
}
mgr := mgr{
c: &c,
db: db,
client: gw,
}
return &mgr, nil
}
// AddToken stores the token in the repository.
func (m *mgr) AddToken(ctx context.Context, token *invitepb.InviteToken) error {
query := "INSERT INTO ocm_tokens SET token=?,initiator=?,expiration=?,description=?"
_, err := m.db.ExecContext(ctx, query, token.Token, conversions.FormatUserID(token.UserId), timestampToTime(token.Expiration), token.Description)
return err
}
func timestampToTime(t *types.Timestamp) time.Time {
return time.Unix(int64(t.Seconds), int64(t.Nanos))
}
type dbToken struct {
Token string
Initiator string
Expiration time.Time
Description string
}
// GetToken gets the token from the repository.
func (m *mgr) GetToken(ctx context.Context, token string) (*invitepb.InviteToken, error) {
query := "SELECT token, initiator, expiration, description FROM ocm_tokens where token=?"
var tkn dbToken
if err := m.db.QueryRowContext(ctx, query, token).Scan(&tkn.Token, &tkn.Initiator, &tkn.Expiration, &tkn.Description); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, invite.ErrTokenNotFound
}
return nil, err
}
return m.convertToInviteToken(ctx, tkn)
}
func (m *mgr) convertToInviteToken(ctx context.Context, tkn dbToken) (*invitepb.InviteToken, error) {
user, err := conversions.ExtractUserID(ctx, m.client, tkn.Initiator)
if err != nil {
return nil, err
}
return &invitepb.InviteToken{
Token: tkn.Token,
UserId: user,
Expiration: &types.Timestamp{
Seconds: uint64(tkn.Expiration.Unix()),
},
Description: tkn.Description,
}, nil
}
func (m *mgr) ListTokens(ctx context.Context, initiator *userpb.UserId) ([]*invitepb.InviteToken, error) {
query := "SELECT token, initiator, expiration, description FROM ocm_tokens WHERE initiator=? AND expiration > NOW()"
tokens := []*invitepb.InviteToken{}
rows, err := m.db.QueryContext(ctx, query, conversions.FormatUserID(initiator))
if err != nil {
return nil, err
}
var tkn dbToken
for rows.Next() {
if err := rows.Scan(&tkn.Token, &tkn.Initiator, &tkn.Expiration, &tkn.Description); err != nil {
continue
}
token, err := m.convertToInviteToken(ctx, tkn)
if err != nil {
return nil, err
}
tokens = append(tokens, token)
}
return tokens, nil
}
// AddRemoteUser stores the remote user.
func (m *mgr) AddRemoteUser(ctx context.Context, initiator *userpb.UserId, remoteUser *userpb.User) error {
query := "INSERT INTO ocm_remote_users SET initiator=?, opaque_user_id=?, idp=?, email=?, display_name=?"
if _, err := m.db.ExecContext(ctx, query, conversions.FormatUserID(initiator), conversions.FormatUserID(remoteUser.Id), remoteUser.Id.Idp, remoteUser.Mail, remoteUser.DisplayName); err != nil {
// check if the user already exist in the db
// https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_dup_entry
var e *mysql.MySQLError
if errors.As(err, &e) && e.Number == 1062 {
return invite.ErrUserAlreadyAccepted
}
return err
}
return nil
}
type dbOCMUser struct {
OpaqueUserID string
Idp string
Email string
DisplayName string
}
// GetRemoteUser retrieves details about a remote user who has accepted an invite to share.
func (m *mgr) GetRemoteUser(ctx context.Context, initiator *userpb.UserId, remoteUserID *userpb.UserId) (*userpb.User, error) {
query := "SELECT opaque_user_id, idp, email, display_name FROM ocm_remote_users WHERE initiator=? AND opaque_user_id=? AND idp=?"
var user dbOCMUser
if err := m.db.QueryRowContext(ctx, query, conversions.FormatUserID(initiator), conversions.FormatUserID(remoteUserID), remoteUserID.Idp).
Scan(&user.OpaqueUserID, &user.Idp, &user.Email, &user.DisplayName); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, errtypes.NotFound(remoteUserID.OpaqueId)
}
return nil, err
}
return user.toCS3User(), nil
}
func (u *dbOCMUser) toCS3User() *userpb.User {
return &userpb.User{
Id: &userpb.UserId{
Idp: u.Idp,
OpaqueId: u.OpaqueUserID,
Type: userpb.UserType_USER_TYPE_FEDERATED,
},
Mail: u.Email,
DisplayName: u.DisplayName,
}
}
// FindRemoteUsers finds remote users who have accepted invites based on their attributes.
func (m *mgr) FindRemoteUsers(ctx context.Context, initiator *userpb.UserId, attr string) ([]*userpb.User, error) {
// TODO: (gdelmont) this query can get really slow in case the number of rows is too high.
// For the time being this is not expected, but if in future this happens, consider to add
// a fulltext index.
query := "SELECT opaque_user_id, idp, email, display_name FROM ocm_remote_users WHERE initiator=? AND (opaque_user_id LIKE ? OR idp LIKE ? OR email LIKE ? OR display_name LIKE ?)"
s := "%" + attr + "%"
params := []any{conversions.FormatUserID(initiator), s, s, s, s}
rows, err := m.db.QueryContext(ctx, query, params...)
if err != nil {
return nil, err
}
var u dbOCMUser
var users []*userpb.User
for rows.Next() {
if err := rows.Scan(&u.OpaqueUserID, &u.Idp, &u.Email, &u.DisplayName); err != nil {
continue
}
users = append(users, u.toCS3User())
}
if err := rows.Err(); err != nil {
return nil, err
}
return users, nil
}
func (m *mgr) DeleteRemoteUser(ctx context.Context, initiator *userpb.UserId, remoteUser *userpb.UserId) error {
query := "DELETE FROM ocm_remote_users WHERE initiator=? AND opaque_user_id=? AND idp=?"
_, err := m.db.ExecContext(ctx, query, conversions.FormatUserID(initiator), conversions.FormatUserID(remoteUser), remoteUser.Idp)
return err
}

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 CERN
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -28,10 +28,11 @@ import (
"sync"
ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
"github.com/cs3org/reva/v2/pkg/appctx"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/ocm/provider"
"github.com/cs3org/reva/v2/pkg/ocm/provider/authorizer/registry"
"github.com/mitchellh/mapstructure"
"github.com/cs3org/reva/v2/pkg/utils/cfg"
"github.com/pkg/errors"
)
@@ -41,26 +42,27 @@ func init() {
// New returns a new authorizer object.
func New(m map[string]interface{}) (provider.Authorizer, error) {
c := &config{}
if err := mapstructure.Decode(m, c); err != nil {
err = errors.Wrap(err, "error decoding conf")
var c config
if err := cfg.Decode(m, &c); err != nil {
return nil, err
}
c.init()
providers := []*ocmprovider.ProviderInfo{}
f, err := os.ReadFile(c.Providers)
if err != nil {
return nil, err
}
providers := []*ocmprovider.ProviderInfo{}
err = json.Unmarshal(f, &providers)
if err != nil {
return nil, err
if !os.IsNotExist(err) {
return nil, err
}
} else {
err = json.Unmarshal(f, &providers)
if err != nil {
return nil, err
}
}
a := &authorizer{
providerIPs: sync.Map{},
conf: c,
conf: &c,
}
a.providers = a.getOCMProviders(providers)
@@ -72,7 +74,7 @@ type config struct {
VerifyRequestHostname bool `mapstructure:"verify_request_hostname"`
}
func (c *config) init() {
func (c *config) ApplyTemplates() {
if c.Providers == "" {
c.Providers = "/etc/revad/ocm-providers.json"
}
@@ -113,9 +115,10 @@ func (a *authorizer) GetInfoByDomain(ctx context.Context, domain string) (*ocmpr
return nil, errtypes.NotFound(domain)
}
func (a *authorizer) IsProviderAllowed(ctx context.Context, provider *ocmprovider.ProviderInfo) error {
func (a *authorizer) IsProviderAllowed(ctx context.Context, pi *ocmprovider.ProviderInfo) error {
log := appctx.GetLogger(ctx)
var err error
normalizedDomain, err := normalizeDomain(provider.Domain)
normalizedDomain, err := normalizeDomain(pi.Domain)
if err != nil {
return err
}
@@ -133,20 +136,22 @@ func (a *authorizer) IsProviderAllowed(ctx context.Context, provider *ocmprovide
switch {
case !providerAuthorized:
return errtypes.NotFound(provider.GetDomain())
return errtypes.NotFound(pi.GetDomain())
case !a.conf.VerifyRequestHostname:
return nil
case len(provider.Services) == 0:
case len(pi.Services) == 0:
return errtypes.NotSupported("No IP provided")
}
var ocmHost string
for _, p := range a.providers {
log.Debug().Msgf("Comparing '%s' to '%s'", p.Domain, normalizedDomain)
if p.Domain == normalizedDomain {
ocmHost, err = a.getOCMHost(p)
if err != nil {
return err
}
break
}
}
if ocmHost == "" {
@@ -169,8 +174,9 @@ func (a *authorizer) IsProviderAllowed(ctx context.Context, provider *ocmprovide
}
for _, ip := range ipList {
if ip == provider.Services[0].Host {
if ip == pi.Services[0].Host {
providerAuthorized = true
break
}
}
if !providerAuthorized {
@@ -194,14 +200,10 @@ func (a *authorizer) getOCMProviders(providers []*ocmprovider.ProviderInfo) (po
return
}
func (a *authorizer) getOCMHost(provider *ocmprovider.ProviderInfo) (string, error) {
for _, s := range provider.Services {
func (a *authorizer) getOCMHost(pi *ocmprovider.ProviderInfo) (string, error) {
for _, s := range pi.Services {
if s.Endpoint.Type.Name == "OCM" {
ocmHost, err := url.Parse(s.Host)
if err != nil {
return "", errors.Wrap(err, "json: error parsing OCM host URL")
}
return ocmHost.Host, nil
return s.Host, nil
}
}
return "", errtypes.NotFound("OCM Host")

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 CERN
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -23,5 +23,5 @@ import (
_ "github.com/cs3org/reva/v2/pkg/ocm/provider/authorizer/json"
_ "github.com/cs3org/reva/v2/pkg/ocm/provider/authorizer/mentix"
_ "github.com/cs3org/reva/v2/pkg/ocm/provider/authorizer/open"
// Add your own here
// Add your own here.
)

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 CERN
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -29,13 +29,12 @@ import (
"sync"
"time"
"github.com/cs3org/reva/v2/pkg/rhttp"
ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/ocm/provider"
"github.com/cs3org/reva/v2/pkg/ocm/provider/authorizer/registry"
"github.com/mitchellh/mapstructure"
"github.com/cs3org/reva/v2/pkg/rhttp"
"github.com/cs3org/reva/v2/pkg/utils/cfg"
"github.com/pkg/errors"
)
@@ -43,7 +42,7 @@ func init() {
registry.Register("mentix", New)
}
// Client is a Mentix API client
// Client is a Mentix API client.
type Client struct {
BaseURL string
HTTPClient *http.Client
@@ -51,12 +50,10 @@ type Client struct {
// New returns a new authorizer object.
func New(m map[string]interface{}) (provider.Authorizer, error) {
c := &config{}
if err := mapstructure.Decode(m, c); err != nil {
err = errors.Wrap(err, "error decoding conf")
var c config
if err := cfg.Decode(m, &c); err != nil {
return nil, err
}
c.init()
client := &Client{
BaseURL: c.URL,
@@ -70,7 +67,7 @@ func New(m map[string]interface{}) (provider.Authorizer, error) {
return &authorizer{
client: client,
providerIPs: sync.Map{},
conf: c,
conf: &c,
}, nil
}
@@ -79,10 +76,10 @@ type config struct {
Timeout int64 `mapstructure:"timeout"`
RefreshInterval int64 `mapstructure:"refresh"`
VerifyRequestHostname bool `mapstructure:"verify_request_hostname"`
Insecure bool `mapstructure:"insecure"`
Insecure bool `mapstructure:"insecure" docs:"false;Whether to skip certificate checks when sending requests."`
}
func (c *config) init() {
func (c *config) ApplyDefaults() {
if c.URL == "" {
c.URL = "http://localhost:9600/mentix/cs3"
}
@@ -96,12 +93,28 @@ type authorizer struct {
conf *config
}
func normalizeDomain(d string) (string, error) {
var urlString string
if strings.Contains(d, "://") {
urlString = d
} else {
urlString = "https://" + d
}
u, err := url.Parse(urlString)
if err != nil {
return "", err
}
return u.Hostname(), nil
}
func (a *authorizer) fetchProviders() ([]*ocmprovider.ProviderInfo, error) {
if (a.providers != nil) && (time.Now().Unix() < a.providersExpiration) {
return a.providers, nil
}
req, err := http.NewRequest("GET", a.client.BaseURL, nil)
req, err := http.NewRequest(http.MethodGet, a.client.BaseURL, nil)
if err != nil {
return nil, err
}
@@ -111,7 +124,7 @@ func (a *authorizer) fetchProviders() ([]*ocmprovider.ProviderInfo, error) {
res, err := a.client.HTTPClient.Do(req)
if err != nil {
err = errors.Wrap(err,
fmt.Sprintf("error fetching provider list from: %s", a.client.BaseURL))
fmt.Sprintf("mentix: error fetching provider list from: %s", a.client.BaseURL))
return nil, err
}
@@ -130,29 +143,37 @@ func (a *authorizer) fetchProviders() ([]*ocmprovider.ProviderInfo, error) {
}
func (a *authorizer) GetInfoByDomain(ctx context.Context, domain string) (*ocmprovider.ProviderInfo, error) {
providers, err := a.fetchProviders()
normalizedDomain, err := normalizeDomain(domain)
if err != nil {
return nil, err
}
providers, err := a.fetchProviders()
if err != nil {
return nil, err
}
for _, p := range providers {
if strings.Contains(p.Domain, domain) {
if strings.Contains(p.Domain, normalizedDomain) {
return p, nil
}
}
return nil, errtypes.NotFound(domain)
}
func (a *authorizer) IsProviderAllowed(ctx context.Context, provider *ocmprovider.ProviderInfo) error {
func (a *authorizer) IsProviderAllowed(ctx context.Context, pi *ocmprovider.ProviderInfo) error {
providers, err := a.fetchProviders()
if err != nil {
return err
}
normalizedDomain, err := normalizeDomain(pi.Domain)
if err != nil {
return err
}
var providerAuthorized bool
if provider.Domain != "" {
if normalizedDomain != "" {
for _, p := range providers {
if p.Domain == provider.Domain {
if p.Domain == normalizedDomain {
providerAuthorized = true
break
}
@@ -163,24 +184,27 @@ func (a *authorizer) IsProviderAllowed(ctx context.Context, provider *ocmprovide
switch {
case !providerAuthorized:
return errtypes.NotFound(provider.GetDomain())
return errtypes.NotFound(pi.GetDomain())
case !a.conf.VerifyRequestHostname:
return nil
case len(provider.Services) == 0:
return errtypes.NotSupported("No IP provided")
case len(pi.Services) == 0:
return errtypes.NotSupported(
fmt.Sprintf("mentix: provider %s has no supported services", pi.GetDomain()))
}
var ocmHost string
for _, p := range providers {
if p.Domain == provider.Domain {
if p.Domain == normalizedDomain {
ocmHost, err = a.getOCMHost(p)
if err != nil {
return err
}
break
}
}
if ocmHost == "" {
return errtypes.InternalError("mentix: ocm host not specified for mesh provider")
return errtypes.NotSupported(
fmt.Sprintf("mentix: provider %s is missing OCM endpoint", pi.GetDomain()))
}
providerAuthorized = false
@@ -190,7 +214,8 @@ func (a *authorizer) IsProviderAllowed(ctx context.Context, provider *ocmprovide
} else {
addr, err := net.LookupIP(ocmHost)
if err != nil {
return errors.Wrap(err, "json: error looking up client IP")
return errors.Wrap(err,
fmt.Sprintf("mentix: error looking up IPs for OCM endpoint %s", ocmHost))
}
for _, a := range addr {
ipList = append(ipList, a.String())
@@ -199,12 +224,16 @@ func (a *authorizer) IsProviderAllowed(ctx context.Context, provider *ocmprovide
}
for _, ip := range ipList {
if ip == provider.Services[0].Host {
if ip == pi.Services[0].Host {
providerAuthorized = true
break
}
}
if !providerAuthorized {
return errtypes.NotFound("OCM Host")
return errtypes.BadRequest(
fmt.Sprintf(
"Invalid requesting OCM endpoint IP %s of provider %s",
pi.Services[0].Host, pi.GetDomain()))
}
return nil
@@ -231,11 +260,7 @@ func (a *authorizer) getOCMProviders(providers []*ocmprovider.ProviderInfo) (po
func (a *authorizer) getOCMHost(provider *ocmprovider.ProviderInfo) (string, error) {
for _, s := range provider.Services {
if s.Endpoint.Type.Name == "OCM" {
ocmHost, err := url.Parse(s.Host)
if err != nil {
return "", errors.Wrap(err, "json: error parsing OCM host URL")
}
return ocmHost.Host, nil
return s.Host, nil
}
}
return "", errtypes.NotFound("OCM Host")

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 CERN
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -21,7 +21,6 @@ package open
import (
"context"
"encoding/json"
"net/url"
"os"
"strings"
@@ -29,8 +28,7 @@ import (
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/ocm/provider"
"github.com/cs3org/reva/v2/pkg/ocm/provider/authorizer/registry"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
"github.com/cs3org/reva/v2/pkg/utils/cfg"
)
func init() {
@@ -39,12 +37,10 @@ func init() {
// New returns a new authorizer object.
func New(m map[string]interface{}) (provider.Authorizer, error) {
c := &config{}
if err := mapstructure.Decode(m, c); err != nil {
err = errors.Wrap(err, "error decoding conf")
var c config
if err := cfg.Decode(m, &c); err != nil {
return nil, err
}
c.init()
f, err := os.ReadFile(c.Providers)
if err != nil {
@@ -67,7 +63,7 @@ type config struct {
Providers string `mapstructure:"providers"`
}
func (c *config) init() {
func (c *config) ApplyDefaults() {
if c.Providers == "" {
c.Providers = "/etc/revad/ocm-providers.json"
}
@@ -107,11 +103,7 @@ func (a *authorizer) getOCMProviders(providers []*ocmprovider.ProviderInfo) (po
func (a *authorizer) getOCMHost(provider *ocmprovider.ProviderInfo) (string, error) {
for _, s := range provider.Services {
if s.Endpoint.Type.Name == "OCM" {
ocmHost, err := url.Parse(s.Host)
if err != nil {
return "", errors.Wrap(err, "json: error parsing OCM host URL")
}
return ocmHost.Host, nil
return s.Host, nil
}
}
return "", errtypes.NotFound("OCM Host")

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 CERN
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -18,7 +18,9 @@
package registry
import "github.com/cs3org/reva/v2/pkg/ocm/provider"
import (
"github.com/cs3org/reva/v2/pkg/ocm/provider"
)
// NewFunc is the function that provider authorizers
// should register at init time.

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 CERN
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View File

@@ -1,603 +0,0 @@
// Copyright 2018-2021 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 json
import (
"context"
"encoding/json"
"fmt"
"io"
"os"
"sync"
"time"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
typespb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/ocm/share"
"github.com/cs3org/reva/v2/pkg/ocm/share/manager/registry"
"github.com/cs3org/reva/v2/pkg/ocm/share/sender"
"github.com/cs3org/reva/v2/pkg/utils"
"github.com/google/uuid"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
"google.golang.org/genproto/protobuf/field_mask"
)
func init() {
registry.Register("json", New)
}
// New returns a new authorizer object.
func New(m map[string]interface{}) (share.Manager, error) {
c, err := parseConfig(m)
if err != nil {
err = errors.Wrap(err, "error creating a new manager")
return nil, err
}
c.init()
// load or create file
model, err := loadOrCreate(c.File)
if err != nil {
err = errors.Wrap(err, "error loading the file containing the shares")
return nil, err
}
mgr := &mgr{
c: c,
model: model,
}
return mgr, nil
}
func loadOrCreate(file string) (*shareModel, error) {
_, err := os.Stat(file)
if os.IsNotExist(err) {
if err := os.WriteFile(file, []byte("{}"), 0700); err != nil {
err = errors.Wrap(err, "error creating the file: "+file)
return nil, err
}
}
fd, err := os.OpenFile(file, os.O_CREATE, 0644)
if err != nil {
err = errors.Wrap(err, "error opening the file: "+file)
return nil, err
}
defer fd.Close()
data, err := io.ReadAll(fd)
if err != nil {
err = errors.Wrap(err, "error reading the data")
return nil, err
}
m := &shareModel{}
if err := json.Unmarshal(data, m); err != nil {
err = errors.Wrap(err, "error decoding data to json")
return nil, err
}
if m.Shares == nil {
m.Shares = map[string]interface{}{}
}
if m.ReceivedShares == nil {
m.ReceivedShares = map[string]interface{}{}
}
m.file = file
return m, nil
}
type shareModel struct {
file string
Shares map[string]interface{} `json:"shares"`
ReceivedShares map[string]interface{} `json:"received_shares"`
}
type config struct {
File string `mapstructure:"file"`
InsecureConnections bool `mapstructure:"insecure_connections"`
}
func (c *config) init() {
if c.File == "" {
c.File = "/var/tmp/reva/ocm-shares.json"
}
}
type mgr struct {
c *config
sync.Mutex // concurrent access to the file
model *shareModel
}
func (m *shareModel) Save() error {
data, err := json.Marshal(m)
if err != nil {
err = errors.Wrap(err, "error encoding to json")
return err
}
if err := os.WriteFile(m.file, data, 0644); err != nil {
err = errors.Wrap(err, "error writing to file: "+m.file)
return err
}
return nil
}
func (m *shareModel) ReadFile() error {
data, err := os.ReadFile(m.file)
if err != nil {
err = errors.Wrap(err, "error reading the data")
return err
}
if err := json.Unmarshal(data, m); err != nil {
err = errors.Wrap(err, "error decoding data to json")
return err
}
return nil
}
func parseConfig(m map[string]interface{}) (*config, error) {
c := &config{}
if err := mapstructure.Decode(m, c); err != nil {
return nil, err
}
return c, nil
}
func genID() string {
return uuid.New().String()
}
// Called from both grpc CreateOCMShare for outgoing
// and http /ocm/shares for incoming
// pi is provider info
// pm is permissions
func (m *mgr) Share(ctx context.Context, md *provider.ResourceId, g *ocm.ShareGrant, name string,
pi *ocmprovider.ProviderInfo, pm string, owner *userpb.UserId, token string, st ocm.Share_ShareType) (*ocm.Share, error) {
id := genID()
now := time.Now().UnixNano()
ts := &typespb.Timestamp{
Seconds: uint64(now / 1000000000),
Nanos: uint32(now % 1000000000),
}
// Since both OCMCore and OCMShareProvider use the same package, we distinguish
// between calls received from them on the basis of whether they provide info
// about the remote provider on which the share is to be created.
// If this info is provided, this call is on the owner's mesh provider and so
// we call the CreateOCMCoreShare method on the remote provider as well,
// else this is received from another provider and we only create a local share.
var isOwnersMeshProvider bool
if pi != nil {
isOwnersMeshProvider = true
}
var userID *userpb.UserId
if !isOwnersMeshProvider {
// Since this call is on the remote provider, the owner of the resource is expected to be specified.
if owner == nil {
return nil, errors.New("json: owner of resource not provided")
}
userID = owner
g.Grantee.Opaque = &typespb.Opaque{
Map: map[string]*typespb.OpaqueEntry{
"token": {
Decoder: "plain",
Value: []byte(token),
},
},
}
} else {
userID = ctxpkg.ContextMustGetUser(ctx).GetId()
}
// do not allow share to myself if share is for a user
if g.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_USER && utils.UserEqual(g.Grantee.GetUserId(), userID) {
return nil, errors.New("json: user and grantee are the same")
}
// check if share already exists.
key := &ocm.ShareKey{
Owner: userID,
ResourceId: md,
Grantee: g.Grantee,
}
_, err := m.getByKey(ctx, key)
// share already exists
if isOwnersMeshProvider && err == nil {
return nil, errtypes.AlreadyExists(key.String())
}
s := &ocm.Share{
Id: &ocm.ShareId{
OpaqueId: id,
},
Name: name,
ResourceId: md,
Permissions: g.Permissions,
Grantee: g.Grantee,
Owner: userID,
Creator: userID,
Ctime: ts,
Mtime: ts,
ShareType: st,
}
if isOwnersMeshProvider {
protocol := map[string]interface{}{
"name": "webdav",
"options": map[string]string{
"permissions": pm,
"token": ctxpkg.ContextMustGetToken(ctx),
},
}
if st == ocm.Share_SHARE_TYPE_TRANSFER {
protocol["name"] = "datatx"
}
requestBodyMap := map[string]interface{}{
"shareWith": g.Grantee.GetUserId().OpaqueId,
"name": name,
"providerId": fmt.Sprintf("%s:%s", md.StorageId, md.OpaqueId),
"owner": userID.OpaqueId,
"protocol": protocol,
"meshProvider": userID.Idp, // FIXME: move this into the 'owner' string?
}
err = sender.Send(requestBodyMap, pi)
if err != nil {
err = errors.Wrap(err, "error sending OCM POST")
return nil, err
}
}
m.Lock()
if err := m.model.ReadFile(); err != nil {
err = errors.Wrap(err, "error reading model")
return nil, err
}
if isOwnersMeshProvider {
encShare, err := utils.MarshalProtoV1ToJSON(s)
if err != nil {
return nil, err
}
m.model.Shares[s.Id.OpaqueId] = string(encShare)
} else {
encShare, err := utils.MarshalProtoV1ToJSON(&ocm.ReceivedShare{
Share: s,
State: ocm.ShareState_SHARE_STATE_PENDING,
})
if err != nil {
return nil, err
}
m.model.ReceivedShares[s.Id.OpaqueId] = string(encShare)
}
if err := m.model.Save(); err != nil {
err = errors.Wrap(err, "error saving model")
return nil, err
}
m.Unlock()
return s, nil
}
func (m *mgr) getByID(ctx context.Context, id *ocm.ShareId) (*ocm.Share, error) {
m.Lock()
defer m.Unlock()
if err := m.model.ReadFile(); err != nil {
err = errors.Wrap(err, "error reading model")
return nil, err
}
if s, ok := m.model.Shares[id.OpaqueId]; ok {
var share ocm.Share
if err := utils.UnmarshalJSONToProtoV1([]byte(s.(string)), &share); err != nil {
return nil, err
}
return &share, nil
}
return nil, errtypes.NotFound(id.String())
}
func (m *mgr) getByKey(ctx context.Context, key *ocm.ShareKey) (*ocm.Share, error) {
m.Lock()
defer m.Unlock()
if err := m.model.ReadFile(); err != nil {
err = errors.Wrap(err, "error reading model")
return nil, err
}
for _, s := range m.model.Shares {
var share ocm.Share
if err := utils.UnmarshalJSONToProtoV1([]byte(s.(string)), &share); err != nil {
continue
}
if (utils.UserEqual(key.Owner, share.Owner) || utils.UserEqual(key.Owner, share.Creator)) &&
utils.ResourceIDEqual(key.ResourceId, share.ResourceId) && utils.GranteeEqual(key.Grantee, share.Grantee) {
return &share, nil
}
}
return nil, errtypes.NotFound(key.String())
}
func (m *mgr) get(ctx context.Context, ref *ocm.ShareReference) (s *ocm.Share, err error) {
switch {
case ref.GetId() != nil:
s, err = m.getByID(ctx, ref.GetId())
case ref.GetKey() != nil:
s, err = m.getByKey(ctx, ref.GetKey())
default:
err = errtypes.NotFound(ref.String())
}
if err != nil {
return nil, err
}
// check if we are the owner
user := ctxpkg.ContextMustGetUser(ctx)
if utils.UserEqual(user.Id, s.Owner) || utils.UserEqual(user.Id, s.Creator) {
return s, nil
}
// we return not found to not disclose information
return nil, errtypes.NotFound(ref.String())
}
func (m *mgr) GetShare(ctx context.Context, ref *ocm.ShareReference) (*ocm.Share, error) {
share, err := m.get(ctx, ref)
if err != nil {
return nil, err
}
return share, nil
}
func (m *mgr) Unshare(ctx context.Context, ref *ocm.ShareReference) error {
m.Lock()
defer m.Unlock()
if err := m.model.ReadFile(); err != nil {
err = errors.Wrap(err, "error reading model")
return err
}
user := ctxpkg.ContextMustGetUser(ctx)
for id, s := range m.model.Shares {
var share ocm.Share
if err := utils.UnmarshalJSONToProtoV1([]byte(s.(string)), &share); err != nil {
continue
}
if sharesEqual(ref, &share) {
if utils.UserEqual(user.Id, share.Owner) || utils.UserEqual(user.Id, share.Creator) {
delete(m.model.Shares, id)
if err := m.model.Save(); err != nil {
err = errors.Wrap(err, "error saving model")
return err
}
return nil
}
}
}
return errtypes.NotFound(ref.String())
}
func sharesEqual(ref *ocm.ShareReference, s *ocm.Share) bool {
if ref.GetId() != nil && s.Id != nil {
if ref.GetId().OpaqueId == s.Id.OpaqueId {
return true
}
} else if ref.GetKey() != nil {
if (utils.UserEqual(ref.GetKey().Owner, s.Owner) || utils.UserEqual(ref.GetKey().Owner, s.Creator)) &&
utils.ResourceIDEqual(ref.GetKey().ResourceId, s.ResourceId) && utils.GranteeEqual(ref.GetKey().Grantee, s.Grantee) {
return true
}
}
return false
}
func (m *mgr) UpdateShare(ctx context.Context, ref *ocm.ShareReference, p *ocm.SharePermissions) (*ocm.Share, error) {
m.Lock()
defer m.Unlock()
if err := m.model.ReadFile(); err != nil {
err = errors.Wrap(err, "error reading model")
return nil, err
}
user := ctxpkg.ContextMustGetUser(ctx)
for id, s := range m.model.Shares {
var share ocm.Share
if err := utils.UnmarshalJSONToProtoV1([]byte(s.(string)), &share); err != nil {
continue
}
if sharesEqual(ref, &share) {
if utils.UserEqual(user.Id, share.Owner) || utils.UserEqual(user.Id, share.Creator) {
now := time.Now().UnixNano()
share.Permissions = p
share.Mtime = &typespb.Timestamp{
Seconds: uint64(now / 1000000000),
Nanos: uint32(now % 1000000000),
}
encShare, err := utils.MarshalProtoV1ToJSON(&share)
if err != nil {
return nil, err
}
m.model.Shares[id] = string(encShare)
if err := m.model.Save(); err != nil {
err = errors.Wrap(err, "error saving model")
return nil, err
}
return &share, nil
}
}
}
return nil, errtypes.NotFound(ref.String())
}
func (m *mgr) ListShares(ctx context.Context, filters []*ocm.ListOCMSharesRequest_Filter) ([]*ocm.Share, error) {
var ss []*ocm.Share
m.Lock()
defer m.Unlock()
if err := m.model.ReadFile(); err != nil {
err = errors.Wrap(err, "error reading model")
return nil, err
}
user := ctxpkg.ContextMustGetUser(ctx)
for _, s := range m.model.Shares {
var share ocm.Share
if err := utils.UnmarshalJSONToProtoV1([]byte(s.(string)), &share); err != nil {
continue
}
if utils.UserEqual(user.Id, share.Owner) || utils.UserEqual(user.Id, share.Creator) {
// no filter we return earlier
if len(filters) == 0 {
ss = append(ss, &share)
} else {
// check filters
// TODO(labkode): add the rest of filters.
for _, f := range filters {
if f.Type == ocm.ListOCMSharesRequest_Filter_TYPE_RESOURCE_ID {
if utils.ResourceIDEqual(share.ResourceId, f.GetResourceId()) {
ss = append(ss, &share)
}
}
}
}
}
}
return ss, nil
}
func (m *mgr) ListReceivedShares(ctx context.Context) ([]*ocm.ReceivedShare, error) {
var rss []*ocm.ReceivedShare
m.Lock()
defer m.Unlock()
if err := m.model.ReadFile(); err != nil {
err = errors.Wrap(err, "error reading model")
return nil, err
}
user := ctxpkg.ContextMustGetUser(ctx)
for _, s := range m.model.ReceivedShares {
var rs ocm.ReceivedShare
if err := utils.UnmarshalJSONToProtoV1([]byte(s.(string)), &rs); err != nil {
continue
}
share := rs.Share
if utils.UserEqual(user.Id, share.Owner) || utils.UserEqual(user.Id, share.Creator) {
// omit shares created by me
continue
}
if share.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_USER && utils.UserEqual(user.Id, share.Grantee.GetUserId()) {
rss = append(rss, &rs)
}
}
return rss, nil
}
func (m *mgr) GetReceivedShare(ctx context.Context, ref *ocm.ShareReference) (*ocm.ReceivedShare, error) {
return m.getReceived(ctx, ref)
}
func (m *mgr) getReceived(ctx context.Context, ref *ocm.ShareReference) (*ocm.ReceivedShare, error) {
m.Lock()
defer m.Unlock()
if err := m.model.ReadFile(); err != nil {
err = errors.Wrap(err, "error reading model")
return nil, err
}
user := ctxpkg.ContextMustGetUser(ctx)
for _, s := range m.model.ReceivedShares {
var rs ocm.ReceivedShare
if err := utils.UnmarshalJSONToProtoV1([]byte(s.(string)), &rs); err != nil {
continue
}
share := rs.Share
if sharesEqual(ref, share) {
if share.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_USER && utils.UserEqual(user.Id, share.Grantee.GetUserId()) {
return &rs, nil
}
}
}
return nil, errtypes.NotFound(ref.String())
}
func (m *mgr) UpdateReceivedShare(ctx context.Context, share *ocm.ReceivedShare, fieldMask *field_mask.FieldMask) (*ocm.ReceivedShare, error) {
rs, err := m.getReceived(ctx, &ocm.ShareReference{Spec: &ocm.ShareReference_Id{Id: share.Share.Id}})
if err != nil {
return nil, err
}
m.Lock()
defer m.Unlock()
for i := range fieldMask.Paths {
switch fieldMask.Paths[i] {
case "state":
rs.State = share.State
case "mount_point":
rs.MountPoint = share.MountPoint
default:
return nil, errtypes.NotSupported("updating " + fieldMask.Paths[i] + " is not supported")
}
}
if err := m.model.ReadFile(); err != nil {
err = errors.Wrap(err, "error reading model")
return nil, err
}
encShare, err := utils.MarshalProtoV1ToJSON(rs)
if err != nil {
return nil, err
}
m.model.ReceivedShares[rs.Share.Id.GetOpaqueId()] = string(encShare)
if err := m.model.Save(); err != nil {
err = errors.Wrap(err, "error saving model")
return nil, err
}
return rs, nil
}

View File

@@ -1,624 +0,0 @@
// Copyright 2018-2021 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 nextcloud verifies a clientID and clientSecret against a Nextcloud backend.
package nextcloud
import (
"context"
"encoding/json"
"io"
"math/rand"
"net/http"
"strings"
"time"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
"github.com/cs3org/reva/v2/pkg/utils"
ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
typespb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/v2/pkg/appctx"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/ocm/share"
"github.com/cs3org/reva/v2/pkg/ocm/share/manager/registry"
"github.com/cs3org/reva/v2/pkg/ocm/share/sender"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
"google.golang.org/genproto/protobuf/field_mask"
)
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
func randSeq(n int) string {
b := make([]rune, n)
for i := range b {
b[i] = letters[rand.Intn(len(letters))]
}
return string(b)
}
func init() {
registry.Register("nextcloud", New)
}
// Manager is the Nextcloud-based implementation of the share.Manager interface
// see https://github.com/cs3org/reva/blob/v1.13.0/pkg/ocm/share/share.go#L30-L57
type Manager struct {
client *http.Client
sharedSecret string
endPoint string
}
// ShareManagerConfig contains config for a Nextcloud-based ShareManager
type ShareManagerConfig struct {
EndPoint string `mapstructure:"endpoint" docs:";The Nextcloud backend endpoint for user check"`
SharedSecret string `mapstructure:"shared_secret"`
MockHTTP bool `mapstructure:"mock_http"`
}
// Action describes a REST request to forward to the Nextcloud backend
type Action struct {
verb string
argS string
}
// GranteeAltMap is an alternative map to JSON-unmarshal a Grantee
// Grantees are hard to unmarshal, so unmarshalling into a map[string]interface{} first,
// see also https://github.com/pondersource/sciencemesh-nextcloud/issues/27
type GranteeAltMap struct {
ID *provider.Grantee_UserId `json:"id"`
}
// ShareAltMap is an alternative map to JSON-unmarshal a Share
type ShareAltMap struct {
ID *ocm.ShareId `json:"id"`
ResourceID *provider.ResourceId `json:"resource_id"`
Permissions *ocm.SharePermissions `json:"permissions"`
Grantee *GranteeAltMap `json:"grantee"`
Owner *userpb.UserId `json:"owner"`
Creator *userpb.UserId `json:"creator"`
Ctime *typespb.Timestamp `json:"ctime"`
Mtime *typespb.Timestamp `json:"mtime"`
}
// ReceivedShareAltMap is an alternative map to JSON-unmarshal a ReceivedShare
type ReceivedShareAltMap struct {
Share *ShareAltMap `json:"share"`
State ocm.ShareState `json:"state"`
}
func (c *ShareManagerConfig) init() {
}
func parseConfig(m map[string]interface{}) (*ShareManagerConfig, error) {
c := &ShareManagerConfig{}
if err := mapstructure.Decode(m, c); err != nil {
err = errors.Wrap(err, "error decoding conf")
return nil, err
}
return c, nil
}
func getUser(ctx context.Context) (*userpb.User, error) {
u, ok := ctxpkg.ContextGetUser(ctx)
if !ok {
err := errors.Wrap(errtypes.UserRequired(""), "nextcloud storage driver: error getting user from ctx")
return nil, err
}
return u, nil
}
// New returns a share manager implementation that verifies against a Nextcloud backend.
func New(m map[string]interface{}) (share.Manager, error) {
c, err := parseConfig(m)
if err != nil {
return nil, err
}
c.init()
return NewShareManager(c)
}
// NewShareManager returns a new Nextcloud-based ShareManager
func NewShareManager(c *ShareManagerConfig) (*Manager, error) {
var client *http.Client
if c.MockHTTP {
// called := make([]string, 0)
// nextcloudServerMock := GetNextcloudServerMock(&called)
// client, _ = TestingHTTPClient(nextcloudServerMock)
// Wait for SetHTTPClient to be called later
client = nil
} else {
if len(c.EndPoint) == 0 {
return nil, errors.New("Please specify 'endpoint' in '[grpc.services.ocmshareprovider.drivers.nextcloud]' and '[grpc.services.ocmcore.drivers.nextcloud]'")
}
client = &http.Client{}
}
return &Manager{
endPoint: c.EndPoint, // e.g. "http://nc/apps/sciencemesh/"
sharedSecret: c.SharedSecret,
client: client,
}, nil
}
// SetHTTPClient sets the HTTP client
func (sm *Manager) SetHTTPClient(c *http.Client) {
sm.client = c
}
func getUsername(ctx context.Context) string {
user, err := getUser(ctx)
if err != nil {
return "unknown"
}
if len(user.Username) > 0 {
return user.Username
}
if len(user.Id.OpaqueId) > 0 {
return user.Id.OpaqueId
}
return "empty-username"
}
func (sm *Manager) do(ctx context.Context, a Action, username string) (int, []byte, error) {
url := sm.endPoint + "~" + username + "/api/ocm/" + a.verb
log := appctx.GetLogger(ctx)
log.Info().Msgf("am.do %s %s", url, a.argS)
req, err := http.NewRequest(http.MethodPost, url, strings.NewReader(a.argS))
if err != nil {
return 0, nil, err
}
req.Header.Set("X-Reva-Secret", sm.sharedSecret)
req.Header.Set("Content-Type", "application/json")
resp, err := sm.client.Do(req)
if err != nil {
return 0, nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return 0, nil, err
}
// curl -i -H 'application/json' -H 'X-Reva-Secret: shared-secret-1' -d '{"md":{"opaque_id":"fileid-/other/q/as"},"g":{"grantee":{"type":1,"Id":{"UserId":{"idp":"revanc2.docker","opaque_id":"marie"}}},"permissions":{"permissions":{"get_path":true,"initiate_file_download":true,"list_container":true,"list_file_versions":true,"stat":true}}},"provider_domain":"cern.ch","resource_type":"file","provider_id":2,"owner_opaque_id":"einstein","owner_display_name":"Albert Einstein","protocol":{"name":"webdav","options":{"sharedSecret":"secret","permissions":"webdav-property"}}}' https://nc1.docker/index.php/apps/sciencemesh/~/api/ocm/addSentShare
log.Info().Msgf("am.do response %d %s", resp.StatusCode, body)
return resp.StatusCode, body, nil
}
// Share is called from both grpc CreateOCMShare for outgoing
// and http /ocm/shares for incoming
// pi is provider info
// pm is permissions
func (sm *Manager) Share(ctx context.Context, md *provider.ResourceId, g *ocm.ShareGrant, name string,
pi *ocmprovider.ProviderInfo, pm string, owner *userpb.UserId, token string, st ocm.Share_ShareType) (*ocm.Share, error) {
// Since both OCMCore and OCMShareProvider use the same package, we distinguish
// between calls received from them on the basis of whether they provide info
// about the remote provider on which the share is to be created.
// If this info is provided, this call is on the owner's mesh provider and so
// we call the CreateOCMCoreShare method on the remote provider as well,
// else this is received from another provider and we only create a local share.
var isOwnersMeshProvider bool
var apiMethod string
var username string
if pi != nil {
isOwnersMeshProvider = true
apiMethod = "addSentShare"
username = getUsername(ctx)
token = randSeq(10)
} else {
apiMethod = "addReceivedShare"
username = g.Grantee.GetUserId().OpaqueId
}
var userID *userpb.UserId
if !isOwnersMeshProvider {
// Since this call is on the remote provider, the owner of the resource is expected to be specified.
if owner == nil {
return nil, errors.New("nextcloud: owner of resource not provided")
}
userID = owner
} else {
userID = ctxpkg.ContextMustGetUser(ctx).GetId()
}
// do not allow share to myself if share is for a user
if g.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_USER && utils.UserEqual(g.Grantee.GetUserId(), userID) {
return nil, errors.New("nextcloud: user and grantee are the same")
}
s := &ocm.Share{
Name: name,
ResourceId: md,
Permissions: g.Permissions,
Grantee: g.Grantee,
Owner: userID,
Creator: userID,
ShareType: st,
}
var encShare []byte
var err error
if isOwnersMeshProvider {
// adding the webdav sharedSecret in the Grantee because Share itself doesn't have an Opaque field,
// see https://cs3org.github.io/cs3apis/#cs3.storage.provider.v1beta1.Grantee
// and https://cs3org.github.io/cs3apis/#cs3.sharing.ocm.v1beta1.Share
s.Grantee.Opaque = &typespb.Opaque{
Map: map[string]*typespb.OpaqueEntry{
"sharedSecret": {
Decoder: "plain",
Value: []byte(token),
},
},
}
encShare, err = utils.MarshalProtoV1ToJSON(s)
if err != nil {
return nil, err
}
} else {
// adding the webdav sharedSecret and remote share id (called the "ProviderID" in OCM) in the Grantee because Share itself doesn't have an Opaque field,
// see https://cs3org.github.io/cs3apis/#cs3.storage.provider.v1beta1.Grantee
// and https://cs3org.github.io/cs3apis/#cs3.sharing.ocm.v1beta1.Share
s.Grantee.Opaque = &typespb.Opaque{
Map: map[string]*typespb.OpaqueEntry{
"sharedSecret": {
Decoder: "plain",
Value: []byte(token),
},
"remoteShareId": {
Decoder: "plain",
Value: g.Grantee.Opaque.Map["remoteShareId"].Value,
},
},
}
encShare, err = utils.MarshalProtoV1ToJSON(&ocm.ReceivedShare{
Share: s,
State: ocm.ShareState_SHARE_STATE_PENDING,
})
if err != nil {
return nil, err
}
}
_, body, err := sm.do(ctx, Action{apiMethod, string(encShare)}, username)
s.Id = &ocm.ShareId{
OpaqueId: string(body),
}
now := time.Now().UnixNano()
s.Ctime = &typespb.Timestamp{
Seconds: uint64(now / 1000000000),
Nanos: uint32(now % 1000000000),
}
if err != nil {
return nil, err
}
if isOwnersMeshProvider {
// token, ok := ctxpkg.ContextGetToken(ctx)
// if !ok {
// return nil, errors.New("Could not get token from context")
// }
var protocol map[string]interface{}
if st == ocm.Share_SHARE_TYPE_TRANSFER {
protocol = map[string]interface{}{
"name": "datatx",
"options": map[string]string{
"permissions": pm,
"token": token, // FIXME: Where is the token for datatx generated?
},
}
} else {
protocol = map[string]interface{}{
"name": "webdav",
"options": map[string]string{
"permissions": pm,
"sharedSecret": token,
},
}
}
requestBodyMap := map[string]interface{}{
"shareWith": g.Grantee.GetUserId().OpaqueId,
"name": name,
"providerId": s.Id.OpaqueId,
"owner": userID.OpaqueId,
"protocol": protocol,
"meshProvider": userID.Idp, // FIXME: move this into the 'owner' string?
}
err = sender.Send(requestBodyMap, pi)
if err != nil {
err = errors.Wrap(err, "error sending OCM POST")
return nil, err
}
}
return s, nil
}
// GetShare as defined in the ocm.share.Manager interface
// https://github.com/cs3org/reva/blob/v1.13.0/pkg/ocm/share/share.go#L30-L57
func (sm *Manager) GetShare(ctx context.Context, ref *ocm.ShareReference) (*ocm.Share, error) {
bodyStr, err := json.Marshal(ref)
if err != nil {
return nil, err
}
_, body, err := sm.do(ctx, Action{"GetShare", string(bodyStr)}, getUsername(ctx))
if err != nil {
return nil, err
}
altResult := &ShareAltMap{}
err = json.Unmarshal(body, &altResult)
if altResult == nil {
return nil, err
}
return &ocm.Share{
Id: altResult.ID,
ResourceId: altResult.ResourceID,
Permissions: altResult.Permissions,
Grantee: &provider.Grantee{
Id: altResult.Grantee.ID,
},
Owner: altResult.Owner,
Creator: altResult.Creator,
Ctime: altResult.Ctime,
Mtime: altResult.Mtime,
}, err
}
// Unshare as defined in the ocm.share.Manager interface
// https://github.com/cs3org/reva/blob/v1.13.0/pkg/ocm/share/share.go#L30-L57
func (sm *Manager) Unshare(ctx context.Context, ref *ocm.ShareReference) error {
bodyStr, err := json.Marshal(ref)
if err != nil {
return err
}
_, _, err = sm.do(ctx, Action{"Unshare", string(bodyStr)}, getUsername(ctx))
return err
}
// UpdateShare as defined in the ocm.share.Manager interface
// https://github.com/cs3org/reva/blob/v1.13.0/pkg/ocm/share/share.go#L30-L57
func (sm *Manager) UpdateShare(ctx context.Context, ref *ocm.ShareReference, p *ocm.SharePermissions) (*ocm.Share, error) {
type paramsObj struct {
Ref *ocm.ShareReference `json:"ref"`
P *ocm.SharePermissions `json:"p"`
}
bodyObj := &paramsObj{
Ref: ref,
P: p,
}
bodyStr, err := json.Marshal(bodyObj)
if err != nil {
return nil, err
}
_, body, err := sm.do(ctx, Action{"UpdateShare", string(bodyStr)}, getUsername(ctx))
if err != nil {
return nil, err
}
altResult := &ShareAltMap{}
err = json.Unmarshal(body, &altResult)
if altResult == nil {
return nil, err
}
return &ocm.Share{
Id: altResult.ID,
ResourceId: altResult.ResourceID,
Permissions: altResult.Permissions,
Grantee: &provider.Grantee{
Id: altResult.Grantee.ID,
},
Owner: altResult.Owner,
Creator: altResult.Creator,
Ctime: altResult.Ctime,
Mtime: altResult.Mtime,
}, err
}
// ListShares as defined in the ocm.share.Manager interface
// https://github.com/cs3org/reva/blob/v1.13.0/pkg/ocm/share/share.go#L30-L57
func (sm *Manager) ListShares(ctx context.Context, filters []*ocm.ListOCMSharesRequest_Filter) ([]*ocm.Share, error) {
bodyStr, err := json.Marshal(filters)
if err != nil {
return nil, err
}
_, respBody, err := sm.do(ctx, Action{"ListShares", string(bodyStr)}, getUsername(ctx))
if err != nil {
return nil, err
}
var respArr []ShareAltMap
err = json.Unmarshal(respBody, &respArr)
if err != nil {
return nil, err
}
var pointers = make([]*ocm.Share, len(respArr))
for i := 0; i < len(respArr); i++ {
altResult := respArr[i]
pointers[i] = &ocm.Share{
Id: altResult.ID,
ResourceId: altResult.ResourceID,
Permissions: altResult.Permissions,
Grantee: &provider.Grantee{
Id: altResult.Grantee.ID,
},
Owner: altResult.Owner,
Creator: altResult.Creator,
Ctime: altResult.Ctime,
Mtime: altResult.Mtime,
}
}
return pointers, err
}
// ListReceivedShares as defined in the ocm.share.Manager interface
// https://github.com/cs3org/reva/blob/v1.13.0/pkg/ocm/share/share.go#L30-L57
func (sm *Manager) ListReceivedShares(ctx context.Context) ([]*ocm.ReceivedShare, error) {
_, respBody, err := sm.do(ctx, Action{"ListReceivedShares", string("")}, getUsername(ctx))
if err != nil {
return nil, err
}
var respArr []ReceivedShareAltMap
err = json.Unmarshal(respBody, &respArr)
if err != nil {
return nil, err
}
var pointers = make([]*ocm.ReceivedShare, len(respArr))
for i := 0; i < len(respArr); i++ {
altResultShare := respArr[i].Share
if altResultShare == nil {
pointers[i] = &ocm.ReceivedShare{
Share: nil,
State: respArr[i].State,
}
} else {
pointers[i] = &ocm.ReceivedShare{
Share: &ocm.Share{
Id: altResultShare.ID,
ResourceId: altResultShare.ResourceID,
Permissions: altResultShare.Permissions,
Grantee: &provider.Grantee{
Id: altResultShare.Grantee.ID,
},
Owner: altResultShare.Owner,
Creator: altResultShare.Creator,
Ctime: altResultShare.Ctime,
Mtime: altResultShare.Mtime,
},
State: respArr[i].State,
}
}
}
return pointers, err
}
// GetReceivedShare as defined in the ocm.share.Manager interface
// https://github.com/cs3org/reva/blob/v1.13.0/pkg/ocm/share/share.go#L29-L54
func (sm *Manager) GetReceivedShare(ctx context.Context, ref *ocm.ShareReference) (*ocm.ReceivedShare, error) {
bodyStr, err := json.Marshal(ref)
if err != nil {
return nil, err
}
_, respBody, err := sm.do(ctx, Action{"GetReceivedShare", string(bodyStr)}, getUsername(ctx))
if err != nil {
return nil, err
}
var altResult ReceivedShareAltMap
err = json.Unmarshal(respBody, &altResult)
if err != nil {
return nil, err
}
altResultShare := altResult.Share
if altResultShare == nil {
return &ocm.ReceivedShare{
Share: nil,
State: altResult.State,
}, err
}
return &ocm.ReceivedShare{
Share: &ocm.Share{
Id: altResultShare.ID,
ResourceId: altResultShare.ResourceID,
Permissions: altResultShare.Permissions,
Grantee: &provider.Grantee{
Id: altResultShare.Grantee.ID,
},
Owner: altResultShare.Owner,
Creator: altResultShare.Creator,
Ctime: altResultShare.Ctime,
Mtime: altResultShare.Mtime,
},
State: altResult.State,
}, err
}
// UpdateReceivedShare as defined in the ocm.share.Manager interface
// https://github.com/cs3org/reva/blob/v1.13.0/pkg/ocm/share/share.go#L30-L57
func (sm Manager) UpdateReceivedShare(ctx context.Context, receivedShare *ocm.ReceivedShare, fieldMask *field_mask.FieldMask) (*ocm.ReceivedShare, error) {
type paramsObj struct {
ReceivedShare *ocm.ReceivedShare `json:"received_share"`
FieldMask *field_mask.FieldMask `json:"field_mask"`
}
bodyObj := &paramsObj{
ReceivedShare: receivedShare,
FieldMask: fieldMask,
}
bodyStr, err := json.Marshal(bodyObj)
if err != nil {
return nil, err
}
_, respBody, err := sm.do(ctx, Action{"UpdateReceivedShare", string(bodyStr)}, getUsername(ctx))
if err != nil {
return nil, err
}
var altResult ReceivedShareAltMap
err = json.Unmarshal(respBody, &altResult)
if err != nil {
return nil, err
}
altResultShare := altResult.Share
if altResultShare == nil {
return &ocm.ReceivedShare{
Share: nil,
State: altResult.State,
}, err
}
return &ocm.ReceivedShare{
Share: &ocm.Share{
Id: altResultShare.ID,
ResourceId: altResultShare.ResourceID,
Permissions: altResultShare.Permissions,
Grantee: &provider.Grantee{
Id: altResultShare.Grantee.ID,
},
Owner: altResultShare.Owner,
Creator: altResultShare.Creator,
Ctime: altResultShare.Ctime,
Mtime: altResultShare.Mtime,
},
State: altResult.State,
}, err
}

View File

@@ -0,0 +1,517 @@
// Copyright 2018-2023 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 json
import (
"context"
"encoding/json"
"io"
"os"
"sync"
"time"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
typespb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/ocm/share"
"github.com/cs3org/reva/v2/pkg/ocm/share/repository/registry"
"github.com/cs3org/reva/v2/pkg/utils"
"github.com/cs3org/reva/v2/pkg/utils/cfg"
"github.com/google/uuid"
"github.com/pkg/errors"
"google.golang.org/genproto/protobuf/field_mask"
)
func init() {
registry.Register("json", New)
}
// New returns a new authorizer object.
func New(m map[string]interface{}) (share.Repository, error) {
var c config
if err := cfg.Decode(m, &c); err != nil {
return nil, err
}
// load or create file
model, err := loadOrCreate(c.File)
if err != nil {
err = errors.Wrap(err, "error loading the file containing the shares")
return nil, err
}
mgr := &mgr{
c: &c,
model: model,
}
return mgr, nil
}
func loadOrCreate(file string) (*shareModel, error) {
_, err := os.Stat(file)
if os.IsNotExist(err) {
if err := os.WriteFile(file, []byte("{}"), 0700); err != nil {
return nil, errors.Wrap(err, "error creating the file: "+file)
}
}
f, err := os.OpenFile(file, os.O_RDONLY, 0644)
if err != nil {
err = errors.Wrap(err, "error opening the file: "+file)
return nil, err
}
defer f.Close()
var m shareModel
if err := json.NewDecoder(f).Decode(&m); err != nil {
if err != io.EOF {
return nil, errors.Wrap(err, "error decoding data to json")
}
}
if m.Shares == nil {
m.Shares = map[string]*ocm.Share{}
}
if m.ReceivedShares == nil {
m.ReceivedShares = map[string]*ocm.ReceivedShare{}
}
return &m, nil
}
type shareModel struct {
Shares map[string]*ocm.Share `json:"shares"` // share_id -> share
ReceivedShares map[string]*ocm.ReceivedShare `json:"received_shares"` // share_id -> share
}
func (s *shareModel) UnmarshalJSON(d []byte) error {
m := struct {
Shares map[string]json.RawMessage `json:"shares"`
ReceivedShares map[string]json.RawMessage `json:"received_shares"`
}{}
if err := json.Unmarshal(d, &m); err != nil {
return err
}
share := map[string]*ocm.Share{}
for k, v := range m.Shares {
var s ocm.Share
if err := utils.UnmarshalJSONToProtoV1(v, &s); err != nil {
return err
}
share[k] = &s
}
received := map[string]*ocm.ReceivedShare{}
for k, v := range m.ReceivedShares {
var s ocm.ReceivedShare
if err := utils.UnmarshalJSONToProtoV1(v, &s); err != nil {
return err
}
received[k] = &s
}
*s = shareModel{
Shares: share,
ReceivedShares: received,
}
return nil
}
func (s *shareModel) MarshalJSON() ([]byte, error) {
shares := map[string]json.RawMessage{}
for k, v := range s.Shares {
d, err := utils.MarshalProtoV1ToJSON(v)
if err != nil {
return nil, err
}
shares[k] = d
}
received := map[string]json.RawMessage{}
for k, v := range s.ReceivedShares {
d, err := utils.MarshalProtoV1ToJSON(v)
if err != nil {
return nil, err
}
received[k] = d
}
return json.Marshal(map[string]any{
"shares": shares,
"received_shares": received,
})
}
type config struct {
File string `mapstructure:"file"`
}
func (c *config) ApplyDefaults() {
if c.File == "" {
c.File = "/var/tmp/reva/ocm-shares.json"
}
}
type mgr struct {
c *config
sync.Mutex // concurrent access to the file
model *shareModel
}
func (m *mgr) save() error {
f, err := os.OpenFile(m.c.File, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return errors.Wrap(err, "error opening file "+m.c.File)
}
defer f.Close()
if err := json.NewEncoder(f).Encode(m.model); err != nil {
return errors.Wrap(err, "error encoding to json")
}
return f.Sync()
}
func (m *mgr) load() error {
f, err := os.OpenFile(m.c.File, os.O_RDONLY, 0644)
if err != nil {
return errors.Wrap(err, "error opening file "+m.c.File)
}
defer f.Close()
d, err := io.ReadAll(f)
if err != nil {
return err
}
var model shareModel
if err := json.Unmarshal(d, &model); err != nil {
return err
}
m.model = &model
return nil
}
func genID() string {
return uuid.New().String()
}
func (m *mgr) StoreShare(ctx context.Context, ocmshare *ocm.Share) (*ocm.Share, error) {
m.Lock()
defer m.Unlock()
if err := m.load(); err != nil {
return nil, err
}
if _, err := m.getByKey(ctx, &ocm.ShareKey{
Owner: ocmshare.Owner,
ResourceId: ocmshare.ResourceId,
Grantee: ocmshare.Grantee,
}); err == nil {
return nil, share.ErrShareAlreadyExisting
}
ocmshare.Id = &ocm.ShareId{OpaqueId: genID()}
clone, err := cloneShare(ocmshare)
if err != nil {
return nil, err
}
m.model.Shares[ocmshare.Id.OpaqueId] = clone
if err := m.save(); err != nil {
return nil, errors.Wrap(err, "error saving share")
}
return ocmshare, nil
}
func cloneShare(s *ocm.Share) (*ocm.Share, error) {
d, err := utils.MarshalProtoV1ToJSON(s)
if err != nil {
return nil, errtypes.InternalError("failed to marshal ocm share")
}
var cloned ocm.Share
if err := utils.UnmarshalJSONToProtoV1(d, &cloned); err != nil {
return nil, errtypes.InternalError("failed to unmarshal ocm share")
}
return &cloned, nil
}
func cloneReceivedShare(s *ocm.ReceivedShare) (*ocm.ReceivedShare, error) {
d, err := utils.MarshalProtoV1ToJSON(s)
if err != nil {
return nil, errtypes.InternalError("failed to marshal ocm received share")
}
var cloned ocm.ReceivedShare
if err := utils.UnmarshalJSONToProtoV1(d, &cloned); err != nil {
return nil, errtypes.InternalError("failed to unmarshal ocm received share")
}
return &cloned, nil
}
func (m *mgr) GetShare(ctx context.Context, user *userpb.User, ref *ocm.ShareReference) (*ocm.Share, error) {
m.Lock()
defer m.Unlock()
var (
s *ocm.Share
err error
)
if err := m.load(); err != nil {
return nil, err
}
switch {
case ref.GetId() != nil:
s, err = m.getByID(ctx, ref.GetId())
case ref.GetKey() != nil:
s, err = m.getByKey(ctx, ref.GetKey())
case ref.GetToken() != "":
return m.getByToken(ctx, ref.GetToken())
default:
err = errtypes.NotFound(ref.String())
}
if err != nil {
return nil, err
}
// check if we are the owner
if utils.UserEqual(user.Id, s.Owner) || utils.UserEqual(user.Id, s.Creator) {
return s, nil
}
return nil, share.ErrShareNotFound
}
func (m *mgr) getByToken(ctx context.Context, token string) (*ocm.Share, error) {
for _, share := range m.model.Shares {
if share.Token == token {
return share, nil
}
}
return nil, errtypes.NotFound(token)
}
func (m *mgr) getByID(ctx context.Context, id *ocm.ShareId) (*ocm.Share, error) {
if share, ok := m.model.Shares[id.OpaqueId]; ok {
return share, nil
}
return nil, errtypes.NotFound(id.String())
}
func (m *mgr) getByKey(ctx context.Context, key *ocm.ShareKey) (*ocm.Share, error) {
for _, share := range m.model.Shares {
if (utils.UserEqual(key.Owner, share.Owner) || utils.UserEqual(key.Owner, share.Creator)) &&
utils.ResourceIDEqual(key.ResourceId, share.ResourceId) && utils.GranteeEqual(key.Grantee, share.Grantee) {
return share, nil
}
}
return nil, share.ErrShareNotFound
}
func (m *mgr) DeleteShare(ctx context.Context, user *userpb.User, ref *ocm.ShareReference) error {
m.Lock()
defer m.Unlock()
if err := m.load(); err != nil {
return err
}
for id, share := range m.model.Shares {
if sharesEqual(ref, share) {
if utils.UserEqual(user.Id, share.Owner) || utils.UserEqual(user.Id, share.Creator) {
delete(m.model.Shares, id)
return m.save()
}
}
}
return errtypes.NotFound(ref.String())
}
func sharesEqual(ref *ocm.ShareReference, s *ocm.Share) bool {
if ref.GetId() != nil && s.Id != nil {
if ref.GetId().OpaqueId == s.Id.OpaqueId {
return true
}
} else if ref.GetKey() != nil {
if (utils.UserEqual(ref.GetKey().Owner, s.Owner) || utils.UserEqual(ref.GetKey().Owner, s.Creator)) &&
utils.ResourceIDEqual(ref.GetKey().ResourceId, s.ResourceId) && utils.GranteeEqual(ref.GetKey().Grantee, s.Grantee) {
return true
}
}
return false
}
func receivedShareEqual(ref *ocm.ShareReference, s *ocm.ReceivedShare) bool {
if ref.GetId() != nil && s.Id != nil {
if ref.GetId().OpaqueId == s.Id.OpaqueId {
return true
}
}
return false
}
func (m *mgr) UpdateShare(ctx context.Context, user *userpb.User, ref *ocm.ShareReference, f ...*ocm.UpdateOCMShareRequest_UpdateField) (*ocm.Share, error) {
return nil, errtypes.NotSupported("not yet implemented")
}
func (m *mgr) ListShares(ctx context.Context, user *userpb.User, filters []*ocm.ListOCMSharesRequest_Filter) ([]*ocm.Share, error) {
var ss []*ocm.Share
m.Lock()
defer m.Unlock()
if err := m.load(); err != nil {
return nil, err
}
for _, share := range m.model.Shares {
if utils.UserEqual(user.Id, share.Owner) || utils.UserEqual(user.Id, share.Creator) {
// no filter we return earlier
if len(filters) == 0 {
ss = append(ss, share)
} else {
// check filters
// TODO(labkode): add the rest of filters.
for _, f := range filters {
if f.Type == ocm.ListOCMSharesRequest_Filter_TYPE_RESOURCE_ID {
if utils.ResourceIDEqual(share.ResourceId, f.GetResourceId()) {
ss = append(ss, share)
}
}
}
}
}
}
return ss, nil
}
func (m *mgr) StoreReceivedShare(ctx context.Context, share *ocm.ReceivedShare) (*ocm.ReceivedShare, error) {
m.Lock()
defer m.Unlock()
if err := m.load(); err != nil {
return nil, err
}
now := time.Now().UnixNano()
ts := &typespb.Timestamp{
Seconds: uint64(now / 1000000000),
Nanos: uint32(now % 1000000000),
}
share.Id = &ocm.ShareId{
OpaqueId: genID(),
}
share.Ctime = ts
share.Mtime = ts
clone, err := cloneReceivedShare(share)
if err != nil {
return nil, err
}
m.model.ReceivedShares[share.Id.OpaqueId] = clone
if err := m.save(); err != nil {
return nil, err
}
return share, nil
}
func (m *mgr) ListReceivedShares(ctx context.Context, user *userpb.User) ([]*ocm.ReceivedShare, error) {
var rss []*ocm.ReceivedShare
m.Lock()
defer m.Unlock()
if err := m.load(); err != nil {
return nil, err
}
for _, share := range m.model.ReceivedShares {
if utils.UserEqual(user.Id, share.Owner) || utils.UserEqual(user.Id, share.Creator) {
// omit shares created by me
continue
}
if share.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_USER && utils.UserEqual(user.Id, share.Grantee.GetUserId()) {
rss = append(rss, share)
}
}
return rss, nil
}
func (m *mgr) GetReceivedShare(ctx context.Context, user *userpb.User, ref *ocm.ShareReference) (*ocm.ReceivedShare, error) {
m.Lock()
defer m.Unlock()
if err := m.load(); err != nil {
return nil, err
}
for _, share := range m.model.ReceivedShares {
if receivedShareEqual(ref, share) {
if share.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_USER && utils.UserEqual(user.Id, share.Grantee.GetUserId()) {
return share, nil
}
}
}
return nil, errtypes.NotFound(ref.String())
}
func (m *mgr) UpdateReceivedShare(ctx context.Context, user *userpb.User, share *ocm.ReceivedShare, fieldMask *field_mask.FieldMask) (*ocm.ReceivedShare, error) {
rs, err := m.GetReceivedShare(ctx, user, &ocm.ShareReference{Spec: &ocm.ShareReference_Id{Id: share.Id}})
if err != nil {
return nil, err
}
m.Lock()
defer m.Unlock()
if err := m.load(); err != nil {
return nil, err
}
for _, mask := range fieldMask.Paths {
switch mask {
case "state":
rs.State = share.State
m.model.ReceivedShares[share.Id.OpaqueId].State = share.State
// TODO case "mount_point":
default:
return nil, errtypes.NotSupported("updating " + mask + " is not supported")
}
}
if err := m.save(); err != nil {
return nil, errors.Wrap(err, "error saving model")
}
return rs, nil
}

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 CERN
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -19,8 +19,8 @@
package loader
import (
// Load core share manager drivers.
_ "github.com/cs3org/reva/v2/pkg/ocm/invite/manager/json"
_ "github.com/cs3org/reva/v2/pkg/ocm/invite/manager/memory"
// Add your own here
// Load core share repository drivers.
_ "github.com/cs3org/reva/v2/pkg/ocm/share/repository/json"
_ "github.com/cs3org/reva/v2/pkg/ocm/share/repository/nextcloud"
// Add your own here.
)

View File

@@ -0,0 +1,437 @@
// Copyright 2018-2023 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 nextcloud verifies a clientID and clientSecret against a Nextcloud backend.
package nextcloud
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"strconv"
"strings"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
typespb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/v2/pkg/appctx"
"github.com/cs3org/reva/v2/pkg/ocm/share"
"github.com/cs3org/reva/v2/pkg/ocm/share/repository/registry"
"github.com/cs3org/reva/v2/pkg/utils"
"github.com/cs3org/reva/v2/pkg/utils/cfg"
"github.com/pkg/errors"
"google.golang.org/genproto/protobuf/field_mask"
)
func init() {
registry.Register("nextcloud", New)
}
// Manager is the Nextcloud-based implementation of the share.Repository interface
// see https://github.com/cs3org/reva/blob/v1.13.0/pkg/ocm/share/share.go#L30-L57
type Manager struct {
client *http.Client
sharedSecret string
webDAVHost string
endPoint string
}
// ShareManagerConfig contains config for a Nextcloud-based ShareManager.
type ShareManagerConfig struct {
EndPoint string `mapstructure:"endpoint" docs:";The Nextcloud backend endpoint for user check"`
SharedSecret string `mapstructure:"shared_secret"`
WebDAVHost string `mapstructure:"webdav_host"`
MockHTTP bool `mapstructure:"mock_http"`
}
// Action describes a REST request to forward to the Nextcloud backend.
type Action struct {
verb string
argS string
}
// GranteeAltMap is an alternative map to JSON-unmarshal a Grantee
// Grantees are hard to unmarshal, so unmarshalling into a map[string]interface{} first,
// see also https://github.com/pondersource/sciencemesh-nextcloud/issues/27
type GranteeAltMap struct {
ID *provider.Grantee_UserId `json:"id"`
}
// ShareAltMap is an alternative map to JSON-unmarshal a Share.
type ShareAltMap struct {
ID *ocm.ShareId `json:"id"`
RemoteShareID string `json:"remote_share_id"`
Permissions *ocm.SharePermissions `json:"permissions"`
Grantee *GranteeAltMap `json:"grantee"`
Owner *userpb.UserId `json:"owner"`
Creator *userpb.UserId `json:"creator"`
Ctime *typespb.Timestamp `json:"ctime"`
Mtime *typespb.Timestamp `json:"mtime"`
}
// ReceivedShareAltMap is an alternative map to JSON-unmarshal a ReceivedShare.
type ReceivedShareAltMap struct {
Share *ShareAltMap `json:"share"`
State ocm.ShareState `json:"state"`
}
// New returns a share manager implementation that verifies against a Nextcloud backend.
func New(m map[string]interface{}) (share.Repository, error) {
var c ShareManagerConfig
if err := cfg.Decode(m, &c); err != nil {
return nil, err
}
return NewShareManager(&c)
}
// NewShareManager returns a new Nextcloud-based ShareManager.
func NewShareManager(c *ShareManagerConfig) (*Manager, error) {
var client *http.Client
if c.MockHTTP {
// called := make([]string, 0)
// nextcloudServerMock := GetNextcloudServerMock(&called)
// client, _ = TestingHTTPClient(nextcloudServerMock)
// Wait for SetHTTPClient to be called later
client = nil
} else {
if len(c.EndPoint) == 0 {
return nil, errors.New("Please specify 'endpoint' in '[grpc.services.ocmshareprovider.drivers.nextcloud]' and '[grpc.services.ocmcore.drivers.nextcloud]'")
}
client = &http.Client{}
}
return &Manager{
endPoint: c.EndPoint, // e.g. "http://nc/apps/sciencemesh/"
sharedSecret: c.SharedSecret,
client: client,
webDAVHost: c.WebDAVHost,
}, nil
}
// SetHTTPClient sets the HTTP client.
func (sm *Manager) SetHTTPClient(c *http.Client) {
sm.client = c
}
// StoreShare stores a share.
func (sm *Manager) StoreShare(ctx context.Context, share *ocm.Share) (*ocm.Share, error) {
encShare, err := utils.MarshalProtoV1ToJSON(share)
if err != nil {
return nil, err
}
_, body, err := sm.do(ctx, Action{"addSentShare", string(encShare)}, getUsername(&userpb.User{Id: share.Creator}))
if err != nil {
return nil, err
}
share.Id = &ocm.ShareId{
OpaqueId: string(body),
}
return share, nil
}
// GetShare gets the information for a share by the given ref.
func (sm *Manager) GetShare(ctx context.Context, user *userpb.User, ref *ocm.ShareReference) (*ocm.Share, error) {
data, err := json.Marshal(ref)
if err != nil {
return nil, err
}
_, body, err := sm.do(ctx, Action{"GetShare", string(data)}, getUsername(user))
if err != nil {
return nil, err
}
altResult := &ShareAltMap{}
if err := json.Unmarshal(body, &altResult); err != nil {
return nil, err
}
return &ocm.Share{
Id: altResult.ID,
Grantee: &provider.Grantee{
Id: altResult.Grantee.ID,
},
Owner: altResult.Owner,
Creator: altResult.Creator,
Ctime: altResult.Ctime,
Mtime: altResult.Mtime,
}, nil
}
// DeleteShare deletes the share pointed by ref.
func (sm *Manager) DeleteShare(ctx context.Context, user *userpb.User, ref *ocm.ShareReference) error {
bodyStr, err := json.Marshal(ref)
if err != nil {
return err
}
_, _, err = sm.do(ctx, Action{"Unshare", string(bodyStr)}, getUsername(user))
return err
}
// UpdateShare updates the mode of the given share.
func (sm *Manager) UpdateShare(ctx context.Context, user *userpb.User, ref *ocm.ShareReference, f ...*ocm.UpdateOCMShareRequest_UpdateField) (*ocm.Share, error) {
type paramsObj struct {
Ref *ocm.ShareReference `json:"ref"`
P *ocm.SharePermissions `json:"p"`
}
bodyObj := &paramsObj{
Ref: ref,
}
data, err := json.Marshal(bodyObj)
if err != nil {
return nil, err
}
_, body, err := sm.do(ctx, Action{"UpdateShare", string(data)}, getUsername(user))
if err != nil {
return nil, err
}
altResult := &ShareAltMap{}
if err := json.Unmarshal(body, &altResult); err != nil {
return nil, err
}
return &ocm.Share{
Id: altResult.ID,
Grantee: &provider.Grantee{
Id: altResult.Grantee.ID,
},
Owner: altResult.Owner,
Creator: altResult.Creator,
Ctime: altResult.Ctime,
Mtime: altResult.Mtime,
}, nil
}
// ListShares returns the shares created by the user. If md is provided is not nil,
// it returns only shares attached to the given resource.
func (sm *Manager) ListShares(ctx context.Context, user *userpb.User, filters []*ocm.ListOCMSharesRequest_Filter) ([]*ocm.Share, error) {
data, err := json.Marshal(filters)
if err != nil {
return nil, err
}
_, respBody, err := sm.do(ctx, Action{"ListShares", string(data)}, getUsername(user))
if err != nil {
return nil, err
}
var respArr []ShareAltMap
if err := json.Unmarshal(respBody, &respArr); err != nil {
return nil, err
}
var lst = make([]*ocm.Share, 0, len(respArr))
for _, altResult := range respArr {
lst = append(lst, &ocm.Share{
Id: altResult.ID,
Grantee: &provider.Grantee{
Id: altResult.Grantee.ID,
},
Owner: altResult.Owner,
Creator: altResult.Creator,
Ctime: altResult.Ctime,
Mtime: altResult.Mtime,
})
}
return lst, nil
}
// StoreReceivedShare stores a received share.
func (sm *Manager) StoreReceivedShare(ctx context.Context, share *ocm.ReceivedShare) (*ocm.ReceivedShare, error) {
data, err := utils.MarshalProtoV1ToJSON(share)
if err != nil {
return nil, err
}
_, body, err := sm.do(ctx, Action{"addReceivedShare", string(data)}, getUsername(&userpb.User{Id: share.Grantee.GetUserId()}))
if err != nil {
return nil, err
}
share.Id = &ocm.ShareId{
OpaqueId: string(body),
}
return share, nil
}
// ListReceivedShares returns the list of shares the user has access.
func (sm *Manager) ListReceivedShares(ctx context.Context, user *userpb.User) ([]*ocm.ReceivedShare, error) {
log := appctx.GetLogger(ctx)
_, respBody, err := sm.do(ctx, Action{"ListReceivedShares", ""}, getUsername(user))
if err != nil {
return nil, err
}
var respArr []ReceivedShareAltMap
if err := json.Unmarshal(respBody, &respArr); err != nil {
return nil, err
}
res := make([]*ocm.ReceivedShare, 0, len(respArr))
for _, share := range respArr {
altResultShare := share.Share
log.Info().Msgf("Unpacking share object %+v\n", altResultShare)
if altResultShare == nil {
continue
}
res = append(res, &ocm.ReceivedShare{
Id: altResultShare.ID,
RemoteShareId: altResultShare.RemoteShareID, // sic, see https://github.com/cs3org/reva/pull/3852#discussion_r1189681465
Grantee: &provider.Grantee{
Id: altResultShare.Grantee.ID,
},
Owner: altResultShare.Owner,
Creator: altResultShare.Creator,
Ctime: altResultShare.Ctime,
Mtime: altResultShare.Mtime,
State: share.State,
})
}
return res, nil
}
// GetReceivedShare returns the information for a received share the user has access.
func (sm *Manager) GetReceivedShare(ctx context.Context, user *userpb.User, ref *ocm.ShareReference) (*ocm.ReceivedShare, error) {
data, err := json.Marshal(ref)
if err != nil {
return nil, err
}
_, respBody, err := sm.do(ctx, Action{"GetReceivedShare", string(data)}, getUsername(user))
if err != nil {
return nil, err
}
var altResult ReceivedShareAltMap
if err := json.Unmarshal(respBody, &altResult); err != nil {
return nil, err
}
altResultShare := altResult.Share
if altResultShare == nil {
return &ocm.ReceivedShare{
State: altResult.State,
}, nil
}
return &ocm.ReceivedShare{
Id: altResultShare.ID,
RemoteShareId: altResultShare.RemoteShareID, // sic, see https://github.com/cs3org/reva/pull/3852#discussion_r1189681465
Grantee: &provider.Grantee{
Id: altResultShare.Grantee.ID,
},
Owner: altResultShare.Owner,
Creator: altResultShare.Creator,
Ctime: altResultShare.Ctime,
Mtime: altResultShare.Mtime,
State: altResult.State,
}, nil
}
// UpdateReceivedShare updates the received share with share state.
func (sm *Manager) UpdateReceivedShare(ctx context.Context, user *userpb.User, share *ocm.ReceivedShare, fieldMask *field_mask.FieldMask) (*ocm.ReceivedShare, error) {
type paramsObj struct {
ReceivedShare *ocm.ReceivedShare `json:"received_share"`
FieldMask *field_mask.FieldMask `json:"field_mask"`
}
bodyObj := &paramsObj{
ReceivedShare: share,
FieldMask: fieldMask,
}
bodyStr, err := json.Marshal(bodyObj)
if err != nil {
return nil, err
}
_, respBody, err := sm.do(ctx, Action{"UpdateReceivedShare", string(bodyStr)}, getUsername(user))
if err != nil {
return nil, err
}
var altResult ReceivedShareAltMap
err = json.Unmarshal(respBody, &altResult)
if err != nil {
return nil, err
}
altResultShare := altResult.Share
if altResultShare == nil {
return &ocm.ReceivedShare{
State: altResult.State,
}, nil
}
return &ocm.ReceivedShare{
Id: altResultShare.ID,
RemoteShareId: altResultShare.RemoteShareID, // sic, see https://github.com/cs3org/reva/pull/3852#discussion_r1189681465
Grantee: &provider.Grantee{
Id: altResultShare.Grantee.ID,
},
Owner: altResultShare.Owner,
Creator: altResultShare.Creator,
Ctime: altResultShare.Ctime,
Mtime: altResultShare.Mtime,
State: altResult.State,
}, nil
}
func getUsername(user *userpb.User) string {
if user != nil && len(user.Username) > 0 {
return user.Username
}
if user != nil && len(user.Id.OpaqueId) > 0 {
return user.Id.OpaqueId
}
return "empty-username"
}
func (sm *Manager) do(ctx context.Context, a Action, username string) (int, []byte, error) {
url := sm.endPoint + "~" + username + "/api/ocm/" + a.verb
log := appctx.GetLogger(ctx)
log.Info().Msgf("am.do %s %s", url, a.argS)
req, err := http.NewRequest(http.MethodPost, url, strings.NewReader(a.argS))
if err != nil {
return 0, nil, err
}
req.Header.Set("X-Reva-Secret", sm.sharedSecret)
req.Header.Set("Content-Type", "application/json")
resp, err := sm.client.Do(req)
if err != nil {
return 0, nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return 0, nil, err
}
// curl -i -H 'application/json' -H 'X-Reva-Secret: shared-secret-1' -d '{"md":{"opaque_id":"fileid-/other/q/as"},"g":{"grantee":{"type":1,"Id":{"UserId":{"idp":"revanc2.docker","opaque_id":"marie"}}},"permissions":{"permissions":{"get_path":true,"initiate_file_download":true,"list_container":true,"list_file_versions":true,"stat":true}}},"provider_domain":"cern.ch","resource_type":"file","provider_id":2,"owner_opaque_id":"einstein","owner_display_name":"Albert Einstein","protocol":{"name":"webdav","options":{"sharedSecret":"secret","permissions":"webdav-property"}}}' https://nc1.docker/index.php/apps/sciencemesh/~/api/ocm/addSentShare
log.Info().Msgf("am.do response %d %s", resp.StatusCode, body)
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
return 0, nil, fmt.Errorf("Unexpected response code from EFSS API: " + strconv.Itoa(resp.StatusCode))
}
return resp.StatusCode, body, nil
}

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 CERN
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@ import (
)
// Response contains data for the Nextcloud mock server to respond
// and to switch to a new server state
// and to switch to a new server state.
type Response struct {
code int
body string
@@ -51,7 +51,7 @@ var responses = map[string]Response{
`POST /apps/sciencemesh/~tester/api/ocm/ListShares [{"type":4,"Term":{"Creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}}]`: {200, `[{"id":{},"resource_id":{},"permissions":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890}}]`, serverStateHome},
`POST /apps/sciencemesh/~tester/api/ocm/ListReceivedShares `: {200, `[{"share":{"id":{},"resource_id":{},"permissions":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890}},"state":2}]`, serverStateHome},
`POST /apps/sciencemesh/~tester/api/ocm/GetReceivedShare {"Spec":{"Id":{"opaque_id":"some-share-id"}}}`: {200, `{"share":{"id":{},"resource_id":{},"permissions":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890}},"state":2}`, serverStateHome},
`POST /apps/sciencemesh/~tester/api/ocm/UpdateReceivedShare {"received_share":{"share":{"id":{},"resource_id":{},"permissions":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890}},"state":2},"field_mask":{"paths":["state"]}}`: {200, `{"share":{"id":{},"resource_id":{},"permissions":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890}},"state":2}`, serverStateHome},
`POST /apps/sciencemesh/~tester/api/ocm/UpdateReceivedShare {"received_share":{"id":{},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890},"state":2},"field_mask":{"paths":["state"]}}`: {200, `{"share":{"id":{},"permissions":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890}},"state":2}`, serverStateHome},
`POST /index.php/apps/sciencemesh/~marie/api/ocm/addReceivedShare {"md":{"opaque_id":"fileid-/some/path"},"g":{"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"permissions":{"permissions":{"get_path":true}}},"provider_domain":"cern.ch","resource_type":"file","provider_id":2,"owner_opaque_id":"einstein","owner_display_name":"Albert Einstein","protocol":{"name":"webdav","options":{"sharedSecret":"secret","permissions":"webdav-property"}}}`: {200, `{"id":{},"resource_id":{},"permissions":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890}}`, serverStateHome},
`POST /index.php/apps/sciencemesh/~marie/api/ocm/GetShare {"Spec":{"Id":{"opaque_id":"some-share-id"}}}`: {200, `{"id":{},"resource_id":{},"permissions":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890}}`, serverStateHome},
@@ -60,10 +60,10 @@ var responses = map[string]Response{
`POST /index.php/apps/sciencemesh/~marie/api/ocm/ListShares [{"type":4,"Term":{"Creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}}]`: {200, `[{"id":{},"resource_id":{},"permissions":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890}}]`, serverStateHome},
`POST /index.php/apps/sciencemesh/~marie/api/ocm/ListReceivedShares `: {200, `[{"share":{"id":{},"resource_id":{},"permissions":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890}},"state":2}]`, serverStateHome},
`POST /index.php/apps/sciencemesh/~marie/api/ocm/GetReceivedShare {"Spec":{"Id":{"opaque_id":"some-share-id"}}}`: {200, `{"share":{"id":{},"resource_id":{},"permissions":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890}},"state":2}`, serverStateHome},
`POST /index.php/apps/sciencemesh/~marie/api/ocm/UpdateReceivedShare {"received_share":{"share":{"id":{},"resource_id":{},"permissions":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890}},"state":2},"field_mask":{"paths":["state"]}}`: {200, `{"share":{"id":{},"resource_id":{},"permissions":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890}},"state":2}`, serverStateHome},
`POST /index.php/apps/sciencemesh/~marie/api/ocm/UpdateReceivedShare {"received_share":{"share":{"id":{},"permissions":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890}},"state":2},"field_mask":{"paths":["state"]}}`: {200, `{"share":{"id":{},"permissions":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890}},"state":2}`, serverStateHome},
}
// GetNextcloudServerMock returns a handler that pretends to be a remote Nextcloud server
// GetNextcloudServerMock returns a handler that pretends to be a remote Nextcloud server.
func GetNextcloudServerMock(called *[]string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
buf := new(strings.Builder)

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 CERN
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -18,16 +18,18 @@
package registry
import "github.com/cs3org/reva/v2/pkg/ocm/invite"
import (
"github.com/cs3org/reva/v2/pkg/ocm/share"
)
// NewFunc is the function that invite managers
// NewFunc is the function that share repositories
// should register at init time.
type NewFunc func(map[string]interface{}) (invite.Manager, error)
type NewFunc func(map[string]interface{}) (share.Repository, error)
// NewFuncs is a map containing all the registered invite managers.
// NewFuncs is a map containing all the registered share repositories.
var NewFuncs = map[string]NewFunc{}
// Register registers a new invite manager new function.
// Register registers a new share repository new function.
// Not safe for concurrent use. Safe for use from package init.
func Register(name string, f NewFunc) {
NewFuncs[name] = f

View File

@@ -1,93 +0,0 @@
// Copyright 2018-2021 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 sender
import (
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"path"
"strings"
"time"
ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
"github.com/cs3org/reva/v2/pkg/rhttp"
"github.com/pkg/errors"
)
const createOCMCoreShareEndpoint = "shares"
func getOCMEndpoint(originProvider *ocmprovider.ProviderInfo) (string, error) {
for _, s := range originProvider.Services {
if s.Endpoint.Type.Name == "OCM" {
return s.Endpoint.Path, nil
}
}
return "", errors.New("json: ocm endpoint not specified for mesh provider")
}
// Send executes the POST to the OCM shares endpoint to create the share at the
// remote site.
func Send(requestBodyMap map[string]interface{}, pi *ocmprovider.ProviderInfo) error {
requestBody, err := json.Marshal(requestBodyMap)
if err != nil {
err = errors.Wrap(err, "error marshalling request body")
return err
}
ocmEndpoint, err := getOCMEndpoint(pi)
if err != nil {
return err
}
u, err := url.Parse(ocmEndpoint)
if err != nil {
return err
}
u.Path = path.Join(u.Path, createOCMCoreShareEndpoint)
recipientURL := u.String()
req, err := http.NewRequest("POST", recipientURL, strings.NewReader(string(requestBody)))
if err != nil {
return errors.Wrap(err, "sender: error framing post request")
}
req.Header.Set("Content-Type", "application/json; param=value")
client := rhttp.GetHTTPClient(
rhttp.Timeout(5 * time.Second),
)
resp, err := client.Do(req)
if err != nil {
err = errors.Wrap(err, "sender: error sending post request")
return err
}
defer resp.Body.Close()
if (resp.StatusCode != http.StatusCreated) && (resp.StatusCode != http.StatusOK) {
respBody, e := io.ReadAll(resp.Body)
if e != nil {
e = errors.Wrap(e, "sender: error reading request body")
return e
}
err = errors.Wrap(fmt.Errorf("%s: %s", resp.Status, string(respBody)), "sender: error sending create ocm core share post request")
return err
}
return nil
}

View File

@@ -1,4 +1,4 @@
// Copyright 2018-2021 CERN
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -22,39 +22,41 @@ import (
"context"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/cs3org/reva/v2/pkg/errtypes"
"google.golang.org/genproto/protobuf/field_mask"
)
// Manager is the interface that manipulates the OCM shares.
type Manager interface {
// Create a new share in fn with the given acl.
Share(ctx context.Context, md *provider.ResourceId, g *ocm.ShareGrant, name string,
pi *ocmprovider.ProviderInfo, pm string, owner *userpb.UserId, token string, st ocm.Share_ShareType) (*ocm.Share, error)
// Repository is the interface that manipulates the OCM shares repository.
type Repository interface {
// StoreShare stores a share.
StoreShare(ctx context.Context, share *ocm.Share) (*ocm.Share, error)
// GetShare gets the information for a share by the given ref.
GetShare(ctx context.Context, ref *ocm.ShareReference) (*ocm.Share, error)
GetShare(ctx context.Context, user *userpb.User, ref *ocm.ShareReference) (*ocm.Share, error)
// Unshare deletes the share pointed by ref.
Unshare(ctx context.Context, ref *ocm.ShareReference) error
// DeleteShare deletes the share pointed by ref.
DeleteShare(ctx context.Context, user *userpb.User, ref *ocm.ShareReference) error
// UpdateShare updates the mode of the given share.
UpdateShare(ctx context.Context, ref *ocm.ShareReference, p *ocm.SharePermissions) (*ocm.Share, error)
UpdateShare(ctx context.Context, user *userpb.User, ref *ocm.ShareReference, f ...*ocm.UpdateOCMShareRequest_UpdateField) (*ocm.Share, error)
// ListShares returns the shares created by the user. If md is provided is not nil,
// it returns only shares attached to the given resource.
ListShares(ctx context.Context, filters []*ocm.ListOCMSharesRequest_Filter) ([]*ocm.Share, error)
ListShares(ctx context.Context, user *userpb.User, filters []*ocm.ListOCMSharesRequest_Filter) ([]*ocm.Share, error)
// StoreReceivedShare stores a received share.
StoreReceivedShare(ctx context.Context, share *ocm.ReceivedShare) (*ocm.ReceivedShare, error)
// ListReceivedShares returns the list of shares the user has access.
ListReceivedShares(ctx context.Context) ([]*ocm.ReceivedShare, error)
ListReceivedShares(ctx context.Context, user *userpb.User) ([]*ocm.ReceivedShare, error)
// GetReceivedShare returns the information for a received share the user has access.
GetReceivedShare(ctx context.Context, ref *ocm.ShareReference) (*ocm.ReceivedShare, error)
GetReceivedShare(ctx context.Context, user *userpb.User, ref *ocm.ShareReference) (*ocm.ReceivedShare, error)
// UpdateReceivedShare updates the received share with share state.
UpdateReceivedShare(ctx context.Context, share *ocm.ReceivedShare, fieldMask *field_mask.FieldMask) (*ocm.ReceivedShare, error)
UpdateReceivedShare(ctx context.Context, user *userpb.User, share *ocm.ReceivedShare, fieldMask *field_mask.FieldMask) (*ocm.ReceivedShare, error)
}
// ResourceIDFilter is an abstraction for creating filter by resource id.
@@ -66,3 +68,10 @@ func ResourceIDFilter(id *provider.ResourceId) *ocm.ListOCMSharesRequest_Filter
},
}
}
// ErrShareAlreadyExisting is the error returned when the share already exists
// for the 3-tuple consisting of (owner, resource, grantee).
var ErrShareAlreadyExisting = errtypes.AlreadyExists("share already exists")
// ErrShareNotFound is the error returned where the share does not exist.
var ErrShareNotFound = errtypes.NotFound("share not found")

View File

@@ -0,0 +1,94 @@
// Copyright 2018-2023 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 share
import (
appprovider "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1"
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
)
// NewWebDAVProtocol is an abstraction for creating a WebDAV protocol.
func NewWebDAVProtocol(uri, shareSecred string, perms *ocm.SharePermissions) *ocm.Protocol {
return &ocm.Protocol{
Term: &ocm.Protocol_WebdavOptions{
WebdavOptions: &ocm.WebDAVProtocol{
Uri: uri,
SharedSecret: shareSecred,
Permissions: perms,
},
},
}
}
// NewWebappProtocol is an abstraction for creating a Webapp protocol.
func NewWebappProtocol(uriTemplate string, viewMode appprovider.ViewMode) *ocm.Protocol {
return &ocm.Protocol{
Term: &ocm.Protocol_WebappOptions{
WebappOptions: &ocm.WebappProtocol{
UriTemplate: uriTemplate,
ViewMode: viewMode,
},
},
}
}
// NewTransferProtocol is an abstraction for creating a Transfer protocol.
func NewTransferProtocol(sourceURI, sharedSecret string, size uint64) *ocm.Protocol {
return &ocm.Protocol{
Term: &ocm.Protocol_TransferOptions{
TransferOptions: &ocm.TransferProtocol{
SourceUri: sourceURI,
SharedSecret: sharedSecret,
Size: size,
},
},
}
}
// NewWebDavAccessMethod is an abstraction for creating a WebDAV access method.
func NewWebDavAccessMethod(perms *provider.ResourcePermissions) *ocm.AccessMethod {
return &ocm.AccessMethod{
Term: &ocm.AccessMethod_WebdavOptions{
WebdavOptions: &ocm.WebDAVAccessMethod{
Permissions: perms,
},
},
}
}
// NewWebappAccessMethod is an abstraction for creating a Webapp access method.
func NewWebappAccessMethod(mode appprovider.ViewMode) *ocm.AccessMethod {
return &ocm.AccessMethod{
Term: &ocm.AccessMethod_WebappOptions{
WebappOptions: &ocm.WebappAccessMethod{
ViewMode: mode,
},
},
}
}
// NewTransferAccessMethod is an abstraction for creating a Transfer access method.
func NewTransferAccessMethod() *ocm.AccessMethod {
return &ocm.AccessMethod{
Term: &ocm.AccessMethod_TransferOptions{
TransferOptions: &ocm.TransferAccessMethod{},
},
}
}

View File

@@ -0,0 +1,465 @@
// Copyright 2018-2023 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 ocm
import (
"context"
"io"
"io/fs"
"net/http"
"net/url"
"path/filepath"
"strings"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
ocmpb "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
typepb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/events"
"github.com/cs3org/reva/v2/pkg/mime"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/v2/pkg/rhttp/router"
"github.com/cs3org/reva/v2/pkg/sharedconf"
"github.com/cs3org/reva/v2/pkg/storage"
"github.com/cs3org/reva/v2/pkg/storage/fs/registry"
"github.com/cs3org/reva/v2/pkg/storagespace"
"github.com/cs3org/reva/v2/pkg/utils"
"github.com/cs3org/reva/v2/pkg/utils/cfg"
"github.com/studio-b12/gowebdav"
)
func init() {
registry.Register("ocmreceived", New)
}
type driver struct {
c *config
gateway gateway.GatewayAPIClient
}
type config struct {
GatewaySVC string `mapstructure:"gatewaysvc"`
}
func (c *config) ApplyDefaults() {
c.GatewaySVC = sharedconf.GetGatewaySVC(c.GatewaySVC)
}
// New creates an OCM storage driver.
func New(m map[string]interface{}, _ events.Stream) (storage.FS, error) {
var c config
if err := cfg.Decode(m, &c); err != nil {
return nil, err
}
gateway, err := pool.GetGatewayServiceClient(c.GatewaySVC)
if err != nil {
return nil, err
}
d := &driver{
c: &c,
gateway: gateway,
}
return d, nil
}
func shareInfoFromPath(path string) (*ocmpb.ShareId, string) {
// the path is of the type /share_id[/rel_path]
shareID, rel := router.ShiftPath(path)
return &ocmpb.ShareId{OpaqueId: shareID}, rel
}
func shareInfoFromReference(ref *provider.Reference) (*ocmpb.ShareId, string) {
if ref.ResourceId == nil {
return shareInfoFromPath(ref.Path)
}
return &ocmpb.ShareId{OpaqueId: ref.ResourceId.OpaqueId}, ref.Path
}
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{
Id: shareID,
},
},
})
if err != nil {
return nil, "", "", err
}
if res.Status.Code != rpc.Code_CODE_OK {
if res.Status.Code == rpc.Code_CODE_NOT_FOUND {
return nil, "", "", errtypes.NotFound("share not found")
}
return nil, "", "", errtypes.InternalError(res.Status.Message)
}
dav, ok := getWebDAVProtocol(res.Share.Protocols)
if !ok {
return nil, "", "", errtypes.NotFound("share does not contain a WebDAV endpoint")
}
return res.Share, dav.Uri, dav.SharedSecret, nil
}
func getWebDAVProtocol(protocols []*ocmpb.Protocol) (*ocmpb.WebDAVProtocol, bool) {
for _, p := range protocols {
if dav, ok := p.Term.(*ocmpb.Protocol_WebdavOptions); ok {
return dav.WebdavOptions, true
}
}
return nil, false
}
func (d *driver) webdavClient(ctx context.Context, ref *provider.Reference) (*gowebdav.Client, *ocmpb.ReceivedShare, string, error) {
id, rel := shareInfoFromReference(ref)
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
}
// FIXME: it's still not clear from the OCM APIs how to use the shared secret
// will use as a token in the bearer authentication as this is the reva implementation
c := gowebdav.NewClient(endpoint, "", "")
c.SetHeader("Authorization", "Bearer "+secret)
return c, share, rel, nil
}
func (d *driver) CreateDir(ctx context.Context, ref *provider.Reference) error {
client, _, rel, err := d.webdavClient(ctx, ref)
if err != nil {
return err
}
return client.MkdirAll(rel, 0)
}
func (d *driver) Delete(ctx context.Context, ref *provider.Reference) error {
client, _, rel, err := d.webdavClient(ctx, ref)
if err != nil {
return err
}
return client.RemoveAll(rel)
}
func (d *driver) TouchFile(ctx context.Context, ref *provider.Reference, markprocessing bool, mtime string) error {
client, _, rel, err := d.webdavClient(ctx, ref)
if err != nil {
return err
}
return client.Write(rel, []byte{}, 0)
}
func (d *driver) Move(ctx context.Context, oldRef, newRef *provider.Reference) error {
client, _, relOld, err := d.webdavClient(ctx, oldRef)
if err != nil {
return err
}
_, relNew := shareInfoFromReference(newRef)
return client.Rename(relOld, relNew, false)
}
func getPathFromShareIDAndRelPath(shareID *ocmpb.ShareId, relPath string) string {
return filepath.Join("/", shareID.OpaqueId, relPath)
}
func convertStatToResourceInfo(ref *provider.Reference, f fs.FileInfo, share *ocmpb.ReceivedShare, relPath string) *provider.ResourceInfo {
t := provider.ResourceType_RESOURCE_TYPE_FILE
if f.IsDir() {
t = provider.ResourceType_RESOURCE_TYPE_CONTAINER
}
var name string
if share.ResourceType == provider.ResourceType_RESOURCE_TYPE_FILE {
name = share.Name
} else {
name = f.Name()
}
webdav, _ := getWebDAVProtocol(share.Protocols)
return &provider.ResourceInfo{
Type: t,
Id: ref.ResourceId,
MimeType: mime.Detect(f.IsDir(), f.Name()),
Path: relPath,
Name: name,
Size: uint64(f.Size()),
Mtime: &typepb.Timestamp{
Seconds: uint64(f.ModTime().Unix()),
},
Owner: share.Creator,
PermissionSet: webdav.Permissions.Permissions,
Checksum: &provider.ResourceChecksum{
Type: provider.ResourceChecksumType_RESOURCE_CHECKSUM_TYPE_INVALID,
},
}
}
func (d *driver) GetMD(ctx context.Context, ref *provider.Reference, _ []string, _ []string) (*provider.ResourceInfo, error) {
client, share, rel, err := d.webdavClient(ctx, ref)
if err != nil {
return nil, err
}
info, err := client.Stat(rel)
if err != nil {
if gowebdav.IsErrNotFound(err) {
return nil, errtypes.NotFound(ref.GetPath())
}
return nil, err
}
return convertStatToResourceInfo(ref, info, share, rel), nil
}
func (d *driver) ListFolder(ctx context.Context, ref *provider.Reference, _ []string, _ []string) ([]*provider.ResourceInfo, error) {
client, share, rel, err := d.webdavClient(ctx, ref)
if err != nil {
return nil, err
}
list, err := client.ReadDir(rel)
if err != nil {
return nil, err
}
res := make([]*provider.ResourceInfo, 0, len(list))
for _, r := range list {
res = append(res, convertStatToResourceInfo(ref, r, share, utils.MakeRelativePath(filepath.Join(rel, r.Name()))))
}
return res, nil
}
func (d *driver) InitiateUpload(ctx context.Context, ref *provider.Reference, _ int64, _ map[string]string) (map[string]string, error) {
shareID, rel := shareInfoFromReference(ref)
p := getPathFromShareIDAndRelPath(shareID, rel)
return map[string]string{
"simple": p,
}, nil
}
func (d *driver) Upload(ctx context.Context, req storage.UploadRequest, _ storage.UploadFinishedFunc) (provider.ResourceInfo, error) {
client, _, rel, err := d.webdavClient(ctx, req.Ref)
if err != nil {
return provider.ResourceInfo{}, err
}
client.SetInterceptor(func(method string, rq *http.Request) {
// Set the content length on the request struct directly instead of the header.
// The content-length header gets reset by the golang http library before
// sendind out the request, resulting in chunked encoding to be used which
// breaks the quota checks in ocdav.
if method == "PUT" {
rq.ContentLength = req.Length
}
})
return provider.ResourceInfo{}, client.WriteStream(rel, req.Body, 0)
}
func (d *driver) Download(ctx context.Context, ref *provider.Reference) (io.ReadCloser, error) {
client, _, rel, err := d.webdavClient(ctx, ref)
if err != nil {
return nil, err
}
return client.ReadStream(rel)
}
func (d *driver) GetPathByID(ctx context.Context, id *provider.ResourceId) (string, error) {
shareID, rel := shareInfoFromReference(&provider.Reference{
ResourceId: id,
})
return getPathFromShareIDAndRelPath(shareID, rel), nil
}
func (d *driver) Shutdown(ctx context.Context) error {
return nil
}
func (d *driver) CreateHome(ctx context.Context) error {
return errtypes.NotSupported("operation not supported")
}
func (d *driver) GetHome(ctx context.Context) (string, error) {
return "", errtypes.NotSupported("operation not supported")
}
func (d *driver) ListRevisions(ctx context.Context, ref *provider.Reference) ([]*provider.FileVersion, error) {
return nil, errtypes.NotSupported("operation not supported")
}
func (d *driver) DownloadRevision(ctx context.Context, ref *provider.Reference, key string) (io.ReadCloser, error) {
return nil, errtypes.NotSupported("operation not supported")
}
func (d *driver) RestoreRevision(ctx context.Context, ref *provider.Reference, key string) error {
return errtypes.NotSupported("operation not supported")
}
func (d *driver) ListRecycle(ctx context.Context, ref *provider.Reference, key, relativePath string) ([]*provider.RecycleItem, error) {
return nil, errtypes.NotSupported("operation not supported")
}
func (d *driver) RestoreRecycleItem(ctx context.Context, ref *provider.Reference, key, relativePath string, restoreRef *provider.Reference) error {
return errtypes.NotSupported("operation not supported")
}
func (d *driver) PurgeRecycleItem(ctx context.Context, ref *provider.Reference, key, relativePath string) error {
return errtypes.NotSupported("operation not supported")
}
func (d *driver) EmptyRecycle(ctx context.Context, ref *provider.Reference) error {
return errtypes.NotSupported("operation not supported")
}
func (d *driver) AddGrant(ctx context.Context, ref *provider.Reference, g *provider.Grant) error {
return errtypes.NotSupported("operation not supported")
}
func (d *driver) DenyGrant(ctx context.Context, ref *provider.Reference, g *provider.Grantee) error {
return errtypes.NotSupported("operation not supported")
}
func (d *driver) RemoveGrant(ctx context.Context, ref *provider.Reference, g *provider.Grant) error {
return errtypes.NotSupported("operation not supported")
}
func (d *driver) UpdateGrant(ctx context.Context, ref *provider.Reference, g *provider.Grant) error {
return errtypes.NotSupported("operation not supported")
}
func (d *driver) ListGrants(ctx context.Context, ref *provider.Reference) ([]*provider.Grant, error) {
return nil, errtypes.NotSupported("operation not supported")
}
func (d *driver) GetQuota(ctx context.Context, ref *provider.Reference) ( /*TotalBytes*/ uint64 /*UsedBytes*/, uint64, uint64, error) {
return 0, 0, 0, errtypes.NotSupported("operation not supported")
}
func (d *driver) CreateReference(ctx context.Context, path string, targetURI *url.URL) error {
return errtypes.NotSupported("operation not supported")
}
func (d *driver) SetArbitraryMetadata(ctx context.Context, ref *provider.Reference, md *provider.ArbitraryMetadata) error {
return errtypes.NotSupported("operation not supported")
}
func (d *driver) UnsetArbitraryMetadata(ctx context.Context, ref *provider.Reference, keys []string) error {
return errtypes.NotSupported("operation not supported")
}
func (d *driver) SetLock(ctx context.Context, ref *provider.Reference, lock *provider.Lock) error {
return errtypes.NotSupported("operation not supported")
}
func (d *driver) GetLock(ctx context.Context, ref *provider.Reference) (*provider.Lock, error) {
return nil, errtypes.NotSupported("operation not supported")
}
func (d *driver) RefreshLock(ctx context.Context, ref *provider.Reference, lock *provider.Lock, existingLockID string) error {
return errtypes.NotSupported("operation not supported")
}
func (d *driver) Unlock(ctx context.Context, ref *provider.Reference, lock *provider.Lock) error {
return errtypes.NotSupported("operation not supported")
}
func (d *driver) ListStorageSpaces(ctx context.Context, filters []*provider.ListStorageSpacesRequest_Filter, _ bool) ([]*provider.StorageSpace, error) {
spaceTypes := map[string]struct{}{}
var exists = struct{}{}
appendTypes := []string{}
for _, f := range filters {
if f.Type == provider.ListStorageSpacesRequest_Filter_TYPE_SPACE_TYPE {
spaceType := f.GetSpaceType()
if spaceType == "+mountpoint" {
appendTypes = append(appendTypes, strings.TrimPrefix(spaceType, "+"))
continue
}
spaceTypes[spaceType] = exists
}
}
lrsRes, err := d.gateway.ListReceivedOCMShares(ctx, &ocmpb.ListReceivedOCMSharesRequest{})
if err != nil {
return nil, err
}
if len(spaceTypes) == 0 {
spaceTypes["mountpoint"] = exists
}
for _, s := range appendTypes {
spaceTypes[s] = exists
}
spaces := []*provider.StorageSpace{}
for k := range spaceTypes {
if k == "mountpoint" {
for _, share := range lrsRes.Shares {
root := &provider.ResourceId{
StorageId: utils.PublicStorageProviderID,
SpaceId: share.Id.OpaqueId,
OpaqueId: share.Id.OpaqueId,
}
space := &provider.StorageSpace{
Id: &provider.StorageSpaceId{
OpaqueId: storagespace.FormatResourceID(*root),
},
SpaceType: "mountpoint",
Owner: &userv1beta1.User{
Id: share.Grantee.GetUserId(),
},
Root: root,
}
spaces = append(spaces, space)
}
}
}
return spaces, nil
}
func (d *driver) CreateStorageSpace(ctx context.Context, req *provider.CreateStorageSpaceRequest) (*provider.CreateStorageSpaceResponse, error) {
return nil, errtypes.NotSupported("operation not supported")
}
func (d *driver) UpdateStorageSpace(ctx context.Context, req *provider.UpdateStorageSpaceRequest) (*provider.UpdateStorageSpaceResponse, error) {
return nil, errtypes.NotSupported("operation not supported")
}
func (d *driver) DeleteStorageSpace(ctx context.Context, req *provider.DeleteStorageSpaceRequest) error {
return errtypes.NotSupported("operation not supported")
}

View File

@@ -131,6 +131,14 @@ func NewAlreadyExists(ctx context.Context, err error, msg string) *rpc.Status {
}
}
// NewInvalidArg returns a Status with CODE_INVALID_ARGUMENT.
func NewInvalidArg(ctx context.Context, msg string) *rpc.Status {
return &rpc.Status{Code: rpc.Code_CODE_INVALID_ARGUMENT,
Message: msg,
Trace: getTrace(ctx),
}
}
// NewConflict returns a Status with Code_CODE_ABORTED.
//
// Deprecated: NewConflict exists for historical compatibility

Some files were not shown because too many files have changed in this diff Show More