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, &notFound) {
   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, &notFound) {
   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  }