Skip to content

Commit e47f910

Browse files
committed
Support OCM v1.0 schema but bail out if the options aren't empty
1 parent b0e3e75 commit e47f910

File tree

11 files changed

+122
-54
lines changed

11 files changed

+122
-54
lines changed

changelog/unreleased/ocm-reconcile.md

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
Enhancement: Support OCM v1.0 schema
2+
3+
Following cs3org/cs3apis#206, we add the fields to ensure
4+
backwards compatibility with OCM v1.0. However, if the
5+
protocol.options undocumented object is not empty, we bail
6+
out for now. Supporting interoperability with OCM v1.0
7+
implementations (notably Nextcloud 25) may come in the future
8+
if the undocumented options are fully reverse engineered.
9+
10+
Also, added viewMode to webapp protocol options
11+
and adapted all SQL code and unit tests.
12+
13+
https://github.com/cs3org/cs3apis/pull/207
14+
https://github.com/cs3org/reva/pull/3757

internal/http/services/ocmd/config.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ type configHandler struct {
5252
func (h *configHandler) init(c *config) {
5353
h.c = c.Config
5454
if h.c.APIVersion == "" {
55-
h.c.APIVersion = "1.0-proposal1"
55+
h.c.APIVersion = "1.1.0"
5656
}
5757
if h.c.Host == "" {
5858
h.c.Host = "localhost"

internal/http/services/ocmd/protocols.go

+21-3
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
2828
providerv1beta1 "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
2929
ocmshare "github.com/cs3org/reva/pkg/ocm/share"
30+
utils "github.com/cs3org/reva/pkg/utils"
3031
)
3132

3233
// Protocols is the list of protocols.
@@ -73,11 +74,12 @@ func (w *WebDAV) ToOCMProtocol() *ocm.Protocol {
7374
// Webapp contains the parameters for the Webapp protocol.
7475
type Webapp struct {
7576
URITemplate string `json:"uriTemplate" validate:"required"`
77+
ViewMode string `json:"viewMode" validate:"required,dive,required,oneof=view read write"`
7678
}
7779

7880
// ToOCMProtocol convert the protocol to a ocm Protocol struct.
7981
func (w *Webapp) ToOCMProtocol() *ocm.Protocol {
80-
return ocmshare.NewWebappProtocol(w.URITemplate)
82+
return ocmshare.NewWebappProtocol(w.URITemplate, utils.GetAPViewMode(w.ViewMode))
8183
}
8284

8385
// Datatx contains the parameters for the Datatx protocol.
@@ -109,11 +111,22 @@ func (p *Protocols) UnmarshalJSON(data []byte) error {
109111

110112
for name, d := range prot {
111113
var res Protocol
114+
115+
// we do not support the OCM v1.0 properties for now, therefore we just skip them
116+
if name == "name" {
117+
continue
118+
}
119+
if name == "options" {
120+
var opt map[string]any
121+
if err := json.Unmarshal(d, &opt); err != nil || len(opt) > 0 {
122+
return fmt.Errorf("protocol options not supported: %s", string(d))
123+
}
124+
continue
125+
}
112126
ctype, ok := protocolImpl[name]
113127
if !ok {
114128
return fmt.Errorf("protocol %s not recognised", name)
115129
}
116-
117130
res = reflect.New(ctype).Interface().(Protocol)
118131
if err := json.Unmarshal(d, &res); err != nil {
119132
return err
@@ -126,10 +139,15 @@ func (p *Protocols) UnmarshalJSON(data []byte) error {
126139

127140
// MarshalJSON implements the Marshaler interface.
128141
func (p Protocols) MarshalJSON() ([]byte, error) {
129-
d := make(map[string]Protocol)
142+
d := make(map[string]any)
130143
for _, prot := range p {
131144
d[getProtocolName(prot)] = prot
132145
}
146+
// fill in the OCM v1.0 properties, but only if at least a protocol was defined
147+
if len(p) > 0 {
148+
d["name"] = "multi"
149+
d["options"] = map[string]any{}
150+
}
133151
return json.Marshal(d)
134152
}
135153

internal/http/services/ocmd/protocols_test.go

+33-17
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,11 @@ func TestUnmarshalProtocol(t *testing.T) {
3737
expected: []Protocol{},
3838
},
3939
{
40-
raw: `{"webdav":{"sharedSecret":"secret","permissions":["read","write"],"url":"http://example.org"}}`,
40+
raw: `{"name":"foo","options":{"unsupported":"value"}}`,
41+
err: `protocol options not supported: {"unsupported":"value"}`,
42+
},
43+
{
44+
raw: `{"name":"multi","options":{},"webdav":{"sharedSecret":"secret","permissions":["read","write"],"url":"http://example.org"}}`,
4145
expected: []Protocol{
4246
&WebDAV{
4347
SharedSecret: "secret",
@@ -47,15 +51,15 @@ func TestUnmarshalProtocol(t *testing.T) {
4751
},
4852
},
4953
{
50-
raw: `{"webapp":{"uriTemplate":"http://example.org/{test}"}}`,
54+
raw: `{"name":"multi","options":{},"webapp":{"uriTemplate":"http://example.org/{test}"}}`,
5155
expected: []Protocol{
5256
&Webapp{
5357
URITemplate: "http://example.org/{test}",
5458
},
5559
},
5660
},
5761
{
58-
raw: `{"datatx":{"sharedSecret":"secret","srcUri":"http://example.org","size":10}}`,
62+
raw: `{"name":"multi","options":{},"datatx":{"sharedSecret":"secret","srcUri":"http://example.org","size":10}}`,
5963
expected: []Protocol{
6064
&Datatx{
6165
SharedSecret: "secret",
@@ -65,7 +69,7 @@ func TestUnmarshalProtocol(t *testing.T) {
6569
},
6670
},
6771
{
68-
raw: `{"webdav":{"sharedSecret":"secret","permissions":["read","write"],"url":"http://example.org"},"webapp":{"uriTemplate":"http://example.org/{test}"},"datatx":{"sharedSecret":"secret","srcUri":"http://example.org","size":10}}`,
72+
raw: `{"name":"multi","options":{},"webdav":{"sharedSecret":"secret","permissions":["read","write"],"url":"http://example.org"},"webapp":{"uriTemplate":"http://example.org/{test}"},"datatx":{"sharedSecret":"secret","srcUri":"http://example.org","size":10}}`,
6973
expected: []Protocol{
7074
&WebDAV{
7175
SharedSecret: "secret",
@@ -125,11 +129,11 @@ func protocolsEqual(p1, p2 Protocols) bool {
125129
func TestMarshalProtocol(t *testing.T) {
126130
tests := []struct {
127131
in Protocols
128-
expected map[string]map[string]any
132+
expected map[string]any
129133
}{
130134
{
131135
in: []Protocol{},
132-
expected: map[string]map[string]any{},
136+
expected: map[string]any{},
133137
},
134138
{
135139
in: []Protocol{
@@ -139,8 +143,10 @@ func TestMarshalProtocol(t *testing.T) {
139143
URL: "http://example.org",
140144
},
141145
},
142-
expected: map[string]map[string]any{
143-
"webdav": {
146+
expected: map[string]any{
147+
"name": "multi",
148+
"options": map[string]any{},
149+
"webdav": map[string]any{
144150
"sharedSecret": "secret",
145151
"permissions": []any{"read"},
146152
"url": "http://example.org",
@@ -151,11 +157,15 @@ func TestMarshalProtocol(t *testing.T) {
151157
in: []Protocol{
152158
&Webapp{
153159
URITemplate: "http://example.org",
160+
ViewMode: "read",
154161
},
155162
},
156-
expected: map[string]map[string]any{
157-
"webapp": {
163+
expected: map[string]any{
164+
"name": "multi",
165+
"options": map[string]any{},
166+
"webapp": map[string]any{
158167
"uriTemplate": "http://example.org",
168+
"viewMode": "read",
159169
},
160170
},
161171
},
@@ -167,8 +177,10 @@ func TestMarshalProtocol(t *testing.T) {
167177
Size: 10,
168178
},
169179
},
170-
expected: map[string]map[string]any{
171-
"datatx": {
180+
expected: map[string]any{
181+
"name": "multi",
182+
"options": map[string]any{},
183+
"datatx": map[string]any{
172184
"sharedSecret": "secret",
173185
"srcUri": "http://example.org/source",
174186
"size": float64(10),
@@ -184,23 +196,27 @@ func TestMarshalProtocol(t *testing.T) {
184196
},
185197
&Webapp{
186198
URITemplate: "http://example.org",
199+
ViewMode: "read",
187200
},
188201
&Datatx{
189202
SharedSecret: "secret",
190203
SourceURI: "http://example.org/source",
191204
Size: 10,
192205
},
193206
},
194-
expected: map[string]map[string]any{
195-
"webdav": {
207+
expected: map[string]any{
208+
"name": "multi",
209+
"options": map[string]any{},
210+
"webdav": map[string]any{
196211
"sharedSecret": "secret",
197212
"permissions": []any{"read"},
198213
"url": "http://example.org",
199214
},
200-
"webapp": {
215+
"webapp": map[string]any{
201216
"uriTemplate": "http://example.org",
217+
"viewMode": "read",
202218
},
203-
"datatx": {
219+
"datatx": map[string]any{
204220
"sharedSecret": "secret",
205221
"srcUri": "http://example.org/source",
206222
"size": float64(10),
@@ -215,7 +231,7 @@ func TestMarshalProtocol(t *testing.T) {
215231
t.Fatal("not expected error", err)
216232
}
217233

218-
var got map[string]map[string]any
234+
var got map[string]any
219235
if err := json.Unmarshal(d, &got); err != nil {
220236
t.Fatal("not expected error", err)
221237
}

internal/http/services/ocmd/shares.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ type createShareRequest struct {
7171
ShareType string `json:"shareType" validate:"required,oneof=user group"` // recipient share type (user or group)
7272
ResourceType string `json:"resourceType" validate:"required,oneof=file folder"`
7373
Expiration uint64 `json:"expiration"`
74-
Protocols Protocols `json:"protocols" validate:"required"`
74+
Protocols Protocols `json:"protocol" validate:"required"`
7575
}
7676

7777
// CreateShare sends all the informations to the consumer needed to start

pkg/ocm/client/client.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ type NewShareRequest struct {
166166
ShareType string `json:"shareType"`
167167
Expiration uint64 `json:"expiration"`
168168
ResourceType string `json:"resourceType"`
169-
Protocols ocmd.Protocols `json:"protocols"`
169+
Protocols ocmd.Protocols `json:"protocol"`
170170
}
171171

172172
func (r *NewShareRequest) toJSON() (io.Reader, error) {
@@ -183,7 +183,7 @@ type NewShareResponse struct {
183183
}
184184

185185
// NewShare creates a new share.
186-
// https://github.com/cs3org/OCM-API/blob/223285aa4d828ed85c361c7382efd08c42b5e719/spec.yaml
186+
// https://github.com/cs3org/OCM-API/blob/develop/spec.yaml
187187
func (c *OCMClient) NewShare(ctx context.Context, endpoint string, r *NewShareRequest) (*NewShareResponse, error) {
188188
url, err := url.JoinPath(endpoint, "shares")
189189
if err != nil {

pkg/ocm/share/repository/sql/conversions.go

+7-6
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import (
2323
"strconv"
2424
"strings"
2525

26-
providerv1beta1 "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1"
26+
appprovider "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1"
2727
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
2828
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
2929
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
@@ -78,8 +78,8 @@ const (
7878
const (
7979
// WebDAVProtocol is the WebDav protocol.
8080
WebDAVProtocol Protocol = iota
81-
// WebappProtcol is the Webapp protocol.
82-
WebappProtcol
81+
// WebappProtocol is the Webapp protocol.
82+
WebappProtocol
8383
// TransferProtocol is the Transfer protocol.
8484
TransferProtocol
8585
)
@@ -171,6 +171,7 @@ type dbProtocol struct {
171171
WebDAVSharedSecret *string
172172
WebDavPermissions *int
173173
WebappURITemplate *string
174+
WebappViewMode *int
174175
TransferSourceURI *string
175176
TransferSharedSecret *string
176177
TransferSize *int
@@ -272,7 +273,7 @@ func convertToCS3AccessMethod(m *dbAccessMethod) *ocm.AccessMethod {
272273
case WebDAVAccessMethod:
273274
return share.NewWebDavAccessMethod(conversions.RoleFromOCSPermissions(conversions.Permissions(*m.WebDAVPermissions)).CS3ResourcePermissions())
274275
case WebappAccessMethod:
275-
return share.NewWebappAccessMethod(providerv1beta1.ViewMode(*m.WebAppViewMode))
276+
return share.NewWebappAccessMethod(appprovider.ViewMode(*m.WebAppViewMode))
276277
case TransferAccessMethod:
277278
return share.NewTransferAccessMethod()
278279
}
@@ -285,8 +286,8 @@ func convertToCS3Protocol(p *dbProtocol) *ocm.Protocol {
285286
return share.NewWebDAVProtocol(*p.WebDAVURI, *p.WebDAVSharedSecret, &ocm.SharePermissions{
286287
Permissions: conversions.RoleFromOCSPermissions(conversions.Permissions(*p.WebDavPermissions)).CS3ResourcePermissions(),
287288
})
288-
case WebappProtcol:
289-
return share.NewWebappProtocol(*p.WebappURITemplate)
289+
case WebappProtocol:
290+
return share.NewWebappProtocol(*p.WebappURITemplate, appprovider.ViewMode(*p.WebappViewMode))
290291
case TransferProtocol:
291292
return share.NewTransferProtocol(*p.TransferSourceURI, *p.TransferSharedSecret, uint64(*p.TransferSize))
292293
}

pkg/ocm/share/repository/sql/sql.go

+7-7
Original file line numberDiff line numberDiff line change
@@ -474,13 +474,13 @@ func storeWebDAVProtocol(tx *sql.Tx, shareID int64, o *ocm.Protocol_WebdavOption
474474
}
475475

476476
func storeWebappProtocol(tx *sql.Tx, shareID int64, o *ocm.Protocol_WebappOptions) error {
477-
pID, err := storeProtocol(tx, shareID, WebappProtcol)
477+
pID, err := storeProtocol(tx, shareID, WebappProtocol)
478478
if err != nil {
479479
return err
480480
}
481481

482-
query := "INSERT INTO ocm_protocol_webapp SET ocm_protocol_id=?, uri_template=?"
483-
params := []any{pID, o.WebappOptions.UriTemplate}
482+
query := "INSERT INTO ocm_protocol_webapp SET ocm_protocol_id=?, uri_template=?, view_mode=?"
483+
params := []any{pID, o.WebappOptions.UriTemplate, o.WebappOptions.ViewMode}
484484

485485
_, err = tx.Exec(query, params...)
486486
return err
@@ -604,7 +604,7 @@ func (m *mgr) getProtocolsIds(ctx context.Context, ids []any) (map[string][]*ocm
604604
if len(ids) == 0 {
605605
return protocols, nil
606606
}
607-
query := "SELECT p.ocm_received_share_id, p.type, dav.uri, dav.shared_secret, dav.permissions, app.uri_template, tx.source_uri, tx.shared_secret, tx.size FROM ocm_received_share_protocols as p LEFT JOIN ocm_protocol_webdav as dav ON p.id=dav.ocm_protocol_id LEFT JOIN ocm_protocol_webapp as app ON p.id=app.ocm_protocol_id LEFT JOIN ocm_protocol_transfer as tx ON p.id=tx.ocm_protocol_id WHERE p.ocm_received_share_id IN "
607+
query := "SELECT p.ocm_received_share_id, p.type, dav.uri, dav.shared_secret, dav.permissions, app.uri_template, app.view_mode, tx.source_uri, tx.shared_secret, tx.size FROM ocm_received_share_protocols as p LEFT JOIN ocm_protocol_webdav as dav ON p.id=dav.ocm_protocol_id LEFT JOIN ocm_protocol_webapp as app ON p.id=app.ocm_protocol_id LEFT JOIN ocm_protocol_transfer as tx ON p.id=tx.ocm_protocol_id WHERE p.ocm_received_share_id IN "
608608
in := strings.Repeat("?,", len(ids))
609609
query += "(" + in[:len(in)-1] + ")"
610610

@@ -615,7 +615,7 @@ func (m *mgr) getProtocolsIds(ctx context.Context, ids []any) (map[string][]*ocm
615615

616616
var p dbProtocol
617617
for rows.Next() {
618-
if err := rows.Scan(&p.ShareID, &p.Type, &p.WebDAVURI, &p.WebDAVSharedSecret, &p.WebDavPermissions, &p.WebappURITemplate, &p.TransferSourceURI, &p.TransferSharedSecret, &p.TransferSize); err != nil {
618+
if err := rows.Scan(&p.ShareID, &p.Type, &p.WebDAVURI, &p.WebDAVSharedSecret, &p.WebDavPermissions, &p.WebappURITemplate, &p.WebappViewMode, &p.TransferSourceURI, &p.TransferSharedSecret, &p.TransferSize); err != nil {
619619
continue
620620
}
621621
protocols[p.ShareID] = append(protocols[p.ShareID], convertToCS3Protocol(&p))
@@ -683,7 +683,7 @@ func (m *mgr) getReceivedByKey(ctx context.Context, user *userpb.User, key *ocm.
683683
}
684684

685685
func (m *mgr) getProtocols(ctx context.Context, id int) ([]*ocm.Protocol, error) {
686-
query := "SELECT p.type, dav.uri, dav.shared_secret, dav.permissions, app.uri_template, tx.source_uri, tx.shared_secret, tx.size FROM ocm_received_share_protocols as p LEFT JOIN ocm_protocol_webdav as dav ON p.id=dav.ocm_protocol_id LEFT JOIN ocm_protocol_webapp as app ON p.id=app.ocm_protocol_id LEFT JOIN ocm_protocol_transfer as tx ON p.id=tx.ocm_protocol_id WHERE p.ocm_received_share_id=?"
686+
query := "SELECT p.type, dav.uri, dav.shared_secret, dav.permissions, app.uri_template, app.view_mode, tx.source_uri, tx.shared_secret, tx.size FROM ocm_received_share_protocols as p LEFT JOIN ocm_protocol_webdav as dav ON p.id=dav.ocm_protocol_id LEFT JOIN ocm_protocol_webapp as app ON p.id=app.ocm_protocol_id LEFT JOIN ocm_protocol_transfer as tx ON p.id=tx.ocm_protocol_id WHERE p.ocm_received_share_id=?"
687687

688688
var protocols []*ocm.Protocol
689689
rows, err := m.db.QueryContext(ctx, query, id)
@@ -693,7 +693,7 @@ func (m *mgr) getProtocols(ctx context.Context, id int) ([]*ocm.Protocol, error)
693693

694694
var p dbProtocol
695695
for rows.Next() {
696-
if err := rows.Scan(&p.Type, &p.WebDAVURI, &p.WebDAVSharedSecret, &p.WebDavPermissions, &p.WebappURITemplate, &p.TransferSourceURI, &p.TransferSharedSecret, &p.TransferSize); err != nil {
696+
if err := rows.Scan(&p.Type, &p.WebDAVURI, &p.WebDAVSharedSecret, &p.WebDavPermissions, &p.WebappURITemplate, &p.WebappViewMode, &p.TransferSourceURI, &p.TransferSharedSecret, &p.TransferSize); err != nil {
697697
continue
698698
}
699699
protocols = append(protocols, convertToCS3Protocol(&p))

0 commit comments

Comments
 (0)