mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-07 04:40:05 -06:00
5
vendor/github.com/cs3org/reva/v2/internal/grpc/services/gateway/storageprovider.go
generated
vendored
5
vendor/github.com/cs3org/reva/v2/internal/grpc/services/gateway/storageprovider.go
generated
vendored
@@ -241,6 +241,11 @@ func (s *svc) ListStorageSpaces(ctx context.Context, req *provider.ListStorageSp
|
||||
// TODO check for allowed filters
|
||||
filters["mask"] = mask
|
||||
}
|
||||
path := utils.ReadPlainFromOpaque(req.Opaque, "path")
|
||||
if path != "" {
|
||||
// TODO check for allowed filters
|
||||
filters["path"] = path
|
||||
}
|
||||
|
||||
for _, f := range req.Filters {
|
||||
switch f.Type {
|
||||
|
||||
120
vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/propfind/propfind.go
generated
vendored
120
vendor/github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/propfind/propfind.go
generated
vendored
@@ -53,6 +53,7 @@ import (
|
||||
"github.com/rs/zerolog"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"google.golang.org/protobuf/types/known/fieldmaskpb"
|
||||
)
|
||||
|
||||
@@ -876,13 +877,67 @@ func ReadPropfind(r io.Reader) (pf XML, status int, err error) {
|
||||
|
||||
// MultistatusResponse converts a list of resource infos into a multistatus response string
|
||||
func MultistatusResponse(ctx context.Context, pf *XML, mds []*provider.ResourceInfo, publicURL, ns string, linkshares map[string]struct{}, returnMinimal bool) ([]byte, error) {
|
||||
responses := make([]*ResponseXML, 0, len(mds))
|
||||
for i := range mds {
|
||||
res, err := mdToPropResponse(ctx, pf, mds[i], publicURL, ns, linkshares, returnMinimal)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
g, ctx := errgroup.WithContext(ctx)
|
||||
|
||||
type work struct {
|
||||
position int
|
||||
info *provider.ResourceInfo
|
||||
}
|
||||
type result struct {
|
||||
position int
|
||||
info *ResponseXML
|
||||
}
|
||||
workChan := make(chan work, len(mds))
|
||||
resultChan := make(chan result, len(mds))
|
||||
|
||||
// Distribute work
|
||||
g.Go(func() error {
|
||||
defer close(workChan)
|
||||
for i, md := range mds {
|
||||
select {
|
||||
case workChan <- work{position: i, info: md}:
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
responses = append(responses, res)
|
||||
return nil
|
||||
})
|
||||
|
||||
// Spawn workers that'll concurrently work the queue
|
||||
numWorkers := 50
|
||||
if len(mds) < numWorkers {
|
||||
numWorkers = len(mds)
|
||||
}
|
||||
for i := 0; i < numWorkers; i++ {
|
||||
g.Go(func() error {
|
||||
for work := range workChan {
|
||||
res, err := mdToPropResponse(ctx, pf, work.info, publicURL, ns, linkshares, returnMinimal)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
select {
|
||||
case resultChan <- result{position: work.position, info: res}:
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Wait for things to settle down, then close results chan
|
||||
go func() {
|
||||
_ = g.Wait() // error is checked later
|
||||
close(resultChan)
|
||||
}()
|
||||
|
||||
if err := g.Wait(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
responses := make([]*ResponseXML, len(mds))
|
||||
for res := range resultChan {
|
||||
responses[res.position] = res.info
|
||||
}
|
||||
|
||||
msr := NewMultiStatusResponseXML()
|
||||
@@ -904,11 +959,12 @@ func mdToPropResponse(ctx context.Context, pf *XML, md *provider.ResourceInfo, p
|
||||
defer span.End()
|
||||
|
||||
sublog := appctx.GetLogger(ctx).With().Interface("md", md).Str("ns", ns).Logger()
|
||||
md.Path = strings.TrimPrefix(md.Path, ns)
|
||||
id := md.Id
|
||||
p := strings.TrimPrefix(md.Path, ns)
|
||||
|
||||
baseURI := ctx.Value(net.CtxKeyBaseURI).(string)
|
||||
|
||||
ref := path.Join(baseURI, md.Path)
|
||||
ref := path.Join(baseURI, p)
|
||||
if md.Type == provider.ResourceType_RESOURCE_TYPE_CONTAINER {
|
||||
ref += "/"
|
||||
}
|
||||
@@ -952,7 +1008,7 @@ func mdToPropResponse(ctx context.Context, pf *XML, md *provider.ResourceInfo, p
|
||||
|
||||
role := conversions.RoleFromResourcePermissions(md.PermissionSet, ls != nil)
|
||||
|
||||
if md.Space != nil && md.Space.SpaceType != "grant" && utils.ResourceIDEqual(md.Space.Root, md.Id) {
|
||||
if md.Space != nil && md.Space.SpaceType != "grant" && utils.ResourceIDEqual(md.Space.Root, id) {
|
||||
// a space root is never shared
|
||||
shareTypes = ""
|
||||
}
|
||||
@@ -969,8 +1025,8 @@ func mdToPropResponse(ctx context.Context, pf *XML, md *provider.ResourceInfo, p
|
||||
}
|
||||
|
||||
// replace fileid of /public/{token} mountpoint with grant fileid
|
||||
if ls != nil && md.Id != nil && md.Id.SpaceId == utils.PublicStorageSpaceID && md.Id.OpaqueId == ls.Token {
|
||||
md.Id = ls.ResourceId
|
||||
if ls != nil && id != nil && id.SpaceId == utils.PublicStorageSpaceID && id.OpaqueId == ls.Token {
|
||||
id = ls.ResourceId
|
||||
}
|
||||
|
||||
propstatOK := PropstatXML{
|
||||
@@ -996,12 +1052,12 @@ func mdToPropResponse(ctx context.Context, pf *XML, md *provider.ResourceInfo, p
|
||||
if pf.Allprop != nil {
|
||||
// return all known properties
|
||||
|
||||
if md.Id != nil {
|
||||
id := storagespace.FormatResourceID(*md.Id)
|
||||
if id != nil {
|
||||
sid := storagespace.FormatResourceID(*id)
|
||||
appendToOK(
|
||||
prop.Escaped("oc:id", id),
|
||||
prop.Escaped("oc:fileid", id),
|
||||
prop.Escaped("oc:spaceid", md.Id.SpaceId),
|
||||
prop.Escaped("oc:id", sid),
|
||||
prop.Escaped("oc:fileid", sid),
|
||||
prop.Escaped("oc:spaceid", id.SpaceId),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1012,7 +1068,7 @@ func mdToPropResponse(ctx context.Context, pf *XML, md *provider.ResourceInfo, p
|
||||
}
|
||||
|
||||
// we need to add the shareid if possible - the only way to extract it here is to parse it from the path
|
||||
if ref, err := storagespace.ParseReference(strings.TrimPrefix(md.Path, "/")); err == nil && ref.GetResourceId().GetSpaceId() == utils.ShareStorageSpaceID {
|
||||
if ref, err := storagespace.ParseReference(strings.TrimPrefix(p, "/")); err == nil && ref.GetResourceId().GetSpaceId() == utils.ShareStorageSpaceID {
|
||||
appendToOK(prop.Raw("oc:shareid", ref.GetResourceId().GetOpaqueId()))
|
||||
}
|
||||
|
||||
@@ -1119,14 +1175,14 @@ func mdToPropResponse(ctx context.Context, pf *XML, md *provider.ResourceInfo, p
|
||||
// TODO(jfd): maybe phoenix and the other clients can just use this id as an opaque string?
|
||||
// I tested the desktop client and phoenix to annotate which properties are requestted, see below cases
|
||||
case "fileid": // phoenix only
|
||||
if md.Id != nil {
|
||||
appendToOK(prop.Escaped("oc:fileid", storagespace.FormatResourceID(*md.Id)))
|
||||
if id != nil {
|
||||
appendToOK(prop.Escaped("oc:fileid", storagespace.FormatResourceID(*id)))
|
||||
} else {
|
||||
appendToNotFound(prop.NotFound("oc:fileid"))
|
||||
}
|
||||
case "id": // desktop client only
|
||||
if md.Id != nil {
|
||||
appendToOK(prop.Escaped("oc:id", storagespace.FormatResourceID(*md.Id)))
|
||||
if id != nil {
|
||||
appendToOK(prop.Escaped("oc:id", storagespace.FormatResourceID(*id)))
|
||||
} else {
|
||||
appendToNotFound(prop.NotFound("oc:id"))
|
||||
}
|
||||
@@ -1137,8 +1193,8 @@ func mdToPropResponse(ctx context.Context, pf *XML, md *provider.ResourceInfo, p
|
||||
appendToNotFound(prop.NotFound("oc:file-parent"))
|
||||
}
|
||||
case "spaceid":
|
||||
if md.Id != nil {
|
||||
appendToOK(prop.Escaped("oc:spaceid", md.Id.SpaceId))
|
||||
if id != nil {
|
||||
appendToOK(prop.Escaped("oc:spaceid", id.SpaceId))
|
||||
} else {
|
||||
appendToNotFound(prop.Escaped("oc:spaceid", ""))
|
||||
}
|
||||
@@ -1204,7 +1260,7 @@ func mdToPropResponse(ctx context.Context, pf *XML, md *provider.ResourceInfo, p
|
||||
// TODO what is the difference to d:quota-used-bytes (which only exists for collections)?
|
||||
// oc:size is available on files and folders and behaves like d:getcontentlength or d:quota-used-bytes respectively
|
||||
// The hasPrefix is a workaround to make children of the link root show a size if they have 0 bytes
|
||||
if ls == nil || strings.HasPrefix(md.Path, "/"+ls.Token+"/") {
|
||||
if ls == nil || strings.HasPrefix(p, "/"+ls.Token+"/") {
|
||||
appendToOK(prop.Escaped("oc:size", size))
|
||||
} else {
|
||||
// link share root collection has no size
|
||||
@@ -1289,8 +1345,8 @@ func mdToPropResponse(ctx context.Context, pf *XML, md *provider.ResourceInfo, p
|
||||
}
|
||||
}
|
||||
|
||||
if md.Id != nil {
|
||||
if _, ok := linkshares[md.Id.OpaqueId]; ok {
|
||||
if id != nil {
|
||||
if _, ok := linkshares[id.OpaqueId]; ok {
|
||||
types.WriteString("<oc:share-type>3</oc:share-type>")
|
||||
}
|
||||
}
|
||||
@@ -1316,12 +1372,12 @@ func mdToPropResponse(ctx context.Context, pf *XML, md *provider.ResourceInfo, p
|
||||
if isPublic && md.Type == provider.ResourceType_RESOURCE_TYPE_FILE {
|
||||
var path string
|
||||
if !ls.PasswordProtected {
|
||||
path = md.Path
|
||||
path = p
|
||||
} else {
|
||||
expiration := time.Unix(int64(ls.Signature.SignatureExpiration.Seconds), int64(ls.Signature.SignatureExpiration.Nanos))
|
||||
var sb strings.Builder
|
||||
|
||||
sb.WriteString(md.Path)
|
||||
sb.WriteString(p)
|
||||
sb.WriteString("?signature=")
|
||||
sb.WriteString(ls.Signature.Signature)
|
||||
sb.WriteString("&expiration=")
|
||||
@@ -1335,8 +1391,8 @@ func mdToPropResponse(ctx context.Context, pf *XML, md *provider.ResourceInfo, p
|
||||
}
|
||||
case "privatelink":
|
||||
privateURL, err := url.Parse(publicURL)
|
||||
if err == nil && md.Id != nil {
|
||||
privateURL.Path = path.Join(privateURL.Path, "f", storagespace.FormatResourceID(*md.Id))
|
||||
if err == nil && id != nil {
|
||||
privateURL.Path = path.Join(privateURL.Path, "f", storagespace.FormatResourceID(*id))
|
||||
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("oc:privatelink", privateURL.String()))
|
||||
} else {
|
||||
propstatNotFound.Prop = append(propstatNotFound.Prop, prop.NotFound("oc:privatelink"))
|
||||
@@ -1344,7 +1400,7 @@ func mdToPropResponse(ctx context.Context, pf *XML, md *provider.ResourceInfo, p
|
||||
case "signature-auth":
|
||||
if isPublic {
|
||||
// We only want to add the attribute to the root of the propfind.
|
||||
if strings.HasSuffix(md.Path, ls.Token) && ls.Signature != nil {
|
||||
if strings.HasSuffix(p, ls.Token) && ls.Signature != nil {
|
||||
expiration := time.Unix(int64(ls.Signature.SignatureExpiration.Seconds), int64(ls.Signature.SignatureExpiration.Nanos))
|
||||
var sb strings.Builder
|
||||
sb.WriteString("<oc:signature>")
|
||||
@@ -1366,7 +1422,7 @@ func mdToPropResponse(ctx context.Context, pf *XML, md *provider.ResourceInfo, p
|
||||
case "name":
|
||||
appendToOK(prop.Escaped("oc:name", md.Name))
|
||||
case "shareid":
|
||||
if ref, err := storagespace.ParseReference(strings.TrimPrefix(md.Path, "/")); err == nil && ref.GetResourceId().GetSpaceId() == utils.ShareStorageSpaceID {
|
||||
if ref, err := storagespace.ParseReference(strings.TrimPrefix(p, "/")); err == nil && ref.GetResourceId().GetSpaceId() == utils.ShareStorageSpaceID {
|
||||
appendToOK(prop.Raw("oc:shareid", ref.GetResourceId().GetOpaqueId()))
|
||||
}
|
||||
case "dDC": // desktop
|
||||
|
||||
@@ -273,7 +273,7 @@ func (h *Handler) listPublicShares(r *http.Request, filters []*link.ListPublicSh
|
||||
return ocsDataPayload, nil, errors.New("bad request")
|
||||
}
|
||||
|
||||
func (h *Handler) isPublicShare(r *http.Request, oid string) bool {
|
||||
func (h *Handler) isPublicShare(r *http.Request, oid string) (*link.PublicShare, bool) {
|
||||
logger := appctx.GetLogger(r.Context())
|
||||
client, err := pool.GetGatewayServiceClient(h.gatewayAddr)
|
||||
if err != nil {
|
||||
@@ -291,19 +291,19 @@ func (h *Handler) isPublicShare(r *http.Request, oid string) bool {
|
||||
})
|
||||
if err != nil {
|
||||
logger.Err(err)
|
||||
return false
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return psRes.GetShare() != nil
|
||||
return psRes.GetShare(), psRes.GetShare() != nil
|
||||
}
|
||||
|
||||
func (h *Handler) updatePublicShare(w http.ResponseWriter, r *http.Request, shareID string) {
|
||||
func (h *Handler) updatePublicShare(w http.ResponseWriter, r *http.Request, share *link.PublicShare) {
|
||||
updates := []*link.UpdatePublicShareRequest_Update{}
|
||||
logger := appctx.GetLogger(r.Context())
|
||||
|
||||
gwC, err := pool.GetGatewayServiceClient(h.gatewayAddr)
|
||||
if err != nil {
|
||||
log.Err(err).Str("shareID", shareID).Msg("updatePublicShare")
|
||||
log.Err(err).Str("shareID", share.GetId().GetOpaqueId()).Msg("updatePublicShare")
|
||||
response.WriteOCSError(w, r, response.MetaBadRequest.StatusCode, "error getting a connection to the gateway service", nil)
|
||||
return
|
||||
}
|
||||
@@ -317,21 +317,7 @@ func (h *Handler) updatePublicShare(w http.ResponseWriter, r *http.Request, shar
|
||||
return
|
||||
}
|
||||
|
||||
before, err := gwC.GetPublicShare(r.Context(), &link.GetPublicShareRequest{
|
||||
Ref: &link.PublicShareReference{
|
||||
Spec: &link.PublicShareReference_Id{
|
||||
Id: &link.PublicShareId{
|
||||
OpaqueId: shareID,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
response.WriteOCSError(w, r, response.MetaBadRequest.StatusCode, "failed to get public share", nil)
|
||||
return
|
||||
}
|
||||
|
||||
createdByUser := publicshare.IsCreatedByUser(*before.Share, user)
|
||||
createdByUser := publicshare.IsCreatedByUser(*share, user)
|
||||
|
||||
// NOTE: you are allowed to update a link TO a public link without the `PublicLink.Write` permission if you created it yourself
|
||||
if (permKey != nil && *permKey != 0) || !createdByUser {
|
||||
@@ -355,9 +341,9 @@ func (h *Handler) updatePublicShare(w http.ResponseWriter, r *http.Request, shar
|
||||
}
|
||||
|
||||
if !createdByUser {
|
||||
sRes, err := gwC.Stat(r.Context(), &provider.StatRequest{Ref: &provider.Reference{ResourceId: before.Share.ResourceId}})
|
||||
sRes, err := gwC.Stat(r.Context(), &provider.StatRequest{Ref: &provider.Reference{ResourceId: share.ResourceId}})
|
||||
if err != nil {
|
||||
log.Err(err).Interface("resource_id", before.Share.ResourceId).Msg("failed to stat shared resource")
|
||||
log.Err(err).Interface("resource_id", share.ResourceId).Msg("failed to stat shared resource")
|
||||
response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "failed to get public share", nil)
|
||||
return
|
||||
}
|
||||
@@ -382,7 +368,7 @@ func (h *Handler) updatePublicShare(w http.ResponseWriter, r *http.Request, shar
|
||||
newName, ok := r.Form["name"]
|
||||
if ok {
|
||||
updatesFound = true
|
||||
if newName[0] != before.Share.DisplayName {
|
||||
if newName[0] != share.DisplayName {
|
||||
updates = append(updates, &link.UpdatePublicShareRequest_Update{
|
||||
Type: link.UpdatePublicShareRequest_Update_TYPE_DISPLAYNAME,
|
||||
DisplayName: newName[0],
|
||||
@@ -404,7 +390,7 @@ func (h *Handler) updatePublicShare(w http.ResponseWriter, r *http.Request, shar
|
||||
publicSharePermissions := &link.PublicSharePermissions{
|
||||
Permissions: newPermissions,
|
||||
}
|
||||
beforePerm, _ := json.Marshal(before.GetShare().Permissions)
|
||||
beforePerm, _ := json.Marshal(share.Permissions)
|
||||
afterPerm, _ := json.Marshal(publicSharePermissions)
|
||||
if string(beforePerm) != string(afterPerm) {
|
||||
logger.Info().Str("shares", "update").Msgf("updating permissions from %v to: %v", string(beforePerm), string(afterPerm))
|
||||
@@ -418,7 +404,7 @@ func (h *Handler) updatePublicShare(w http.ResponseWriter, r *http.Request, shar
|
||||
}
|
||||
}
|
||||
|
||||
statReq := provider.StatRequest{Ref: &provider.Reference{ResourceId: before.Share.ResourceId}}
|
||||
statReq := provider.StatRequest{Ref: &provider.Reference{ResourceId: share.ResourceId}}
|
||||
statRes, err := gwC.Stat(r.Context(), &statReq)
|
||||
if err != nil {
|
||||
log.Debug().Err(err).Str("shares", "update public share").Msg("error during stat")
|
||||
@@ -446,7 +432,7 @@ func (h *Handler) updatePublicShare(w http.ResponseWriter, r *http.Request, shar
|
||||
}
|
||||
}
|
||||
|
||||
beforeExpiration, _ := json.Marshal(before.Share.Expiration)
|
||||
beforeExpiration, _ := json.Marshal(share.Expiration)
|
||||
afterExpiration, _ := json.Marshal(newExpiration)
|
||||
if string(afterExpiration) != string(beforeExpiration) {
|
||||
logger.Debug().Str("shares", "update").Msgf("updating expire date from %v to: %v", string(beforeExpiration), string(afterExpiration))
|
||||
@@ -473,47 +459,45 @@ func (h *Handler) updatePublicShare(w http.ResponseWriter, r *http.Request, shar
|
||||
})
|
||||
}
|
||||
|
||||
publicShare := before.Share
|
||||
|
||||
// Updates are atomical. See: https://github.com/cs3org/cs3apis/pull/67#issuecomment-617651428 so in order to get the latest updated version
|
||||
if len(updates) > 0 {
|
||||
uRes := &link.UpdatePublicShareResponse{Share: before.Share}
|
||||
uRes := &link.UpdatePublicShareResponse{Share: share}
|
||||
for k := range updates {
|
||||
uRes, err = gwC.UpdatePublicShare(r.Context(), &link.UpdatePublicShareRequest{
|
||||
Ref: &link.PublicShareReference{
|
||||
Spec: &link.PublicShareReference_Id{
|
||||
Id: &link.PublicShareId{
|
||||
OpaqueId: shareID,
|
||||
OpaqueId: share.Id.OpaqueId,
|
||||
},
|
||||
},
|
||||
},
|
||||
Update: updates[k],
|
||||
})
|
||||
if err != nil {
|
||||
log.Err(err).Str("shareID", shareID).Msg("sending update request to public link provider")
|
||||
log.Err(err).Str("shareID", share.Id.OpaqueId).Msg("sending update request to public link provider")
|
||||
response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "Error sending update request to public link provider", err)
|
||||
return
|
||||
}
|
||||
if uRes.Status.Code != rpc.Code_CODE_OK {
|
||||
log.Debug().Str("shareID", shareID).Msgf("sending update request to public link provider failed: %s", uRes.Status.Message)
|
||||
log.Debug().Str("shareID", share.Id.OpaqueId).Msgf("sending update request to public link provider failed: %s", uRes.Status.Message)
|
||||
response.WriteOCSError(w, r, response.MetaServerError.StatusCode, fmt.Sprintf("Error sending update request to public link provider: %s", uRes.Status.Message), nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
publicShare = uRes.Share
|
||||
share = uRes.Share
|
||||
} else if !updatesFound {
|
||||
response.WriteOCSError(w, r, response.MetaBadRequest.StatusCode, "No updates specified in request", nil)
|
||||
return
|
||||
}
|
||||
|
||||
s := conversions.PublicShare2ShareData(publicShare, r, h.publicURL)
|
||||
s := conversions.PublicShare2ShareData(share, r, h.publicURL)
|
||||
h.addFileInfo(r.Context(), s, statRes.Info)
|
||||
h.mapUserIds(r.Context(), gwC, s)
|
||||
|
||||
response.WriteOCSSuccess(w, r, s)
|
||||
}
|
||||
|
||||
func (h *Handler) removePublicShare(w http.ResponseWriter, r *http.Request, shareID string) {
|
||||
func (h *Handler) removePublicShare(w http.ResponseWriter, r *http.Request, share *link.PublicShare) {
|
||||
ctx := r.Context()
|
||||
|
||||
c, err := pool.GetGatewayServiceClient(h.gatewayAddr)
|
||||
@@ -522,25 +506,11 @@ func (h *Handler) removePublicShare(w http.ResponseWriter, r *http.Request, shar
|
||||
return
|
||||
}
|
||||
|
||||
before, err := c.GetPublicShare(r.Context(), &link.GetPublicShareRequest{
|
||||
Ref: &link.PublicShareReference{
|
||||
Spec: &link.PublicShareReference_Id{
|
||||
Id: &link.PublicShareId{
|
||||
OpaqueId: shareID,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
response.WriteOCSError(w, r, response.MetaBadRequest.StatusCode, "failed to get public share", nil)
|
||||
return
|
||||
}
|
||||
|
||||
u := ctxpkg.ContextMustGetUser(ctx)
|
||||
if !publicshare.IsCreatedByUser(*before.Share, u) {
|
||||
sRes, err := c.Stat(r.Context(), &provider.StatRequest{Ref: &provider.Reference{ResourceId: before.Share.ResourceId}})
|
||||
if !publicshare.IsCreatedByUser(*share, u) {
|
||||
sRes, err := c.Stat(r.Context(), &provider.StatRequest{Ref: &provider.Reference{ResourceId: share.ResourceId}})
|
||||
if err != nil {
|
||||
log.Err(err).Interface("resource_id", before.Share.ResourceId).Msg("failed to stat shared resource")
|
||||
log.Err(err).Interface("resource_id", share.ResourceId).Msg("failed to stat shared resource")
|
||||
response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "failed to get public share", nil)
|
||||
return
|
||||
}
|
||||
@@ -555,7 +525,7 @@ func (h *Handler) removePublicShare(w http.ResponseWriter, r *http.Request, shar
|
||||
Ref: &link.PublicShareReference{
|
||||
Spec: &link.PublicShareReference_Id{
|
||||
Id: &link.PublicShareId{
|
||||
OpaqueId: shareID,
|
||||
OpaqueId: share.GetId().GetOpaqueId(),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -679,16 +679,21 @@ func (h *Handler) UpdateShare(w http.ResponseWriter, r *http.Request) {
|
||||
shareID := chi.URLParam(r, "shareid")
|
||||
// FIXME: isPublicShare is already doing a GetShare and GetPublicShare,
|
||||
// we should just reuse that object when doing updates
|
||||
if h.isPublicShare(r, shareID) {
|
||||
h.updatePublicShare(w, r, shareID)
|
||||
if share, ok := h.isPublicShare(r, shareID); ok {
|
||||
h.updatePublicShare(w, r, share)
|
||||
return
|
||||
}
|
||||
h.updateShare(w, r, shareID) // TODO PUT is used with incomplete data to update a share}
|
||||
|
||||
if share, ok := h.isUserShare(r, shareID); ok {
|
||||
h.updateShare(w, r, share) // TODO PUT is used with incomplete data to update a share}
|
||||
return
|
||||
}
|
||||
response.WriteOCSError(w, r, response.MetaNotFound.StatusCode, "cannot find share", nil)
|
||||
}
|
||||
|
||||
func (h *Handler) updateShare(w http.ResponseWriter, r *http.Request, shareID string) {
|
||||
func (h *Handler) updateShare(w http.ResponseWriter, r *http.Request, share *collaboration.Share) {
|
||||
ctx := r.Context()
|
||||
sublog := appctx.GetLogger(ctx).With().Str("shareID", shareID).Logger()
|
||||
sublog := appctx.GetLogger(ctx).With().Str("shareID", share.GetId().GetOpaqueId()).Logger()
|
||||
|
||||
client, err := pool.GetGatewayServiceClient(h.gatewayAddr)
|
||||
if err != nil {
|
||||
@@ -696,28 +701,7 @@ func (h *Handler) updateShare(w http.ResponseWriter, r *http.Request, shareID st
|
||||
return
|
||||
}
|
||||
|
||||
shareR, err := client.GetShare(r.Context(), &collaboration.GetShareRequest{
|
||||
Ref: &collaboration.ShareReference{
|
||||
Spec: &collaboration.ShareReference_Id{
|
||||
Id: &collaboration.ShareId{
|
||||
OpaqueId: shareID,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error sending a grpc update share request", err)
|
||||
return
|
||||
}
|
||||
|
||||
if shareR.Status.GetCode() != rpc.Code_CODE_OK {
|
||||
// TODO: error code from shareR response
|
||||
response.WriteOCSError(w, r, response.MetaNotFound.StatusCode, "cant find requested share", fmt.Errorf("Can't find share %s. Response code: %v", shareID, shareR.Status.GetCode()))
|
||||
return
|
||||
}
|
||||
|
||||
info, status, err := h.getResourceInfoByID(ctx, client, shareR.Share.ResourceId)
|
||||
info, status, err := h.getResourceInfoByID(ctx, client, share.ResourceId)
|
||||
if err != nil || status.Code != rpc.Code_CODE_OK {
|
||||
response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error mapping share data", err)
|
||||
return
|
||||
@@ -729,7 +713,7 @@ func (h *Handler) updateShare(w http.ResponseWriter, r *http.Request, shareID st
|
||||
return
|
||||
}
|
||||
|
||||
shareR.Share.Permissions = &collaboration.SharePermissions{Permissions: role.CS3ResourcePermissions()}
|
||||
share.Permissions = &collaboration.SharePermissions{Permissions: role.CS3ResourcePermissions()}
|
||||
|
||||
var fieldMaskPaths = []string{"permissions"}
|
||||
|
||||
@@ -747,16 +731,16 @@ func (h *Handler) updateShare(w http.ResponseWriter, r *http.Request, shareID st
|
||||
Nanos: uint32(expiration.UnixNano() % int64(time.Second)),
|
||||
}
|
||||
|
||||
shareR.Share.Expiration = expirationTs
|
||||
share.Expiration = expirationTs
|
||||
fieldMaskPaths = append(fieldMaskPaths, "expiration")
|
||||
} else if r.Form.Has("expireDate") {
|
||||
// If the expiration parameter was sent but is empty, then the expiration should be removed.
|
||||
shareR.Share.Expiration = nil
|
||||
share.Expiration = nil
|
||||
fieldMaskPaths = append(fieldMaskPaths, "expiration")
|
||||
}
|
||||
|
||||
uReq := &collaboration.UpdateShareRequest{
|
||||
Share: shareR.Share,
|
||||
Share: share,
|
||||
UpdateMask: &fieldmaskpb.FieldMask{
|
||||
Paths: fieldMaskPaths,
|
||||
},
|
||||
@@ -777,10 +761,10 @@ func (h *Handler) updateShare(w http.ResponseWriter, r *http.Request, shareID st
|
||||
}
|
||||
|
||||
if currentUser, ok := ctxpkg.ContextGetUser(ctx); ok {
|
||||
h.statCache.RemoveStat(currentUser.Id, shareR.Share.ResourceId)
|
||||
h.statCache.RemoveStat(currentUser.Id, share.ResourceId)
|
||||
}
|
||||
|
||||
share, err := conversions.CS3Share2ShareData(ctx, uRes.Share)
|
||||
resultshare, err := conversions.CS3Share2ShareData(ctx, uRes.Share)
|
||||
if err != nil {
|
||||
response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error mapping share data", err)
|
||||
return
|
||||
@@ -807,24 +791,30 @@ func (h *Handler) updateShare(w http.ResponseWriter, r *http.Request, shareID st
|
||||
return
|
||||
}
|
||||
|
||||
h.addFileInfo(r.Context(), share, statRes.Info)
|
||||
h.mapUserIds(ctx, client, share)
|
||||
h.addFileInfo(r.Context(), resultshare, statRes.Info)
|
||||
h.mapUserIds(ctx, client, resultshare)
|
||||
|
||||
response.WriteOCSSuccess(w, r, share)
|
||||
response.WriteOCSSuccess(w, r, resultshare)
|
||||
}
|
||||
|
||||
// RemoveShare handles DELETE requests on /apps/files_sharing/api/v1/shares/(shareid)
|
||||
func (h *Handler) RemoveShare(w http.ResponseWriter, r *http.Request) {
|
||||
shareID := chi.URLParam(r, "shareid")
|
||||
switch {
|
||||
case h.isPublicShare(r, shareID):
|
||||
h.removePublicShare(w, r, shareID)
|
||||
case h.isUserShare(r, shareID):
|
||||
h.removeUserShare(w, r, shareID)
|
||||
default:
|
||||
// The request is a remove space member request.
|
||||
h.removeSpaceMember(w, r, shareID)
|
||||
if share, ok := h.isPublicShare(r, shareID); ok {
|
||||
h.removePublicShare(w, r, share)
|
||||
return
|
||||
}
|
||||
if share, ok := h.isUserShare(r, shareID); ok {
|
||||
h.removeUserShare(w, r, share)
|
||||
return
|
||||
}
|
||||
|
||||
if prov, ok := h.isSpaceShare(r, shareID); ok {
|
||||
// The request is a remove space member request.
|
||||
h.removeSpaceMember(w, r, shareID, prov)
|
||||
return
|
||||
}
|
||||
response.WriteOCSError(w, r, response.MetaNotFound.StatusCode, "cannot find share", nil)
|
||||
}
|
||||
|
||||
// ListShares handles GET requests on /apps/files_sharing/api/v1/shares
|
||||
|
||||
@@ -143,7 +143,21 @@ func (h *Handler) addSpaceMember(w http.ResponseWriter, r *http.Request, info *p
|
||||
response.WriteOCSSuccess(w, r, nil)
|
||||
}
|
||||
|
||||
func (h *Handler) removeSpaceMember(w http.ResponseWriter, r *http.Request, spaceID string) {
|
||||
func (h *Handler) isSpaceShare(r *http.Request, spaceID string) (*registry.ProviderInfo, bool) {
|
||||
ref, err := storagespace.ParseReference(spaceID)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if ref.ResourceId.OpaqueId == "" {
|
||||
ref.ResourceId.OpaqueId = ref.ResourceId.SpaceId
|
||||
}
|
||||
|
||||
p, err := h.findProvider(r.Context(), &ref)
|
||||
return p, err == nil
|
||||
}
|
||||
|
||||
func (h *Handler) removeSpaceMember(w http.ResponseWriter, r *http.Request, spaceID string, prov *registry.ProviderInfo) {
|
||||
ctx := r.Context()
|
||||
|
||||
shareWith := r.URL.Query().Get("shareWith")
|
||||
@@ -168,13 +182,7 @@ func (h *Handler) removeSpaceMember(w http.ResponseWriter, r *http.Request, spac
|
||||
ref.ResourceId.OpaqueId = ref.ResourceId.SpaceId
|
||||
}
|
||||
|
||||
p, err := h.findProvider(ctx, &ref)
|
||||
if err != nil {
|
||||
response.WriteOCSError(w, r, response.MetaNotFound.StatusCode, "error getting storage provider", err)
|
||||
return
|
||||
}
|
||||
|
||||
providerClient, err := h.getStorageProviderClient(p)
|
||||
providerClient, err := h.getStorageProviderClient(prov)
|
||||
if err != nil {
|
||||
response.WriteOCSError(w, r, response.MetaNotFound.StatusCode, "error getting storage provider client", err)
|
||||
return
|
||||
|
||||
@@ -129,7 +129,7 @@ func (h *Handler) createUserShare(w http.ResponseWriter, r *http.Request, statIn
|
||||
return share, nil
|
||||
}
|
||||
|
||||
func (h *Handler) isUserShare(r *http.Request, oid string) bool {
|
||||
func (h *Handler) isUserShare(r *http.Request, oid string) (*collaboration.Share, bool) {
|
||||
logger := appctx.GetLogger(r.Context())
|
||||
client, err := pool.GetGatewayServiceClient(h.gatewayAddr)
|
||||
if err != nil {
|
||||
@@ -147,13 +147,13 @@ func (h *Handler) isUserShare(r *http.Request, oid string) bool {
|
||||
})
|
||||
if err != nil {
|
||||
logger.Err(err)
|
||||
return false
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return getShareRes.GetShare() != nil
|
||||
return getShareRes.GetShare(), getShareRes.GetShare() != nil
|
||||
}
|
||||
|
||||
func (h *Handler) removeUserShare(w http.ResponseWriter, r *http.Request, shareID string) {
|
||||
func (h *Handler) removeUserShare(w http.ResponseWriter, r *http.Request, share *collaboration.Share) {
|
||||
ctx := r.Context()
|
||||
|
||||
uClient, err := h.getClient()
|
||||
@@ -164,26 +164,11 @@ func (h *Handler) removeUserShare(w http.ResponseWriter, r *http.Request, shareI
|
||||
|
||||
shareRef := &collaboration.ShareReference{
|
||||
Spec: &collaboration.ShareReference_Id{
|
||||
Id: &collaboration.ShareId{
|
||||
OpaqueId: shareID,
|
||||
},
|
||||
Id: share.Id,
|
||||
},
|
||||
}
|
||||
// Get the share, so that we can include it in the response.
|
||||
getShareResp, err := uClient.GetShare(ctx, &collaboration.GetShareRequest{Ref: shareRef})
|
||||
if err != nil {
|
||||
response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error sending a grpc delete share request", err)
|
||||
return
|
||||
} else 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.CS3Share2ShareData(ctx, getShareResp.Share)
|
||||
data, err := conversions.CS3Share2ShareData(ctx, share)
|
||||
if err != nil {
|
||||
response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "deleting share failed", err)
|
||||
return
|
||||
@@ -207,7 +192,7 @@ func (h *Handler) removeUserShare(w http.ResponseWriter, r *http.Request, shareI
|
||||
return
|
||||
}
|
||||
if currentUser, ok := ctxpkg.ContextGetUser(ctx); ok {
|
||||
h.statCache.RemoveStat(currentUser.Id, getShareResp.Share.ResourceId)
|
||||
h.statCache.RemoveStat(currentUser.Id, share.ResourceId)
|
||||
}
|
||||
response.WriteOCSSuccess(w, r, data)
|
||||
}
|
||||
|
||||
42
vendor/github.com/cs3org/reva/v2/pkg/storage/registry/spaces/spaces.go
generated
vendored
42
vendor/github.com/cs3org/reva/v2/pkg/storage/registry/spaces/spaces.go
generated
vendored
@@ -22,6 +22,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
@@ -534,9 +535,10 @@ func (r *registry) findProvidersForResource(ctx context.Context, id string, find
|
||||
|
||||
// findProvidersForAbsolutePathReference takes a path and returns the storage provider with the longest matching path prefix
|
||||
// FIXME use regex to return the correct provider when multiple are configured
|
||||
func (r *registry) findProvidersForAbsolutePathReference(ctx context.Context, path string, unique, unrestricted bool, _ string) []*registrypb.ProviderInfo {
|
||||
func (r *registry) findProvidersForAbsolutePathReference(ctx context.Context, requestedPath string, unique, unrestricted bool, _ string) []*registrypb.ProviderInfo {
|
||||
currentUser := ctxpkg.ContextMustGetUser(ctx)
|
||||
|
||||
pathSegments := strings.Split(strings.TrimPrefix(requestedPath, string(os.PathSeparator)), string(os.PathSeparator))
|
||||
deepestMountPath := ""
|
||||
var deepestMountSpace *providerpb.StorageSpace
|
||||
var deepestMountPathProvider *registrypb.ProviderInfo
|
||||
@@ -549,12 +551,42 @@ func (r *registry) findProvidersForAbsolutePathReference(ctx context.Context, pa
|
||||
var spaces []*providerpb.StorageSpace
|
||||
var err error
|
||||
|
||||
// check if any space in the provider has a valid mountpoint
|
||||
containsRelatedSpace := false
|
||||
|
||||
spaceLoop:
|
||||
for _, space := range provider.Spaces {
|
||||
spacePath, _ := space.SpacePath(currentUser, nil)
|
||||
spacePathSegments := strings.Split(strings.TrimPrefix(spacePath, string(os.PathSeparator)), string(os.PathSeparator))
|
||||
|
||||
for i, segment := range spacePathSegments {
|
||||
if i >= len(pathSegments) {
|
||||
break
|
||||
}
|
||||
if pathSegments[i] != segment {
|
||||
if segment != "" && !strings.Contains(segment, "{{") {
|
||||
// Mount path points elsewhere -> irrelevant
|
||||
continue spaceLoop
|
||||
}
|
||||
// Encountered a template which couldn't be filled -> potentially relevant
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
containsRelatedSpace = true
|
||||
break
|
||||
}
|
||||
|
||||
if !containsRelatedSpace {
|
||||
continue
|
||||
}
|
||||
|
||||
// when listing paths also return mountpoints
|
||||
filters := []*providerpb.ListStorageSpacesRequest_Filter{
|
||||
{
|
||||
Type: providerpb.ListStorageSpacesRequest_Filter_TYPE_PATH,
|
||||
Term: &providerpb.ListStorageSpacesRequest_Filter_Path{
|
||||
Path: strings.TrimPrefix(path, p.ProviderPath),
|
||||
Path: strings.TrimPrefix(requestedPath, p.ProviderPath), // FIXME this no longer has an effect as the p.Providerpath is always empty
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -595,14 +627,14 @@ func (r *registry) findProvidersForAbsolutePathReference(ctx context.Context, pa
|
||||
|
||||
// determine deepest mount point
|
||||
switch {
|
||||
case spacePath == path && unique:
|
||||
case spacePath == requestedPath && unique:
|
||||
validSpaces = append(validSpaces, space)
|
||||
|
||||
deepestMountPath = spacePath
|
||||
deepestMountSpace = space
|
||||
deepestMountPathProvider = p
|
||||
|
||||
case !unique && isSubpath(spacePath, path):
|
||||
case !unique && isSubpath(spacePath, requestedPath):
|
||||
// and add all providers below and exactly matching the path
|
||||
// requested /foo, mountPath /foo/sub
|
||||
validSpaces = append(validSpaces, space)
|
||||
@@ -612,7 +644,7 @@ func (r *registry) findProvidersForAbsolutePathReference(ctx context.Context, pa
|
||||
deepestMountPathProvider = p
|
||||
}
|
||||
|
||||
case isSubpath(path, spacePath) && len(spacePath) > len(deepestMountPath):
|
||||
case isSubpath(requestedPath, spacePath) && len(spacePath) > len(deepestMountPath):
|
||||
// eg. three providers: /foo, /foo/sub, /foo/sub/bar
|
||||
// requested /foo/sub/mob
|
||||
deepestMountPath = spacePath
|
||||
|
||||
Reference in New Issue
Block a user