diff --git a/go.mod b/go.mod index 44f05c8c8..064ef8ecf 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/coreos/go-oidc v2.2.1+incompatible github.com/coreos/go-oidc/v3 v3.9.0 github.com/cs3org/go-cs3apis v0.0.0-20231023073225-7748710e0781 - github.com/cs3org/reva/v2 v2.17.0 + github.com/cs3org/reva/v2 v2.17.1-0.20231214082636-a8467337208a github.com/dhowden/tag v0.0.0-20230630033851-978a0926ee25 github.com/disintegration/imaging v1.6.2 github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e diff --git a/go.sum b/go.sum index 0d2d4b43d..80f4a4d8e 100644 --- a/go.sum +++ b/go.sum @@ -1021,8 +1021,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-20231023073225-7748710e0781 h1:BUdwkIlf8IS2FasrrPg8gGPHQPOrQ18MS1Oew2tmGtY= github.com/cs3org/go-cs3apis v0.0.0-20231023073225-7748710e0781/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY= -github.com/cs3org/reva/v2 v2.17.0 h1:cp7WXY+mZGLie4CKvIe3K+D/wG3sKVYrZJfs9Qnzioo= -github.com/cs3org/reva/v2 v2.17.0/go.mod h1:9hmBNVK+RSMSupWci9MQLmmj1NsJ8Bv49tqKbxMdxJY= +github.com/cs3org/reva/v2 v2.17.1-0.20231214082636-a8467337208a h1:ri98OWOuAY5tF3jpeKSItna3O4I0SedxzVgPQJPZXoM= +github.com/cs3org/reva/v2 v2.17.1-0.20231214082636-a8467337208a/go.mod h1:oX1YtLKGr7jatGk0CpPM4GKbSEIdHhmsQuSAYElnN1U= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= 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= diff --git a/vendor/github.com/cs3org/reva/v2/internal/http/services/ocmd/protocols.go b/vendor/github.com/cs3org/reva/v2/internal/http/services/ocmd/protocols.go index 0c7735838..882f42b4a 100644 --- a/vendor/github.com/cs3org/reva/v2/internal/http/services/ocmd/protocols.go +++ b/vendor/github.com/cs3org/reva/v2/internal/http/services/ocmd/protocols.go @@ -59,11 +59,18 @@ func (w *WebDAV) ToOCMProtocol() *ocm.Protocol { switch p { case "read": perms.Permissions.GetPath = true + perms.Permissions.GetQuota = true perms.Permissions.InitiateFileDownload = true perms.Permissions.ListContainer = true + perms.Permissions.ListRecycle = true perms.Permissions.Stat = true case "write": perms.Permissions.InitiateFileUpload = true + perms.Permissions.RestoreRecycleItem = true + perms.Permissions.CreateContainer = true + perms.Permissions.Delete = true + perms.Permissions.Move = true + perms.Permissions.ListGrants = true case "share": perms.Reshare = true } diff --git a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/propfind/propfind.go b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/propfind/propfind.go index d410bfcba..b2d098fff 100644 --- a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/propfind/propfind.go +++ b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/propfind/propfind.go @@ -1078,7 +1078,6 @@ func mdToPropResponse(ctx context.Context, pf *XML, md *provider.ResourceInfo, p } shareTypes = utils.ReadPlainFromOpaque(md.Opaque, "share-types") } - role := conversions.RoleFromResourcePermissions(md.PermissionSet, ls != nil) if md.Space != nil && md.Space.SpaceType != "grant" && utils.ResourceIDEqual(md.Space.Root, id) { @@ -1174,6 +1173,7 @@ func mdToPropResponse(ctx context.Context, pf *XML, md *provider.ResourceInfo, p if md.Name != "" { appendToOK(prop.Escaped("oc:name", md.Name)) + appendToOK(prop.Escaped("d:displayname", md.Name)) } if md.Etag != "" { diff --git a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/config/config.go b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/config/config.go index 01a815d80..09c5baf43 100644 --- a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/config/config.go +++ b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/config/config.go @@ -50,6 +50,7 @@ type Config struct { OCMMountPoint string `mapstructure:"ocm_mount_point"` ListOCMShares bool `mapstructure:"list_ocm_shares"` Notifications map[string]interface{} `mapstructure:"notifications"` + IncludeOCMSharees bool `mapstructure:"include_ocm_sharees"` } // Init sets sane defaults diff --git a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/sharees/sharees.go b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/sharees/sharees.go index 3feaf9096..e3e3bbbec 100644 --- a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/sharees/sharees.go +++ b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/sharees/sharees.go @@ -24,6 +24,8 @@ import ( grouppb "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1" userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" + invitepb "github.com/cs3org/go-cs3apis/cs3/ocm/invite/v1beta1" + rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" "github.com/cs3org/reva/v2/pkg/conversions" "github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/config" @@ -37,12 +39,14 @@ import ( type Handler struct { gatewayAddr string additionalInfoAttribute string + includeOCMSharees bool } // Init initializes this and any contained handlers func (h *Handler) Init(c *config.Config) { h.gatewayAddr = c.GatewaySvc h.additionalInfoAttribute = c.AdditionalInfoAttribute + h.includeOCMSharees = c.IncludeOCMSharees } // FindSharees implements the /apps/files_sharing/api/v1/sharees endpoint @@ -79,6 +83,27 @@ func (h *Handler) FindSharees(w http.ResponseWriter, r *http.Request) { } } + if h.includeOCMSharees { + remoteUsersRes, err := gwc.FindAcceptedUsers(r.Context(), &invitepb.FindAcceptedUsersRequest{Filter: term}) + if err != nil { + response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error searching remote users", err) + return + } + if remoteUsersRes.Status.Code != rpc.Code_CODE_OK { + response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error searching remote users", nil) + return + } + for _, user := range remoteUsersRes.GetAcceptedUsers() { + match := h.userAsMatch(user) + log.Debug().Interface("user", user).Interface("match", match).Msg("mapped") + if h.isExactMatch(match, term) { + exactUserMatches = append(exactUserMatches, match) + } else { + userMatches = append(userMatches, match) + } + } + } + groupsRes, err := gwc.FindGroups(r.Context(), &grouppb.FindGroupsRequest{Filter: term, SkipFetchingMembers: true}) if err != nil { response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error searching groups", err) @@ -111,21 +136,27 @@ func (h *Handler) FindSharees(w http.ResponseWriter, r *http.Request) { } func (h *Handler) userAsMatch(u *userpb.User) *conversions.MatchData { - var ocsUserType int - if u.Id.Type == userpb.UserType_USER_TYPE_GUEST || u.Id.Type == userpb.UserType_USER_TYPE_LIGHTWEIGHT { - ocsUserType = 1 + data := &conversions.MatchValueData{ + ShareType: int(conversions.ShareTypeUser), + // api compatibility with oc10: mark guest users in share invite dialogue + UserType: 0, + // api compatibility with oc10: always use the username + ShareWith: u.Username, + ShareWithAdditionalInfo: h.getAdditionalInfoAttribute(u), + } + + switch u.Id.Type { + case userpb.UserType_USER_TYPE_GUEST, userpb.UserType_USER_TYPE_LIGHTWEIGHT: + data.UserType = 1 + case userpb.UserType_USER_TYPE_FEDERATED: + data.ShareType = int(conversions.ShareTypeFederatedCloudShare) + data.ShareWith = u.Id.OpaqueId + data.ShareWithProvider = u.Id.Idp } return &conversions.MatchData{ Label: u.DisplayName, - Value: &conversions.MatchValueData{ - ShareType: int(conversions.ShareTypeUser), - // api compatibility with oc10: mark guest users in share invite dialogue - UserType: ocsUserType, - // api compatibility with oc10: always use the username - ShareWith: u.Username, - ShareWithAdditionalInfo: h.getAdditionalInfoAttribute(u), - }, + Value: data, } } diff --git a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/pending.go b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/pending.go index 8709502c6..b53d18021 100644 --- a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/pending.go +++ b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/pending.go @@ -31,6 +31,7 @@ import ( gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1" + ocmv1beta1 "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" "github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/response" "github.com/cs3org/reva/v2/pkg/appctx" @@ -50,6 +51,12 @@ const ( func (h *Handler) AcceptReceivedShare(w http.ResponseWriter, r *http.Request) { ctx := r.Context() shareID := chi.URLParam(r, shareidkey) + + if h.isFederatedReceivedShare(r, shareID) { + h.updateReceivedFederatedShare(w, r, shareID, false) + return + } + client, err := h.getClient() if err != nil { response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error getting grpc gateway client", err) @@ -148,6 +155,12 @@ func (h *Handler) AcceptReceivedShare(w http.ResponseWriter, r *http.Request) { // RejectReceivedShare handles DELETE Requests on /apps/files_sharing/api/v1/shares/{shareid} func (h *Handler) RejectReceivedShare(w http.ResponseWriter, r *http.Request) { shareID := chi.URLParam(r, "shareid") + + if h.isFederatedReceivedShare(r, shareID) { + h.updateReceivedFederatedShare(w, r, shareID, true) + return + } + // we need to add a path to the share receivedShare := &collaboration.ReceivedShare{ Share: &collaboration.Share{ @@ -254,6 +267,76 @@ func (h *Handler) updateReceivedShare(w http.ResponseWriter, r *http.Request, re return data } +func (h *Handler) updateReceivedFederatedShare(w http.ResponseWriter, r *http.Request, shareID string, rejectShare bool) { + ctx := r.Context() + + client, err := h.getClient() + if err != nil { + response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error getting grpc gateway client", err) + return + } + + share, err := client.GetReceivedOCMShare(ctx, &ocmv1beta1.GetReceivedOCMShareRequest{ + Ref: &ocmv1beta1.ShareReference{ + Spec: &ocmv1beta1.ShareReference_Id{ + Id: &ocmv1beta1.ShareId{ + OpaqueId: shareID, + }, + }, + }, + }) + if err != nil { + response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "grpc update received share request failed", err) + return + } + if share.Status.Code != rpc.Code_CODE_OK { + if share.Status.Code == rpc.Code_CODE_NOT_FOUND { + response.WriteOCSError(w, r, response.MetaNotFound.StatusCode, "not found", nil) + return + } + response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "grpc update received share request failed", errors.Errorf("code: %d, message: %s", share.Status.Code, share.Status.Message)) + return + } + + req := &ocmv1beta1.UpdateReceivedOCMShareRequest{ + Share: &ocmv1beta1.ReceivedShare{ + Id: &ocmv1beta1.ShareId{ + OpaqueId: shareID, + }, + }, + UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"state"}}, + } + if rejectShare { + req.Share.State = ocmv1beta1.ShareState_SHARE_STATE_REJECTED + } else { + req.Share.State = ocmv1beta1.ShareState_SHARE_STATE_ACCEPTED + } + + updateRes, err := client.UpdateReceivedOCMShare(ctx, req) + if err != nil { + response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "grpc update received share request failed", err) + return + } + + if updateRes.Status.Code != rpc.Code_CODE_OK { + if updateRes.Status.Code == rpc.Code_CODE_NOT_FOUND { + response.WriteOCSError(w, r, response.MetaNotFound.StatusCode, "not found", nil) + return + } + response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "grpc update received share request failed", errors.Errorf("code: %d, message: %s", updateRes.Status.Code, updateRes.Status.Message)) + return + } + + data, err := conversions.ReceivedOCMShare2ShareData(share.Share, h.ocmLocalMount(share.Share)) + if err != nil { + response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "grpc update received share request failed", err) + return + } + h.mapUserIdsReceivedFederatedShare(ctx, client, data) + data.State = mapOCMState(req.Share.State) + response.WriteOCSSuccess(w, r, []*conversions.ShareData{data}) +} + // getReceivedShareHideFlagFromShareId returns the hide flag of a received share based on its ID. func (h *Handler) getReceivedShareHideFlagFromShareID(ctx context.Context, shareID string) bool { client, err := h.getClient() diff --git a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/remote.go b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/remote.go index c118f559c..7cbf49468 100644 --- a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/remote.go +++ b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/remote.go @@ -49,7 +49,7 @@ func (h *Handler) createFederatedCloudShare(w http.ResponseWriter, r *http.Reque return } - shareWithUser, shareWithProvider := r.FormValue("shareWithUser"), r.FormValue("shareWithProvider") + shareWithUser, shareWithProvider := r.FormValue("shareWith"), r.FormValue("shareWithProvider") if shareWithUser == "" || shareWithProvider == "" { response.WriteOCSError(w, r, response.MetaBadRequest.StatusCode, "missing shareWith parameters", nil) return diff --git a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go index 2621a3313..a2552b69e 100644 --- a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go +++ b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go @@ -48,6 +48,7 @@ import ( "google.golang.org/grpc/metadata" "google.golang.org/protobuf/types/known/fieldmaskpb" + ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1" ocmv1beta1 "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1" "github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/config" "github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/response" @@ -642,6 +643,66 @@ func (h *Handler) GetShare(w http.ResponseWriter, r *http.Request) { } } + if share == nil { + // check if we have a federated share + req := &ocm.GetOCMShareRequest{ + Ref: &ocm.ShareReference{ + Spec: &ocm.ShareReference_Id{ + Id: &ocm.ShareId{ + OpaqueId: shareID, + }, + }, + }, + } + ocmShareResponse, err := client.GetOCMShare(ctx, req) + if err != nil { + response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error sending a grpc get ocm share request", err) + return + } + + ocmShare := ocmShareResponse.GetShare() + if ocmShare != nil { + resourceID = ocmShare.ResourceId + share, err = conversions.OCMShare2ShareData(ocmShare) + if err != nil { + response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error mapping share data", err) + return + } + } + } + + if share == nil { + // check if we have an incoming federated share + req := &ocm.GetReceivedOCMShareRequest{ + Ref: &ocm.ShareReference{ + Spec: &ocm.ShareReference_Id{ + Id: &ocm.ShareId{ + OpaqueId: shareID, + }, + }, + }, + } + ocmShareResponse, err := client.GetReceivedOCMShare(ctx, req) + if err != nil { + response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error sending a grpc get ocm share request", err) + return + } + + ocmShare := ocmShareResponse.GetShare() + if ocmShare != nil { + resourceID = &provider.ResourceId{ + StorageId: utils.OCMStorageProviderID, + SpaceId: ocmShare.Id.OpaqueId, + OpaqueId: ocmShare.Id.OpaqueId, + } + share, err = conversions.ReceivedOCMShare2ShareData(ocmShare, h.ocmLocalMount(ocmShare)) + if err != nil { + response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error mapping share data", err) + return + } + } + } + if share == nil { sublog.Debug().Msg("no share found with this id") response.WriteOCSError(w, r, response.MetaNotFound.StatusCode, "share not found", nil) @@ -857,6 +918,10 @@ func (h *Handler) RemoveShare(w http.ResponseWriter, r *http.Request) { h.removeUserShare(w, r, share) return } + if h.isFederatedShare(r, shareID) { + h.removeFederatedShare(w, r, shareID) + return + } if prov, ok := h.isSpaceShare(r, shareID); ok { // The request is a remove space member request. diff --git a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/user.go b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/user.go index d67d0f2d2..04498b220 100644 --- a/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/user.go +++ b/vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/user.go @@ -155,6 +155,106 @@ func (h *Handler) isUserShare(r *http.Request, oid string) (*collaboration.Share return getShareRes.GetShare(), getShareRes.GetShare() != nil } +func (h *Handler) isFederatedShare(r *http.Request, shareID string) bool { + log := appctx.GetLogger(r.Context()) + client, err := pool.GetGatewayServiceClient(h.gatewayAddr) + if err != nil { + log.Err(err).Send() + return false + } + + getShareRes, err := client.GetOCMShare(r.Context(), &ocmpb.GetOCMShareRequest{ + Ref: &ocmpb.ShareReference{ + Spec: &ocmpb.ShareReference_Id{ + Id: &ocmpb.ShareId{ + OpaqueId: shareID, + }, + }, + }, + }) + if err != nil { + log.Err(err).Send() + return false + } + + return getShareRes.GetShare() != nil +} + +func (h *Handler) removeFederatedShare(w http.ResponseWriter, r *http.Request, shareID string) { + ctx := r.Context() + + client, err := pool.GetGatewayServiceClient(h.gatewayAddr) + if err != nil { + response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error getting grpc gateway client", err) + return + } + + shareRef := &ocmpb.ShareReference_Id{Id: &ocmpb.ShareId{OpaqueId: shareID}} + // Get the share, so that we can include it in the response. + getShareResp, err := client.GetOCMShare(ctx, &ocmpb.GetOCMShareRequest{Ref: &ocmpb.ShareReference{Spec: shareRef}}) + if err != nil { + response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error sending a grpc delete share request", err) + return + } + if getShareResp.Status.Code != rpc.Code_CODE_OK { + if getShareResp.Status.Code == rpc.Code_CODE_NOT_FOUND { + response.WriteOCSError(w, r, response.MetaNotFound.StatusCode, "not found", nil) + return + } + response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "deleting share failed", err) + return + } + + data, err := conversions.OCMShare2ShareData(getShareResp.Share) + if err != nil { + response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "deleting share failed", err) + return + } + // A deleted share should not have an ID. + data.ID = "" + + uRes, err := client.RemoveOCMShare(ctx, &ocmpb.RemoveOCMShareRequest{Ref: &ocmpb.ShareReference{Spec: shareRef}}) + if err != nil { + response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error sending a grpc delete share request", err) + return + } + + if uRes.Status.Code != rpc.Code_CODE_OK { + if uRes.Status.Code == rpc.Code_CODE_NOT_FOUND { + response.WriteOCSError(w, r, response.MetaNotFound.StatusCode, "not found", nil) + return + } + response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "grpc delete share request failed", err) + return + } + response.WriteOCSSuccess(w, r, data) +} + +func (h *Handler) isFederatedReceivedShare(r *http.Request, shareID string) bool { + log := appctx.GetLogger(r.Context()) + client, err := pool.GetGatewayServiceClient(h.gatewayAddr) + if err != nil { + log.Err(err).Send() + return false + } + + getShareRes, err := client.GetReceivedOCMShare(r.Context(), &ocmpb.GetReceivedOCMShareRequest{ + Ref: &ocmpb.ShareReference{ + Spec: &ocmpb.ShareReference_Id{ + Id: &ocmpb.ShareId{ + OpaqueId: shareID, + }, + }, + }, + }) + if err != nil { + log.Err(err).Send() + return false + } + + return getShareRes.GetShare() != nil +} + func (h *Handler) removeUserShare(w http.ResponseWriter, r *http.Request, share *collaboration.Share) { ctx := r.Context() diff --git a/vendor/github.com/cs3org/reva/v2/internal/http/services/sciencemesh/sciencemesh.go b/vendor/github.com/cs3org/reva/v2/internal/http/services/sciencemesh/sciencemesh.go index e98d49d9f..49dbde86b 100644 --- a/vendor/github.com/cs3org/reva/v2/internal/http/services/sciencemesh/sciencemesh.go +++ b/vendor/github.com/cs3org/reva/v2/internal/http/services/sciencemesh/sciencemesh.go @@ -63,8 +63,8 @@ type config struct { Prefix string `mapstructure:"prefix"` SMTPCredentials *smtpclient.SMTPCredentials `mapstructure:"smtp_credentials" validate:"required"` GatewaySvc string `mapstructure:"gatewaysvc" validate:"required"` - MeshDirectoryURL string `mapstructure:"mesh_directory_url" validate:"required"` ProviderDomain string `mapstructure:"provider_domain" validate:"required"` + MeshDirectoryURL string `mapstructure:"mesh_directory_url"` SubjectTemplate string `mapstructure:"subject_template"` BodyTemplatePath string `mapstructure:"body_template_path"` OCMMountPoint string `mapstructure:"ocm_mount_point"` diff --git a/vendor/github.com/cs3org/reva/v2/internal/http/services/sciencemesh/token.go b/vendor/github.com/cs3org/reva/v2/internal/http/services/sciencemesh/token.go index 946aa9743..4879a9400 100644 --- a/vendor/github.com/cs3org/reva/v2/internal/http/services/sciencemesh/token.go +++ b/vendor/github.com/cs3org/reva/v2/internal/http/services/sciencemesh/token.go @@ -76,7 +76,7 @@ type token struct { Token string `json:"token"` Description string `json:"description,omitempty"` Expiration uint64 `json:"expiration,omitempty"` - InviteLink string `json:"invite_link"` + InviteLink string `json:"invite_link,omitempty"` } // Generate generates an invitation token and if a recipient is specified, @@ -122,7 +122,9 @@ func (h *tokenHandler) prepareGenerateTokenResponse(tkn *invitepb.InviteToken) * res := &token{ Token: tkn.Token, Description: tkn.Description, - InviteLink: h.meshDirectoryURL + "?token=" + tkn.Token + "&providerDomain=" + h.providerDomain, + } + if h.meshDirectoryURL != "" { + res.InviteLink = h.meshDirectoryURL + "?token=" + tkn.Token + "&providerDomain=" + h.providerDomain } if tkn.Expiration != nil { res.Expiration = tkn.Expiration.Seconds @@ -187,7 +189,7 @@ func (h *tokenHandler) AcceptInvite(w http.ResponseWriter, r *http.Request) { reqres.WriteError(w, r, reqres.APIErrorAlreadyExist, "user already known", nil) return case rpc.Code_CODE_PERMISSION_DENIED: - reqres.WriteError(w, r, reqres.APIErrorUnauthenticated, "remove service not trusted", nil) + reqres.WriteError(w, r, reqres.APIErrorUnauthenticated, "remote service not trusted", nil) return default: reqres.WriteError(w, r, reqres.APIErrorServerError, "unexpected error: "+forwardInviteResponse.Status.Message, errors.New(forwardInviteResponse.Status.Message)) diff --git a/vendor/github.com/cs3org/reva/v2/pkg/conversions/main.go b/vendor/github.com/cs3org/reva/v2/pkg/conversions/main.go index 755faa64a..8ef5dc395 100644 --- a/vendor/github.com/cs3org/reva/v2/pkg/conversions/main.go +++ b/vendor/github.com/cs3org/reva/v2/pkg/conversions/main.go @@ -21,15 +21,19 @@ package conversions import ( "context" + "encoding/base64" "fmt" "net/http" "path" + "path/filepath" "time" "github.com/cs3org/reva/v2/pkg/errtypes" "github.com/cs3org/reva/v2/pkg/mime" "github.com/cs3org/reva/v2/pkg/publicshare" + "github.com/cs3org/reva/v2/pkg/storagespace" "github.com/cs3org/reva/v2/pkg/user" + "github.com/cs3org/reva/v2/pkg/utils" grouppb "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1" userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" @@ -222,6 +226,7 @@ type MatchData struct { type MatchValueData struct { ShareType int `json:"shareType" xml:"shareType"` ShareWith string `json:"shareWith" xml:"shareWith"` + ShareWithProvider string `json:"shareWithProvider" xml:"shareWithProvider"` ShareWithAdditionalInfo string `json:"shareWithAdditionalInfo" xml:"shareWithAdditionalInfo,omitempty"` UserType int `json:"userType" xml:"userType"` } @@ -325,6 +330,10 @@ func ReceivedOCMShare2ShareData(share *ocm.ReceivedShare, path string) (*ShareDa return nil, errtypes.InternalError("webdav endpoint not in share") } + opaqueid := base64.StdEncoding.EncodeToString([]byte("/")) + + shareTarget := filepath.Join("/Shares", share.Name) + s := &ShareData{ ID: share.Id.OpaqueId, UIDOwner: formatRemoteUser(share.Creator), @@ -332,13 +341,18 @@ func ReceivedOCMShare2ShareData(share *ocm.ReceivedShare, path string) (*ShareDa ShareWith: share.Grantee.GetUserId().OpaqueId, Permissions: RoleFromResourcePermissions(webdav.GetPermissions().GetPermissions(), false).OCSPermissions(), ShareType: ShareTypeFederatedCloudShare, - Path: path, - FileTarget: path, + Path: shareTarget, + FileTarget: shareTarget, MimeType: mime.Detect(share.ResourceType == provider.ResourceType_RESOURCE_TYPE_CONTAINER, share.Name), ItemType: ResourceType(share.ResourceType).String(), - ItemSource: path, - STime: share.Ctime.Seconds, - Name: share.Name, + ItemSource: storagespace.FormatResourceID(provider.ResourceId{ + StorageId: utils.OCMStorageProviderID, + SpaceId: share.Id.OpaqueId, + OpaqueId: opaqueid, + }), + STime: share.Ctime.Seconds, + Name: share.Name, + SpaceID: storagespace.FormatStorageID(utils.OCMStorageProviderID, share.Id.OpaqueId), } if share.Expiration != nil { diff --git a/vendor/github.com/cs3org/reva/v2/pkg/ocm/invite/repository/json/json.go b/vendor/github.com/cs3org/reva/v2/pkg/ocm/invite/repository/json/json.go index b5a64ef10..9fd92b0ef 100644 --- a/vendor/github.com/cs3org/reva/v2/pkg/ocm/invite/repository/json/json.go +++ b/vendor/github.com/cs3org/reva/v2/pkg/ocm/invite/repository/json/json.go @@ -22,7 +22,9 @@ import ( "context" "encoding/json" "io" + "net/url" "os" + "path/filepath" "strings" "sync" "time" @@ -89,6 +91,9 @@ func New(m map[string]interface{}) (invite.Repository, error) { func loadOrCreate(file string) (*inviteModel, error) { _, err := os.Stat(file) if os.IsNotExist(err) { + if err := os.MkdirAll(filepath.Dir(file), 0700); err != nil { + return nil, errors.Wrap(err, "error creating the ocm storage dir: "+filepath.Dir(file)) + } if err := os.WriteFile(file, []byte("{}"), 0700); err != nil { return nil, errors.Wrap(err, "error creating the invite storage file: "+file) } @@ -169,7 +174,7 @@ func (m *manager) ListTokens(ctx context.Context, initiator *userpb.UserId) ([]* } func tokenIsExpired(token *invitepb.InviteToken) bool { - return token.Expiration != nil && token.Expiration.Seconds > uint64(time.Now().Unix()) + return token.Expiration != nil && token.Expiration.Seconds < uint64(time.Now().Unix()) } func (m *manager) AddRemoteUser(ctx context.Context, initiator *userpb.UserId, remoteUser *userpb.User) error { @@ -177,7 +182,7 @@ func (m *manager) AddRemoteUser(ctx context.Context, initiator *userpb.UserId, r defer m.Unlock() for _, acceptedUser := range m.model.AcceptedUsers[initiator.GetOpaqueId()] { - if acceptedUser.Id.GetOpaqueId() == remoteUser.Id.OpaqueId && acceptedUser.Id.GetIdp() == remoteUser.Id.Idp { + if acceptedUser.Id.GetOpaqueId() == remoteUser.Id.OpaqueId && idpsEqual(acceptedUser.Id.GetIdp(), remoteUser.Id.Idp) { return invite.ErrUserAlreadyAccepted } } @@ -189,6 +194,31 @@ func (m *manager) AddRemoteUser(ctx context.Context, initiator *userpb.UserId, r return nil } +func idpsEqual(idp1, idp2 string) bool { + normalizeIDP := func(s string) (string, error) { + u, err := url.Parse(s) + if err != nil { + return "", errors.New("could not parse url") + } + + if u.Scheme == "" { + return strings.ToLower(u.Path), nil // the string is just a hostname + } + return strings.ToLower(u.Hostname()), nil + } + + domain1, err := normalizeIDP(idp1) + if err != nil { + return false + } + domain2, err := normalizeIDP(idp2) + if err != nil { + return false + } + + return domain1 == domain2 +} + func (m *manager) GetRemoteUser(ctx context.Context, initiator *userpb.UserId, remoteUserID *userpb.UserId) (*userpb.User, error) { m.RLock() defer m.RUnlock() @@ -201,7 +231,7 @@ func (m *manager) GetRemoteUser(ctx context.Context, initiator *userpb.UserId, r acceptedUser.Id.GetOpaqueId(), acceptedUser.Id.GetIdp(), ) - if (acceptedUser.Id.GetOpaqueId() == remoteUserID.OpaqueId) && (remoteUserID.Idp == "" || acceptedUser.Id.GetIdp() == remoteUserID.Idp) { + if (acceptedUser.Id.GetOpaqueId() == remoteUserID.OpaqueId) && (remoteUserID.Idp == "" || idpsEqual(acceptedUser.Id.GetIdp(), remoteUserID.Idp)) { return acceptedUser, nil } } diff --git a/vendor/github.com/cs3org/reva/v2/pkg/ocm/storage/received/ocm.go b/vendor/github.com/cs3org/reva/v2/pkg/ocm/storage/received/ocm.go index 7c74a59c1..95ab95492 100644 --- a/vendor/github.com/cs3org/reva/v2/pkg/ocm/storage/received/ocm.go +++ b/vendor/github.com/cs3org/reva/v2/pkg/ocm/storage/received/ocm.go @@ -20,6 +20,8 @@ package ocm import ( "context" + "crypto/tls" + "encoding/base64" "io" "io/fs" "net/http" @@ -58,12 +60,39 @@ type driver struct { type config struct { GatewaySVC string `mapstructure:"gatewaysvc"` + Insecure bool `mapstructure:"insecure"` } func (c *config) ApplyDefaults() { c.GatewaySVC = sharedconf.GetGatewaySVC(c.GatewaySVC) } +// BearerAuthenticator represents an authenticator that adds a Bearer token to the Authorization header of HTTP requests. +type BearerAuthenticator struct { + token string +} + +// Authorize adds the Bearer token to the Authorization header of the provided HTTP request. +func (b BearerAuthenticator) Authorize(_ *http.Client, r *http.Request, _ string) error { + r.Header.Add("Authorization", "Bearer "+b.token) + return nil +} + +// Verify is not implemented for the BearerAuthenticator. It always returns false and nil error. +func (BearerAuthenticator) Verify(*http.Client, *http.Response, string) (bool, error) { + return false, nil +} + +// Clone creates a new instance of the BearerAuthenticator. +func (BearerAuthenticator) Clone() gowebdav.Authenticator { + return BearerAuthenticator{} +} + +// Close is not implemented for the BearerAuthenticator. It always returns nil. +func (BearerAuthenticator) Close() error { + return nil +} + // New creates an OCM storage driver. func New(m map[string]interface{}, _ events.Stream) (storage.FS, error) { var c config @@ -95,7 +124,16 @@ func shareInfoFromReference(ref *provider.Reference) (*ocmpb.ShareId, string) { return shareInfoFromPath(ref.Path) } - return &ocmpb.ShareId{OpaqueId: ref.ResourceId.OpaqueId}, ref.Path + if ref.ResourceId.SpaceId == ref.ResourceId.OpaqueId { + return &ocmpb.ShareId{OpaqueId: ref.ResourceId.SpaceId}, ref.Path + } + decodedBytes, err := base64.StdEncoding.DecodeString(ref.ResourceId.OpaqueId) + if err != nil { + // this should never happen + return &ocmpb.ShareId{OpaqueId: ref.ResourceId.SpaceId}, ref.Path + } + return &ocmpb.ShareId{OpaqueId: ref.ResourceId.SpaceId}, filepath.Join(string(decodedBytes), ref.Path) + } func (d *driver) getWebDAVFromShare(ctx context.Context, shareID *ocmpb.ShareId) (*ocmpb.ReceivedShare, string, string, error) { @@ -150,8 +188,12 @@ func (d *driver) webdavClient(ctx context.Context, ref *provider.Reference) (*go // FIXME: it's still not clear from the OCM APIs how to use the shared secret // will use as a token in the bearer authentication as this is the reva implementation - c := gowebdav.NewClient(endpoint, "", "") - c.SetHeader("Authorization", "Bearer "+secret) + c := gowebdav.NewAuthClient(endpoint, gowebdav.NewPreemptiveAuth(BearerAuthenticator{token: secret})) + if d.c.Insecure { + c.SetTransport(&http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + }) + } return c, share, rel, nil } @@ -194,7 +236,7 @@ func getPathFromShareIDAndRelPath(shareID *ocmpb.ShareId, relPath string) string return filepath.Join("/", shareID.OpaqueId, relPath) } -func convertStatToResourceInfo(ref *provider.Reference, f fs.FileInfo, share *ocmpb.ReceivedShare, relPath string) *provider.ResourceInfo { +func convertStatToResourceInfo(ref *provider.Reference, f fs.FileInfo, share *ocmpb.ReceivedShare) (*provider.ResourceInfo, error) { t := provider.ResourceType_RESOURCE_TYPE_FILE if f.IsDir() { t = provider.ResourceType_RESOURCE_TYPE_CONTAINER @@ -207,24 +249,36 @@ func convertStatToResourceInfo(ref *provider.Reference, f fs.FileInfo, share *oc name = f.Name() } - webdav, _ := getWebDAVProtocol(share.Protocols) + webdavFile, ok := f.(gowebdav.File) + if !ok { + return nil, errtypes.InternalError("could not get webdav props") + } + opaqueid := base64.StdEncoding.EncodeToString([]byte(webdavFile.Path())) + + // ids are of the format $! + id := &provider.ResourceId{ + StorageId: utils.OCMStorageProviderID, + SpaceId: share.Id.OpaqueId, + OpaqueId: opaqueid, + } + webdavProtocol, _ := getWebDAVProtocol(share.Protocols) return &provider.ResourceInfo{ Type: t, - Id: ref.ResourceId, + Id: id, MimeType: mime.Detect(f.IsDir(), f.Name()), - Path: relPath, + Path: name, Name: name, Size: uint64(f.Size()), Mtime: &typepb.Timestamp{ Seconds: uint64(f.ModTime().Unix()), }, Owner: share.Creator, - PermissionSet: webdav.Permissions.Permissions, + PermissionSet: webdavProtocol.Permissions.Permissions, Checksum: &provider.ResourceChecksum{ Type: provider.ResourceChecksumType_RESOURCE_CHECKSUM_TYPE_INVALID, }, - } + }, nil } func (d *driver) GetMD(ctx context.Context, ref *provider.Reference, _ []string, _ []string) (*provider.ResourceInfo, error) { @@ -233,7 +287,7 @@ func (d *driver) GetMD(ctx context.Context, ref *provider.Reference, _ []string, return nil, err } - info, err := client.Stat(rel) + info, err := client.StatWithProps(rel, []string{}) // request all properties by giving an empty list if err != nil { if gowebdav.IsErrNotFound(err) { return nil, errtypes.NotFound(ref.GetPath()) @@ -241,7 +295,7 @@ func (d *driver) GetMD(ctx context.Context, ref *provider.Reference, _ []string, return nil, err } - return convertStatToResourceInfo(ref, info, share, rel), nil + return convertStatToResourceInfo(ref, info, share) } func (d *driver) ListFolder(ctx context.Context, ref *provider.Reference, _ []string, _ []string) ([]*provider.ResourceInfo, error) { @@ -250,14 +304,18 @@ func (d *driver) ListFolder(ctx context.Context, ref *provider.Reference, _ []st return nil, err } - list, err := client.ReadDir(rel) + list, err := client.ReadDirWithProps(rel, []string{}) // request all properties by giving an empty list if err != nil { return nil, err } res := make([]*provider.ResourceInfo, 0, len(list)) for _, r := range list { - res = append(res, convertStatToResourceInfo(ref, r, share, utils.MakeRelativePath(filepath.Join(rel, r.Name())))) + info, err := convertStatToResourceInfo(ref, r, share) + if err != nil { + return nil, err + } + res = append(res, info) } return res, nil } @@ -429,7 +487,7 @@ func (d *driver) ListStorageSpaces(ctx context.Context, filters []*provider.List if k == "mountpoint" { for _, share := range lrsRes.Shares { root := &provider.ResourceId{ - StorageId: utils.PublicStorageProviderID, + StorageId: utils.OCMStorageProviderID, SpaceId: share.Id.OpaqueId, OpaqueId: share.Id.OpaqueId, } diff --git a/vendor/github.com/cs3org/reva/v2/pkg/utils/utils.go b/vendor/github.com/cs3org/reva/v2/pkg/utils/utils.go index fe4dc130d..8f97f7be8 100644 --- a/vendor/github.com/cs3org/reva/v2/pkg/utils/utils.go +++ b/vendor/github.com/cs3org/reva/v2/pkg/utils/utils.go @@ -59,6 +59,11 @@ var ( // PublicStorageSpaceID is the space id used by the sharestorageprovider PublicStorageSpaceID = "7993447f-687f-490d-875c-ac95e89a62a4" + // OCMStorageProviderID is the storage id used by the ocmreceived storageprovider + OCMStorageProviderID = "89f37a33-858b-45fa-8890-a1f2b27d90e1" + // OCMStorageSpaceID is the space id used by the ocmreceived storageprovider + OCMStorageSpaceID = "89f37a33-858b-45fa-8890-a1f2b27d90e1" + // SpaceGrant is used to signal the storageprovider that the grant is on a space SpaceGrant struct{} ) diff --git a/vendor/modules.txt b/vendor/modules.txt index 84d58d061..fe15ed96b 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -362,7 +362,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.17.0 +# github.com/cs3org/reva/v2 v2.17.1-0.20231214082636-a8467337208a ## explicit; go 1.21 github.com/cs3org/reva/v2/cmd/revad/internal/grace github.com/cs3org/reva/v2/cmd/revad/runtime