From 2e694b0f5b0f2245ba31dfc761b04ecd699e332b Mon Sep 17 00:00:00 2001 From: Hugo Gonzalez Labrador Date: Wed, 31 Mar 2021 16:35:43 +0200 Subject: [PATCH] allow full paths targets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit add changelog fix logic more fixes use full paths for file target use path and name from shares jail if it is configured Signed-off-by: Jörn Friedrich Dreyer adjust tests, lots of them Signed-off-by: Jörn Friedrich Dreyer make share_prefix determine paths Signed-off-by: Jörn Friedrich Dreyer revert test exceptions Signed-off-by: Jörn Friedrich Dreyer drop unrelated changes after rebase Signed-off-by: Jörn Friedrich Dreyer fix rebase Signed-off-by: Jörn Friedrich Dreyer fix tests Signed-off-by: Jörn Friedrich Dreyer --- changelog/unreleased/fix-sharing-paths.md | 6 ++ .../services/owncloud/ocs/conversions/main.go | 2 +- .../handlers/apps/sharing/shares/shares.go | 78 ++++++++++++++++++- 3 files changed, 81 insertions(+), 5 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 00000000000..c59bc5c38a8 --- /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/conversions/main.go b/internal/http/services/owncloud/ocs/conversions/main.go index 0097f84b9b2..6593b4650e3 100644 --- a/internal/http/services/owncloud/ocs/conversions/main.go +++ b/internal/http/services/owncloud/ocs/conversions/main.go @@ -120,7 +120,7 @@ type ShareData struct { FileSource string `json:"file_source" xml:"file_source"` // The unique node id of the parent node of the item being shared. FileParent string `json:"file_parent" xml:"file_parent"` - // The basename of the shared file. + // The mount path of the shared file. FileTarget string `json:"file_target" xml:"file_target"` // The uid of the share recipient. This is either // - a GID (group id) if it is being shared with a group or 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 ce315925bb9..e99cf026207 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 @@ -608,6 +608,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 @@ -648,8 +669,42 @@ 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) @@ -658,6 +713,15 @@ func (h *Handler) listSharesWithMe(w http.ResponseWriter, r *http.Request) { 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) @@ -790,12 +854,18 @@ 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 { + s.Path = path.Join("/", info.Path) + 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("/", info.Path) + s.Path = path.Join("/", info.Path) + default: s.FileTarget = path.Join(h.sharePrefix, path.Base(info.Path)) + s.Path = path.Join("/", 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 // TODO FileParent: // item type s.ItemType = conversions.ResourceType(info.GetType()).String()