1
0
mirror of https://github.com/cs3org/reva.git synced 2025-04-18 13:44:12 +03:00

Basic implementation of OCM 1.2 payloads (#5076)

* ocm: adapt to match OCM 1.2 specs, use discovery in all cases when receiving a share

* ocm: some field renames for OCM 1.2, prior to changing the CS3APIs

* Refactored OCM payloads to remove duplicates

* Added ocm 1.2 optional fields (unused for now)

* Enable OCM discovery endpoint for the tests to execute discovery when accepting an OCM share

* tests: use plain logging, not json

* ocm: fixed discovery

* Use new ocm 1.2 fields from CS3APIs

* Implemented caching of the webdav clients for OCM, with fallback to v1.0 access

* changelog

* Use ttlcache as opposed to custom goroutine

* Partially reverted logic to access a remote share, see PR comments

* Proper implementation using the owner's server address

* localfs: added logging

* Fixed example to run standalone OCM tests

* logs for download / upload / move in localfs

* the new entry in .well-known/ocm is now exposed in the config

* nginx: redirect .well-known to revad

---------

Co-authored-by: Jesse Geens <jgeens@cern.ch>
This commit is contained in:
Giuseppe Lo Presti 2025-03-18 19:22:21 +01:00 committed by GitHub
parent 1943e7839b
commit bf89ab5b1f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
45 changed files with 514 additions and 317 deletions

View File

@ -0,0 +1,11 @@
Enhancement: implement OCM 1.2
This PR brings in the implementation of parts of OpenCloudMesh 1.2, including:
* Adopting the new properties of the OCM 1.2 payloads, without implementing any new functionality for now. In particular, any non-empty `requirement` in a share will be rejected (a test was added for that).
* Extending the OCM discovery endpoint.
* Using the remote OCM discovery endpoint to establish the full URL of an incoming remote share, regardless if provided or not. When sending a share, though, we still send a full URL.
* Caching the webdav client used to connect to remote endpoints, with added compatibility to OCM 1.0 remote servers.
* Some refactoring and consolidation of duplicated code.
* Improved logging.
https://github.com/cs3org/reva/pull/5076

View File

@ -197,7 +197,7 @@ func getAccessMethods(webdav, webapp, datatx bool, rol string) ([]*ocm.AccessMet
if err != nil {
return nil, err
}
m = append(m, ocmshare.NewWebDavAccessMethod(perm))
m = append(m, ocmshare.NewWebDavAccessMethod(perm, []string{}))
}
if webapp {
v, err := getOCMViewMode(rol)

View File

@ -75,7 +75,8 @@ func ocmShareUpdateCommand() *command {
AccessMethods: &ocm.AccessMethod{
Term: &ocm.AccessMethod_WebdavOptions{
WebdavOptions: &ocm.WebDAVAccessMethod{
Permissions: perm,
Permissions: perm,
Requirements: []string{},
},
},
},

View File

@ -146,6 +146,8 @@ enable_home_creation = true
[grpc.services.storageprovider.drivers.localhome]
user_layout = "{{.Username}}"
root = "/revalocalstorage"
share_folder = "/revashares"
[[grpc.services.storageprovider]]
driver = "ocmoutcoming"
@ -257,6 +259,7 @@ driver = "localhome"
[http.services.dataprovider.drivers.localhome]
user_layout = "{{.Username}}"
root = "/revalocalstorage"
[[http.services.dataprovider]]
address = ":443"
@ -406,3 +409,7 @@ debug = true
exposed_headers = []
[http.middlewares.log]
level = "debug"
[http.interceptors.log]
level = "debug"

View File

@ -115,6 +115,11 @@ http {
proxy_set_header Host $host;
}
location ^~ /.well-known/ {
proxy_pass https://revad;
proxy_set_header Host $host;
}
location ^~ /ocm/ {
proxy_pass https://revad;
proxy_set_header Host $host;

2
go.mod
View File

@ -13,7 +13,7 @@ require (
github.com/coreos/go-oidc/v3 v3.12.0
github.com/creasty/defaults v1.8.0
github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e
github.com/cs3org/go-cs3apis v0.0.0-20241105092511-3ad35d174fc1
github.com/cs3org/go-cs3apis v0.0.0-20250218144737-544dd3919658
github.com/dgraph-io/ristretto v0.2.0
github.com/dolthub/go-mysql-server v0.14.0
github.com/gdexlab/go-render v1.0.1

4
go.sum
View File

@ -891,8 +891,8 @@ github.com/creasty/defaults v1.8.0 h1:z27FJxCAa0JKt3utc0sCImAEb+spPucmKoOdLHvHYK
github.com/creasty/defaults v1.8.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM=
github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e h1:tqSPWQeueWTKnJVMJffz4pz0o1WuQxJ28+5x5JgaHD8=
github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e/go.mod h1:XJEZ3/EQuI3BXTp/6DUzFr850vlxq11I6satRtz0YQ4=
github.com/cs3org/go-cs3apis v0.0.0-20241105092511-3ad35d174fc1 h1:RU6LT6mkD16xZs011+8foU7T3LrPvTTSWeTQ9OgfhkA=
github.com/cs3org/go-cs3apis v0.0.0-20241105092511-3ad35d174fc1/go.mod h1:DedpcqXl193qF/08Y04IO0PpxyyMu8+GrkD6kWK2MEQ=
github.com/cs3org/go-cs3apis v0.0.0-20250218144737-544dd3919658 h1:CmH7twDuNUrHQXChZMafWjsEp1V47KutJlOAt6FjzGA=
github.com/cs3org/go-cs3apis v0.0.0-20250218144737-544dd3919658/go.mod h1:DedpcqXl193qF/08Y04IO0PpxyyMu8+GrkD6kWK2MEQ=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=

View File

@ -191,7 +191,8 @@ func (s *service) getWebdavProtocol(share *ocm.Share, m *ocm.AccessMethod_Webdav
return &ocmd.WebDAV{
Permissions: perms,
URL: s.webdavURL(share),
Requirements: m.WebdavOptions.Requirements,
URI: s.webdavURL(share),
SharedSecret: share.Token,
}
}
@ -202,7 +203,7 @@ func (s *service) getWebappProtocol(share *ocm.Share) *ocmd.Webapp {
panic(err)
}
return &ocmd.Webapp{
URITemplate: b.String(),
URI: b.String(),
}
}

View File

@ -121,7 +121,7 @@ func (h *appsHandler) webappTemplate(ctx context.Context, id *ocmpb.ShareId) (st
return "", errtypes.BadRequest("share does not contain webapp protocol")
}
return webapp.UriTemplate, nil
return webapp.Uri, nil
}
func getWebappProtocol(protocols []*ocmpb.Protocol) (*ocmpb.WebappProtocol, bool) {

View File

@ -103,7 +103,7 @@ func (h *sharesHandler) CreateShare(w http.ResponseWriter, r *http.Request) {
perm, viewMode := getPermissionsByRole(req.Role)
log.Debug().Msg("calling gatewayClient.CreateOCMShare from sciencemesh/share.go")
log.Debug().Msg("calling gatewayClient.CreateOCMShare")
shareRes, err := h.gatewayClient.CreateOCMShare(ctx, &ocm.CreateOCMShareRequest{
ResourceId: statRes.Info.Id,
Grantee: &providerpb.Grantee{
@ -117,11 +117,11 @@ func (h *sharesHandler) CreateShare(w http.ResponseWriter, r *http.Request) {
},
RecipientMeshProvider: recipientProviderInfo.ProviderInfo,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(perm),
share.NewWebDavAccessMethod(perm, []string{}),
share.NewWebappAccessMethod(viewMode),
},
})
log.Debug().Msg("called gatewayClient.CreateOCMShare from sciencemesh/share.go")
log.Debug().Any("response", shareRes).Msg("called gatewayClient.CreateOCMShare")
switch {
case err != nil:

View File

@ -19,7 +19,6 @@
package ocmd
import (
"bytes"
"context"
"crypto/tls"
"encoding/json"
@ -71,70 +70,59 @@ func NewClient(timeout time.Duration, insecure bool) *OCMClient {
// Discover returns a number of properties used to discover the capabilities offered by a remote cloud storage.
// https://cs3org.github.io/OCM-API/docs.html?branch=develop&repo=OCM-API&user=cs3org#/paths/~1ocm-provider/get
func (c *OCMClient) Discover(ctx context.Context, endpoint string) (*wellknown.OcmDiscoveryData, error) {
url, err := url.JoinPath(endpoint, "/ocm-provider")
if err != nil {
return nil, err
}
log := appctx.GetLogger(ctx)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return nil, errors.Wrap(err, "error creating request")
}
req.Header.Set("Content-Type", "application/json")
remoteurl, _ := url.JoinPath(endpoint, "/.well-known/ocm")
body, err := c.discover(ctx, remoteurl)
if err != nil || len(body) == 0 {
log.Debug().Err(err).Str("sender", remoteurl).Str("response", string(body)).Msg("invalid or empty response, falling back to legacy discovery")
remoteurl, _ := url.JoinPath(endpoint, "/ocm-provider") // legacy discovery endpoint
resp, err := c.client.Do(req)
if err != nil {
return nil, errors.Wrap(err, "error doing request")
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
body, err = c.discover(ctx, remoteurl)
if err != nil || len(body) == 0 {
log.Warn().Err(err).Str("sender", remoteurl).Str("response", string(body)).Msg("invalid or empty response")
return nil, errtypes.BadRequest("Invalid response on OCM discovery")
}
}
var disco wellknown.OcmDiscoveryData
err = json.Unmarshal(body, &disco)
if err != nil {
log := appctx.GetLogger(ctx)
log.Warn().Str("sender", endpoint).Str("response", string(body)).Msg("malformed response")
return nil, errtypes.InternalError("Invalid payload on OCM discovery")
log.Warn().Err(err).Str("sender", remoteurl).Str("response", string(body)).Msg("malformed response")
return nil, errtypes.BadRequest("Invalid payload on OCM discovery")
}
log.Debug().Str("sender", remoteurl).Any("response", disco).Msg("discovery response")
return &disco, nil
}
// NewShareRequest contains the parameters for creating a new OCM share.
type NewShareRequest struct {
ShareWith string `json:"shareWith"`
Name string `json:"name"`
Description string `json:"description"`
ProviderID string `json:"providerId"`
Owner string `json:"owner"`
Sender string `json:"sender"`
OwnerDisplayName string `json:"ownerDisplayName"`
SenderDisplayName string `json:"senderDisplayName"`
ShareType string `json:"shareType"`
Expiration uint64 `json:"expiration"`
ResourceType string `json:"resourceType"`
Protocols Protocols `json:"protocol"`
}
func (c *OCMClient) discover(ctx context.Context, url string) ([]byte, error) {
log := appctx.GetLogger(ctx)
func (r *NewShareRequest) toJSON() (io.Reader, error) {
var b bytes.Buffer
if err := json.NewEncoder(&b).Encode(r); err != nil {
return nil, err
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return nil, errors.Wrap(err, "error creating OCM discovery request")
}
return &b, nil
req.Header.Set("Content-Type", "application/json")
resp, err := c.client.Do(req)
if err != nil {
return nil, errors.Wrap(err, "error doing OCM discovery request")
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
log.Warn().Str("sender", url).Any("response", resp).Int("status", resp.StatusCode).Msg("discovery returned")
return nil, errtypes.BadRequest("Remote does not offer a valid OCM discovery endpoint")
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, errors.Wrap(err, "malformed remote OCM discovery")
}
return body, nil
}
// NewShareResponse is the response returned when creating a new share.
type NewShareResponse struct {
RecipientDisplayName string `json:"recipientDisplayName"`
}
// NewShare creates a new share.
// https://github.com/cs3org/OCM-API/blob/develop/spec.yaml
// NewShare sends a new OCM share to the remote system.
func (c *OCMClient) NewShare(ctx context.Context, endpoint string, r *NewShareRequest) (*NewShareResponse, error) {
url, err := url.JoinPath(endpoint, "shares")
if err != nil {
@ -182,35 +170,9 @@ func (c *OCMClient) parseNewShareResponse(r *http.Response) (*NewShareResponse,
return nil, errtypes.InternalError(string(body))
}
// InviteAcceptedRequest contains the parameters for accepting
// an invitation.
type InviteAcceptedRequest struct {
UserID string `json:"userID"`
Email string `json:"email"`
Name string `json:"name"`
RecipientProvider string `json:"recipientProvider"`
Token string `json:"token"`
}
// User contains the remote user's information when accepting
// an invitation.
type User struct {
UserID string `json:"userID"`
Email string `json:"email"`
Name string `json:"name"`
}
func (r *InviteAcceptedRequest) toJSON() (io.Reader, error) {
var b bytes.Buffer
if err := json.NewEncoder(&b).Encode(r); err != nil {
return nil, err
}
return &b, nil
}
// InviteAccepted informs the sender that the invitation was accepted to start sharing
// InviteAccepted informs the remote end that the invitation was accepted to start sharing
// https://cs3org.github.io/OCM-API/docs.html?branch=develop&repo=OCM-API&user=cs3org#/paths/~1invite-accepted/post
func (c *OCMClient) InviteAccepted(ctx context.Context, endpoint string, r *InviteAcceptedRequest) (*User, error) {
func (c *OCMClient) InviteAccepted(ctx context.Context, endpoint string, r *InviteAcceptedRequest) (*RemoteUser, error) {
url, err := url.JoinPath(endpoint, "invite-accepted")
if err != nil {
return nil, err
@ -236,10 +198,10 @@ func (c *OCMClient) InviteAccepted(ctx context.Context, endpoint string, r *Invi
return c.parseInviteAcceptedResponse(resp)
}
func (c *OCMClient) parseInviteAcceptedResponse(r *http.Response) (*User, error) {
func (c *OCMClient) parseInviteAcceptedResponse(r *http.Response) (*RemoteUser, error) {
switch r.StatusCode {
case http.StatusOK:
var u User
var u RemoteUser
if err := json.NewDecoder(r.Body).Decode(&u); err != nil {
return nil, errors.Wrap(err, "error decoding response body")
}

View File

@ -49,14 +49,6 @@ func (h *invitesHandler) init(c *config) error {
return nil
}
type acceptInviteRequest struct {
Token string `json:"token"`
UserID string `json:"userID"`
RecipientProvider string `json:"recipientProvider"`
Name string `json:"name"`
Email string `json:"email"`
}
// AcceptInvite informs avout an accepted invitation so that the users
// can initiate the OCM share creation.
func (h *invitesHandler) AcceptInvite(w http.ResponseWriter, r *http.Request) {
@ -68,6 +60,7 @@ func (h *invitesHandler) AcceptInvite(w http.ResponseWriter, r *http.Request) {
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "missing parameters in request", err)
return
}
log.Info().Any("req", req).Msg("OCM /invite-accepted request received")
if req.Token == "" || req.UserID == "" || req.RecipientProvider == "" {
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "token, userID and recipiendProvider must not be null", nil)
@ -138,7 +131,7 @@ func (h *invitesHandler) AcceptInvite(w http.ResponseWriter, r *http.Request) {
}
}
if err := json.NewEncoder(w).Encode(&user{
if err := json.NewEncoder(w).Encode(&RemoteUser{
UserID: acceptInviteResponse.UserId.OpaqueId,
Email: acceptInviteResponse.Email,
Name: acceptInviteResponse.DisplayName,
@ -152,14 +145,8 @@ func (h *invitesHandler) AcceptInvite(w http.ResponseWriter, r *http.Request) {
log.Info().Str("user", fmt.Sprintf("%s@%s", userObj.Id.OpaqueId, userObj.Id.Idp)).Str("token", req.Token).Msg("added to accepted users")
}
type user struct {
UserID string `json:"userID"`
Email string `json:"email"`
Name string `json:"name"`
}
func getAcceptInviteRequest(r *http.Request) (*acceptInviteRequest, error) {
var req acceptInviteRequest
func getAcceptInviteRequest(r *http.Request) (*InviteAcceptedRequest, error) {
var req InviteAcceptedRequest
contentType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err == nil && contentType == "application/json" {
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {

View File

@ -54,25 +54,26 @@ func TestUnmarshalProtocol(t *testing.T) {
&WebDAV{
SharedSecret: "secret",
Permissions: []string{"read", "write", "share"},
URL: "",
URI: "",
},
},
},
{
raw: `{"name":"multi","options":{},"webdav":{"sharedSecret":"secret","permissions":["read","write"],"url":"http://example.org"}}`,
raw: `{"name":"multi","options":{},"webdav":{"sharedSecret":"secret","permissions":["read","write"],"requirements":["req"],"uri":"http://example.org"}}`,
expected: []Protocol{
&WebDAV{
SharedSecret: "secret",
Permissions: []string{"read", "write"},
URL: "http://example.org",
Requirements: []string{"req"},
URI: "http://example.org",
},
},
},
{
raw: `{"name":"multi","options":{},"webapp":{"uriTemplate":"http://example.org/{test}"}}`,
raw: `{"name":"multi","options":{},"webapp":{"uri":"http://example.org/test"}}`,
expected: []Protocol{
&Webapp{
URITemplate: "http://example.org/{test}",
URI: "http://example.org/test",
},
},
},
@ -87,15 +88,15 @@ func TestUnmarshalProtocol(t *testing.T) {
},
},
{
raw: `{"name":"multi","options":{},"webdav":{"sharedSecret":"secret","permissions":["read","write"],"url":"http://example.org"},"webapp":{"uriTemplate":"http://example.org/{test}"},"datatx":{"sharedSecret":"secret","srcUri":"http://example.org","size":10}}`,
raw: `{"name":"multi","options":{},"webdav":{"sharedSecret":"secret","permissions":["read","write"],"uri":"http://example.org"},"webapp":{"uri":"http://example.org/test"},"datatx":{"sharedSecret":"secret","srcUri":"http://example.org","size":10}}`,
expected: []Protocol{
&WebDAV{
SharedSecret: "secret",
Permissions: []string{"read", "write"},
URL: "http://example.org",
URI: "http://example.org",
},
&Webapp{
URITemplate: "http://example.org/{test}",
URI: "http://example.org/test",
},
&Datatx{
SharedSecret: "secret",
@ -155,7 +156,8 @@ func TestMarshalProtocol(t *testing.T) {
&WebDAV{
SharedSecret: "secret",
Permissions: []string{"read"},
URL: "http://example.org",
Requirements: []string{},
URI: "http://example.org",
},
},
expected: map[string]any{
@ -164,23 +166,25 @@ func TestMarshalProtocol(t *testing.T) {
"webdav": map[string]any{
"sharedSecret": "secret",
"permissions": []any{"read"},
"url": "http://example.org",
"requirements": []any{},
"uri": "http://example.org",
},
},
},
{
in: []Protocol{
&Webapp{
URITemplate: "http://example.org",
ViewMode: "read",
URI: "http://example.org",
ViewMode: "read",
},
},
expected: map[string]any{
"name": "multi",
"options": map[string]any{},
"webapp": map[string]any{
"uriTemplate": "http://example.org",
"viewMode": "read",
"uri": "http://example.org",
"viewMode": "read",
"sharedSecret": "",
},
},
},
@ -207,11 +211,12 @@ func TestMarshalProtocol(t *testing.T) {
&WebDAV{
SharedSecret: "secret",
Permissions: []string{"read"},
URL: "http://example.org",
Requirements: []string{"req"},
URI: "http://example.org",
},
&Webapp{
URITemplate: "http://example.org",
ViewMode: "read",
URI: "http://example.org",
ViewMode: "read",
},
&Datatx{
SharedSecret: "secret",
@ -225,11 +230,13 @@ func TestMarshalProtocol(t *testing.T) {
"webdav": map[string]any{
"sharedSecret": "secret",
"permissions": []any{"read"},
"url": "http://example.org",
"requirements": []any{"req"},
"uri": "http://example.org",
},
"webapp": map[string]any{
"uriTemplate": "http://example.org",
"viewMode": "read",
"uri": "http://example.org",
"viewMode": "read",
"sharedSecret": "",
},
"datatx": map[string]any{
"sharedSecret": "secret",

View File

@ -19,11 +19,12 @@
package ocmd
import (
"context"
"encoding/json"
"fmt"
"mime"
"net/http"
"path/filepath"
"net/url"
"strings"
"time"
@ -63,27 +64,12 @@ func (h *sharesHandler) init(c *config) error {
return nil
}
type createShareRequest struct {
ShareWith string `json:"shareWith" validate:"required"` // identifier of the recipient of the share
Name string `json:"name" validate:"required"` // name of the resource
Description string `json:"description"` // (optional) description of the resource
ProviderID string `json:"providerId" validate:"required"` // unique identifier of the resource at provider side
Owner string `json:"owner" validate:"required"` // unique identifier of the owner at provider side
Sender string `json:"sender" validate:"required"` // unique indentifier of the user who wants to share the resource at provider side
OwnerDisplayName string `json:"ownerDisplayName"` // display name of the owner of the resource
SenderDisplayName string `json:"senderDisplayName"` // dispay name of the user who wants to share the resource
ShareType string `json:"shareType" validate:"required,oneof=user group"` // recipient share type (user or group)
ResourceType string `json:"resourceType" validate:"required,oneof=file folder"`
Expiration uint64 `json:"expiration"`
Protocols Protocols `json:"protocol" validate:"required"`
}
// CreateShare sends all the informations to the consumer needed to start
// synchronization between the two services.
// CreateShare implements the OCM /shares call.
func (h *sharesHandler) CreateShare(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
log := appctx.GetLogger(ctx)
req, err := getCreateShareRequest(r)
log.Info().Any("req", req).Msg("OCM /shares request received")
if err != nil {
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, err.Error(), nil)
return
@ -114,7 +100,7 @@ func (h *sharesHandler) CreateShare(w http.ResponseWriter, r *http.Request) {
Provider: &providerInfo,
})
if err != nil {
reqres.WriteError(w, r, reqres.APIErrorServerError, "error sending a grpc is provider allowed request", err)
reqres.WriteError(w, r, reqres.APIErrorServerError, "error sending a grpc isProviderAllowed request", err)
return
}
if providerAllowedResp.Status.Code != rpc.Code_CODE_OK {
@ -124,7 +110,7 @@ func (h *sharesHandler) CreateShare(w http.ResponseWriter, r *http.Request) {
shareWith, _, err := getIDAndMeshProvider(req.ShareWith)
if err != nil {
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, err.Error(), nil)
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "error with mesh provider", err)
return
}
@ -142,19 +128,19 @@ func (h *sharesHandler) CreateShare(w http.ResponseWriter, r *http.Request) {
owner, err := getUserIDFromOCMUser(req.Owner)
if err != nil {
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, err.Error(), nil)
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "error with remote owner", err)
return
}
sender, err := getUserIDFromOCMUser(req.Sender)
if err != nil {
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, err.Error(), nil)
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "error with remote sender", err)
return
}
protocols, err := getAndResolveProtocols(req.Protocols, r)
protocols, err := getAndResolveProtocols(ctx, req.Protocols, owner.Idp)
if err != nil {
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, err.Error(), nil)
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "error with protocols payload", err)
return
}
@ -176,6 +162,7 @@ func (h *sharesHandler) CreateShare(w http.ResponseWriter, r *http.Request) {
}
}
log.Info().Any("req", createShareReq).Msg("CreateOCMCoreShare payload")
createShareResp, err := h.gatewayClient.CreateOCMCoreShare(ctx, createShareReq)
if err != nil {
reqres.WriteError(w, r, reqres.APIErrorServerError, "error creating ocm share", err)
@ -220,15 +207,15 @@ func getIDAndMeshProvider(user string) (string, string, error) {
return strings.Join(split[:len(split)-1], "@"), split[len(split)-1], nil
}
func getCreateShareRequest(r *http.Request) (*createShareRequest, error) {
var req createShareRequest
func getCreateShareRequest(r *http.Request) (*NewShareRequest, error) {
var req NewShareRequest
contentType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err == nil && contentType == "application/json" {
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, err
return nil, errors.Wrap(err, "malformed OCM /shares request")
}
} else {
return nil, errors.New("body request not recognised")
return nil, errors.New("malformed OCM /shares request payload")
}
// validate the request
if err := validate.Struct(req); err != nil {
@ -260,45 +247,81 @@ func getOCMShareType(t string) ocm.ShareType {
}
}
func getAndResolveProtocols(p Protocols, r *http.Request) ([]*ocm.Protocol, error) {
func getAndResolveProtocols(ctx context.Context, p Protocols, ownerServer string) ([]*ocm.Protocol, error) {
protos := make([]*ocm.Protocol, 0, len(p))
for _, data := range p {
var uri string
ocmProto := data.ToOCMProtocol()
if GetProtocolName(data) == "webdav" && ocmProto.GetWebdavOptions().Uri == "" {
// This is an OCM 1.0 payload with only webdav: we need to resolve the remote URL
remoteRoot, err := discoverOcmWebdavRoot(r)
if err != nil {
return nil, err
protocolName := GetProtocolName(data)
switch protocolName {
case "webdav":
uri = ocmProto.GetWebdavOptions().Uri
reqs := ocmProto.GetWebdavOptions().Requirements
if len(reqs) > 0 {
// we currently do not support any kind of requirement
return nil, errtypes.BadRequest(fmt.Sprintf("incoming OCM share with requirements %+v not supported at this endpoint", reqs))
}
ocmProto.GetWebdavOptions().Uri = filepath.Join(remoteRoot, ocmProto.GetWebdavOptions().SharedSecret)
case "webapp":
uri = ocmProto.GetWebappOptions().Uri
}
// If the `uri` contains a hostname, use it as is
u, _ := url.Parse(uri)
if u.Host != "" {
protos = append(protos, ocmProto)
continue
}
// otherwise use as endpoint the owner's server from the payload
remoteRoot, err := discoverOcmRoot(ctx, ownerServer, protocolName)
if err != nil {
return nil, err
}
if strings.HasPrefix(uri, "/") {
// only take the host from remoteRoot and append the absolute uri
u, _ := url.Parse(remoteRoot)
u.Path = uri
uri = u.String()
} else {
// relative uri
uri, _ = url.JoinPath(remoteRoot, uri)
}
switch protocolName {
case "webdav":
ocmProto.GetWebdavOptions().Uri = uri
case "webapp":
ocmProto.GetWebappOptions().Uri = uri
}
protos = append(protos, ocmProto)
}
return protos, nil
}
func discoverOcmWebdavRoot(r *http.Request) (string, error) {
// implements the OCM discovery logic to fetch the WebDAV root at the remote host that sent the share, see
func discoverOcmRoot(ctx context.Context, ownerServer string, proto string) (string, error) {
// implements the OCM discovery logic to fetch the root at the remote host that sent the share for the given proto, see
// https://cs3org.github.io/OCM-API/docs.html?branch=v1.1.0&repo=OCM-API&user=cs3org#/paths/~1ocm-provider/get
ctx := r.Context()
log := appctx.GetLogger(ctx)
log.Debug().Str("sender", r.Host).Msg("received OCM 1.0 share, attempting to discover sender endpoint")
ocmClient := NewClient(time.Duration(10)*time.Second, true)
ocmCaps, err := ocmClient.Discover(ctx, r.Host)
ocmCaps, err := ocmClient.Discover(ctx, "https://"+ownerServer)
if err != nil {
log.Warn().Str("sender", r.Host).Err(err).Msg("failed to discover OCM sender")
log.Warn().Str("sender", ownerServer).Err(err).Msg("failed to discover OCM sender")
return "", err
}
for _, t := range ocmCaps.ResourceTypes {
webdavRoot, ok := t.Protocols["webdav"]
protoRoot, ok := t.Protocols[proto]
if ok {
// assume the first resourceType that exposes a webdav root is OK to use: as a matter of fact,
// assume the first resourceType that exposes a root is OK to use: as a matter of fact,
// no implementation exists yet that exposes multiple resource types with different roots.
return filepath.Join(ocmCaps.Endpoint, webdavRoot), nil
u, _ := url.Parse(ocmCaps.Endpoint)
u.Path = protoRoot
u.RawQuery = ""
log.Debug().Str("sender", ownerServer).Str("proto", proto).Str("URL", u.String()).Msg("resolved protocol URL")
return u.String(), nil
}
}
log.Warn().Str("sender", r.Host).Interface("response", ocmCaps).Msg("missing webdav root")
return "", errtypes.NotFound("WebDAV root not found on OCM discovery")
log.Warn().Str("sender", ownerServer).Interface("response", ocmCaps).Msg("missing protocol root")
return "", errtypes.NotFound(fmt.Sprintf("root not found on OCM discovery for protocol %s", proto))
}

View File

@ -19,9 +19,11 @@
package ocmd
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"reflect"
"strings"
@ -31,13 +33,72 @@ import (
utils "github.com/cs3org/reva/pkg/utils"
)
// Protocols is the list of protocols.
// In this file we group the definitions of the OCM payloads according to the official specs
// at https://github.com/cs3org/OCM-API/blob/develop/spec.yaml
// InviteAcceptedRequest contains the payload of an OCM /invite-accepted request.
// https://cs3org.github.io/OCM-API/docs.html?branch=develop&repo=OCM-API&user=cs3org#/paths/~1invite-accepted/post
type InviteAcceptedRequest struct {
UserID string `json:"userID" validate:"required"`
Email string `json:"email"`
Name string `json:"name"`
RecipientProvider string `json:"recipientProvider"`
Token string `json:"token"`
}
// RemoteUser contains the remote user's information both when sending an /invite-accepted call and when sending back a response to /invite-accepted
type RemoteUser struct {
UserID string `json:"userID"`
Email string `json:"email"`
Name string `json:"name"`
}
func (r *InviteAcceptedRequest) toJSON() (io.Reader, error) {
var b bytes.Buffer
if err := json.NewEncoder(&b).Encode(r); err != nil {
return nil, err
}
return &b, nil
}
// NewShareRequest contains the payload of an OCM /share request.
// https://cs3org.github.io/OCM-API/docs.html?branch=develop&repo=OCM-API&user=cs3org#/paths/~1shares/post
type NewShareRequest struct {
ShareWith string `json:"shareWith" validate:"required"` // identifier of the recipient of the share
Name string `json:"name" validate:"required"` // name of the resource
Description string `json:"description"` // (optional) description of the resource
ProviderID string `json:"providerId" validate:"required"` // unique identifier of the resource at provider side
Owner string `json:"owner" validate:"required"` // unique identifier of the owner at provider side
Sender string `json:"sender" validate:"required"` // unique indentifier of the user who wants to share the resource at provider side
OwnerDisplayName string `json:"ownerDisplayName"` // display name of the owner of the resource
SenderDisplayName string `json:"senderDisplayName"` // dispay name of the user who wants to share the resource
Code string `json:"code"` // nonce to be exchanged for a bearer token (not implemented for now)
ShareType string `json:"shareType" validate:"required,oneof=user group"` // recipient share type (user or group)
ResourceType string `json:"resourceType" validate:"required,oneof=file folder"`
Expiration uint64 `json:"expiration"`
Protocols Protocols `json:"protocol" validate:"required"`
}
func (r *NewShareRequest) toJSON() (io.Reader, error) {
var b bytes.Buffer
if err := json.NewEncoder(&b).Encode(r); err != nil {
return nil, err
}
return &b, nil
}
// NewShareResponse is the response returned when creating a new share.
type NewShareResponse struct {
RecipientDisplayName string `json:"recipientDisplayName"`
}
// Protocols is the list of OCM protocols.
type Protocols []Protocol
// Protocol represents the way of access the resource
// in the OCM share.
type Protocol interface {
// ToOCMProtocol convert the protocol to a ocm Protocol struct
// ToOCMProtocol converts the protocol to a CS3API OCM `Protocol` struct
ToOCMProtocol() *ocm.Protocol
}
@ -47,7 +108,8 @@ type Protocol interface {
type WebDAV struct {
SharedSecret string `json:"sharedSecret" validate:"required"`
Permissions []string `json:"permissions" validate:"required,dive,required,oneof=read write share"`
URL string `json:"url" validate:"required"`
Requirements []string `json:"requirements"`
URI string `json:"uri" validate:"required"`
}
// ToOCMProtocol convert the protocol to a ocm Protocol struct.
@ -69,18 +131,19 @@ func (w *WebDAV) ToOCMProtocol() *ocm.Protocol {
}
}
return ocmshare.NewWebDAVProtocol(w.URL, w.SharedSecret, perms)
return ocmshare.NewWebDAVProtocol(w.URI, w.SharedSecret, perms, w.Requirements)
}
// Webapp contains the parameters for the Webapp protocol.
type Webapp struct {
URITemplate string `json:"uriTemplate" validate:"required"`
ViewMode string `json:"viewMode" validate:"required,dive,required,oneof=view read write"`
URI string `json:"uri" validate:"required"`
ViewMode string `json:"viewMode" validate:"required,dive,required,oneof=view read write"`
SharedSecret string `json:"sharedSecret"`
}
// ToOCMProtocol convert the protocol to a ocm Protocol struct.
func (w *Webapp) ToOCMProtocol() *ocm.Protocol {
return ocmshare.NewWebappProtocol(w.URITemplate, utils.GetAppViewMode(w.ViewMode))
return ocmshare.NewWebappProtocol(w.URI, utils.GetAppViewMode(w.ViewMode))
}
// Datatx contains the parameters for the Datatx protocol.
@ -134,7 +197,7 @@ func (p *Protocols) UnmarshalJSON(data []byte) error {
res = &WebDAV{
SharedSecret: ss,
Permissions: []string{"read", "write", "share"},
URL: "",
URI: "",
}
*p = append(*p, res)
}
@ -163,7 +226,7 @@ func (p Protocols) MarshalJSON() ([]byte, error) {
for _, prot := range p {
d[GetProtocolName(prot)] = prot
}
// fill in the OCM v1.0 properties: for now we only create OCM 1.1 payloads,
// fill in the OCM v1.0 properties: we only create OCM 1.1+ payloads,
// irrespective from the capabilities of the remote server.
d["name"] = "multi"
d["options"] = map[string]any{}

View File

@ -184,12 +184,13 @@ func (h *DavHandler) Handler(s *svc) http.Handler {
c, err := pool.GetGatewayServiceClient(pool.Endpoint(s.c.GatewaySvc))
if err != nil {
log.Error().Err(err).Msg("error getting gateway during OCM authentication")
w.WriteHeader(http.StatusNotFound)
return
}
var token, ocmshare string
// OCM v1.1 (OCIS et al.).
// OCM v1.1+ (OCIS et al.).
bearer := strings.TrimPrefix(r.Header.Get("Authorization"), "Bearer ")
if bearer != "" {
// Bearer token is the shared secret, path is /{shareId}/path/to/resource.

View File

@ -263,7 +263,7 @@ func (s *svc) getResourceInfos(ctx context.Context, w http.ResponseWriter, r *ht
res, err := client.Stat(ctx, req)
if err != nil {
log.Error().Err(err).Interface("req", req).Msg("error sending a grpc stat request")
log.Error().Err(err).Interface("req", req).Msg("error sending a stat request to the gateway")
w.WriteHeader(http.StatusInternalServerError)
return nil, nil, false
} else if res.Status.Code != rpc.Code_CODE_OK {

View File

@ -111,7 +111,7 @@ func (h *Handler) createFederatedCloudShare(w http.ResponseWriter, r *http.Reque
},
RecipientMeshProvider: providerInfoResp.ProviderInfo,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(role.CS3ResourcePermissions()),
share.NewWebDavAccessMethod(role.CS3ResourcePermissions(), []string{}),
share.NewWebappAccessMethod(getViewModeFromRole(role)),
},
})

View File

@ -60,9 +60,7 @@ type APIError struct {
// WriteError handles writing error responses.
func WriteError(w http.ResponseWriter, r *http.Request, code APIErrorCode, message string, e error) {
if e != nil {
appctx.GetLogger(r.Context()).Error().Err(e).Msg(message)
}
appctx.GetLogger(r.Context()).Error().Err(e).Any("code", code).Str("message", message).Msg("sending back error response")
var encoded []byte
var err error

View File

@ -27,25 +27,27 @@ import (
"github.com/cs3org/reva/pkg/appctx"
)
const OCMAPIVersion = "1.1.0"
const OCMAPIVersion = "1.2.0"
type OcmProviderConfig struct {
OCMPrefix string `docs:"ocm;The prefix URL where the OCM API is served." mapstructure:"ocm_prefix"`
Endpoint string `docs:"This host's full URL. If it's not configured, it is assumed OCM is not available." mapstructure:"endpoint"`
Provider string `docs:"reva;A friendly name that defines this service." mapstructure:"provider"`
WebdavRoot string `docs:"/remote.php/dav/ocm;The root URL of the WebDAV endpoint to serve OCM shares." mapstructure:"webdav_root"`
WebappRoot string `docs:"/external/sciencemesh;The root URL to serve Web apps via OCM." mapstructure:"webapp_root"`
EnableWebapp bool `docs:"false;Whether web apps are enabled in OCM shares." mapstructure:"enable_webapp"`
EnableDatatx bool `docs:"false;Whether data transfers are enabled in OCM shares." mapstructure:"enable_datatx"`
OCMPrefix string `docs:"ocm;The prefix URL where the OCM API is served." mapstructure:"ocm_prefix"`
Endpoint string `docs:"This host's full URL. If it's not configured, it is assumed OCM is not available." mapstructure:"endpoint"`
Provider string `docs:"reva;A friendly name that defines this service." mapstructure:"provider"`
WebdavRoot string `docs:"/remote.php/dav/ocm;The root URL of the WebDAV endpoint to serve OCM shares." mapstructure:"webdav_root"`
WebappRoot string `docs:"/external/sciencemesh;The root URL to serve Web apps via OCM." mapstructure:"webapp_root"`
InviteAcceptDialog string `docs:"/sciencemesh-app/invitations;The frontend URL where to land when receiving an invitation" mapstructure:"invite_accept_dialog"`
EnableWebapp bool `docs:"false;Whether web apps are enabled in OCM shares." mapstructure:"enable_webapp"`
EnableDatatx bool `docs:"false;Whether data transfers are enabled in OCM shares." mapstructure:"enable_datatx"`
}
type OcmDiscoveryData struct {
Enabled bool `json:"enabled" xml:"enabled"`
APIVersion string `json:"apiVersion" xml:"apiVersion"`
Endpoint string `json:"endPoint" xml:"endPoint"`
Provider string `json:"provider" xml:"provider"`
ResourceTypes []resourceTypes `json:"resourceTypes" xml:"resourceTypes"`
Capabilities []string `json:"capabilities" xml:"capabilities"`
Enabled bool `json:"enabled" xml:"enabled"`
APIVersion string `json:"apiVersion" xml:"apiVersion"`
Endpoint string `json:"endPoint" xml:"endPoint"`
Provider string `json:"provider" xml:"provider"`
ResourceTypes []resourceTypes `json:"resourceTypes" xml:"resourceTypes"`
Capabilities []string `json:"capabilities" xml:"capabilities"`
InviteAcceptDialog string `json:"inviteAcceptDialog" xml:"inviteAcceptDialog"`
}
type resourceTypes struct {
@ -77,6 +79,9 @@ func (c *OcmProviderConfig) ApplyDefaults() {
if c.WebappRoot[len(c.WebappRoot)-1:] != "/" {
c.WebappRoot += "/"
}
if c.InviteAcceptDialog == "" {
c.InviteAcceptDialog = "/sciencemesh-app/invitations"
}
}
func (h *wkocmHandler) init(c *OcmProviderConfig) {
@ -124,7 +129,8 @@ func (h *wkocmHandler) init(c *OcmProviderConfig) {
Protocols: rtProtos, // expose the protocols as per configuration
}}
// for now we hardcode the capabilities, as this is currently only advisory
d.Capabilities = []string{"/invite-accepted"}
d.Capabilities = []string{"invites", "webdav-uri", "protocol-object"}
d.InviteAcceptDialog, _ = url.JoinPath(c.Endpoint, c.InviteAcceptDialog)
h.data = d
}

View File

@ -97,8 +97,8 @@ type EfssShare struct {
Permissions int `json:"permissions" validate:"required"`
} `json:"webdav" validate:"required"`
WebApp struct {
URITemplate string `json:"uri_template"`
ViewMode string `json:"view_mode"`
URI string `json:"uri_template"`
ViewMode string `json:"view_mode"`
} `json:"webapp" validate:"omitempty"`
DataTx struct {
SourceURI string `json:"source_uri"`
@ -181,7 +181,7 @@ func (sm *Manager) efssShareToOcm(resp *EfssShare) *ocm.Share {
// first generate the map of access methods, assuming WebDAV is always present
var am = make([]*ocm.AccessMethod, 0, 3)
am = append(am, share.NewWebDavAccessMethod(conversions.RoleFromOCSPermissions(
conversions.Permissions(resp.Protocols.WebDAV.Permissions)).CS3ResourcePermissions()))
conversions.Permissions(resp.Protocols.WebDAV.Permissions)).CS3ResourcePermissions(), []string{}))
if resp.Protocols.WebApp.ViewMode != "" {
am = append(am, share.NewWebappAccessMethod(utils.GetAppViewMode(resp.Protocols.WebApp.ViewMode)))
}
@ -326,9 +326,9 @@ func efssReceivedShareToOcm(resp *ReceivedEfssShare) *ocm.ReceivedShare {
var proto = make([]*ocm.Protocol, 0, 3)
proto = append(proto, share.NewWebDAVProtocol(resp.Share.Protocols.WebDAV.URI, resp.Share.Token, &ocm.SharePermissions{
Permissions: conversions.RoleFromOCSPermissions(conversions.Permissions(resp.Share.Protocols.WebDAV.Permissions)).CS3ResourcePermissions(),
}))
}, []string{}))
if resp.Share.Protocols.WebApp.ViewMode != "" {
proto = append(proto, share.NewWebappProtocol(resp.Share.Protocols.WebApp.URITemplate, utils.GetAppViewMode(resp.Share.Protocols.WebApp.ViewMode)))
proto = append(proto, share.NewWebappProtocol(resp.Share.Protocols.WebApp.URI, utils.GetAppViewMode(resp.Share.Protocols.WebApp.ViewMode)))
}
if resp.Share.Protocols.DataTx.SourceURI != "" {
proto = append(proto, share.NewTransferProtocol(resp.Share.Protocols.DataTx.SourceURI, resp.Share.Token, uint64(resp.Share.Protocols.DataTx.Size)))

View File

@ -283,7 +283,7 @@ var _ = Describe("Nextcloud", func() {
OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
},
AccessMethods: []*ocm.AccessMethod{
ocmshare.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
ocmshare.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
ocmshare.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_WRITE),
ocmshare.NewTransferAccessMethod(),
},
@ -422,7 +422,7 @@ var _ = Describe("Nextcloud", func() {
},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
ocmshare.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
ocmshare.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
ocmshare.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_WRITE),
ocmshare.NewTransferAccessMethod(),
},
@ -475,7 +475,7 @@ var _ = Describe("Nextcloud", func() {
Protocols: []*ocm.Protocol{
ocmshare.NewWebDAVProtocol("webdav-uri", "some-token", &ocm.SharePermissions{
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
}),
}, []string{}),
ocmshare.NewWebappProtocol("app-uri-template", appprovider.ViewMode_VIEW_MODE_READ_WRITE),
ocmshare.NewTransferProtocol("source-uri", "some-token", 1),
},
@ -533,7 +533,7 @@ var _ = Describe("Nextcloud", func() {
Protocols: []*ocm.Protocol{
ocmshare.NewWebDAVProtocol("webdav-uri", "some-token", &ocm.SharePermissions{
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
}),
}, []string{}),
ocmshare.NewWebappProtocol("app-uri-template", appprovider.ViewMode_VIEW_MODE_READ_WRITE),
ocmshare.NewTransferProtocol("source-uri", "some-token", 1),
},
@ -622,7 +622,7 @@ var _ = Describe("Nextcloud", func() {
Protocols: []*ocm.Protocol{
ocmshare.NewWebDAVProtocol("webdav-uri", "some-token", &ocm.SharePermissions{
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
}),
}, []string{}),
ocmshare.NewWebappProtocol("app-uri-template", appprovider.ViewMode_VIEW_MODE_READ_WRITE),
ocmshare.NewTransferProtocol("source-uri", "some-token", 1),
},

View File

@ -169,7 +169,7 @@ type dbProtocol struct {
WebDAVURI *string
WebDAVSharedSecret *string
WebDavPermissions *int
WebappURITemplate *string
WebappURI *string
WebappViewMode *int
TransferSourceURI *string
TransferSharedSecret *string
@ -267,7 +267,9 @@ func convertToCS3OCMReceivedShare(s *dbReceivedShare, p []*ocm.Protocol) *ocm.Re
func convertToCS3AccessMethod(m *dbAccessMethod) *ocm.AccessMethod {
switch m.Type {
case WebDAVAccessMethod:
return share.NewWebDavAccessMethod(conversions.RoleFromOCSPermissions(conversions.Permissions(*m.WebDAVPermissions)).CS3ResourcePermissions())
return share.NewWebDavAccessMethod(
conversions.RoleFromOCSPermissions(conversions.Permissions(*m.WebDAVPermissions)).CS3ResourcePermissions(),
[]string{}) // TODO persist requirements
case WebappAccessMethod:
return share.NewWebappAccessMethod(appprovider.ViewMode(*m.WebAppViewMode))
case TransferAccessMethod:
@ -281,9 +283,9 @@ func convertToCS3Protocol(p *dbProtocol) *ocm.Protocol {
case WebDAVProtocol:
return share.NewWebDAVProtocol(*p.WebDAVURI, *p.WebDAVSharedSecret, &ocm.SharePermissions{
Permissions: conversions.RoleFromOCSPermissions(conversions.Permissions(*p.WebDavPermissions)).CS3ResourcePermissions(),
})
}, []string{}) // TODO persist requirements
case WebappProtocol:
return share.NewWebappProtocol(*p.WebappURITemplate, appprovider.ViewMode(*p.WebappViewMode))
return share.NewWebappProtocol(*p.WebappURI, appprovider.ViewMode(*p.WebappViewMode))
case TransferProtocol:
return share.NewTransferProtocol(*p.TransferSourceURI, *p.TransferSharedSecret, uint64(*p.TransferSize))
}

View File

@ -572,7 +572,7 @@ func storeWebappProtocol(tx *sql.Tx, shareID int64, o *ocm.Protocol_WebappOption
}
query := "INSERT INTO ocm_protocol_webapp SET ocm_protocol_id=?, uri_template=?, view_mode=?"
params := []any{pID, o.WebappOptions.UriTemplate, o.WebappOptions.ViewMode}
params := []any{pID, o.WebappOptions.Uri, o.WebappOptions.ViewMode}
_, err = tx.Exec(query, params...)
return err
@ -707,7 +707,7 @@ func (m *mgr) getProtocolsIds(ctx context.Context, ids []any) (map[string][]*ocm
var p dbProtocol
for rows.Next() {
if err := rows.Scan(&p.ShareID, &p.Type, &p.WebDAVURI, &p.WebDAVSharedSecret, &p.WebDavPermissions, &p.WebappURITemplate, &p.WebappViewMode, &p.TransferSourceURI, &p.TransferSharedSecret, &p.TransferSize); err != nil {
if err := rows.Scan(&p.ShareID, &p.Type, &p.WebDAVURI, &p.WebDAVSharedSecret, &p.WebDavPermissions, &p.WebappURI, &p.WebappViewMode, &p.TransferSourceURI, &p.TransferSharedSecret, &p.TransferSize); err != nil {
continue
}
protocols[p.ShareID] = append(protocols[p.ShareID], convertToCS3Protocol(&p))
@ -763,7 +763,7 @@ func (m *mgr) getProtocols(ctx context.Context, id int) ([]*ocm.Protocol, error)
var p dbProtocol
for rows.Next() {
if err := rows.Scan(&p.Type, &p.WebDAVURI, &p.WebDAVSharedSecret, &p.WebDavPermissions, &p.WebappURITemplate, &p.WebappViewMode, &p.TransferSourceURI, &p.TransferSharedSecret, &p.TransferSize); err != nil {
if err := rows.Scan(&p.Type, &p.WebDAVURI, &p.WebDAVSharedSecret, &p.WebDavPermissions, &p.WebappURI, &p.WebappViewMode, &p.TransferSourceURI, &p.TransferSharedSecret, &p.TransferSize); err != nil {
continue
}
protocols = append(protocols, convertToCS3Protocol(&p))

View File

@ -286,7 +286,7 @@ func createReceivedShareTables(ctx *sql.Context, initData []*ocm.ReceivedShare)
must(webdav.Insert(ctx, sql.NewRow(i, prot.WebdavOptions.Uri, prot.WebdavOptions.SharedSecret, int64(conversions.RoleFromResourcePermissions(prot.WebdavOptions.Permissions.Permissions).OCSPermissions()))))
case *ocm.Protocol_WebappOptions:
must(protocols.Insert(ctx, sql.NewRow(i, mustInt(share.Id.OpaqueId), int8(WebappProtocol))))
must(webapp.Insert(ctx, sql.NewRow(i, prot.WebappOptions.UriTemplate, int8(prot.WebappOptions.ViewMode))))
must(webapp.Insert(ctx, sql.NewRow(i, prot.WebappOptions.Uri, int8(prot.WebappOptions.ViewMode))))
case *ocm.Protocol_TransferOptions:
must(protocols.Insert(ctx, sql.NewRow(i, mustInt(share.Id.OpaqueId), int8(TransferProtocol))))
must(transfer.Insert(ctx, sql.NewRow(i, prot.TransferOptions.SourceUri, prot.TransferOptions.SharedSecret, int64(prot.TransferOptions.Size))))
@ -342,7 +342,7 @@ func TestGetShare(t *testing.T) {
Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468},
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions())},
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{})},
},
},
query: &ocm.ShareReference{Spec: &ocm.ShareReference_Id{Id: &ocm.ShareId{OpaqueId: "1"}}},
@ -359,7 +359,7 @@ func TestGetShare(t *testing.T) {
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
Expiration: &typesv1beta1.Timestamp{},
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions())},
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{})},
},
},
{
@ -376,7 +376,7 @@ func TestGetShare(t *testing.T) {
Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468},
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions())},
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{})},
},
},
query: &ocm.ShareReference{
@ -396,7 +396,7 @@ func TestGetShare(t *testing.T) {
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
Expiration: &typesv1beta1.Timestamp{},
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions())},
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{})},
},
},
{
@ -413,7 +413,7 @@ func TestGetShare(t *testing.T) {
Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468},
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions())},
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{})},
},
},
query: &ocm.ShareReference{
@ -437,7 +437,7 @@ func TestGetShare(t *testing.T) {
Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468},
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions())},
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{})},
},
},
query: &ocm.ShareReference{
@ -462,7 +462,7 @@ func TestGetShare(t *testing.T) {
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
Expiration: &typesv1beta1.Timestamp{},
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions())},
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{})},
},
},
{
@ -479,7 +479,7 @@ func TestGetShare(t *testing.T) {
Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468},
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions())},
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{})},
},
},
query: &ocm.ShareReference{
@ -508,7 +508,7 @@ func TestGetShare(t *testing.T) {
Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468},
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions())},
AccessMethods: []*ocm.AccessMethod{share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{})},
},
},
query: &ocm.ShareReference{
@ -538,7 +538,7 @@ func TestGetShare(t *testing.T) {
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
share.NewTransferAccessMethod(),
},
@ -559,7 +559,7 @@ func TestGetShare(t *testing.T) {
ShareType: ocm.ShareType_SHARE_TYPE_USER,
Expiration: &typesv1beta1.Timestamp{},
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
share.NewTransferAccessMethod(),
},
@ -580,7 +580,7 @@ func TestGetShare(t *testing.T) {
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
share.NewTransferAccessMethod(),
},
@ -601,7 +601,7 @@ func TestGetShare(t *testing.T) {
ShareType: ocm.ShareType_SHARE_TYPE_USER,
Expiration: &typesv1beta1.Timestamp{},
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
share.NewTransferAccessMethod(),
},
@ -671,7 +671,7 @@ func TestListShares(t *testing.T) {
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
share.NewTransferAccessMethod(),
},
@ -693,7 +693,7 @@ func TestListShares(t *testing.T) {
ShareType: ocm.ShareType_SHARE_TYPE_USER,
Expiration: &typesv1beta1.Timestamp{},
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
share.NewTransferAccessMethod(),
},
@ -715,7 +715,7 @@ func TestListShares(t *testing.T) {
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
share.NewTransferAccessMethod(),
},
@ -732,7 +732,7 @@ func TestListShares(t *testing.T) {
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
},
},
},
@ -752,7 +752,7 @@ func TestListShares(t *testing.T) {
ShareType: ocm.ShareType_SHARE_TYPE_USER,
Expiration: &typesv1beta1.Timestamp{},
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
share.NewTransferAccessMethod(),
},
@ -770,7 +770,7 @@ func TestListShares(t *testing.T) {
Expiration: &typesv1beta1.Timestamp{},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
},
},
},
@ -790,7 +790,7 @@ func TestListShares(t *testing.T) {
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
share.NewTransferAccessMethod(),
},
@ -807,7 +807,7 @@ func TestListShares(t *testing.T) {
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
},
},
},
@ -827,7 +827,7 @@ func TestListShares(t *testing.T) {
ShareType: ocm.ShareType_SHARE_TYPE_USER,
Expiration: &typesv1beta1.Timestamp{},
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
},
},
},
@ -847,7 +847,7 @@ func TestListShares(t *testing.T) {
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
share.NewTransferAccessMethod(),
},
@ -864,7 +864,7 @@ func TestListShares(t *testing.T) {
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
},
},
},
@ -891,7 +891,7 @@ func TestListShares(t *testing.T) {
ShareType: ocm.ShareType_SHARE_TYPE_USER,
Expiration: &typesv1beta1.Timestamp{},
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
},
},
},
@ -911,7 +911,7 @@ func TestListShares(t *testing.T) {
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
share.NewTransferAccessMethod(),
},
@ -928,7 +928,7 @@ func TestListShares(t *testing.T) {
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
},
},
},
@ -958,7 +958,7 @@ func TestListShares(t *testing.T) {
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
share.NewTransferAccessMethod(),
},
@ -975,7 +975,7 @@ func TestListShares(t *testing.T) {
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
},
},
{
@ -990,7 +990,7 @@ func TestListShares(t *testing.T) {
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
},
},
},
@ -1023,7 +1023,7 @@ func TestListShares(t *testing.T) {
ShareType: ocm.ShareType_SHARE_TYPE_USER,
Expiration: &typesv1beta1.Timestamp{},
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
share.NewTransferAccessMethod(),
},
@ -1041,7 +1041,7 @@ func TestListShares(t *testing.T) {
ShareType: ocm.ShareType_SHARE_TYPE_USER,
Expiration: &typesv1beta1.Timestamp{},
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
},
},
},
@ -1140,7 +1140,7 @@ func TestStoreShare(t *testing.T) {
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
},
},
@ -1169,7 +1169,7 @@ func TestStoreShare(t *testing.T) {
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
},
},
},
@ -1184,7 +1184,7 @@ func TestStoreShare(t *testing.T) {
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
},
},
expected: storeShareExpected{
@ -1218,7 +1218,7 @@ func TestStoreShare(t *testing.T) {
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
},
},
},
@ -1233,7 +1233,7 @@ func TestStoreShare(t *testing.T) {
Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
},
},
err: share.ErrShareAlreadyExisting,
@ -1297,7 +1297,7 @@ func TestUpdateShare(t *testing.T) {
Mtime: &typesv1beta1.Timestamp{Seconds: 1686061921},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
},
},
@ -1330,7 +1330,7 @@ func TestUpdateShare(t *testing.T) {
Mtime: &typesv1beta1.Timestamp{Seconds: 1686061921},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
},
},
@ -1340,7 +1340,7 @@ func TestUpdateShare(t *testing.T) {
fields: []*ocm.UpdateOCMShareRequest_UpdateField{
{
Field: &ocm.UpdateOCMShareRequest_UpdateField_AccessMethods{
AccessMethods: share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
AccessMethods: share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
},
},
{
@ -1374,7 +1374,7 @@ func TestUpdateShare(t *testing.T) {
Mtime: &typesv1beta1.Timestamp{Seconds: 1686061921},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
},
},
@ -1411,7 +1411,7 @@ func TestUpdateShare(t *testing.T) {
Mtime: &typesv1beta1.Timestamp{Seconds: 1686061921},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
},
},
@ -1425,7 +1425,7 @@ func TestUpdateShare(t *testing.T) {
fields: []*ocm.UpdateOCMShareRequest_UpdateField{
{
Field: &ocm.UpdateOCMShareRequest_UpdateField_AccessMethods{
AccessMethods: share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
AccessMethods: share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
},
},
{
@ -1459,7 +1459,7 @@ func TestUpdateShare(t *testing.T) {
Mtime: &typesv1beta1.Timestamp{Seconds: 1686061921},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
},
},
@ -1484,7 +1484,7 @@ func TestUpdateShare(t *testing.T) {
Mtime: &typesv1beta1.Timestamp{Seconds: 1686061921},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
share.NewWebappAccessMethod(appprovider.ViewMode_VIEW_MODE_READ_ONLY),
},
},
@ -1498,7 +1498,7 @@ func TestUpdateShare(t *testing.T) {
fields: []*ocm.UpdateOCMShareRequest_UpdateField{
{
Field: &ocm.UpdateOCMShareRequest_UpdateField_AccessMethods{
AccessMethods: share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
AccessMethods: share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
},
},
{
@ -1579,7 +1579,7 @@ func TestGetReceivedShare(t *testing.T) {
Protocols: []*ocm.Protocol{
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
}),
}, []string{}),
},
},
},
@ -1601,7 +1601,7 @@ func TestGetReceivedShare(t *testing.T) {
Protocols: []*ocm.Protocol{
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
}),
}, []string{}),
},
},
},
@ -1623,7 +1623,7 @@ func TestGetReceivedShare(t *testing.T) {
Protocols: []*ocm.Protocol{
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
}),
}, []string{}),
},
},
},
@ -1649,7 +1649,7 @@ func TestGetReceivedShare(t *testing.T) {
Protocols: []*ocm.Protocol{
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
}),
}, []string{}),
share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234", appprovider.ViewMode_VIEW_MODE_READ_WRITE),
share.NewTransferProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", 10),
},
@ -1673,7 +1673,7 @@ func TestGetReceivedShare(t *testing.T) {
Protocols: []*ocm.Protocol{
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
}),
}, []string{}),
share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234", appprovider.ViewMode_VIEW_MODE_READ_WRITE),
share.NewTransferProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", 10),
},
@ -1743,7 +1743,7 @@ func TestUpdateReceivedShare(t *testing.T) {
Protocols: []*ocm.Protocol{
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
}),
}, []string{}),
},
},
},
@ -1779,7 +1779,7 @@ func TestUpdateReceivedShare(t *testing.T) {
Protocols: []*ocm.Protocol{
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
}),
}, []string{}),
},
},
},
@ -1855,7 +1855,7 @@ func TestListReceviedShares(t *testing.T) {
Protocols: []*ocm.Protocol{
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
}),
}, []string{}),
share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234", appprovider.ViewMode_VIEW_MODE_READ_WRITE),
share.NewTransferProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", 10),
},
@ -1879,7 +1879,7 @@ func TestListReceviedShares(t *testing.T) {
Protocols: []*ocm.Protocol{
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
}),
}, []string{}),
share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234", appprovider.ViewMode_VIEW_MODE_READ_WRITE),
share.NewTransferProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", 10),
},
@ -1904,7 +1904,7 @@ func TestListReceviedShares(t *testing.T) {
Protocols: []*ocm.Protocol{
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
}),
}, []string{}),
share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234", appprovider.ViewMode_VIEW_MODE_READ_WRITE),
share.NewTransferProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", 10),
},
@ -1944,7 +1944,7 @@ func TestListReceviedShares(t *testing.T) {
Protocols: []*ocm.Protocol{
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
}),
}, []string{}),
share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234", appprovider.ViewMode_VIEW_MODE_READ_WRITE),
share.NewTransferProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", 10),
},
@ -1986,7 +1986,7 @@ func TestListReceviedShares(t *testing.T) {
Protocols: []*ocm.Protocol{
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
}),
}, []string{}),
share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234", appprovider.ViewMode_VIEW_MODE_READ_WRITE),
share.NewTransferProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", 10),
},
@ -2026,7 +2026,7 @@ func TestListReceviedShares(t *testing.T) {
Protocols: []*ocm.Protocol{
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
}),
}, []string{}),
share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234", appprovider.ViewMode_VIEW_MODE_READ_WRITE),
share.NewTransferProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", 10),
},
@ -2106,7 +2106,7 @@ func TestStoreReceivedShare(t *testing.T) {
Protocols: []*ocm.Protocol{
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
}),
}, []string{}),
},
},
expected: storeReceivedShareExpected{
@ -2135,7 +2135,7 @@ func TestStoreReceivedShare(t *testing.T) {
Protocols: []*ocm.Protocol{
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
}),
}, []string{}),
},
},
},
@ -2153,7 +2153,7 @@ func TestStoreReceivedShare(t *testing.T) {
Protocols: []*ocm.Protocol{
share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{
Permissions: conversions.NewEditorRole().CS3ResourcePermissions(),
}),
}, []string{}),
share.NewTransferProtocol("https://transfer.cernbox.cern.ch/ocm/1234", "secret", 100),
share.NewWebappProtocol("https://app.cernbox.cern.ch/ocm/1234", appprovider.ViewMode_VIEW_MODE_READ_WRITE),
},

View File

@ -25,25 +25,26 @@ import (
)
// NewWebDAVProtocol is an abstraction for creating a WebDAV protocol.
func NewWebDAVProtocol(uri, sharedSecret string, perms *ocm.SharePermissions) *ocm.Protocol {
func NewWebDAVProtocol(uri, sharedSecret string, perms *ocm.SharePermissions, reqs []string) *ocm.Protocol {
return &ocm.Protocol{
Term: &ocm.Protocol_WebdavOptions{
WebdavOptions: &ocm.WebDAVProtocol{
Uri: uri,
SharedSecret: sharedSecret,
Permissions: perms,
Requirements: reqs,
},
},
}
}
// NewWebappProtocol is an abstraction for creating a Webapp protocol.
func NewWebappProtocol(uriTemplate string, viewMode appprovider.ViewMode) *ocm.Protocol {
func NewWebappProtocol(uri string, viewMode appprovider.ViewMode) *ocm.Protocol {
return &ocm.Protocol{
Term: &ocm.Protocol_WebappOptions{
WebappOptions: &ocm.WebappProtocol{
UriTemplate: uriTemplate,
ViewMode: viewMode,
Uri: uri,
ViewMode: viewMode,
},
},
}
@ -63,11 +64,12 @@ func NewTransferProtocol(sourceURI, sharedSecret string, size uint64) *ocm.Proto
}
// NewWebDavAccessMethod is an abstraction for creating a WebDAV access method.
func NewWebDavAccessMethod(perms *provider.ResourcePermissions) *ocm.AccessMethod {
func NewWebDavAccessMethod(perms *provider.ResourcePermissions, reqs []string) *ocm.AccessMethod {
return &ocm.AccessMethod{
Term: &ocm.AccessMethod_WebdavOptions{
WebdavOptions: &ocm.WebDAVAccessMethod{
Permissions: perms,
Permissions: perms,
Requirements: reqs,
},
},
}

View File

@ -26,6 +26,7 @@ import (
"net/url"
"path/filepath"
"strings"
"time"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
@ -43,15 +44,22 @@ import (
"github.com/cs3org/reva/pkg/storage/fs/registry"
"github.com/cs3org/reva/pkg/utils/cfg"
"github.com/studio-b12/gowebdav"
"github.com/ReneKroon/ttlcache/v2"
)
func init() {
registry.Register("ocmreceived", New)
}
type cachedClient struct {
client *gowebdav.Client
share *ocmpb.ReceivedShare
}
type driver struct {
c *config
gateway gateway.GatewayAPIClient
ccache *ttlcache.Cache
}
type config struct {
@ -78,8 +86,8 @@ func New(ctx context.Context, m map[string]interface{}) (storage.FS, error) {
d := &driver{
c: &c,
gateway: gateway,
ccache: ttlcache.NewCache(), // this is a cache of webdav clients
}
return d, nil
}
@ -106,7 +114,6 @@ func shareInfoFromReference(ref *provider.Reference) (*ocmpb.ShareId, string) {
}
func (d *driver) getWebDAVFromShare(ctx context.Context, shareID *ocmpb.ShareId) (*ocmpb.ReceivedShare, string, string, error) {
// TODO: we may want to cache the share
res, err := d.gateway.GetReceivedOCMShare(ctx, &ocmpb.GetReceivedOCMShareRequest{
Ref: &ocmpb.ShareReference{
Spec: &ocmpb.ShareReference_Id{
@ -143,13 +150,21 @@ func getWebDAVProtocol(protocols []*ocmpb.Protocol) (*ocmpb.WebDAVProtocol, bool
}
func (d *driver) webdavClient(ctx context.Context, ref *provider.Reference) (*gowebdav.Client, *ocmpb.ReceivedShare, string, error) {
log := appctx.GetLogger(ctx)
id, rel := shareInfoFromReference(ref)
// check first if we have a cached webdav client
if entry, err := d.ccache.Get(id.OpaqueId); err == nil {
cc := entry.(*cachedClient)
log.Info().Interface("share", cc.share).Str("rel", rel).Msg("accessing OCM share via cached client")
return cc.client, cc.share, rel, nil
}
// we don't, build a webdav client
share, endpoint, secret, err := d.getWebDAVFromShare(ctx, id)
if err != nil {
return nil, nil, "", err
}
endpoint, err = url.PathUnescape(endpoint)
if err != nil {
return nil, nil, "", err
@ -158,9 +173,20 @@ func (d *driver) webdavClient(ctx context.Context, ref *provider.Reference) (*go
// use the secret as bearer authentication according to OCM v1.1+
c := gowebdav.NewClient(endpoint, "", "")
c.SetHeader("Authorization", "Bearer "+secret)
_, err = c.Stat(rel)
if err != nil {
// if we got an error, try to use OCM v1.0 basic auth
log.Info().Str("endpoint", endpoint).Interface("share", share).Str("rel", rel).Str("secret", secret).Err(err).Msg("falling back to OCM v1.0 access")
c.SetHeader("Authorization", "Basic "+secret+":")
} else {
log.Info().Str("endpoint", endpoint).Interface("share", share).Str("rel", rel).Str("secret", secret).Msg("using OCM v1.1 access")
}
log := appctx.GetLogger(ctx)
log.Info().Str("endpoint", endpoint).Interface("share", share).Str("rel", rel).Str("secret", secret).Msg("Accessing OCM share")
// add to cache and return
d.ccache.SetWithTTL(id.OpaqueId, &cachedClient{
client: c,
share: share,
}, time.Hour)
return c, share, rel, nil
}

View File

@ -162,6 +162,7 @@ func getUser(ctx context.Context) (*userpb.User, error) {
}
func (fs *localfs) wrap(ctx context.Context, p string) string {
log := appctx.GetLogger(ctx)
// This is to prevent path traversal.
// With this p can't break out of its parent folder
p = path.Join("/", p)
@ -175,6 +176,7 @@ func (fs *localfs) wrap(ctx context.Context, p string) string {
} else {
internal = path.Join(fs.conf.DataDirectory, p)
}
log.Debug().Str("old", p).Str("wrapped", internal).Msg("localfs: wrap")
return internal
}
@ -842,6 +844,8 @@ func (fs *localfs) Delete(ctx context.Context, ref *provider.Reference) error {
}
func (fs *localfs) Move(ctx context.Context, oldRef, newRef *provider.Reference) error {
log := appctx.GetLogger(ctx)
log.Debug().Any("from", oldRef).Any("to", newRef).Msg("localfs: move")
oldName, err := fs.resolve(ctx, oldRef)
if err != nil {
return errors.Wrap(err, "localfs: error resolving ref")
@ -860,6 +864,7 @@ func (fs *localfs) Move(ctx context.Context, oldRef, newRef *provider.Reference)
newName = fs.wrap(ctx, newName)
if err := os.Rename(oldName, newName); err != nil {
log.Error().Err(err).Msg("localfs: error moving " + oldName + " to " + newName)
return errors.Wrap(err, "localfs: error moving "+oldName+" to "+newName)
}
@ -912,6 +917,7 @@ func (fs *localfs) moveReferences(ctx context.Context, oldName, newName string)
}
func (fs *localfs) GetMD(ctx context.Context, ref *provider.Reference, mdKeys []string) (*provider.ResourceInfo, error) {
log := appctx.GetLogger(ctx)
fn, err := fs.resolve(ctx, ref)
if err != nil {
return nil, errors.Wrap(err, "localfs: error resolving ref")
@ -926,6 +932,7 @@ func (fs *localfs) GetMD(ctx context.Context, ref *provider.Reference, mdKeys []
fn = fs.wrap(ctx, fn)
md, err := os.Stat(fn)
if err != nil {
log.Warn().Str("path", fn).Any("md", md).Err(err).Msg("failed stat call in localfs")
if os.IsNotExist(err) {
return nil, errtypes.NotFound(fn)
}
@ -952,6 +959,7 @@ func (fs *localfs) getMDShareFolder(ctx context.Context, p string, mdKeys []stri
}
func (fs *localfs) ListFolder(ctx context.Context, ref *provider.Reference, mdKeys []string) ([]*provider.ResourceInfo, error) {
log := appctx.GetLogger(ctx)
fn, err := fs.resolve(ctx, ref)
if err != nil {
return nil, errors.Wrap(err, "localfs: error resolving ref")
@ -960,6 +968,7 @@ func (fs *localfs) ListFolder(ctx context.Context, ref *provider.Reference, mdKe
if fn == "/" {
homeFiles, err := fs.listFolder(ctx, fn, mdKeys)
if err != nil {
log.Warn().Err(err).Msg("failed to execute listFolder for root")
return nil, err
}
if !fs.conf.DisableHome {
@ -973,14 +982,22 @@ func (fs *localfs) ListFolder(ctx context.Context, ref *provider.Reference, mdKe
}
if fs.isShareFolderRoot(ctx, fn) {
return fs.listShareFolderRoot(ctx, fn, mdKeys)
res, err := fs.listShareFolderRoot(ctx, fn, mdKeys)
if err != nil {
log.Warn().Str("fn", fn).Err(err).Msg("failed to execute listShareFolderRoot")
}
return res, err
}
if fs.isShareFolderChild(ctx, fn) {
return nil, errtypes.PermissionDenied("localfs: error listing folders inside the shared folder, only file references are stored inside")
}
return fs.listFolder(ctx, fn, mdKeys)
res, err := fs.listFolder(ctx, fn, mdKeys)
if err != nil {
log.Warn().Str("fn", fn).Err(err).Msg("failed to execute listFolder")
}
return res, err
}
func (fs *localfs) listFolder(ctx context.Context, fn string, mdKeys []string) ([]*provider.ResourceInfo, error) {
@ -1050,7 +1067,10 @@ func (fs *localfs) listShareFolderRoot(ctx context.Context, home string, mdKeys
func (fs *localfs) Download(ctx context.Context, ref *provider.Reference) (io.ReadCloser, error) {
fn, err := fs.resolve(ctx, ref)
log := appctx.GetLogger(ctx)
if err != nil {
log.Error().Err(err).Any("ref", ref).Msg("localfs: error resolving ref")
return nil, errors.Wrap(err, "localfs: error resolving ref")
}
@ -1062,8 +1082,10 @@ func (fs *localfs) Download(ctx context.Context, ref *provider.Reference) (io.Re
r, err := os.Open(fn)
if err != nil {
if os.IsNotExist(err) {
log.Error().Err(err).Str("path", fn).Msg("localfs: file not found")
return nil, errtypes.NotFound(fn)
}
log.Error().Err(err).Str("path", fn).Msg("localfs: error opening file")
return nil, errors.Wrap(err, "localfs: error reading "+fn)
}
return r, nil

View File

@ -40,7 +40,9 @@ import (
var defaultFilePerm = os.FileMode(0664)
func (fs *localfs) Upload(ctx context.Context, ref *provider.Reference, r io.ReadCloser, metadata map[string]string) error {
log := appctx.GetLogger(ctx)
upload, err := fs.GetUpload(ctx, ref.GetPath())
log.Info().Any("upload", upload).Msg("localfs: upload")
if err != nil {
return errors.Wrap(err, "localfs: error retrieving upload")
}
@ -156,6 +158,7 @@ func (fs *localfs) NewUpload(ctx context.Context, info tusd.FileInfo) (upload tu
info.ID = uuid.New().String()
binPath, err := fs.getUploadPath(ctx, info.ID)
log.Info().Str("upload-path", binPath).Err(err).Msg("localfs: got upload path")
if err != nil {
return nil, errors.Wrap(err, "localfs: error resolving upload path")
}
@ -307,6 +310,7 @@ func (upload *fileUpload) writeInfo() error {
// FinishUpload finishes an upload and moves the file to the internal destination.
func (upload *fileUpload) FinishUpload(ctx context.Context) error {
log := appctx.GetLogger(ctx)
np := upload.info.Storage["InternalDestination"]
// TODO check etag with If-Match header
@ -318,6 +322,7 @@ func (upload *fileUpload) FinishUpload(ctx context.Context) error {
//}
// if destination exists
log.Info().Str("oldpath", upload.binPath).Str("newpath", np).Msg("localfs: FinishUpload")
if _, err := os.Stat(np); err == nil {
// create revision
if err := upload.fs.archiveRevision(upload.ctx, np); err != nil {
@ -327,6 +332,7 @@ func (upload *fileUpload) FinishUpload(ctx context.Context) error {
err := os.Rename(upload.binPath, np)
if err != nil {
log.Error().Msg("localfs: Failed to rename in FinishUpload")
return err
}

View File

@ -1,5 +1,4 @@
[log]
mode = "json"
[shared]
gatewaysvc = "{{grpc_address}}"

View File

@ -1,5 +1,4 @@
[log]
mode = "json"
[shared]
gatewaysvc = "{{cernboxgw_address}}"
@ -21,3 +20,12 @@ driver = "json"
[http.middlewares.providerauthorizer.drivers.json]
providers = "fixtures/ocm-providers.demo.json"
[http.services.wellknown]
[http.services.wellknown.ocmprovider]
ocm_prefix = "ocm"
provider = "Reva for CERNBox"
endpoint = "http://{{cernboxhttp_address}}"
enable_webapp = true
enable_datatx = true

View File

@ -1,5 +1,4 @@
[log]
mode = "json"
[shared]
gatewaysvc = "{{grpc_address}}"

View File

@ -1,5 +1,4 @@
[log]
mode = "json"
[shared]
gatewaysvc = "{{cesnetgw_address}}"
@ -21,3 +20,12 @@ driver = "json"
[http.middlewares.providerauthorizer.drivers.json]
providers = "fixtures/ocm-providers.demo.json"
[http.services.wellknown]
[http.services.wellknown.ocmprovider]
ocm_prefix = "ocm"
provider = "Reva for CESNET"
endpoint = "http://{{cesnethttp_address}}"
enable_webapp = true
enable_datatx = true

View File

@ -1,5 +1,4 @@
[log]
mode = "json"
[shared]
gatewaysvc = "{{cernboxgw_address}}"

View File

@ -1,5 +1,4 @@
[log]
mode = "json"
[shared]
gatewaysvc = "{{cernboxgw_address}}"

View File

@ -1,5 +1,4 @@
[log]
mode = "json"
[shared]
gatewaysvc = "{{cernboxgw_address}}"

View File

@ -1,5 +1,4 @@
[log]
mode = "json"
[shared]
gatewaysvc = "{{cernboxgw_address}}"
@ -19,4 +18,4 @@ machine_secret = "secret"
[grpc.services.authprovider]
auth_manager = "ocmshares"
[grpc.services.authprovider.auth_managers.ocmshares]
[grpc.services.authprovider.auth_managers.ocmshares]

View File

@ -1,5 +1,4 @@
[log]
mode = "json"
[shared]
gatewaysvc = "{{grpc_address}}"
@ -39,6 +38,7 @@ driver = "static"
[grpc.services.authregistry.drivers.static.rules]
basic = "{{grpc_address}}"
bearer = "{{grpc_address}}"
ocmshares = "{{cernboxoutcomingocm_address}}"
machine = "{{cernboxmachineauth_address}}"

View File

@ -1,5 +1,4 @@
[log]
mode = "json"
[shared]
gatewaysvc = "{{cernboxgw_address}}"
@ -14,6 +13,10 @@ provider_domain = "{{cernboxhttp_address}}"
mesh_directory_url = "http://meshdir"
smtp_credentials = {}
[http.middlewares.auth]
credential_chain = ["publicshares", "basic", "bearer"]
token_strategy_chain = ["bearer", "header"]
[http.middlewares.cors]
[http.middlewares.providerauthorizer]
@ -31,3 +34,11 @@ driver = "localhome"
root = "{{localhome_root}}"
[http.services.ocdav]
[http.services.wellknown]
[http.services.wellknown.ocmprovider]
ocm_prefix = "ocm"
provider = "Reva for CERNBox"
endpoint = "http://{{cernboxhttp_address}}"
enable_webapp = true
enable_datatx = true

View File

@ -1,5 +1,4 @@
[log]
mode = "json"
[shared]
gatewaysvc = "{{grpc_address}}"

View File

@ -1,5 +1,4 @@
[log]
mode = "json"
[shared]
gatewaysvc = "{{cesnetgw_address}}"
@ -28,3 +27,11 @@ providers = "fixtures/ocm-providers.demo.json"
driver = "ocmreceived"
[http.services.dataprovider.drivers.ocmreceived]
[http.services.wellknown]
[http.services.wellknown.ocmprovider]
ocm_prefix = "ocm"
provider = "Reva for CESNET"
endpoint = "http://{{cesnethttp_address}}"
enable_webapp = true
enable_datatx = true

View File

@ -1,3 +1,5 @@
[log]
[grpc]
address = "{{grpc_address}}"

View File

@ -1,3 +1,5 @@
[log]
[grpc]
address = "{{grpc_address}}"
@ -9,4 +11,4 @@ root = "{{root}}"
treetime_accounting = true
treesize_accounting = true
enable_home = true
userprovidersvc = "localhost:18000"
userprovidersvc = "localhost:18000"

View File

@ -1,3 +1,5 @@
[log]
[grpc]
address = "{{grpc_address}}"

View File

@ -197,7 +197,7 @@ var _ = Describe("ocm share", func() {
},
},
AccessMethods: []*ocmv1beta1.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
},
RecipientMeshProvider: cesnet.ProviderInfo,
})
@ -278,7 +278,7 @@ var _ = Describe("ocm share", func() {
},
},
AccessMethods: []*ocmv1beta1.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
},
RecipientMeshProvider: cesnet.ProviderInfo,
})
@ -374,7 +374,7 @@ var _ = Describe("ocm share", func() {
},
},
AccessMethods: []*ocmv1beta1.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewViewerRole().CS3ResourcePermissions(), []string{}),
},
RecipientMeshProvider: cesnet.ProviderInfo,
})
@ -477,7 +477,7 @@ var _ = Describe("ocm share", func() {
},
},
AccessMethods: []*ocmv1beta1.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
},
RecipientMeshProvider: cesnet.ProviderInfo,
})
@ -626,7 +626,7 @@ var _ = Describe("ocm share", func() {
},
},
AccessMethods: []*ocmv1beta1.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
},
RecipientMeshProvider: cesnet.ProviderInfo,
})
@ -643,7 +643,7 @@ var _ = Describe("ocm share", func() {
},
},
AccessMethods: []*ocmv1beta1.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
},
RecipientMeshProvider: cesnet.ProviderInfo,
})
@ -668,7 +668,7 @@ var _ = Describe("ocm share", func() {
},
},
AccessMethods: []*ocmv1beta1.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions()),
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{}),
},
RecipientMeshProvider: cesnet.ProviderInfo,
})
@ -677,6 +677,40 @@ var _ = Describe("ocm share", func() {
})
})
Context("einstein creates a share with a requirement that cannot be met", func() {
It("fail with bad request error", func() {
fileToShare := &provider.Reference{
Path: "/home/file-with-req",
}
By("creating a file")
Expect(helpers.CreateFile(ctxEinstein, cernboxgw, fileToShare.Path, []byte("test"))).To(Succeed())
By("share the file with marie")
info, err := stat(ctxEinstein, cernboxgw, fileToShare)
Expect(err).ToNot(HaveOccurred())
cesnet, err := cernboxgw.GetInfoByDomain(ctxEinstein, &ocmproviderpb.GetInfoByDomainRequest{
Domain: "cesnet.cz",
})
Expect(err).ToNot(HaveOccurred())
Expect(cesnet.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
createShareRes, err := cernboxgw.CreateOCMShare(ctxEinstein, &ocmv1beta1.CreateOCMShareRequest{
ResourceId: info.Id,
Grantee: &provider.Grantee{
Id: &provider.Grantee_UserId{
UserId: marie.Id,
},
},
AccessMethods: []*ocmv1beta1.AccessMethod{
share.NewWebDavAccessMethod(conversions.NewEditorRole().CS3ResourcePermissions(), []string{"unsupported-requirement"}),
},
RecipientMeshProvider: cesnet.ProviderInfo,
})
Expect(err).ToNot(HaveOccurred())
Expect(createShareRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_INVALID_ARGUMENT))
})
})
})
})