github.com/cs3org/reva/v2@v2.27.7/internal/http/services/sciencemesh/share.go (about) 1 // Copyright 2018-2023 CERN 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // In applying this license, CERN does not waive the privileges and immunities 16 // granted to it by virtue of its status as an Intergovernmental Organization 17 // or submit itself to any jurisdiction. 18 19 package sciencemesh 20 21 import ( 22 "encoding/json" 23 "errors" 24 "mime" 25 "net/http" 26 27 appprovider "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1" 28 gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" 29 userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" 30 ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1" 31 rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" 32 ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1" 33 providerpb "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" 34 "github.com/cs3org/reva/v2/internal/http/services/reqres" 35 "github.com/cs3org/reva/v2/pkg/appctx" 36 "github.com/cs3org/reva/v2/pkg/conversions" 37 "github.com/cs3org/reva/v2/pkg/ocm/share" 38 "github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool" 39 "github.com/go-playground/validator/v10" 40 ) 41 42 var validate = validator.New() 43 44 type sharesHandler struct { 45 gatewayClient gateway.GatewayAPIClient 46 } 47 48 func (h *sharesHandler) init(c *config) error { 49 var err error 50 h.gatewayClient, err = pool.GetGatewayServiceClient(c.GatewaySvc) 51 return err 52 } 53 54 type createShareRequest struct { 55 SourcePath string `json:"sourcePath" validate:"required"` 56 TargetPath string `json:"targetPath" validate:"required"` 57 Type string `json:"type"` 58 Role string `json:"role" validate:"oneof=viewer editor"` 59 RecipientUsername string `json:"recipientUsername" validate:"required"` 60 RecipientHost string `json:"recipientHost" validate:"required"` 61 } 62 63 // CreateShare creates an OCM share. 64 func (h *sharesHandler) CreateShare(w http.ResponseWriter, r *http.Request) { 65 log := appctx.GetLogger(r.Context()) 66 67 req, err := getCreateShareRequest(r) 68 if err != nil { 69 reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "invalid parameters", err) 70 return 71 } 72 73 ctx := r.Context() 74 75 statRes, err := h.gatewayClient.Stat(ctx, &providerpb.StatRequest{ 76 Ref: &providerpb.Reference{ 77 Path: req.SourcePath, 78 }, 79 }) 80 switch { 81 case err != nil: 82 reqres.WriteError(w, r, reqres.APIErrorServerError, "unexpected error", err) 83 return 84 case statRes.Status.Code == rpc.Code_CODE_NOT_FOUND: 85 reqres.WriteError(w, r, reqres.APIErrorNotFound, statRes.Status.Message, nil) 86 return 87 case statRes.Status.Code != rpc.Code_CODE_OK: 88 reqres.WriteError(w, r, reqres.APIErrorServerError, statRes.Status.Message, errors.New(statRes.Status.Message)) 89 return 90 } 91 92 recipientProviderInfo, err := h.gatewayClient.GetInfoByDomain(ctx, &ocmprovider.GetInfoByDomainRequest{ 93 Domain: req.RecipientHost, 94 }) 95 if err != nil { 96 reqres.WriteError(w, r, reqres.APIErrorServerError, "error sending a grpc get invite by domain info request", err) 97 return 98 } 99 if recipientProviderInfo.Status.Code != rpc.Code_CODE_OK { 100 reqres.WriteError(w, r, reqres.APIErrorNotFound, recipientProviderInfo.Status.Message, errors.New(recipientProviderInfo.Status.Message)) 101 return 102 } 103 104 perm, viewMode := getPermissionsByRole(req.Role) 105 106 log.Debug().Msg("calling gatewayClient.CreateOCMShare from sciencemesh/share.go") 107 shareRes, err := h.gatewayClient.CreateOCMShare(ctx, &ocm.CreateOCMShareRequest{ 108 ResourceId: statRes.Info.Id, 109 Grantee: &providerpb.Grantee{ 110 Type: providerpb.GranteeType_GRANTEE_TYPE_USER, 111 Id: &providerpb.Grantee_UserId{ 112 UserId: &userpb.UserId{ 113 Idp: req.RecipientHost, 114 OpaqueId: req.RecipientUsername, 115 }, 116 }, 117 }, 118 RecipientMeshProvider: recipientProviderInfo.ProviderInfo, 119 AccessMethods: []*ocm.AccessMethod{ 120 share.NewWebDavAccessMethod(perm), 121 share.NewWebappAccessMethod(viewMode), 122 }, 123 }) 124 log.Debug().Msg("called gatewayClient.CreateOCMShare from sciencemesh/share.go") 125 126 switch { 127 case err != nil: 128 reqres.WriteError(w, r, reqres.APIErrorServerError, "error sending a grpc CreateOCMShare", err) 129 return 130 case shareRes.Status.Code == rpc.Code_CODE_NOT_FOUND: 131 reqres.WriteError(w, r, reqres.APIErrorNotFound, shareRes.Status.Message, nil) 132 return 133 case shareRes.Status.Code == rpc.Code_CODE_ALREADY_EXISTS: 134 reqres.WriteError(w, r, reqres.APIErrorAlreadyExist, shareRes.Status.Message, nil) 135 return 136 case shareRes.Status.Code != rpc.Code_CODE_OK: 137 reqres.WriteError(w, r, reqres.APIErrorAlreadyExist, shareRes.Status.Message, errors.New(shareRes.Status.Message)) 138 return 139 } 140 141 if err := json.NewEncoder(w).Encode(shareRes); err != nil { 142 log.Error().Err(err).Msg("error encoding response") 143 w.WriteHeader(http.StatusInternalServerError) 144 return 145 } 146 147 w.WriteHeader(http.StatusOK) 148 } 149 150 func getPermissionsByRole(role string) (*providerpb.ResourcePermissions, appprovider.ViewMode) { 151 switch role { 152 case "viewer": 153 return conversions.NewViewerRole().CS3ResourcePermissions(), appprovider.ViewMode_VIEW_MODE_READ_ONLY 154 case "editor": 155 return conversions.NewEditorRole().CS3ResourcePermissions(), appprovider.ViewMode_VIEW_MODE_READ_WRITE 156 } 157 return nil, 0 158 } 159 160 func getCreateShareRequest(r *http.Request) (*createShareRequest, error) { 161 var req createShareRequest 162 contentType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) 163 if err == nil && contentType == "application/json" { 164 if err := json.NewDecoder(r.Body).Decode(&req); err != nil { 165 return nil, err 166 } 167 } else { 168 return nil, errors.New("body request not recognised") 169 } 170 // set defaults 171 if req.Type == "" { 172 req.Type = "viewer" 173 } 174 // validate the request 175 if err := validate.Struct(req); err != nil { 176 return nil, err 177 } 178 return &req, nil 179 }