mirror of
https://github.com/owncloud/ocis.git
synced 2025-04-18 23:44:07 +03:00
Add the ocm notification handler
This commit is contained in:
parent
ceca4111ec
commit
d828e82b7c
2
.gitignore
vendored
2
.gitignore
vendored
@ -38,7 +38,7 @@ vendor-php
|
||||
# API acceptance tests - auto-generated files
|
||||
.php-cs-fixer.cache
|
||||
|
||||
# QA activity reports
|
||||
# QA activity reports
|
||||
tests/qa-activity-report/reports/
|
||||
|
||||
# drone CI is in .drone.star, do not let someone accidentally commit a local .drone.yml
|
||||
|
6
changelog/unreleased/add-ocm-notificatin-handler.md
Normal file
6
changelog/unreleased/add-ocm-notificatin-handler.md
Normal file
@ -0,0 +1,6 @@
|
||||
Enhancement: Add the ocm notification handler
|
||||
|
||||
Added the ocm notification handler that allows receiving a notification from a remote party about changes to a previously known entity.
|
||||
|
||||
https://github.com/owncloud/ocis/pull/11005
|
||||
https://github.com/owncloud/enterprise/issues/7075
|
2
go.mod
2
go.mod
@ -17,7 +17,7 @@ require (
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible
|
||||
github.com/coreos/go-oidc/v3 v3.11.0
|
||||
github.com/cs3org/go-cs3apis v0.0.0-20241105092511-3ad35d174fc1
|
||||
github.com/cs3org/reva/v2 v2.27.5-0.20250205144957-2a7145a1d4ad
|
||||
github.com/cs3org/reva/v2 v2.27.5-0.20250217133727-8aefc9e791f7
|
||||
github.com/davidbyttow/govips/v2 v2.16.0
|
||||
github.com/dhowden/tag v0.0.0-20240417053706-3d75831295e8
|
||||
github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e
|
||||
|
4
go.sum
4
go.sum
@ -251,8 +251,8 @@ github.com/crewjam/saml v0.4.14 h1:g9FBNx62osKusnFzs3QTN5L9CVA/Egfgm+stJShzw/c=
|
||||
github.com/crewjam/saml v0.4.14/go.mod h1:UVSZCf18jJkk6GpWNVqcyQJMD5HsRugBPf4I1nl2mME=
|
||||
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/reva/v2 v2.27.5-0.20250205144957-2a7145a1d4ad h1:Ae/greWkZD/skjC70ZCxDVnABxga7sqWD6GpGbDzwg0=
|
||||
github.com/cs3org/reva/v2 v2.27.5-0.20250205144957-2a7145a1d4ad/go.mod h1:8yvuebW1eCKzRfzNXy+RSYYEESmMp5mCuM6MQ47zJow=
|
||||
github.com/cs3org/reva/v2 v2.27.5-0.20250217133727-8aefc9e791f7 h1:slkg8L8rG4ei0OKwEMDZ7EY88d3cduzO53rWMY6lX+A=
|
||||
github.com/cs3org/reva/v2 v2.27.5-0.20250217133727-8aefc9e791f7/go.mod h1:1H26PMXoa1rDrIoZ7lGOerq1Bg07/5srYfRaKfxBSsc=
|
||||
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
|
||||
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||
|
2
vendor/github.com/cs3org/reva/v2/internal/grpc/services/gateway/ocmcore.go
generated
vendored
2
vendor/github.com/cs3org/reva/v2/internal/grpc/services/gateway/ocmcore.go
generated
vendored
@ -69,7 +69,7 @@ func (s *svc) DeleteOCMCoreShare(ctx context.Context, req *ocmcore.DeleteOCMCore
|
||||
|
||||
res, err := c.DeleteOCMCoreShare(ctx, req)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "gateway: error calling UpdateOCMCoreShare")
|
||||
return nil, errors.Wrap(err, "gateway: error calling DeleteOCMCoreShare")
|
||||
}
|
||||
|
||||
return res, nil
|
||||
|
37
vendor/github.com/cs3org/reva/v2/internal/grpc/services/ocmcore/ocmcore.go
generated
vendored
37
vendor/github.com/cs3org/reva/v2/internal/grpc/services/ocmcore/ocmcore.go
generated
vendored
@ -20,9 +20,11 @@ package ocmcore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||
ocmcore "github.com/cs3org/go-cs3apis/cs3/ocm/core/v1beta1"
|
||||
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
|
||||
providerpb "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
@ -30,8 +32,10 @@ import (
|
||||
"github.com/cs3org/reva/v2/pkg/errtypes"
|
||||
"github.com/cs3org/reva/v2/pkg/ocm/share"
|
||||
"github.com/cs3org/reva/v2/pkg/ocm/share/repository/registry"
|
||||
ocmuser "github.com/cs3org/reva/v2/pkg/ocm/user"
|
||||
"github.com/cs3org/reva/v2/pkg/rgrpc"
|
||||
"github.com/cs3org/reva/v2/pkg/rgrpc/status"
|
||||
"github.com/cs3org/reva/v2/pkg/utils"
|
||||
"github.com/cs3org/reva/v2/pkg/utils/cfg"
|
||||
"github.com/rs/zerolog"
|
||||
"google.golang.org/grpc"
|
||||
@ -93,7 +97,11 @@ func (s *service) Close() error {
|
||||
}
|
||||
|
||||
func (s *service) UnprotectedEndpoints() []string {
|
||||
return []string{"/cs3.ocm.core.v1beta1.OcmCoreAPI/CreateOCMCoreShare"}
|
||||
return []string{
|
||||
ocmcore.OcmCoreAPI_CreateOCMCoreShare_FullMethodName,
|
||||
ocmcore.OcmCoreAPI_UpdateOCMCoreShare_FullMethodName,
|
||||
ocmcore.OcmCoreAPI_DeleteOCMCoreShare_FullMethodName,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateOCMCoreShare is called when an OCM request comes into this reva instance from.
|
||||
@ -144,5 +152,30 @@ func (s *service) UpdateOCMCoreShare(ctx context.Context, req *ocmcore.UpdateOCM
|
||||
}
|
||||
|
||||
func (s *service) DeleteOCMCoreShare(ctx context.Context, req *ocmcore.DeleteOCMCoreShareRequest) (*ocmcore.DeleteOCMCoreShareResponse, error) {
|
||||
return nil, errtypes.NotSupported("not implemented")
|
||||
grantee := utils.ReadPlainFromOpaque(req.GetOpaque(), "grantee")
|
||||
if grantee == "" {
|
||||
return nil, errtypes.UserRequired("missing remote user id in a metadata")
|
||||
}
|
||||
|
||||
user := &userpb.User{Id: ocmuser.RemoteID(&userpb.UserId{OpaqueId: grantee})}
|
||||
|
||||
err := s.repo.DeleteReceivedShare(ctx, user, &ocm.ShareReference{
|
||||
Spec: &ocm.ShareReference_Id{
|
||||
Id: &ocm.ShareId{
|
||||
OpaqueId: req.GetId(),
|
||||
},
|
||||
},
|
||||
})
|
||||
res := &ocmcore.DeleteOCMCoreShareResponse{}
|
||||
if err == nil {
|
||||
res.Status = status.NewOK(ctx)
|
||||
} else {
|
||||
var notFound errtypes.NotFound
|
||||
if errors.As(err, ¬Found) {
|
||||
res.Status = status.NewNotFound(ctx, "remote ocm share not found")
|
||||
} else {
|
||||
res.Status = status.NewInternal(ctx, "error deleting remote ocm share")
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
@ -170,6 +170,12 @@ func (s *service) ForwardInvite(ctx context.Context, req *invitepb.ForwardInvite
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if req.GetOriginSystemProvider().Domain == s.conf.ProviderDomain {
|
||||
return &invitepb.ForwardInviteResponse{
|
||||
Status: status.NewInvalid(ctx, "can not accept an invite from the same instance"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Accept the invitation on the remote OCM provider
|
||||
remoteUser, err := s.ocmClient.InviteAccepted(ctx, ocmEndpoint, &client.InviteAcceptedRequest{
|
||||
Token: req.InviteToken.GetToken(),
|
||||
|
@ -38,6 +38,7 @@ import (
|
||||
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
|
||||
"github.com/cs3org/reva/v2/pkg/errtypes"
|
||||
"github.com/cs3org/reva/v2/pkg/ocm/client"
|
||||
"github.com/cs3org/reva/v2/pkg/ocm/payload"
|
||||
"github.com/cs3org/reva/v2/pkg/ocm/share"
|
||||
"github.com/cs3org/reva/v2/pkg/ocm/share/repository/registry"
|
||||
ocmuser "github.com/cs3org/reva/v2/pkg/ocm/user"
|
||||
@ -379,9 +380,22 @@ func (s *service) CreateOCMShare(ctx context.Context, req *ocm.CreateOCMShareReq
|
||||
}
|
||||
|
||||
func (s *service) RemoveOCMShare(ctx context.Context, req *ocm.RemoveOCMShareRequest) (*ocm.RemoveOCMShareResponse, error) {
|
||||
// TODO (gdelmont): notify the remote provider using the /notification ocm endpoint
|
||||
// https://cs3org.github.io/OCM-API/docs.html?branch=develop&repo=OCM-API&user=cs3org#/paths/~1notifications/post
|
||||
user := ctxpkg.ContextMustGetUser(ctx)
|
||||
getShareRes, err := s.GetOCMShare(ctx, &ocm.GetOCMShareRequest{
|
||||
Ref: req.Ref,
|
||||
})
|
||||
if err != nil {
|
||||
return &ocm.RemoveOCMShareResponse{
|
||||
Status: status.NewInternal(ctx, "error getting ocm share"),
|
||||
}, nil
|
||||
}
|
||||
if getShareRes.Status.Code != rpc.Code_CODE_OK {
|
||||
res := &ocm.RemoveOCMShareResponse{
|
||||
Status: getShareRes.GetStatus(),
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
if err := s.repo.DeleteShare(ctx, user, req.Ref); err != nil {
|
||||
if errors.Is(err, share.ErrShareNotFound) {
|
||||
return &ocm.RemoveOCMShareResponse{
|
||||
@ -389,10 +403,54 @@ func (s *service) RemoveOCMShare(ctx context.Context, req *ocm.RemoveOCMShareReq
|
||||
}, nil
|
||||
}
|
||||
return &ocm.RemoveOCMShareResponse{
|
||||
Status: status.NewInternal(ctx, "error removing share"),
|
||||
Status: status.NewInternal(ctx, "error deleting share"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// TODO: We should not fail the whole operation if the notification fails
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return &ocm.RemoveOCMShareResponse{
|
||||
Status: status.NewInternal(ctx, "error getting gateway client"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
providerInfoResp, err := gatewayClient.GetInfoByDomain(ctx, &ocmprovider.GetInfoByDomainRequest{
|
||||
Domain: getShareRes.GetShare().GetGrantee().GetUserId().GetIdp(),
|
||||
})
|
||||
if err != nil {
|
||||
return &ocm.RemoveOCMShareResponse{
|
||||
Status: status.NewInternal(ctx, "error getting provider info"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
if providerInfoResp.Status.Code != rpc.Code_CODE_OK {
|
||||
return &ocm.RemoveOCMShareResponse{
|
||||
Status: providerInfoResp.Status,
|
||||
}, nil
|
||||
}
|
||||
|
||||
ocmEndpoint, err := getOCMEndpoint(providerInfoResp.GetProviderInfo())
|
||||
if err != nil {
|
||||
return &ocm.RemoveOCMShareResponse{
|
||||
Status: status.NewInternal(ctx, "the selected provider does not have an OCM endpoint"),
|
||||
}, nil
|
||||
}
|
||||
newShareReq := &payload.NotificationRequest{
|
||||
NotificationType: payload.SHARE_UNSHARED,
|
||||
ResourceType: "file", // use type "file" for shared files or folders
|
||||
ProviderId: getShareRes.GetShare().GetId().GetOpaqueId(),
|
||||
Notification: &payload.Notification{
|
||||
Grantee: getShareRes.GetShare().GetGrantee().GetUserId().GetOpaqueId(),
|
||||
},
|
||||
}
|
||||
// https://cs3org.github.io/OCM-API/docs.html?branch=develop&repo=OCM-API&user=cs3org#/paths/~1notifications/post
|
||||
err = s.client.NotifyRemote(ctx, ocmEndpoint, newShareReq)
|
||||
if err != nil {
|
||||
// Continue even if the notification fails
|
||||
appctx.GetLogger(ctx).Err(err).Msg("error notifying ocm remote provider")
|
||||
}
|
||||
|
||||
return &ocm.RemoveOCMShareResponse{
|
||||
Status: status.NewOK(ctx),
|
||||
}, nil
|
||||
|
113
vendor/github.com/cs3org/reva/v2/internal/http/services/ocmd/notifications.go
generated
vendored
113
vendor/github.com/cs3org/reva/v2/internal/http/services/ocmd/notifications.go
generated
vendored
@ -19,20 +19,36 @@
|
||||
package ocmd
|
||||
|
||||
import (
|
||||
"io"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"mime"
|
||||
"net/http"
|
||||
|
||||
"github.com/cs3org/reva/v2/internal/http/services/reqres"
|
||||
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||
ocmcore "github.com/cs3org/go-cs3apis/cs3/ocm/core/v1beta1"
|
||||
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
|
||||
"github.com/cs3org/reva/v2/pkg/appctx"
|
||||
"github.com/cs3org/reva/v2/pkg/ocm/payload"
|
||||
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/cs3org/reva/v2/pkg/utils"
|
||||
"github.com/go-chi/render"
|
||||
)
|
||||
|
||||
// var validate = validator.New()
|
||||
|
||||
type notifHandler struct {
|
||||
gatewaySelector *pool.Selector[gateway.GatewayAPIClient]
|
||||
}
|
||||
|
||||
func (h *notifHandler) init(c *config) error {
|
||||
gatewaySelector, err := pool.GatewaySelector(c.GatewaySvc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h.gatewaySelector = gatewaySelector
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -42,25 +58,100 @@ func (h *notifHandler) init(c *config) error {
|
||||
func (h *notifHandler) Notifications(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
log := appctx.GetLogger(ctx)
|
||||
req, err := getNotification(r)
|
||||
req, err := getNotification(w, r)
|
||||
if err != nil {
|
||||
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, err.Error(), nil)
|
||||
renderErrorBadRequest(w, r, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// TODO(lopresti) this is all to be implemented. For now we just log what we got
|
||||
log.Debug().Msgf("Received OCM notification: %+v", req)
|
||||
|
||||
// this is to please Nextcloud
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
var status *rpc.Status
|
||||
switch req.NotificationType {
|
||||
case payload.SHARE_UNSHARED:
|
||||
if req.Notification.Grantee == "" {
|
||||
renderErrorBadRequest(w, r, http.StatusBadRequest, "grantee is required")
|
||||
}
|
||||
status, err = h.handleShareUnshared(ctx, req)
|
||||
if err != nil {
|
||||
log.Err(err).Any("NotificationRequest", req).Msg("error getting gateway client")
|
||||
renderErrorBadRequest(w, r, http.StatusInternalServerError, status.GetMessage())
|
||||
}
|
||||
case payload.SHARE_CHANGE_PERMISSION:
|
||||
// TODO implement the SHARE_CHANGE_PERMISSION
|
||||
w.WriteHeader(http.StatusNotImplemented)
|
||||
return
|
||||
default:
|
||||
renderErrorBadRequest(w, r, http.StatusBadRequest, "NotificationType "+req.NotificationType+" is not supported")
|
||||
return
|
||||
}
|
||||
// parse the response status
|
||||
switch status.GetCode() {
|
||||
case rpc.Code_CODE_OK:
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
return
|
||||
case rpc.Code_CODE_INVALID_ARGUMENT:
|
||||
renderErrorBadRequest(w, r, http.StatusBadRequest, status.GetMessage())
|
||||
return
|
||||
case rpc.Code_CODE_UNAUTHENTICATED:
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
case rpc.Code_CODE_PERMISSION_DENIED:
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
return
|
||||
default:
|
||||
log.Error().Str("code", status.GetCode().String()).Str("message", status.GetMessage()).Str("NotificationType", req.NotificationType).Msg("error handling notification")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func getNotification(r *http.Request) (string, error) {
|
||||
// var req notificationRequest
|
||||
func (h *notifHandler) handleShareUnshared(ctx context.Context, req *payload.NotificationRequest) (*rpc.Status, error) {
|
||||
gatewayClient, err := h.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting gateway client: %w", err)
|
||||
}
|
||||
|
||||
o := &typesv1beta1.Opaque{}
|
||||
utils.AppendPlainToOpaque(o, "grantee", req.Notification.Grantee)
|
||||
|
||||
res, err := gatewayClient.DeleteOCMCoreShare(ctx, &ocmcore.DeleteOCMCoreShareRequest{
|
||||
Id: req.ProviderId,
|
||||
Opaque: o,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error calling DeleteOCMCoreShare: %w", err)
|
||||
}
|
||||
return res.GetStatus(), nil
|
||||
}
|
||||
|
||||
func getNotification(w http.ResponseWriter, r *http.Request) (*payload.NotificationRequest, error) {
|
||||
contentType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
||||
if err == nil && contentType == "application/json" {
|
||||
bytes, _ := io.ReadAll(r.Body)
|
||||
return string(bytes), nil
|
||||
n := &payload.NotificationRequest{}
|
||||
err := json.NewDecoder(r.Body).Decode(&n)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
return "", nil
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func renderJSON(w http.ResponseWriter, r *http.Request, statusCode int, resp any) {
|
||||
render.Status(r, statusCode)
|
||||
render.JSON(w, r, resp)
|
||||
}
|
||||
|
||||
func renderErrorBadRequest(w http.ResponseWriter, r *http.Request, statusCode int, message string) {
|
||||
resp := &payload.ErrorMessageResponse{
|
||||
Message: "BAD_REQUEST",
|
||||
ValidationErrors: []*payload.ValidationError{
|
||||
{
|
||||
Name: "Notification",
|
||||
Message: message,
|
||||
},
|
||||
},
|
||||
}
|
||||
renderJSON(w, r, http.StatusBadRequest, resp)
|
||||
}
|
||||
|
12
vendor/github.com/cs3org/reva/v2/internal/http/services/ocmd/shares.go
generated
vendored
12
vendor/github.com/cs3org/reva/v2/internal/http/services/ocmd/shares.go
generated
vendored
@ -27,15 +27,13 @@ import (
|
||||
"strings"
|
||||
|
||||
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||
providerpb "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
|
||||
|
||||
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||
ocmcore "github.com/cs3org/go-cs3apis/cs3/ocm/core/v1beta1"
|
||||
ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
|
||||
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
|
||||
|
||||
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
|
||||
providerpb "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
|
||||
"github.com/cs3org/reva/v2/internal/http/services/reqres"
|
||||
"github.com/cs3org/reva/v2/pkg/appctx"
|
||||
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
|
||||
@ -78,7 +76,7 @@ type createShareRequest struct {
|
||||
Protocols Protocols `json:"protocol" validate:"required"`
|
||||
}
|
||||
|
||||
// CreateShare sends all the informations to the consumer needed to start
|
||||
// CreateShare sends all the information to the consumer needed to start
|
||||
// synchronization between the two services.
|
||||
func (h *sharesHandler) CreateShare(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
@ -180,7 +178,7 @@ func (h *sharesHandler) CreateShare(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if userRes.Status.Code != rpc.Code_CODE_OK {
|
||||
if createShareResp.Status.Code != rpc.Code_CODE_OK {
|
||||
// TODO: define errors in the cs3apis
|
||||
reqres.WriteError(w, r, reqres.APIErrorServerError, "error creating ocm share", errors.New(createShareResp.Status.Message))
|
||||
return
|
||||
|
68
vendor/github.com/cs3org/reva/v2/pkg/ocm/client/client.go
generated
vendored
68
vendor/github.com/cs3org/reva/v2/pkg/ocm/client/client.go
generated
vendored
@ -22,14 +22,17 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/cs3org/reva/v2/internal/http/services/ocmd"
|
||||
"github.com/cs3org/reva/v2/pkg/appctx"
|
||||
"github.com/cs3org/reva/v2/pkg/errtypes"
|
||||
"github.com/cs3org/reva/v2/pkg/ocm/payload"
|
||||
"github.com/cs3org/reva/v2/pkg/rhttp"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@ -278,3 +281,68 @@ func (c *OCMClient) Discovery(ctx context.Context, endpoint string) (*Capabiliti
|
||||
|
||||
return &cap, nil
|
||||
}
|
||||
|
||||
// NotifyRemote sends a notification to a remote OCM instance.
|
||||
// Send a notification to a remote party about a previously known entity
|
||||
// Notifications are optional messages. They are expected to be used to inform the other party about a change about a previously known entity,
|
||||
// such as a share or a trusted user. For example, a notification MAY be sent by a recipient to let the provider know that
|
||||
// the recipient declined a share. In this case, the provider site MAY mark the share as declined for its user(s). Similarly,
|
||||
// it MAY be sent by a provider to let the recipient know that the provider removed a given share, such that the recipient MAY clean it up from its database.
|
||||
// A notification MAY also be sent to let a recipient know that the provider removed that recipient from the list of trusted users, along with any related share.
|
||||
// The recipient MAY reciprocally remove that provider from the list of trusted users, along with any related share.
|
||||
// https://cs3org.github.io/OCM-API/docs.html?branch=develop&repo=OCM-API&user=cs3org#/paths/~1notifications/post
|
||||
func (c *OCMClient) NotifyRemote(ctx context.Context, endpoint string, r *payload.NotificationRequest) error {
|
||||
url, err := url.JoinPath(endpoint, "notifications")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
body, err := r.ToJSON()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, body)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error creating request")
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error doing request")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
err = c.parseNotifyRemoteResponse(resp, nil)
|
||||
if err != nil {
|
||||
appctx.GetLogger(ctx).Err(err).Msg("error notifying remote OCM instance")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *OCMClient) parseNotifyRemoteResponse(r *http.Response, resp any) error {
|
||||
var err error
|
||||
switch r.StatusCode {
|
||||
case http.StatusOK, http.StatusCreated:
|
||||
if resp == nil {
|
||||
return nil
|
||||
}
|
||||
err := json.NewDecoder(r.Body).Decode(&resp)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, fmt.Sprintf("http status code: %v, error decoding response body", r.StatusCode))
|
||||
}
|
||||
return nil
|
||||
case http.StatusBadRequest:
|
||||
err = ErrInvalidParameters
|
||||
case http.StatusUnauthorized, http.StatusForbidden:
|
||||
err = ErrServiceNotTrusted
|
||||
default:
|
||||
err = errtypes.InternalError("request finished whit code " + strconv.Itoa(r.StatusCode))
|
||||
}
|
||||
|
||||
body, err2 := io.ReadAll(r.Body)
|
||||
if err2 != nil {
|
||||
return errors.Wrap(err, "error reading response body "+err2.Error())
|
||||
}
|
||||
return errors.Wrap(err, string(body))
|
||||
}
|
||||
|
54
vendor/github.com/cs3org/reva/v2/pkg/ocm/payload/payload.go
generated
vendored
Normal file
54
vendor/github.com/cs3org/reva/v2/pkg/ocm/payload/payload.go
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
package payload
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
)
|
||||
|
||||
const (
|
||||
// https://cs3org.github.io/OCM-API/docs.html?branch=develop&repo=OCM-API&user=cs3org#/paths/~1notifications/post
|
||||
// NotificationType one of "SHARE_ACCEPTED", "SHARE_DECLINED", "SHARE_CHANGE_PERMISSION", "SHARE_UNSHARED", "USER_REMOVED"
|
||||
SHARE_UNSHARED = "SHARE_UNSHARED"
|
||||
SHARE_CHANGE_PERMISSION = "SHARE_CHANGE_PERMISSION"
|
||||
)
|
||||
|
||||
// NotificationRequest is the request payload for the OCM API notifications endpoint.
|
||||
// https://cs3org.github.io/OCM-API/docs.html?branch=develop&repo=OCM-API&user=cs3org#/paths/~1notifications/post
|
||||
type NotificationRequest struct {
|
||||
NotificationType string `json:"notificationType" validate:"required"`
|
||||
ResourceType string `json:"resourceType" validate:"required"`
|
||||
// Identifier to identify the shared resource at the provider side. This is unique per provider such that if the same resource is shared twice, this providerId will not be repeated.
|
||||
ProviderId string `json:"providerId" validate:"required"`
|
||||
// Optional additional parameters, depending on the notification and the resource type.
|
||||
Notification *Notification `json:"notification,omitempty"`
|
||||
}
|
||||
|
||||
// Notification is the payload for the notification field in the NotificationRequest.
|
||||
type Notification struct {
|
||||
// Owner string `json:"owner,omitempty"`
|
||||
Grantee string `json:"grantee,omitempty"`
|
||||
SharedSecret string `json:"sharedSecret,omitempty"`
|
||||
}
|
||||
|
||||
// ToJSON returns the JSON io.Reader of the NotificationRequest.
|
||||
func (r *NotificationRequest) ToJSON() (io.Reader, error) {
|
||||
var b bytes.Buffer
|
||||
if err := json.NewEncoder(&b).Encode(r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &b, nil
|
||||
}
|
||||
|
||||
// ErrorMessageResponse is the response returned by the OCM API in case of an error.
|
||||
// https://cs3org.github.io/OCM-API/docs.html?branch=develop&repo=OCM-API&user=cs3org#/paths/~1notifications/post
|
||||
type ErrorMessageResponse struct {
|
||||
Message string `json:"message"`
|
||||
ValidationErrors []*ValidationError `json:"validationErrors,omitempty"`
|
||||
}
|
||||
|
||||
// ValidationError is the payload for the validationErrors field in the ErrorMessageResponse.
|
||||
type ValidationError struct {
|
||||
Name string `json:"name"`
|
||||
Message string `json:"message"`
|
||||
}
|
23
vendor/github.com/cs3org/reva/v2/pkg/ocm/share/repository/json/json.go
generated
vendored
23
vendor/github.com/cs3org/reva/v2/pkg/ocm/share/repository/json/json.go
generated
vendored
@ -379,6 +379,12 @@ func receivedShareEqual(ref *ocm.ShareReference, s *ocm.ReceivedShare) bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
// Match the reserved share by the remote share id
|
||||
if ref.GetId() != nil && s.RemoteShareId != "" {
|
||||
if ref.GetId().GetOpaqueId() == s.RemoteShareId {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@ -589,6 +595,23 @@ func (m *mgr) GetReceivedShare(ctx context.Context, user *userpb.User, ref *ocm.
|
||||
return nil, errtypes.NotFound(ref.String())
|
||||
}
|
||||
|
||||
func (m *mgr) DeleteReceivedShare(ctx context.Context, user *userpb.User, ref *ocm.ShareReference) error {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
if err := m.load(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for id, share := range m.model.ReceivedShares {
|
||||
if receivedShareEqual(ref, share) && utils.UserEqual(user.Id, share.GetGrantee().GetUserId()) {
|
||||
delete(m.model.ReceivedShares, id)
|
||||
return m.save()
|
||||
}
|
||||
}
|
||||
return errtypes.NotFound(ref.String())
|
||||
}
|
||||
|
||||
func (m *mgr) UpdateReceivedShare(ctx context.Context, user *userpb.User, share *ocm.ReceivedShare, fieldMask *field_mask.FieldMask) (*ocm.ReceivedShare, error) {
|
||||
rs, err := m.GetReceivedShare(ctx, user, &ocm.ShareReference{Spec: &ocm.ShareReference_Id{Id: share.Id}})
|
||||
if err != nil {
|
||||
|
6
vendor/github.com/cs3org/reva/v2/pkg/ocm/share/repository/nextcloud/nextcloud.go
generated
vendored
6
vendor/github.com/cs3org/reva/v2/pkg/ocm/share/repository/nextcloud/nextcloud.go
generated
vendored
@ -28,6 +28,7 @@ import (
|
||||
"strings"
|
||||
|
||||
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||
"github.com/cs3org/reva/v2/pkg/errtypes"
|
||||
|
||||
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
@ -345,6 +346,11 @@ func (sm *Manager) GetReceivedShare(ctx context.Context, user *userpb.User, ref
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteReceivedShare deletes the share pointed by ref.
|
||||
func (sm *Manager) DeleteReceivedShare(ctx context.Context, user *userpb.User, ref *ocm.ShareReference) error {
|
||||
return errtypes.NotSupported("not implemented")
|
||||
}
|
||||
|
||||
// UpdateReceivedShare updates the received share with share state.
|
||||
func (sm *Manager) UpdateReceivedShare(ctx context.Context, user *userpb.User, share *ocm.ReceivedShare, fieldMask *field_mask.FieldMask) (*ocm.ReceivedShare, error) {
|
||||
type paramsObj struct {
|
||||
|
3
vendor/github.com/cs3org/reva/v2/pkg/ocm/share/share.go
generated
vendored
3
vendor/github.com/cs3org/reva/v2/pkg/ocm/share/share.go
generated
vendored
@ -55,6 +55,9 @@ type Repository interface {
|
||||
// GetReceivedShare returns the information for a received share the user has access.
|
||||
GetReceivedShare(ctx context.Context, user *userpb.User, ref *ocm.ShareReference) (*ocm.ReceivedShare, error)
|
||||
|
||||
// DeleteReceivedShare deletes the share pointed by ref.
|
||||
DeleteReceivedShare(ctx context.Context, user *userpb.User, ref *ocm.ShareReference) error
|
||||
|
||||
// UpdateReceivedShare updates the received share with share state.
|
||||
UpdateReceivedShare(ctx context.Context, user *userpb.User, share *ocm.ReceivedShare, fieldMask *field_mask.FieldMask) (*ocm.ReceivedShare, error)
|
||||
}
|
||||
|
3
vendor/modules.txt
vendored
3
vendor/modules.txt
vendored
@ -367,7 +367,7 @@ github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1
|
||||
github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1
|
||||
github.com/cs3org/go-cs3apis/cs3/tx/v1beta1
|
||||
github.com/cs3org/go-cs3apis/cs3/types/v1beta1
|
||||
# github.com/cs3org/reva/v2 v2.27.5-0.20250205144957-2a7145a1d4ad
|
||||
# github.com/cs3org/reva/v2 v2.27.5-0.20250217133727-8aefc9e791f7
|
||||
## explicit; go 1.22.7
|
||||
github.com/cs3org/reva/v2/cmd/revad/internal/grace
|
||||
github.com/cs3org/reva/v2/cmd/revad/runtime
|
||||
@ -558,6 +558,7 @@ github.com/cs3org/reva/v2/pkg/ocm/invite/repository/loader
|
||||
github.com/cs3org/reva/v2/pkg/ocm/invite/repository/memory
|
||||
github.com/cs3org/reva/v2/pkg/ocm/invite/repository/registry
|
||||
github.com/cs3org/reva/v2/pkg/ocm/invite/repository/sql
|
||||
github.com/cs3org/reva/v2/pkg/ocm/payload
|
||||
github.com/cs3org/reva/v2/pkg/ocm/provider
|
||||
github.com/cs3org/reva/v2/pkg/ocm/provider/authorizer/json
|
||||
github.com/cs3org/reva/v2/pkg/ocm/provider/authorizer/loader
|
||||
|
Loading…
x
Reference in New Issue
Block a user