From d78f39cc1f474b4ed89ba71e9470cccefefc9fbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Tue, 7 Nov 2023 10:51:33 +0100 Subject: [PATCH 01/28] Use the OCMStorageProvider for accessing ocm shares --- pkg/conversions/main.go | 13 ++++++++++--- pkg/ocm/storage/received/ocm.go | 2 +- pkg/utils/utils.go | 5 +++++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/pkg/conversions/main.go b/pkg/conversions/main.go index 755faa64ad..c6f9cc8548 100644 --- a/pkg/conversions/main.go +++ b/pkg/conversions/main.go @@ -29,7 +29,9 @@ import ( "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" @@ -336,9 +338,14 @@ func ReceivedOCMShare2ShareData(share *ocm.ReceivedShare, path string) (*ShareDa FileTarget: path, 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: share.Id.OpaqueId, + }), + STime: share.Ctime.Seconds, + Name: share.Name, + SpaceID: storagespace.FormatStorageID(utils.OCMStorageProviderID, share.Id.OpaqueId), } if share.Expiration != nil { diff --git a/pkg/ocm/storage/received/ocm.go b/pkg/ocm/storage/received/ocm.go index 7c74a59c1a..3600728d02 100644 --- a/pkg/ocm/storage/received/ocm.go +++ b/pkg/ocm/storage/received/ocm.go @@ -429,7 +429,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/pkg/utils/utils.go b/pkg/utils/utils.go index fe4dc130d8..8f97f7be81 100644 --- a/pkg/utils/utils.go +++ b/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{} ) From 30b95134df694c85f93628674cbcfb9c9c749694 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Wed, 8 Nov 2023 11:27:07 +0100 Subject: [PATCH 02/28] Make ocm shares available via GetShare() --- .../handlers/apps/sharing/shares/shares.go | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go index 2621a33132..b230905fc4 100644 --- a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go +++ b/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) From c6f888e6aa05f486c2b9688d8637742d9f084c52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Wed, 8 Nov 2023 17:17:32 +0100 Subject: [PATCH 03/28] Implement accepting/rejecting federated shares --- .../handlers/apps/sharing/shares/pending.go | 83 +++++++++++++++++++ .../ocs/handlers/apps/sharing/shares/user.go | 50 +++++++++++ 2 files changed, 133 insertions(+) diff --git a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/pending.go b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/pending.go index 8709502c6b..b53d18021b 100644 --- a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/pending.go +++ b/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/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/user.go b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/user.go index d67d0f2d2e..5c60fc1c2d 100644 --- a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/user.go +++ b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/user.go @@ -155,6 +155,56 @@ 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) 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() From cfe2e917e6f13a4a716e644df3af9a7be9d5c69a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Thu, 9 Nov 2023 08:17:32 +0100 Subject: [PATCH 04/28] Fix removing federated shares --- .../handlers/apps/sharing/shares/shares.go | 4 ++ .../ocs/handlers/apps/sharing/shares/user.go | 50 +++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go index b230905fc4..a2552b69ea 100644 --- a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go +++ b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/shares.go @@ -918,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/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/user.go b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/user.go index 5c60fc1c2d..04498b2205 100644 --- a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/user.go +++ b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/user.go @@ -180,6 +180,56 @@ func (h *Handler) isFederatedShare(r *http.Request, shareID string) bool { 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) From 8cf10e45fd9be9fff16a72b55058f632d8ec93e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Thu, 9 Nov 2023 08:47:08 +0100 Subject: [PATCH 05/28] Fix write permissions of ocm shares --- internal/http/services/ocmd/protocols.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/http/services/ocmd/protocols.go b/internal/http/services/ocmd/protocols.go index 0c77358387..bbcc51350e 100644 --- a/internal/http/services/ocmd/protocols.go +++ b/internal/http/services/ocmd/protocols.go @@ -63,7 +63,11 @@ func (w *WebDAV) ToOCMProtocol() *ocm.Protocol { perms.Permissions.ListContainer = true perms.Permissions.Stat = true case "write": + perms.Permissions.CreateContainer = true perms.Permissions.InitiateFileUpload = true + perms.Permissions.Delete = true + perms.Permissions.Move = true + perms.Permissions.ListGrants = true case "share": perms.Reshare = true } From d92575df76f399511a20d967b439c8a56ac1fc62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Thu, 9 Nov 2023 09:11:36 +0100 Subject: [PATCH 06/28] Make the mesh directory URL optional --- internal/http/services/sciencemesh/sciencemesh.go | 2 +- internal/http/services/sciencemesh/token.go | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/internal/http/services/sciencemesh/sciencemesh.go b/internal/http/services/sciencemesh/sciencemesh.go index e98d49d9fe..49dbde86b5 100644 --- a/internal/http/services/sciencemesh/sciencemesh.go +++ b/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/internal/http/services/sciencemesh/token.go b/internal/http/services/sciencemesh/token.go index 946aa97430..e7d69693b2 100644 --- a/internal/http/services/sciencemesh/token.go +++ b/internal/http/services/sciencemesh/token.go @@ -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 From 4c4a47b8d6692470d792cb9e14d74e98a5a48c76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Thu, 9 Nov 2023 11:22:43 +0100 Subject: [PATCH 07/28] Omit empty invite links --- internal/http/services/sciencemesh/token.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/http/services/sciencemesh/token.go b/internal/http/services/sciencemesh/token.go index e7d69693b2..aaa4b1b184 100644 --- a/internal/http/services/sciencemesh/token.go +++ b/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, From 404b5f377f7dbabeaae75dd8ef04d4b5c1645a80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Fri, 10 Nov 2023 11:06:54 +0100 Subject: [PATCH 08/28] Fix typo --- internal/http/services/sciencemesh/token.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/http/services/sciencemesh/token.go b/internal/http/services/sciencemesh/token.go index aaa4b1b184..4879a9400f 100644 --- a/internal/http/services/sciencemesh/token.go +++ b/internal/http/services/sciencemesh/token.go @@ -189,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)) From caacf8e7d7db5057f73fb67832e16d1eac417c85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Fri, 10 Nov 2023 11:07:06 +0100 Subject: [PATCH 09/28] Be more robust matching idps --- pkg/ocm/invite/repository/json/json.go | 30 ++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/pkg/ocm/invite/repository/json/json.go b/pkg/ocm/invite/repository/json/json.go index b5a64ef10d..dc0bb0cd9d 100644 --- a/pkg/ocm/invite/repository/json/json.go +++ b/pkg/ocm/invite/repository/json/json.go @@ -22,6 +22,7 @@ import ( "context" "encoding/json" "io" + "net/url" "os" "strings" "sync" @@ -177,7 +178,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 +190,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 +227,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 } } From d3ab37322707d10b3e2c822caaca93b67447595e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Mon, 13 Nov 2023 07:40:09 +0100 Subject: [PATCH 10/28] Add changelog --- changelog/2.17.0_2023-12-12/ocm.md | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog/2.17.0_2023-12-12/ocm.md b/changelog/2.17.0_2023-12-12/ocm.md index 755ca39f48..341e478372 100644 --- a/changelog/2.17.0_2023-12-12/ocm.md +++ b/changelog/2.17.0_2023-12-12/ocm.md @@ -2,5 +2,6 @@ Enhancement: Port OCM changes from master We pulled in the latest ocm changes from master and are now compatible with the main go-cs3apis again. +https://github.com/cs3org/reva/pull/4333 https://github.com/cs3org/reva/pull/4281 https://github.com/cs3org/reva/pull/4239 From 00ff898bc3e7ab6d99ac8fae262f37d52fd2e9e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Mon, 13 Nov 2023 08:14:06 +0100 Subject: [PATCH 11/28] Fix wrong paths in path-based ocm propfinds --- pkg/ocm/storage/received/ocm.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/ocm/storage/received/ocm.go b/pkg/ocm/storage/received/ocm.go index 3600728d02..d28523821d 100644 --- a/pkg/ocm/storage/received/ocm.go +++ b/pkg/ocm/storage/received/ocm.go @@ -194,7 +194,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 { t := provider.ResourceType_RESOURCE_TYPE_FILE if f.IsDir() { t = provider.ResourceType_RESOURCE_TYPE_CONTAINER @@ -213,7 +213,7 @@ func convertStatToResourceInfo(ref *provider.Reference, f fs.FileInfo, share *oc Type: t, Id: ref.ResourceId, MimeType: mime.Detect(f.IsDir(), f.Name()), - Path: relPath, + Path: name, Name: name, Size: uint64(f.Size()), Mtime: &typepb.Timestamp{ @@ -241,7 +241,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), nil } func (d *driver) ListFolder(ctx context.Context, ref *provider.Reference, _ []string, _ []string) ([]*provider.ResourceInfo, error) { @@ -257,7 +257,7 @@ func (d *driver) ListFolder(ctx context.Context, ref *provider.Reference, _ []st 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())))) + res = append(res, convertStatToResourceInfo(ref, r, share)) } return res, nil } From 86188050011cbe120765c190ca849399ce331565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Mon, 13 Nov 2023 08:35:42 +0100 Subject: [PATCH 12/28] Fix integration tests --- tests/integration/grpc/ocm_share_test.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/integration/grpc/ocm_share_test.go b/tests/integration/grpc/ocm_share_test.go index 1a8c39a2ec..7a7f6054e5 100644 --- a/tests/integration/grpc/ocm_share_test.go +++ b/tests/integration/grpc/ocm_share_test.go @@ -51,10 +51,14 @@ import ( var ( editorPermissions = &provider.ResourcePermissions{ + CreateContainer: true, + Delete: true, + GetPath: true, InitiateFileDownload: true, InitiateFileUpload: true, ListContainer: true, - GetPath: true, + ListGrants: true, + Move: true, Stat: true, } viewerPermissions = &provider.ResourcePermissions{ @@ -574,7 +578,7 @@ var _ = Describe("ocm share", func() { SpaceId: share.Id.OpaqueId, }, Name: "foo", - Path: "./dir/foo", + Path: "foo", Size: 7, Type: provider.ResourceType_RESOURCE_TYPE_FILE, PermissionSet: editorPermissions, @@ -586,7 +590,7 @@ var _ = Describe("ocm share", func() { SpaceId: share.Id.OpaqueId, }, Name: "bar", - Path: "./dir/bar", + Path: "bar", Size: 0, Type: provider.ResourceType_RESOURCE_TYPE_CONTAINER, PermissionSet: editorPermissions, From 049bc1d1bac1dd0fbe6a931040fa4878fa40414c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Tue, 14 Nov 2023 11:41:53 +0100 Subject: [PATCH 13/28] Fix logic when detecting expired tokens --- pkg/ocm/invite/repository/json/json.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/ocm/invite/repository/json/json.go b/pkg/ocm/invite/repository/json/json.go index dc0bb0cd9d..860e4883ce 100644 --- a/pkg/ocm/invite/repository/json/json.go +++ b/pkg/ocm/invite/repository/json/json.go @@ -170,7 +170,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 { From 012e23110032624eeae8e14bb14783cca2309383 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Fri, 17 Nov 2023 09:37:04 +0100 Subject: [PATCH 14/28] Use the actual fileids retrieved from the PROPFIND as the file ids --- pkg/ocm/storage/received/ocm.go | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/pkg/ocm/storage/received/ocm.go b/pkg/ocm/storage/received/ocm.go index d28523821d..21abed3674 100644 --- a/pkg/ocm/storage/received/ocm.go +++ b/pkg/ocm/storage/received/ocm.go @@ -20,6 +20,7 @@ package ocm import ( "context" + "encoding/xml" "io" "io/fs" "net/http" @@ -194,7 +195,11 @@ 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) *provider.ResourceInfo { +func convertStatToResourceInfo(ref *provider.Reference, f fs.FileInfo, share *ocmpb.ReceivedShare) (*provider.ResourceInfo, error) { + props, ok := f.Sys().(gowebdav.Props) + if !ok { + return nil, errtypes.InternalError("could not get webdav props") + } t := provider.ResourceType_RESOURCE_TYPE_FILE if f.IsDir() { t = provider.ResourceType_RESOURCE_TYPE_CONTAINER @@ -207,11 +212,15 @@ func convertStatToResourceInfo(ref *provider.Reference, f fs.FileInfo, share *oc name = f.Name() } - webdav, _ := getWebDAVProtocol(share.Protocols) + id, err := storagespace.ParseID(props.GetString(xml.Name{Space: "http://owncloud.org/ns", Local: "fileid"})) + if err != nil { + return nil, err + } + webdavProtocol, _ := getWebDAVProtocol(share.Protocols) return &provider.ResourceInfo{ Type: t, - Id: ref.ResourceId, + Id: &id, MimeType: mime.Detect(f.IsDir(), f.Name()), Path: name, Name: name, @@ -220,11 +229,11 @@ func convertStatToResourceInfo(ref *provider.Reference, f fs.FileInfo, share *oc 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 +242,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 +250,7 @@ func (d *driver) GetMD(ctx context.Context, ref *provider.Reference, _ []string, return nil, err } - return convertStatToResourceInfo(ref, info, share), nil + return convertStatToResourceInfo(ref, info, share) } func (d *driver) ListFolder(ctx context.Context, ref *provider.Reference, _ []string, _ []string) ([]*provider.ResourceInfo, error) { @@ -250,14 +259,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)) + info, err := convertStatToResourceInfo(ref, r, share) + if err != nil { + return nil, err + } + res = append(res, info) } return res, nil } From b33b0d19fee5418cb960aa36ac2d6174e7d4a620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Fri, 17 Nov 2023 09:39:50 +0100 Subject: [PATCH 15/28] Use webdav client fork which supports retrieving custom props --- go.mod | 2 ++ go.sum | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index a534bf5a48..692c5ee1b4 100644 --- a/go.mod +++ b/go.mod @@ -230,3 +230,5 @@ require ( ) replace github.com/go-micro/plugins/v4/store/nats-js-kv => github.com/kobergj/plugins/v4/store/nats-js-kv v0.0.0-20231207143248-4d424e3ae348 + +replace github.com/studio-b12/gowebdav => github.com/aduffeck/gowebdav v0.0.0-20231117083401-b14990633b9d diff --git a/go.sum b/go.sum index 6e6ce496e3..32b5f30ab1 100644 --- a/go.sum +++ b/go.sum @@ -425,6 +425,8 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= +github.com/aduffeck/gowebdav v0.0.0-20231117083401-b14990633b9d h1:Y37AUa3JNBl5YmIarl3sx/ftW+7oWgu2Cp0eExZsQPA= +github.com/aduffeck/gowebdav v0.0.0-20231117083401-b14990633b9d/go.mod h1:bHA7t77X/QFExdeAnDzK6vKM34kEZAcE1OX4MfiwjkE= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -1210,8 +1212,6 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/studio-b12/gowebdav v0.0.0-20221015232716-17255f2e7423 h1:Wd8WDEEusB5+En4PiRWJp1cP59QLNsQun+mOTW8+s6s= -github.com/studio-b12/gowebdav v0.0.0-20221015232716-17255f2e7423/go.mod h1:bHA7t77X/QFExdeAnDzK6vKM34kEZAcE1OX4MfiwjkE= github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE= From dcefdde916fc1b02fa83b164cf9ecad579281406 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Mon, 20 Nov 2023 07:45:45 +0100 Subject: [PATCH 16/28] Change format of ocm share file ids to $! --- pkg/ocm/storage/received/ocm.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/pkg/ocm/storage/received/ocm.go b/pkg/ocm/storage/received/ocm.go index 21abed3674..73be2129d1 100644 --- a/pkg/ocm/storage/received/ocm.go +++ b/pkg/ocm/storage/received/ocm.go @@ -21,6 +21,7 @@ package ocm import ( "context" "encoding/xml" + "fmt" "io" "io/fs" "net/http" @@ -212,15 +213,22 @@ func convertStatToResourceInfo(ref *provider.Reference, f fs.FileInfo, share *oc name = f.Name() } - id, err := storagespace.ParseID(props.GetString(xml.Name{Space: "http://owncloud.org/ns", Local: "fileid"})) + remoteId, err := storagespace.ParseID(props.GetString(xml.Name{Space: "http://owncloud.org/ns", Local: "fileid"})) if err != nil { return nil, err } + + // ids are of the format $! + id := &provider.ResourceId{ + StorageId: utils.OCMStorageProviderID, + SpaceId: share.Id.OpaqueId, + OpaqueId: fmt.Sprintf("%s:%s:%s", remoteId.StorageId, remoteId.SpaceId, remoteId.OpaqueId), + } webdavProtocol, _ := getWebDAVProtocol(share.Protocols) return &provider.ResourceInfo{ Type: t, - Id: &id, + Id: id, MimeType: mime.Detect(f.IsDir(), f.Name()), Path: name, Name: name, From e79c140857347c7ea1e5d9bfa26ce397404a8cc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Mon, 20 Nov 2023 15:19:37 +0100 Subject: [PATCH 17/28] Include remote users in the sharee response --- .../handlers/apps/sharing/sharees/sharees.go | 49 ++++++++++++++----- .../handlers/apps/sharing/shares/remote.go | 2 +- pkg/conversions/main.go | 1 + 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/internal/http/services/owncloud/ocs/handlers/apps/sharing/sharees/sharees.go b/internal/http/services/owncloud/ocs/handlers/apps/sharing/sharees/sharees.go index 3feaf9096c..7d1a46aad3 100644 --- a/internal/http/services/owncloud/ocs/handlers/apps/sharing/sharees/sharees.go +++ b/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" @@ -79,6 +81,25 @@ func (h *Handler) FindSharees(w http.ResponseWriter, r *http.Request) { } } + 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 +132,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/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/remote.go b/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/remote.go index c118f559c8..7cbf494682 100644 --- a/internal/http/services/owncloud/ocs/handlers/apps/sharing/shares/remote.go +++ b/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/pkg/conversions/main.go b/pkg/conversions/main.go index c6f9cc8548..6ff462be8d 100644 --- a/pkg/conversions/main.go +++ b/pkg/conversions/main.go @@ -224,6 +224,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"` } From 2b5d49ce469a194083595950148b903c4c58f9f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Tue, 21 Nov 2023 07:42:57 +0100 Subject: [PATCH 18/28] Allow for disabling the certificate check for webdav connections --- pkg/ocm/storage/received/ocm.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pkg/ocm/storage/received/ocm.go b/pkg/ocm/storage/received/ocm.go index 73be2129d1..6870586195 100644 --- a/pkg/ocm/storage/received/ocm.go +++ b/pkg/ocm/storage/received/ocm.go @@ -20,6 +20,7 @@ package ocm import ( "context" + "crypto/tls" "encoding/xml" "fmt" "io" @@ -60,6 +61,7 @@ type driver struct { type config struct { GatewaySVC string `mapstructure:"gatewaysvc"` + Insecure bool `mapstructure:"insecure"` } func (c *config) ApplyDefaults() { @@ -153,6 +155,11 @@ 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, "", "") + if d.c.Insecure { + c.SetTransport(&http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + }) + } c.SetHeader("Authorization", "Bearer "+secret) return c, share, rel, nil From 2b7bbb31e30aaf0769779c5b0a17107770d821f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Tue, 21 Nov 2023 08:58:43 +0100 Subject: [PATCH 19/28] Fix tests --- tests/integration/grpc/ocm_share_test.go | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/tests/integration/grpc/ocm_share_test.go b/tests/integration/grpc/ocm_share_test.go index 7a7f6054e5..e1a3df64f1 100644 --- a/tests/integration/grpc/ocm_share_test.go +++ b/tests/integration/grpc/ocm_share_test.go @@ -265,7 +265,7 @@ var _ = Describe("ocm share", func() { Expect(statRes.Info.Id).ToNot(BeNil()) checkResourceInfo(statRes.Info, &provider.ResourceInfo{ Name: "new-file", - Path: ".", + Path: "new-file", Size: 4, Type: provider.ResourceType_RESOURCE_TYPE_FILE, PermissionSet: viewerPermissions, @@ -331,9 +331,18 @@ var _ = Describe("ocm share", func() { webdav, ok := protocol.Term.(*ocmv1beta1.Protocol_WebdavOptions) Expect(ok).To(BeTrue()) - webdavClient := gowebdav.NewClient(webdav.WebdavOptions.Uri, "", "") data := []byte("new-content") + webdavClient := gowebdav.NewClient(webdav.WebdavOptions.Uri, "", "") webdavClient.SetHeader(net.HeaderContentLength, strconv.Itoa(len(data))) + webdavClient.SetInterceptor(func(method string, rq *http.Request) { + // Set the content length on the request struct directly instead of the header. + // The content-length header gets reset by the golang http library before + // sendind out the request, resulting in chunked encoding to be used which + // breaks the quota checks in ocdav. + if method == "PUT" { + rq.ContentLength = int64(len(data)) + } + }) err = webdavClient.Write(".", data, 0) Expect(err).ToNot(HaveOccurred()) @@ -349,7 +358,7 @@ var _ = Describe("ocm share", func() { Expect(statRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK)) checkResourceInfo(statRes.Info, &provider.ResourceInfo{ Name: "new-file", - Path: ".", + Path: "new-file", Size: uint64(len(data)), Type: provider.ResourceType_RESOURCE_TYPE_FILE, PermissionSet: editorPermissions, @@ -453,7 +462,7 @@ var _ = Describe("ocm share", func() { OpaqueId: share.Id.OpaqueId, }, Name: "foo", - Path: "./dir/foo", + Path: "foo", Size: 7, Type: provider.ResourceType_RESOURCE_TYPE_FILE, PermissionSet: viewerPermissions, @@ -465,7 +474,7 @@ var _ = Describe("ocm share", func() { OpaqueId: share.Id.OpaqueId, }, Name: "bar", - Path: "./dir/bar", + Path: "bar", Size: 0, Type: provider.ResourceType_RESOURCE_TYPE_CONTAINER, PermissionSet: viewerPermissions, From b6136ac618fd380d674886c4716aabfa88436d98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Tue, 21 Nov 2023 11:06:54 +0100 Subject: [PATCH 20/28] Include the displayname when requesting all Props --- internal/http/services/owncloud/ocdav/propfind/propfind.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/http/services/owncloud/ocdav/propfind/propfind.go b/internal/http/services/owncloud/ocdav/propfind/propfind.go index d410bfcba7..3405c402e6 100644 --- a/internal/http/services/owncloud/ocdav/propfind/propfind.go +++ b/internal/http/services/owncloud/ocdav/propfind/propfind.go @@ -1174,6 +1174,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 != "" { From f8e64e0a86769721f3784a02e21da80ab62a9ac4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Tue, 21 Nov 2023 15:46:13 +0100 Subject: [PATCH 21/28] Fix rw permissions --- internal/http/services/ocmd/protocols.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/internal/http/services/ocmd/protocols.go b/internal/http/services/ocmd/protocols.go index bbcc51350e..882f42b4a9 100644 --- a/internal/http/services/ocmd/protocols.go +++ b/internal/http/services/ocmd/protocols.go @@ -59,12 +59,15 @@ 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.CreateContainer = true perms.Permissions.InitiateFileUpload = true + perms.Permissions.RestoreRecycleItem = true + perms.Permissions.CreateContainer = true perms.Permissions.Delete = true perms.Permissions.Move = true perms.Permissions.ListGrants = true From 9011bc74decccc669c22ef584735338d88f2c756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Wed, 22 Nov 2023 11:33:06 +0100 Subject: [PATCH 22/28] Change ocm fileids to a base64 representation of the path in the share --- .../services/owncloud/ocdav/propfind/propfind.go | 1 - pkg/conversions/main.go | 13 ++++++++++--- pkg/ocm/storage/received/ocm.go | 16 +++++++--------- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/internal/http/services/owncloud/ocdav/propfind/propfind.go b/internal/http/services/owncloud/ocdav/propfind/propfind.go index 3405c402e6..b2d098fffc 100644 --- a/internal/http/services/owncloud/ocdav/propfind/propfind.go +++ b/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) { diff --git a/pkg/conversions/main.go b/pkg/conversions/main.go index 6ff462be8d..b7ee836b3a 100644 --- a/pkg/conversions/main.go +++ b/pkg/conversions/main.go @@ -21,9 +21,11 @@ package conversions import ( "context" + "encoding/base64" "fmt" "net/http" "path" + "path/filepath" "time" "github.com/cs3org/reva/v2/pkg/errtypes" @@ -328,6 +330,11 @@ func ReceivedOCMShare2ShareData(share *ocm.ReceivedShare, path string) (*ShareDa return nil, errtypes.InternalError("webdav endpoint not in share") } + opaqueid := fmt.Sprintf("%s:%s", share.Id.OpaqueId, "/") + opaqueid = base64.StdEncoding.EncodeToString([]byte(opaqueid)) + + shareTarget := filepath.Join("/Shares", share.Name) + s := &ShareData{ ID: share.Id.OpaqueId, UIDOwner: formatRemoteUser(share.Creator), @@ -335,14 +342,14 @@ 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: storagespace.FormatResourceID(provider.ResourceId{ StorageId: utils.OCMStorageProviderID, SpaceId: share.Id.OpaqueId, - OpaqueId: share.Id.OpaqueId, + OpaqueId: opaqueid, }), STime: share.Ctime.Seconds, Name: share.Name, diff --git a/pkg/ocm/storage/received/ocm.go b/pkg/ocm/storage/received/ocm.go index 6870586195..6bdcb45935 100644 --- a/pkg/ocm/storage/received/ocm.go +++ b/pkg/ocm/storage/received/ocm.go @@ -21,7 +21,7 @@ package ocm import ( "context" "crypto/tls" - "encoding/xml" + "encoding/base64" "fmt" "io" "io/fs" @@ -204,10 +204,6 @@ func getPathFromShareIDAndRelPath(shareID *ocmpb.ShareId, relPath string) string } func convertStatToResourceInfo(ref *provider.Reference, f fs.FileInfo, share *ocmpb.ReceivedShare) (*provider.ResourceInfo, error) { - props, ok := f.Sys().(gowebdav.Props) - if !ok { - return nil, errtypes.InternalError("could not get webdav props") - } t := provider.ResourceType_RESOURCE_TYPE_FILE if f.IsDir() { t = provider.ResourceType_RESOURCE_TYPE_CONTAINER @@ -220,16 +216,18 @@ func convertStatToResourceInfo(ref *provider.Reference, f fs.FileInfo, share *oc name = f.Name() } - remoteId, err := storagespace.ParseID(props.GetString(xml.Name{Space: "http://owncloud.org/ns", Local: "fileid"})) - if err != nil { - return nil, err + webdavFile, ok := f.(gowebdav.File) + if !ok { + return nil, errtypes.InternalError("could not get webdav props") } + opaqueid := fmt.Sprintf("%s:%s", share.Id.OpaqueId, webdavFile.Path()) + opaqueid = base64.StdEncoding.EncodeToString([]byte(opaqueid)) // ids are of the format $! id := &provider.ResourceId{ StorageId: utils.OCMStorageProviderID, SpaceId: share.Id.OpaqueId, - OpaqueId: fmt.Sprintf("%s:%s:%s", remoteId.StorageId, remoteId.SpaceId, remoteId.OpaqueId), + OpaqueId: opaqueid, } webdavProtocol, _ := getWebDAVProtocol(share.Protocols) From fc9701ced965a8e7684e162a0cd31fc1ec6aa34a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Wed, 22 Nov 2023 15:52:18 +0100 Subject: [PATCH 23/28] Support id based requests --- pkg/conversions/main.go | 3 +-- pkg/ocm/storage/received/ocm.go | 15 +++++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/pkg/conversions/main.go b/pkg/conversions/main.go index b7ee836b3a..8ef5dc395a 100644 --- a/pkg/conversions/main.go +++ b/pkg/conversions/main.go @@ -330,8 +330,7 @@ func ReceivedOCMShare2ShareData(share *ocm.ReceivedShare, path string) (*ShareDa return nil, errtypes.InternalError("webdav endpoint not in share") } - opaqueid := fmt.Sprintf("%s:%s", share.Id.OpaqueId, "/") - opaqueid = base64.StdEncoding.EncodeToString([]byte(opaqueid)) + opaqueid := base64.StdEncoding.EncodeToString([]byte("/")) shareTarget := filepath.Join("/Shares", share.Name) diff --git a/pkg/ocm/storage/received/ocm.go b/pkg/ocm/storage/received/ocm.go index 6bdcb45935..5c321751fe 100644 --- a/pkg/ocm/storage/received/ocm.go +++ b/pkg/ocm/storage/received/ocm.go @@ -22,7 +22,6 @@ import ( "context" "crypto/tls" "encoding/base64" - "fmt" "io" "io/fs" "net/http" @@ -99,7 +98,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) { @@ -220,8 +228,7 @@ func convertStatToResourceInfo(ref *provider.Reference, f fs.FileInfo, share *oc if !ok { return nil, errtypes.InternalError("could not get webdav props") } - opaqueid := fmt.Sprintf("%s:%s", share.Id.OpaqueId, webdavFile.Path()) - opaqueid = base64.StdEncoding.EncodeToString([]byte(opaqueid)) + opaqueid := base64.StdEncoding.EncodeToString([]byte(webdavFile.Path())) // ids are of the format $! id := &provider.ResourceId{ From 91eec0df7a1f24bf90b2831078b1551dad5aa4cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Thu, 23 Nov 2023 15:46:31 +0100 Subject: [PATCH 24/28] Properly authenticate webdav requests, preventing double requests --- pkg/ocm/storage/received/ocm.go | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/pkg/ocm/storage/received/ocm.go b/pkg/ocm/storage/received/ocm.go index 5c321751fe..95ab95492e 100644 --- a/pkg/ocm/storage/received/ocm.go +++ b/pkg/ocm/storage/received/ocm.go @@ -67,6 +67,32 @@ 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 @@ -162,13 +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 := gowebdav.NewAuthClient(endpoint, gowebdav.NewPreemptiveAuth(BearerAuthenticator{token: secret})) if d.c.Insecure { c.SetTransport(&http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, }) } - c.SetHeader("Authorization", "Bearer "+secret) return c, share, rel, nil } From e7cb956d6bd98da1d7cda085c11c6b1854eaf2de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Wed, 22 Nov 2023 11:32:51 +0100 Subject: [PATCH 25/28] Bump gowebdav lib --- go.mod | 2 +- go.sum | 4 ++-- pkg/ocm/invite/repository/json/json.go | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 692c5ee1b4..4a1338ce10 100644 --- a/go.mod +++ b/go.mod @@ -231,4 +231,4 @@ require ( replace github.com/go-micro/plugins/v4/store/nats-js-kv => github.com/kobergj/plugins/v4/store/nats-js-kv v0.0.0-20231207143248-4d424e3ae348 -replace github.com/studio-b12/gowebdav => github.com/aduffeck/gowebdav v0.0.0-20231117083401-b14990633b9d +replace github.com/studio-b12/gowebdav => github.com/aduffeck/gowebdav v0.0.0-20231123085457-ff658b6ea159 diff --git a/go.sum b/go.sum index 32b5f30ab1..eba6267bab 100644 --- a/go.sum +++ b/go.sum @@ -425,8 +425,8 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= -github.com/aduffeck/gowebdav v0.0.0-20231117083401-b14990633b9d h1:Y37AUa3JNBl5YmIarl3sx/ftW+7oWgu2Cp0eExZsQPA= -github.com/aduffeck/gowebdav v0.0.0-20231117083401-b14990633b9d/go.mod h1:bHA7t77X/QFExdeAnDzK6vKM34kEZAcE1OX4MfiwjkE= +github.com/aduffeck/gowebdav v0.0.0-20231123085457-ff658b6ea159 h1:m63hhLqbqmLGGPtyTtjTdxae61d9tMbRdKvMaDHWcDs= +github.com/aduffeck/gowebdav v0.0.0-20231123085457-ff658b6ea159/go.mod h1:bHA7t77X/QFExdeAnDzK6vKM34kEZAcE1OX4MfiwjkE= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= diff --git a/pkg/ocm/invite/repository/json/json.go b/pkg/ocm/invite/repository/json/json.go index 860e4883ce..9fd92b0efb 100644 --- a/pkg/ocm/invite/repository/json/json.go +++ b/pkg/ocm/invite/repository/json/json.go @@ -24,6 +24,7 @@ import ( "io" "net/url" "os" + "path/filepath" "strings" "sync" "time" @@ -90,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) } From 8644961d6c0624d9c3dc01a1651f2ad9666e4c06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Tue, 12 Dec 2023 11:58:21 +0100 Subject: [PATCH 26/28] Add a flag for including ocm sharees --- .../services/owncloud/ocs/config/config.go | 1 + .../handlers/apps/sharing/sharees/sharees.go | 36 ++++++++++--------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/internal/http/services/owncloud/ocs/config/config.go b/internal/http/services/owncloud/ocs/config/config.go index 01a815d80a..09c5baf43d 100644 --- a/internal/http/services/owncloud/ocs/config/config.go +++ b/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/internal/http/services/owncloud/ocs/handlers/apps/sharing/sharees/sharees.go b/internal/http/services/owncloud/ocs/handlers/apps/sharing/sharees/sharees.go index 7d1a46aad3..e3e3bbbeca 100644 --- a/internal/http/services/owncloud/ocs/handlers/apps/sharing/sharees/sharees.go +++ b/internal/http/services/owncloud/ocs/handlers/apps/sharing/sharees/sharees.go @@ -39,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 @@ -81,22 +83,24 @@ func (h *Handler) FindSharees(w http.ResponseWriter, r *http.Request) { } } - 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) + 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) + } } } From 30a39632b7e4cb544fd0088231685824cf59a539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Tue, 12 Dec 2023 12:40:25 +0100 Subject: [PATCH 27/28] Fix test expectations --- tests/integration/grpc/ocm_share_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/integration/grpc/ocm_share_test.go b/tests/integration/grpc/ocm_share_test.go index e1a3df64f1..67e22450c1 100644 --- a/tests/integration/grpc/ocm_share_test.go +++ b/tests/integration/grpc/ocm_share_test.go @@ -54,10 +54,13 @@ var ( CreateContainer: true, Delete: true, GetPath: true, + GetQuota: true, InitiateFileDownload: true, InitiateFileUpload: true, ListContainer: true, ListGrants: true, + ListRecycle: true, + RestoreRecycleItem: true, Move: true, Stat: true, } @@ -65,7 +68,9 @@ var ( Stat: true, InitiateFileDownload: true, GetPath: true, + GetQuota: true, ListContainer: true, + ListRecycle: true, } ) From 9a0c42192a46738af9741f78919c47a79f76e638 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Wed, 13 Dec 2023 08:30:39 +0100 Subject: [PATCH 28/28] Add changelog --- changelog/unreleased/ocm.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changelog/unreleased/ocm.md diff --git a/changelog/unreleased/ocm.md b/changelog/unreleased/ocm.md new file mode 100644 index 0000000000..f5e160f388 --- /dev/null +++ b/changelog/unreleased/ocm.md @@ -0,0 +1,5 @@ +Bugfix: Improve OCM support + +We fixed several bugs with OCM support. + +https://github.com/cs3org/reva/pull/4333