From afa06f7d83d5751b94e37e7bc3e1c5ef9580e06a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Friedrich=20Dreyer?= Date: Mon, 13 Sep 2021 08:24:54 +0200 Subject: [PATCH] Allow full paths (#1739) --- changelog/unreleased/fix-sharing-paths.md | 6 ++ .../handlers/apps/sharing/shares/shares.go | 78 ++++++++++++++++++- 2 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 changelog/unreleased/fix-sharing-paths.md diff --git a/changelog/unreleased/fix-sharing-paths.md b/changelog/unreleased/fix-sharing-paths.md new file mode 100644 index 0000000000..c59bc5c38a --- /dev/null +++ b/changelog/unreleased/fix-sharing-paths.md @@ -0,0 +1,6 @@ +Bugfix: Allow to expose full paths in OCS API + +Before this fix a share file_target was always harcoded to use a base path. +This fix provides the possiblity to expose full paths in the OCIS API and asymptotically in OCIS web. + +https://github.com/cs3org/reva/pull/1605 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 dd5ca8c682..304509c868 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 @@ -560,6 +560,27 @@ func (h *Handler) listSharesWithMe(w http.ResponseWriter, r *http.Request) { return } + // in a jailed namespace we have to point to the mount point in the users /Shares jail + // to do that we have to list the /Shares jail and use those paths instead of stating the shared resources + // The stat results would start with a path outside the jail and thus be inaccessible + + var shareJailInfos []*provider.ResourceInfo + + if h.sharePrefix != "/" { + // we only need the path from the share jail for accepted shares + if stateFilter == collaboration.ShareState_SHARE_STATE_ACCEPTED || stateFilter == ocsStateUnknown { + // only log errors. They may happen but we can continue trying to at least list the shares + lcRes, err := client.ListContainer(ctx, &provider.ListContainerRequest{ + Ref: &provider.Reference{Path: path.Join(h.homeNamespace, h.sharePrefix)}, + }) + if err != nil || lcRes.Status.Code != rpc.Code_CODE_OK { + h.logProblems(lcRes.GetStatus(), err, "could not list container, continuing without share jail path info") + } else { + shareJailInfos = lcRes.Infos + } + } + } + shares := make([]*conversions.ShareData, 0, len(lrsRes.GetShares())) // TODO(refs) filter out "invalid" shares @@ -600,16 +621,60 @@ func (h *Handler) listSharesWithMe(w http.ResponseWriter, r *http.Request) { h.mapUserIds(r.Context(), client, data) if data.State == ocsStateAccepted { + // only accepted shares can be accessed when jailing users into their home. + // in this case we cannot stat shared resources that are outside the users home (/home), + // the path (/users/u-u-i-d/foo) will not be accessible + + // in a global namespace we can access the share using the full path + // in a jailed namespace we have to point to the mount point in the users /Shares jail + // - needed for oc10 hot migration + // or use the /dav/spaces/ endpoint? + + // list /Shares and match fileids with list of received shares + // - only works for a /Shares folder jail + // - does not work for freely mountable shares as in oc10 because we would need to iterate over the whole tree, there is no listing of mountpoints, yet + + // can we return the mountpoint when the gateway resolves the listing of shares? + // - no, the gateway only sees the same list any has the same options as the ocs service + // - we would need to have a list of mountpoints for the shares -> owncloudstorageprovider for hot migration migration + + // best we can do for now is stat the /Shares jail if it is set and return those paths + + // if we are in a jail and the current share has been accepted use the stat from the share jail // Needed because received shares can be jailed in a folder in the users home - data.Path = path.Join(h.sharePrefix, path.Base(info.Path)) + + if h.sharePrefix != "/" { + // if we have share jail infos use them to build the path + if sji := findMatch(shareJailInfos, rs.Share.ResourceId); sji != nil { + // override path with info from share jail + data.FileTarget = path.Join(h.sharePrefix, path.Base(sji.Path)) + data.Path = path.Join(h.sharePrefix, path.Base(sji.Path)) + } else { + data.FileTarget = path.Join(h.sharePrefix, path.Base(info.Path)) + data.Path = path.Join(h.sharePrefix, path.Base(info.Path)) + } + } else { + data.FileTarget = info.Path + data.Path = info.Path + } } shares = append(shares, data) + log.Debug().Msgf("share: %+v", *data) } response.WriteOCSSuccess(w, r, shares) } +func findMatch(shareJailInfos []*provider.ResourceInfo, id *provider.ResourceId) *provider.ResourceInfo { + for i := range shareJailInfos { + if shareJailInfos[i].Id != nil && shareJailInfos[i].Id.StorageId == id.StorageId && shareJailInfos[i].Id.OpaqueId == id.OpaqueId { + return shareJailInfos[i] + } + } + return nil +} + func (h *Handler) listSharesWithOthers(w http.ResponseWriter, r *http.Request) { shares := make([]*conversions.ShareData, 0) @@ -731,12 +796,17 @@ func (h *Handler) addFileInfo(ctx context.Context, s *conversions.ShareData, inf // TODO Storage: int s.ItemSource = wrapResourceID(info.Id) s.FileSource = s.ItemSource - if s.ShareType == conversions.ShareTypePublicLink { + switch { + case s.ShareType == conversions.ShareTypePublicLink: s.FileTarget = path.Join("/", path.Base(info.Path)) - } else { + s.Path = path.Join("/", path.Base(info.Path)) + case h.sharePrefix == "/": + s.FileTarget = path.Join("/", path.Base(info.Path)) + s.Path = path.Join("/", path.Base(info.Path)) + default: s.FileTarget = path.Join(h.sharePrefix, path.Base(info.Path)) + s.Path = path.Join("/", path.Base(info.Path)) } - s.Path = path.Join("/", path.Base(info.Path)) // TODO hm this might have to be relative to the users home ... depends on the webdav_namespace config s.StorageID = storageIDPrefix + s.FileTarget // TODO FileParent: // item type