github.com/cs3org/reva/v2@v2.27.7/internal/grpc/services/ocmcore/ocmcore.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 ocmcore 20 21 import ( 22 "context" 23 "errors" 24 "fmt" 25 "time" 26 27 userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" 28 ocmcore "github.com/cs3org/go-cs3apis/cs3/ocm/core/v1beta1" 29 ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1" 30 providerpb "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" 31 typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" 32 "github.com/cs3org/reva/v2/pkg/errtypes" 33 "github.com/cs3org/reva/v2/pkg/ocm/share" 34 "github.com/cs3org/reva/v2/pkg/ocm/share/repository/registry" 35 ocmuser "github.com/cs3org/reva/v2/pkg/ocm/user" 36 "github.com/cs3org/reva/v2/pkg/rgrpc" 37 "github.com/cs3org/reva/v2/pkg/rgrpc/status" 38 "github.com/cs3org/reva/v2/pkg/utils" 39 "github.com/cs3org/reva/v2/pkg/utils/cfg" 40 "github.com/rs/zerolog" 41 "google.golang.org/grpc" 42 "google.golang.org/protobuf/types/known/fieldmaskpb" 43 ) 44 45 func init() { 46 rgrpc.Register("ocmcore", New) 47 } 48 49 type config struct { 50 Driver string `mapstructure:"driver"` 51 Drivers map[string]map[string]interface{} `mapstructure:"drivers"` 52 } 53 54 type service struct { 55 conf *config 56 repo share.Repository 57 } 58 59 func (c *config) ApplyDefaults() { 60 if c.Driver == "" { 61 c.Driver = "json" 62 } 63 } 64 65 func (s *service) Register(ss *grpc.Server) { 66 ocmcore.RegisterOcmCoreAPIServer(ss, s) 67 } 68 69 func getShareRepository(c *config) (share.Repository, error) { 70 if f, ok := registry.NewFuncs[c.Driver]; ok { 71 return f(c.Drivers[c.Driver]) 72 } 73 return nil, errtypes.NotFound(fmt.Sprintf("driver not found: %s", c.Driver)) 74 } 75 76 // New creates a new ocm core svc. 77 func New(m map[string]interface{}, ss *grpc.Server, _ *zerolog.Logger) (rgrpc.Service, error) { 78 var c config 79 if err := cfg.Decode(m, &c); err != nil { 80 return nil, err 81 } 82 83 repo, err := getShareRepository(&c) 84 if err != nil { 85 return nil, err 86 } 87 88 service := &service{ 89 conf: &c, 90 repo: repo, 91 } 92 93 return service, nil 94 } 95 96 func (s *service) Close() error { 97 return nil 98 } 99 100 func (s *service) UnprotectedEndpoints() []string { 101 return []string{ 102 ocmcore.OcmCoreAPI_CreateOCMCoreShare_FullMethodName, 103 ocmcore.OcmCoreAPI_UpdateOCMCoreShare_FullMethodName, 104 ocmcore.OcmCoreAPI_DeleteOCMCoreShare_FullMethodName, 105 } 106 } 107 108 // CreateOCMCoreShare is called when an OCM request comes into this reva instance from. 109 func (s *service) CreateOCMCoreShare(ctx context.Context, req *ocmcore.CreateOCMCoreShareRequest) (*ocmcore.CreateOCMCoreShareResponse, error) { 110 if req.ShareType != ocm.ShareType_SHARE_TYPE_USER { 111 return nil, errtypes.NotSupported("share type not supported") 112 } 113 114 now := &typesv1beta1.Timestamp{ 115 Seconds: uint64(time.Now().Unix()), 116 } 117 118 share, err := s.repo.StoreReceivedShare(ctx, &ocm.ReceivedShare{ 119 RemoteShareId: req.ResourceId, 120 Name: req.Name, 121 Grantee: &providerpb.Grantee{ 122 Type: providerpb.GranteeType_GRANTEE_TYPE_USER, 123 Id: &providerpb.Grantee_UserId{ 124 UserId: req.ShareWith, 125 }, 126 }, 127 ResourceType: req.ResourceType, 128 ShareType: req.ShareType, 129 Owner: req.Owner, 130 Creator: req.Sender, 131 Protocols: req.Protocols, 132 Ctime: now, 133 Mtime: now, 134 Expiration: req.Expiration, 135 State: ocm.ShareState_SHARE_STATE_PENDING, 136 }) 137 if err != nil { 138 // TODO: identify errors 139 return &ocmcore.CreateOCMCoreShareResponse{ 140 Status: status.NewInternal(ctx, err.Error()), 141 }, nil 142 } 143 144 return &ocmcore.CreateOCMCoreShareResponse{ 145 Status: status.NewOK(ctx), 146 Id: share.Id.OpaqueId, 147 Created: share.Ctime, 148 }, nil 149 } 150 151 func (s *service) UpdateOCMCoreShare(ctx context.Context, req *ocmcore.UpdateOCMCoreShareRequest) (*ocmcore.UpdateOCMCoreShareResponse, error) { 152 grantee := utils.ReadPlainFromOpaque(req.GetOpaque(), "grantee") 153 if grantee == "" { 154 return nil, errtypes.UserRequired("missing remote user id in a metadata") 155 } 156 if req == nil || len(req.Protocols) == 0 { 157 return nil, errtypes.PreconditionFailed("missing protocols in a request") 158 } 159 fileMask := &fieldmaskpb.FieldMask{Paths: []string{"protocols"}} 160 161 user := &userpb.User{Id: ocmuser.RemoteID(&userpb.UserId{OpaqueId: grantee})} 162 _, err := s.repo.UpdateReceivedShare(ctx, user, &ocm.ReceivedShare{ 163 Id: &ocm.ShareId{ 164 OpaqueId: req.GetOcmShareId(), 165 }, 166 Protocols: req.Protocols, 167 }, fileMask) 168 res := &ocmcore.UpdateOCMCoreShareResponse{} 169 if err == nil { 170 res.Status = status.NewOK(ctx) 171 } else { 172 var notFound errtypes.NotFound 173 if errors.As(err, ¬Found) { 174 res.Status = status.NewNotFound(ctx, "remote ocm share not found") 175 } else { 176 res.Status = status.NewInternal(ctx, "error deleting remote ocm share") 177 } 178 } 179 return res, nil 180 } 181 182 func (s *service) DeleteOCMCoreShare(ctx context.Context, req *ocmcore.DeleteOCMCoreShareRequest) (*ocmcore.DeleteOCMCoreShareResponse, error) { 183 grantee := utils.ReadPlainFromOpaque(req.GetOpaque(), "grantee") 184 if grantee == "" { 185 return nil, errtypes.UserRequired("missing remote user id in a metadata") 186 } 187 188 user := &userpb.User{Id: ocmuser.RemoteID(&userpb.UserId{OpaqueId: grantee})} 189 190 err := s.repo.DeleteReceivedShare(ctx, user, &ocm.ShareReference{ 191 Spec: &ocm.ShareReference_Id{ 192 Id: &ocm.ShareId{ 193 OpaqueId: req.GetId(), 194 }, 195 }, 196 }) 197 res := &ocmcore.DeleteOCMCoreShareResponse{} 198 if err == nil { 199 res.Status = status.NewOK(ctx) 200 } else { 201 var notFound errtypes.NotFound 202 if errors.As(err, ¬Found) { 203 res.Status = status.NewNotFound(ctx, "remote ocm share not found") 204 } else { 205 res.Status = status.NewInternal(ctx, "error deleting remote ocm share") 206 } 207 } 208 return res, nil 209 }