do not automatically expand drive root permissions

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>
This commit is contained in:
Jörn Friedrich Dreyer
2025-03-26 14:39:32 +01:00
committed by Ralf Haferkamp
parent 7e1a21994b
commit 981e8fe5a3
9 changed files with 507 additions and 192 deletions

View File

@@ -13,6 +13,7 @@ import (
"github.com/opencloud-eu/opencloud/pkg/log"
"github.com/opencloud-eu/opencloud/pkg/shared"
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
"github.com/opencloud-eu/opencloud/services/graph/pkg/odata"
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
libregraph "github.com/opencloud-eu/libre-graph-api-go"
)
@@ -81,7 +82,7 @@ func (i *CS3) GetUsers(ctx context.Context, oreq *godata.GoDataRequest) ([]*libr
return nil, errorcode.New(errorcode.ServiceNotAvailable, err.Error())
}
search, err := GetSearchValues(oreq.Query)
search, err := odata.GetSearchValues(oreq.Query)
if err != nil {
return nil, err
}
@@ -132,7 +133,7 @@ func (i *CS3) GetGroups(ctx context.Context, oreq *godata.GoDataRequest) ([]*lib
return nil, errorcode.New(errorcode.ServiceNotAvailable, err.Error())
}
search, err := GetSearchValues(oreq.Query)
search, err := odata.GetSearchValues(oreq.Query)
if err != nil {
return nil, err
}

View File

@@ -19,6 +19,7 @@ import (
"github.com/opencloud-eu/opencloud/pkg/log"
"github.com/opencloud-eu/opencloud/services/graph/pkg/config"
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
"github.com/opencloud-eu/opencloud/services/graph/pkg/odata"
)
const (
@@ -563,7 +564,7 @@ func (i *LDAP) GetUser(ctx context.Context, nameOrID string, oreq *godata.GoData
}
}
exp, err := GetExpandValues(oreq.Query)
exp, err := odata.GetExpandValues(oreq.Query)
if err != nil {
return nil, err
}
@@ -593,12 +594,12 @@ func (i *LDAP) FilterUsers(ctx context.Context, oreq *godata.GoDataRequest, filt
return nil, err
}
search, err := GetSearchValues(oreq.Query)
search, err := odata.GetSearchValues(oreq.Query)
if err != nil {
return nil, err
}
exp, err := GetExpandValues(oreq.Query)
exp, err := odata.GetExpandValues(oreq.Query)
if err != nil {
return nil, err
}

View File

@@ -15,6 +15,7 @@ import (
libregraph "github.com/opencloud-eu/libre-graph-api-go"
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
"github.com/opencloud-eu/opencloud/services/graph/pkg/odata"
)
type groupAttributeMap struct {
@@ -59,17 +60,17 @@ func (i *LDAP) GetGroups(ctx context.Context, oreq *godata.GoDataRequest) ([]*li
logger := i.logger.SubloggerWithRequestID(ctx)
logger.Debug().Str("backend", "ldap").Msg("GetGroups")
search, err := GetSearchValues(oreq.Query)
search, err := odata.GetSearchValues(oreq.Query)
if err != nil {
return nil, err
}
var expandMembers bool
exp, err := GetExpandValues(oreq.Query)
exp, err := odata.GetExpandValues(oreq.Query)
if err != nil {
return nil, err
}
sel, err := GetSelectValues(oreq.Query)
sel, err := odata.GetSelectValues(oreq.Query)
if err != nil {
return nil, err
}
@@ -146,7 +147,7 @@ func (i *LDAP) GetGroupMembers(ctx context.Context, groupID string, req *godata.
logger := i.logger.SubloggerWithRequestID(ctx)
logger.Debug().Str("backend", "ldap").Msg("GetGroupMembers")
exp, err := GetExpandValues(req.Query)
exp, err := odata.GetExpandValues(req.Query)
if err != nil {
return nil, err
}
@@ -156,7 +157,7 @@ func (i *LDAP) GetGroupMembers(ctx context.Context, groupID string, req *godata.
return nil, err
}
searchTerm, err := GetSearchValues(req.Query)
searchTerm, err := odata.GetSearchValues(req.Query)
if err != nil {
return nil, err
}

View File

@@ -1,63 +0,0 @@
package identity
import (
"strings"
"github.com/CiscoM31/godata"
)
// GetExpandValues extracts the values of the $expand query parameter and
// returns them in a []string, rejects any $expand value that consists of more
// than just a single path segment
func GetExpandValues(req *godata.GoDataQuery) ([]string, error) {
if req == nil || req.Expand == nil {
return []string{}, nil
}
expand := make([]string, 0, len(req.Expand.ExpandItems))
for _, item := range req.Expand.ExpandItems {
if item.Filter != nil || item.At != nil || item.Search != nil ||
item.OrderBy != nil || item.Skip != nil || item.Top != nil ||
item.Select != nil || item.Compute != nil || item.Expand != nil ||
item.Levels != 0 {
return []string{}, godata.NotImplementedError("options for $expand not supported")
}
if len(item.Path) > 1 {
return []string{}, godata.NotImplementedError("multiple segments in $expand not supported")
}
expand = append(expand, item.Path[0].Value)
}
return expand, nil
}
// GetSelectValues extracts the values of the $select query parameter and
// returns them in a []string, rejects any $select value that consists of more
// than just a single path segment
func GetSelectValues(req *godata.GoDataQuery) ([]string, error) {
if req == nil || req.Select == nil {
return []string{}, nil
}
sel := make([]string, 0, len(req.Select.SelectItems))
for _, item := range req.Select.SelectItems {
if len(item.Segments) > 1 {
return []string{}, godata.NotImplementedError("multiple segments in $select not supported")
}
sel = append(sel, item.Segments[0].Value)
}
return sel, nil
}
// GetSearchValues extracts the value of the $search query parameter and returns
// it as a string. Rejects any search query that is more than just a simple string
func GetSearchValues(req *godata.GoDataQuery) (string, error) {
if req == nil || req.Search == nil {
return "", nil
}
// Only allow simple search queries for now
if len(req.Search.Tree.Children) != 0 {
return "", godata.NotImplementedError("complex search queries are not supported")
}
searchValue := strings.Trim(req.Search.Tree.Token.Value, "\"")
return searchValue, nil
}

View File

@@ -0,0 +1,104 @@
package odata
import (
"strings"
"github.com/CiscoM31/godata"
)
// GetExpandValues extracts the values of the $expand query parameter and
// returns them in a []string, rejecting any $expand value that consists of more
// than just a single path segment.
func GetExpandValues(req *godata.GoDataQuery) ([]string, error) {
if req == nil || req.Expand == nil {
return []string{}, nil
}
var expand []string
for _, item := range req.Expand.ExpandItems {
paths, err := collectExpandPaths(item, "")
if err != nil {
return nil, err
}
expand = append(expand, paths...)
}
return expand, nil
}
// collectExpandPaths recursively collects all valid expand paths from the given item.
func collectExpandPaths(item *godata.ExpandItem, prefix string) ([]string, error) {
if err := validateExpandItem(item); err != nil {
return nil, err
}
// Build the current path
currentPath := prefix
if len(item.Path) > 0 {
if len(item.Path) > 1 {
return nil, godata.NotImplementedError("multiple segments in $expand not supported")
}
if currentPath == "" {
currentPath = item.Path[0].Value
} else {
currentPath += "." + item.Path[0].Value
}
}
// Collect all paths, including nested ones
paths := []string{currentPath}
if item.Expand != nil {
for _, subItem := range item.Expand.ExpandItems {
subPaths, err := collectExpandPaths(subItem, currentPath)
if err != nil {
return nil, err
}
paths = append(paths, subPaths...)
}
}
return paths, nil
}
// validateExpandItem checks if an expand item contains unsupported options.
func validateExpandItem(item *godata.ExpandItem) error {
if item.Filter != nil || item.At != nil || item.Search != nil ||
item.OrderBy != nil || item.Skip != nil || item.Top != nil ||
item.Select != nil || item.Compute != nil || item.Levels != 0 {
return godata.NotImplementedError("options for $expand not supported")
}
return nil
}
// GetSelectValues extracts the values of the $select query parameter and
// returns them in a []string, rejects any $select value that consists of more
// than just a single path segment
func GetSelectValues(req *godata.GoDataQuery) ([]string, error) {
if req == nil || req.Select == nil {
return []string{}, nil
}
sel := make([]string, 0, len(req.Select.SelectItems))
for _, item := range req.Select.SelectItems {
if len(item.Segments) > 1 {
return []string{}, godata.NotImplementedError("multiple segments in $select not supported")
}
sel = append(sel, item.Segments[0].Value)
}
return sel, nil
}
// GetSearchValues extracts the value of the $search query parameter and returns
// it as a string. Rejects any search query that is more than just a simple string
func GetSearchValues(req *godata.GoDataQuery) (string, error) {
if req == nil || req.Search == nil {
return "", nil
}
// Only allow simple search queries for now
if len(req.Search.Tree.Children) != 0 {
return "", godata.NotImplementedError("complex search queries are not supported")
}
searchValue := strings.Trim(req.Search.Tree.Token.Value, "\"")
return searchValue, nil
}

View File

@@ -0,0 +1,160 @@
package odata
import (
"testing"
"github.com/CiscoM31/godata"
"github.com/stretchr/testify/assert"
)
func TestGetExpandValues(t *testing.T) {
t.Run("NilRequest", func(t *testing.T) {
result, err := GetExpandValues(nil)
assert.NoError(t, err)
assert.Empty(t, result)
})
t.Run("EmptyExpand", func(t *testing.T) {
req := &godata.GoDataQuery{}
result, err := GetExpandValues(req)
assert.NoError(t, err)
assert.Empty(t, result)
})
t.Run("SinglePathSegment", func(t *testing.T) {
req := &godata.GoDataQuery{
Expand: &godata.GoDataExpandQuery{
ExpandItems: []*godata.ExpandItem{
{Path: []*godata.Token{{Value: "orders"}}},
},
},
}
result, err := GetExpandValues(req)
assert.NoError(t, err)
assert.Equal(t, []string{"orders"}, result)
})
t.Run("MultiplePathSegments", func(t *testing.T) {
req := &godata.GoDataQuery{
Expand: &godata.GoDataExpandQuery{
ExpandItems: []*godata.ExpandItem{
{Path: []*godata.Token{{Value: "orders"}, {Value: "details"}}},
},
},
}
result, err := GetExpandValues(req)
assert.Error(t, err)
assert.Empty(t, result)
})
t.Run("NestedExpand", func(t *testing.T) {
req := &godata.GoDataQuery{
Expand: &godata.GoDataExpandQuery{
ExpandItems: []*godata.ExpandItem{
{
Path: []*godata.Token{{Value: "items"}},
Expand: &godata.GoDataExpandQuery{
ExpandItems: []*godata.ExpandItem{
{
Path: []*godata.Token{{Value: "subitem"}},
Expand: &godata.GoDataExpandQuery{
ExpandItems: []*godata.ExpandItem{
{Path: []*godata.Token{{Value: "subsubitems"}}},
},
},
},
},
},
},
},
},
}
result, err := GetExpandValues(req)
assert.NoError(t, err)
assert.Subset(t, result, []string{"items", "items.subitem", "items.subitem.subsubitems"}, "must contain all levels of expansion")
})
}
func TestGetSelectValues(t *testing.T) {
t.Run("NilRequest", func(t *testing.T) {
result, err := GetSelectValues(nil)
assert.NoError(t, err)
assert.Empty(t, result)
})
t.Run("EmptySelect", func(t *testing.T) {
req := &godata.GoDataQuery{}
result, err := GetSelectValues(req)
assert.NoError(t, err)
assert.Empty(t, result)
})
t.Run("SinglePathSegment", func(t *testing.T) {
req := &godata.GoDataQuery{
Select: &godata.GoDataSelectQuery{
SelectItems: []*godata.SelectItem{
{Segments: []*godata.Token{{Value: "name"}}},
},
},
}
result, err := GetSelectValues(req)
assert.NoError(t, err)
assert.Equal(t, []string{"name"}, result)
})
t.Run("MultiplePathSegments", func(t *testing.T) {
req := &godata.GoDataQuery{
Select: &godata.GoDataSelectQuery{
SelectItems: []*godata.SelectItem{
{Segments: []*godata.Token{{Value: "name"}, {Value: "first"}}},
},
},
}
result, err := GetSelectValues(req)
assert.Error(t, err)
assert.Empty(t, result)
})
}
func TestGetSearchValues(t *testing.T) {
t.Run("NilRequest", func(t *testing.T) {
result, err := GetSearchValues(nil)
assert.NoError(t, err)
assert.Empty(t, result)
})
t.Run("EmptySearch", func(t *testing.T) {
req := &godata.GoDataQuery{}
result, err := GetSearchValues(req)
assert.NoError(t, err)
assert.Empty(t, result)
})
t.Run("SimpleSearch", func(t *testing.T) {
req := &godata.GoDataQuery{
Search: &godata.GoDataSearchQuery{
Tree: &godata.ParseNode{
Token: &godata.Token{Value: "test"},
},
},
}
result, err := GetSearchValues(req)
assert.NoError(t, err)
assert.Equal(t, "test", result)
})
t.Run("ComplexSearch", func(t *testing.T) {
req := &godata.GoDataQuery{
Search: &godata.GoDataSearchQuery{
Tree: &godata.ParseNode{
Children: []*godata.ParseNode{
{Token: &godata.Token{Value: "test"}},
},
},
},
}
result, err := GetSearchValues(req)
assert.Error(t, err)
assert.Empty(t, result)
})
}

View File

@@ -8,6 +8,7 @@ import (
"net/http"
"net/url"
"path"
"slices"
"sort"
"strconv"
"strings"
@@ -32,6 +33,7 @@ import (
v0 "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/messages/settings/v0"
settingssvc "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/settings/v0"
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
"github.com/opencloud-eu/opencloud/services/graph/pkg/odata"
settingsServiceExt "github.com/opencloud-eu/opencloud/services/settings/pkg/store/defaults"
)
@@ -168,31 +170,63 @@ func (g Graph) GetAllDrivesV1Beta1(w http.ResponseWriter, r *http.Request) {
}
}
func sanitizePath(path string, apiVersion APIVersion) string {
switch apiVersion {
case APIVersion_1:
return strings.TrimPrefix(path, "/graph/v1.0/")
case APIVersion_1_Beta_1:
return strings.TrimPrefix(path, "/graph/v1beta1.0/")
default:
return path
}
}
// parseDriveRequest parses the odata request and returns the parsed request and a boolean indicating if the request should expand root driveItems.
func parseDriveRequest(r *http.Request) (*godata.GoDataRequest, bool, error) {
odataReq, err := godata.ParseRequest(r.Context(), sanitizePath(r.URL.Path, APIVersion_1), r.URL.Query())
if err != nil {
return nil, false, errorcode.New(errorcode.InvalidRequest, err.Error())
}
exp, err := odata.GetExpandValues(odataReq.Query)
if err != nil {
return nil, false, errorcode.New(errorcode.InvalidRequest, err.Error())
}
expandPermissions := false
if slices.Contains(exp, "root.permissions") {
expandPermissions = true
}
return odataReq, expandPermissions, nil
}
// getDrives implements the Service interface.
func (g Graph) getDrives(r *http.Request, unrestricted bool, apiVersion APIVersion) ([]*libregraph.Drive, error) {
logger := g.logger.SubloggerWithRequestID(r.Context())
logger.Info().
Interface("query", r.URL.Query()).
Bool("unrestricted", unrestricted).
Msg("calling get drives")
sanitizedPath := strings.TrimPrefix(r.URL.Path, "/graph/v1.0/")
// Parse the request with odata parser
odataReq, err := godata.ParseRequest(r.Context(), sanitizedPath, r.URL.Query())
if err != nil {
logger.Debug().Err(err).Interface("query", r.URL.Query()).Msg("could not get drives: query error")
return nil, errorcode.New(errorcode.InvalidRequest, err.Error())
}
ctx := r.Context()
log := g.logger.SubloggerWithRequestID(ctx).With().Interface("query", r.URL.Query()).Bool("unrestricted", unrestricted).Logger()
log.Debug().Msg("calling get drives")
webDavBaseURL, err := g.getWebDavBaseURL()
if err != nil {
log.Error().Err(err).Msg("could not get drives: error parsing url")
return nil, errorcode.New(errorcode.GeneralException, err.Error())
}
log = log.With().Str("url", webDavBaseURL.String()).Logger()
odataReq, expandPermissions, err := parseDriveRequest(r)
if err != nil {
log.Debug().Err(err).Msg("could not get drives: error parsing odata request")
return nil, err
}
filters, err := generateCs3Filters(odataReq)
if err != nil {
logger.Debug().Err(err).Interface("query", r.URL.Query()).Msg("could not get drives: error parsing filters")
log.Debug().Err(err).Msg("could not get drives: error parsing filters")
return nil, errorcode.New(errorcode.NotSupported, err.Error())
}
if !unrestricted {
user, ok := revactx.ContextGetUser(r.Context())
if !ok {
logger.Debug().Msg("could not create drive: invalid user")
log.Debug().Msg("could not create drive: invalid user")
return nil, errorcode.New(errorcode.AccessDenied, "invalid user")
}
filters = append(filters, &storageprovider.ListStorageSpacesRequest_Filter{
@@ -203,39 +237,32 @@ func (g Graph) getDrives(r *http.Request, unrestricted bool, apiVersion APIVersi
})
}
logger.Debug().
log.Debug().
Interface("filters", filters).
Bool("unrestricted", unrestricted).
Msg("calling list storage spaces on backend")
res, err := g.ListStorageSpacesWithFilters(ctx, filters, unrestricted)
switch {
case err != nil:
logger.Error().Err(err).Msg("could not get drives: transport error")
log.Error().Err(err).Msg("could not get drives: transport error")
return nil, errorcode.New(errorcode.GeneralException, err.Error())
case res.Status.Code != cs3rpc.Code_CODE_OK:
if res.Status.Code == cs3rpc.Code_CODE_NOT_FOUND {
// ok, empty return
return nil, nil
}
logger.Debug().Str("message", res.GetStatus().GetMessage()).Msg("could not get drives: grpc error")
log.Debug().Str("message", res.GetStatus().GetMessage()).Msg("could not get drives: grpc error")
return nil, errorcode.New(errorcode.GeneralException, res.Status.Message)
}
webDavBaseURL, err := g.getWebDavBaseURL()
spaces, err := g.formatDrives(ctx, webDavBaseURL, res.StorageSpaces, apiVersion, expandPermissions)
if err != nil {
logger.Error().Err(err).Str("url", webDavBaseURL.String()).Msg("could not get drives: error parsing url")
return nil, errorcode.New(errorcode.GeneralException, err.Error())
}
spaces, err := g.formatDrives(ctx, webDavBaseURL, res.StorageSpaces, apiVersion)
if err != nil {
logger.Debug().Err(err).Msg("could not get drives: error parsing grpc response")
log.Debug().Err(err).Msg("could not get drives: error parsing grpc response")
return nil, errorcode.New(errorcode.GeneralException, err.Error())
}
spaces, err = sortSpaces(odataReq, spaces)
if err != nil {
logger.Debug().Err(err).Msg("could not get drives: error sorting the spaces list according to query")
log.Debug().Err(err).Msg("could not get drives: error sorting the spaces list according to query")
return nil, errorcode.New(errorcode.InvalidRequest, err.Error())
}
@@ -245,15 +272,32 @@ func (g Graph) getDrives(r *http.Request, unrestricted bool, apiVersion APIVersi
// GetSingleDrive does a lookup of a single space by spaceId
func (g Graph) GetSingleDrive(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
logger := g.logger.SubloggerWithRequestID(ctx)
logger.Info().Interface("query", r.URL.Query()).Msg("calling get drive")
log := g.logger.SubloggerWithRequestID(ctx).With().Interface("query", r.URL.Query()).Logger()
log.Debug().Msg("calling get drive")
rid, err := parseIDParam(r, "driveID")
if err != nil {
errorcode.RenderError(w, r, err)
return
}
log := logger.With().Str("storage", rid.StorageId).Str("space", rid.SpaceId).Str("node", rid.OpaqueId).Logger()
log = log.With().Str("storage", rid.StorageId).Str("space", rid.SpaceId).Str("node", rid.OpaqueId).Logger()
webDavBaseURL, err := g.getWebDavBaseURL()
if err != nil {
log.Error().Err(err).Msg("could not get drive: error parsing webdav base url")
errorcode.RenderError(w, r, err)
return
}
log = log.With().Str("url", webDavBaseURL.String()).Logger()
_, expandPermissions, err := parseDriveRequest(r)
if err != nil {
log.Debug().Err(err).Msg("could not get drives: error parsing odata request")
errorcode.RenderError(w, r, err)
return
}
log.Debug().Msg("calling list storage spaces with id filter")
@@ -281,13 +325,7 @@ func (g Graph) GetSingleDrive(w http.ResponseWriter, r *http.Request) {
return
}
webDavBaseURL, err := g.getWebDavBaseURL()
if err != nil {
log.Error().Err(err).Str("url", webDavBaseURL.String()).Msg("could not get drive: error parsing webdav base url")
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
return
}
spaces, err := g.formatDrives(ctx, webDavBaseURL, res.StorageSpaces, APIVersion_1)
spaces, err := g.formatDrives(ctx, webDavBaseURL, res.StorageSpaces, APIVersion_1, expandPermissions)
if err != nil {
log.Debug().Err(err).Msg("could not get drive: error parsing grpc response")
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
@@ -324,14 +362,28 @@ func (g Graph) canCreateSpace(ctx context.Context, ownPersonalHome bool) bool {
// CreateDrive creates a storage drive (space).
func (g Graph) CreateDrive(w http.ResponseWriter, r *http.Request) {
logger := g.logger.SubloggerWithRequestID(r.Context())
logger.Info().Msg("calling create drive")
ctx := r.Context()
log := g.logger.SubloggerWithRequestID(ctx).With().Interface("query", r.URL.Query()).Logger()
log.Debug().Msg("calling create drive")
webDavBaseURL, err := g.getWebDavBaseURL()
if err != nil {
log.Error().Err(err).Msg("could not create drive: error parsing webdav base url")
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
return
}
log = log.With().Str("url", webDavBaseURL.String()).Logger()
_, expandPermissions, err := parseDriveRequest(r)
if err != nil {
log.Debug().Err(err).Msg("could not create drive: error parsing odata request")
errorcode.RenderError(w, r, err)
}
us, ok := revactx.ContextGetUser(ctx)
if !ok {
logger.Debug().Msg("could not create drive: invalid user")
log.Debug().Msg("could not create drive: invalid user")
errorcode.NotAllowed.Render(w, r, http.StatusUnauthorized, "invalid user")
return
}
@@ -339,7 +391,7 @@ func (g Graph) CreateDrive(w http.ResponseWriter, r *http.Request) {
// TODO determine if the user tries to create his own personal space and pass that as a boolean
canCreateSpace := g.canCreateSpace(ctx, false)
if !canCreateSpace {
logger.Debug().Bool("cancreatespace", canCreateSpace).Msg("could not create drive: insufficient permissions")
log.Debug().Bool("cancreatespace", canCreateSpace).Msg("could not create drive: insufficient permissions")
// if the permission is not existing for the user in context we can assume we don't have it. Return 401.
errorcode.NotAllowed.Render(w, r, http.StatusForbidden, "insufficient permissions to create a space.")
return
@@ -347,20 +399,20 @@ func (g Graph) CreateDrive(w http.ResponseWriter, r *http.Request) {
gatewayClient, err := g.gatewaySelector.Next()
if err != nil {
logger.Error().Err(err).Msg("could not select next gateway client")
log.Error().Err(err).Msg("could not select next gateway client")
errorcode.ServiceNotAvailable.Render(w, r, http.StatusInternalServerError, "could not select next gateway client, aborting")
return
}
drive := libregraph.Drive{}
if err := StrictJSONUnmarshal(r.Body, &drive); err != nil {
logger.Debug().Err(err).Interface("body", r.Body).Msg("could not create drive: invalid body schema definition")
log.Debug().Err(err).Interface("body", r.Body).Msg("could not create drive: invalid body schema definition")
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "invalid body schema definition")
return
}
spaceName := strings.TrimSpace(drive.Name)
if err := validateSpaceName(spaceName); err != nil {
logger.Debug().Str("name", spaceName).Err(err).Msg("could not create drive: name validation failed")
log.Debug().Str("name", spaceName).Err(err).Msg("could not create drive: name validation failed")
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, fmt.Sprintf("invalid spacename: %s", err.Error()))
return
}
@@ -373,7 +425,7 @@ func (g Graph) CreateDrive(w http.ResponseWriter, r *http.Request) {
case "", _spaceTypeProject:
driveType = _spaceTypeProject
default:
logger.Debug().Str("type", driveType).Msg("could not create drive: drives of this type cannot be created via this api")
log.Debug().Str("type", driveType).Msg("could not create drive: drives of this type cannot be created via this api")
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "drives of this type cannot be created via this api")
return
}
@@ -398,39 +450,32 @@ func (g Graph) CreateDrive(w http.ResponseWriter, r *http.Request) {
resp, err := gatewayClient.CreateStorageSpace(ctx, &csr)
if err != nil {
logger.Error().Err(err).Msg("could not create drive: transport error")
log.Error().Err(err).Msg("could not create drive: transport error")
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
return
}
if resp.GetStatus().GetCode() != cs3rpc.Code_CODE_OK {
if resp.GetStatus().GetCode() == cs3rpc.Code_CODE_PERMISSION_DENIED {
logger.Debug().Str("grpcmessage", resp.GetStatus().GetMessage()).Msg("could not create drive: permission denied")
log.Debug().Str("grpcmessage", resp.GetStatus().GetMessage()).Msg("could not create drive: permission denied")
errorcode.NotAllowed.Render(w, r, http.StatusForbidden, "permission denied")
return
}
if resp.GetStatus().GetCode() == cs3rpc.Code_CODE_INVALID_ARGUMENT {
logger.Debug().Str("grpcmessage", resp.GetStatus().GetMessage()).Msg("could not create drive: bad request")
log.Debug().Str("grpcmessage", resp.GetStatus().GetMessage()).Msg("could not create drive: bad request")
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, resp.GetStatus().GetMessage())
return
}
logger.Debug().Interface("grpcmessage", csr).Str("grpc", resp.GetStatus().GetMessage()).Msg("could not create drive: grpc error")
log.Debug().Interface("grpcmessage", csr).Str("grpc", resp.GetStatus().GetMessage()).Msg("could not create drive: grpc error")
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, resp.GetStatus().GetMessage())
return
}
webDavBaseURL, err := g.getWebDavBaseURL()
if err != nil {
logger.Error().Str("url", webDavBaseURL.String()).Err(err).Msg("could not create drive: error parsing webdav base url")
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
return
}
space := resp.GetStorageSpace()
if t := r.URL.Query().Get(TemplateParameter); t != "" && driveType == _spaceTypeProject {
loc := l10n.MustGetUserLocale(ctx, us.GetId().GetOpaqueId(), r.Header.Get(HeaderAcceptLanguage), g.valueService)
if err := g.applySpaceTemplate(ctx, gatewayClient, space.GetRoot(), t, loc); err != nil {
logger.Error().Err(err).Msg("could not apply template to space")
log.Error().Err(err).Msg("could not apply template to space")
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
return
}
@@ -438,20 +483,20 @@ func (g Graph) CreateDrive(w http.ResponseWriter, r *http.Request) {
// refetch the drive to get quota information - should we calculate this ourselves to avoid the extra call?
space, err = utils.GetSpace(ctx, space.GetId().GetOpaqueId(), gatewayClient)
if err != nil {
logger.Error().Err(err).Msg("could not refetch space")
log.Error().Err(err).Msg("could not refetch space")
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
return
}
}
spaces, err := g.formatDrives(ctx, webDavBaseURL, []*storageprovider.StorageSpace{space}, APIVersion_1)
spaces, err := g.formatDrives(ctx, webDavBaseURL, []*storageprovider.StorageSpace{space}, APIVersion_1, expandPermissions)
if err != nil {
logger.Debug().Err(err).Msg("could not get drive: error parsing grpc response")
log.Debug().Err(err).Msg("could not get drive: error parsing grpc response")
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
return
}
if len(spaces) == 0 {
logger.Error().Msg("could not convert space")
log.Error().Msg("could not convert space")
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, "could not convert space")
return
}
@@ -462,8 +507,8 @@ func (g Graph) CreateDrive(w http.ResponseWriter, r *http.Request) {
// UpdateDrive updates the properties of a storage drive (space).
func (g Graph) UpdateDrive(w http.ResponseWriter, r *http.Request) {
logger := g.logger.SubloggerWithRequestID(r.Context())
logger.Info().Msg("calling update drive")
log := g.logger.SubloggerWithRequestID(r.Context()).With().Interface("query", r.URL.Query()).Logger()
log.Debug().Msg("calling update drive")
rid, err := parseIDParam(r, "driveID")
if err != nil {
@@ -471,9 +516,26 @@ func (g Graph) UpdateDrive(w http.ResponseWriter, r *http.Request) {
return
}
log = log.With().Str("storage", rid.StorageId).Str("space", rid.SpaceId).Str("node", rid.OpaqueId).Logger()
webDavBaseURL, err := g.getWebDavBaseURL()
if err != nil {
log.Error().Err(err).Interface("url", webDavBaseURL.String()).Msg("could not update drive: error parsing url")
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
return
}
log = log.With().Str("url", webDavBaseURL.String()).Logger()
_, expandPermissions, err := parseDriveRequest(r)
if err != nil {
log.Debug().Err(err).Msg("could not create drive: error parsing odata request")
errorcode.RenderError(w, r, err)
}
drive := libregraph.DriveUpdate{}
if err = StrictJSONUnmarshal(r.Body, &drive); err != nil {
logger.Debug().Err(err).Interface("body", r.Body).Msg("could not update drive, invalid request body")
log.Debug().Err(err).Interface("body", r.Body).Msg("could not update drive, invalid request body")
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, fmt.Sprintf("invalid request body: error: %v", err.Error()))
return
}
@@ -526,7 +588,7 @@ func (g Graph) UpdateDrive(w http.ResponseWriter, r *http.Request) {
if drive.GetName() != "" {
spacename := strings.TrimSpace(drive.GetName())
if err := validateSpaceName(spacename); err != nil {
logger.Info().Err(err).Msg("could not update drive: spacename invalid")
log.Info().Err(err).Msg("could not update drive: spacename invalid")
errorcode.GeneralException.Render(w, r, http.StatusBadRequest, err.Error())
return
}
@@ -552,12 +614,12 @@ func (g Graph) UpdateDrive(w http.ResponseWriter, r *http.Request) {
canSetSpaceQuota, err := g.canSetSpaceQuota(r.Context(), user, dt)
if err != nil {
logger.Error().Err(err).Msg("could not update drive: failed to check if the user can set space quota")
log.Error().Err(err).Msg("could not update drive: failed to check if the user can set space quota")
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
return
}
if !canSetSpaceQuota {
logger.Debug().
log.Debug().
Bool("cansetspacequota", canSetSpaceQuota).
Msg("could not update drive: user is not allowed to set the space quota")
errorcode.NotAllowed.Render(w, r, http.StatusForbidden, "user is not allowed to set the space quota")
@@ -568,10 +630,10 @@ func (g Graph) UpdateDrive(w http.ResponseWriter, r *http.Request) {
}
}
logger.Debug().Interface("payload", updateSpaceRequest).Msg("calling update space on backend")
log.Debug().Interface("payload", updateSpaceRequest).Msg("calling update space on backend")
resp, err := gatewayClient.UpdateStorageSpace(r.Context(), updateSpaceRequest)
if err != nil {
logger.Error().Err(err).Msg("could not update drive: transport error")
log.Error().Err(err).Msg("could not update drive: transport error")
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, "transport error")
return
}
@@ -579,38 +641,31 @@ func (g Graph) UpdateDrive(w http.ResponseWriter, r *http.Request) {
if resp.GetStatus().GetCode() != cs3rpc.Code_CODE_OK {
switch resp.Status.GetCode() {
case cs3rpc.Code_CODE_NOT_FOUND:
logger.Debug().Interface("id", rid).Msg("could not update drive: drive not found")
log.Debug().Msg("could not update drive: drive not found")
errorcode.ItemNotFound.Render(w, r, http.StatusNotFound, "drive not found")
return
case cs3rpc.Code_CODE_PERMISSION_DENIED:
logger.Debug().Interface("id", rid).Msg("could not update drive, permission denied")
log.Debug().Msg("could not update drive, permission denied")
errorcode.ItemNotFound.Render(w, r, http.StatusNotFound, "drive not found")
return
case cs3rpc.Code_CODE_INVALID_ARGUMENT:
logger.Debug().Interface("id", rid).Msg("could not update drive, invalid argument")
log.Debug().Msg("could not update drive, invalid argument")
errorcode.NotAllowed.Render(w, r, http.StatusBadRequest, resp.GetStatus().GetMessage())
return
case cs3rpc.Code_CODE_UNIMPLEMENTED:
logger.Debug().Interface("id", rid).Msg("could not delete drive: delete not implemented for this type of drive")
log.Debug().Msg("could not delete drive: delete not implemented for this type of drive")
errorcode.NotAllowed.Render(w, r, http.StatusMethodNotAllowed, "drive cannot be updated")
return
default:
logger.Debug().Interface("id", rid).Str("grpc", resp.GetStatus().GetMessage()).Msg("could not update drive: grpc error")
log.Debug().Str("grpc", resp.GetStatus().GetMessage()).Msg("could not update drive: grpc error")
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, "grpc error")
return
}
}
webDavBaseURL, err := g.getWebDavBaseURL()
spaces, err := g.formatDrives(r.Context(), webDavBaseURL, []*storageprovider.StorageSpace{resp.StorageSpace}, APIVersion_1, expandPermissions)
if err != nil {
logger.Error().Err(err).Interface("url", webDavBaseURL.String()).Msg("could not update drive: error parsing url")
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
return
}
spaces, err := g.formatDrives(r.Context(), webDavBaseURL, []*storageprovider.StorageSpace{resp.StorageSpace}, APIVersion_1)
if err != nil {
logger.Debug().Err(err).Msg("could not update drive: error parsing grpc response")
log.Debug().Err(err).Msg("could not update drive: error parsing grpc response")
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
return
}
@@ -619,7 +674,7 @@ func (g Graph) UpdateDrive(w http.ResponseWriter, r *http.Request) {
render.JSON(w, r, spaces[0])
}
func (g Graph) formatDrives(ctx context.Context, baseURL *url.URL, storageSpaces []*storageprovider.StorageSpace, apiVersion APIVersion) ([]*libregraph.Drive, error) {
func (g Graph) formatDrives(ctx context.Context, baseURL *url.URL, storageSpaces []*storageprovider.StorageSpace, apiVersion APIVersion, expandPermissions bool) ([]*libregraph.Drive, error) {
errg, ctx := errgroup.WithContext(ctx)
work := make(chan *storageprovider.StorageSpace, len(storageSpaces))
results := make(chan *libregraph.Drive, len(storageSpaces))
@@ -649,7 +704,7 @@ func (g Graph) formatDrives(ctx context.Context, baseURL *url.URL, storageSpaces
// skip OCM shares they are no supposed to show up in the drives list
continue
}
res, err := g.cs3StorageSpaceToDrive(ctx, baseURL, storageSpace, apiVersion)
res, err := g.cs3StorageSpaceToDrive(ctx, baseURL, storageSpace, apiVersion, expandPermissions)
if err != nil {
return err
}
@@ -733,7 +788,7 @@ func (g Graph) ListStorageSpacesWithFilters(ctx context.Context, filters []*stor
return res, err
}
func (g Graph) cs3StorageSpaceToDrive(ctx context.Context, baseURL *url.URL, space *storageprovider.StorageSpace, apiVersion APIVersion) (*libregraph.Drive, error) {
func (g Graph) cs3StorageSpaceToDrive(ctx context.Context, baseURL *url.URL, space *storageprovider.StorageSpace, apiVersion APIVersion, expandPermissions bool) (*libregraph.Drive, error) {
logger := g.logger.SubloggerWithRequestID(ctx)
if space.Root == nil {
logger.Error().Msg("unable to parse space: space has no root")
@@ -745,18 +800,20 @@ func (g Graph) cs3StorageSpaceToDrive(ctx context.Context, baseURL *url.URL, spa
}
spaceID := storagespace.FormatResourceID(spaceRid)
permissions := g.cs3SpacePermissionsToLibreGraph(ctx, space, apiVersion)
drive := &libregraph.Drive{
Id: libregraph.PtrString(spaceID),
Name: space.Name,
//"createdDateTime": "string (timestamp)", // TODO read from StorageSpace ... needs Opaque for now
DriveType: &space.SpaceType,
// we currently always expandt the root because it carries the deleted property that indiccates if a space is trashed
Root: &libregraph.DriveItem{
Id: libregraph.PtrString(storagespace.FormatResourceID(spaceRid)),
Permissions: permissions,
Id: libregraph.PtrString(storagespace.FormatResourceID(spaceRid)),
},
}
if expandPermissions {
drive.Root.Permissions = g.cs3SpacePermissionsToLibreGraph(ctx, space, apiVersion)
}
if space.SpaceType == _spaceTypeMountpoint {
var remoteItem *libregraph.RemoteItem
grantID := storageprovider.ResourceId{

View File

@@ -489,8 +489,42 @@ var _ = Describe("Graph", func() {
Expect(libreError.Error.Message).To(Equal("internal quota error"))
Expect(libreError.Error.Code).To(Equal(errorcode.GeneralException.String()))
})
It("omit permissions by default", func() {
gatewayClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Times(1).Return(&provider.ListStorageSpacesResponse{
Status: status.NewOK(ctx),
StorageSpaces: []*provider.StorageSpace{
{
Opaque: utils.AppendJSONToOpaque(nil, "grants", map[string]provider.ResourcePermissions{
"1": *conversions.NewManagerRole().CS3ResourcePermissions(),
}),
Root: &provider.ResourceId{},
},
},
}, nil)
gatewayClient.On("InitiateFileDownload", mock.Anything, mock.Anything).Return(&gateway.InitiateFileDownloadResponse{
Status: status.NewNotFound(ctx, "not found"),
}, nil)
gatewayClient.On("GetQuota", mock.Anything, mock.Anything).Return(&provider.GetQuotaResponse{
Status: status.NewUnimplemented(ctx, fmt.Errorf("not supported"), "not supported"),
}, nil)
gatewayClient.On("GetUser", mock.Anything, mock.Anything).Return(&userprovider.GetUserResponse{
Status: status.NewUnimplemented(ctx, fmt.Errorf("not supported"), "not supported"),
}, nil)
r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives", nil)
r = r.WithContext(ctx)
rr := httptest.NewRecorder()
svc.GetDrivesV1(rr, r)
Expect(rr.Code).To(Equal(http.StatusOK))
jsonData := gjson.Get(rr.Body.String(), "value")
Expect(jsonData.Get("#").Num).To(Equal(float64(1)))
Expect(jsonData.Get("0.root.permissions").Exists()).To(BeFalse())
})
})
DescribeTable("GetDrivesV1Beta1 and GetAllDrivesV1Beta1",
DescribeTable("GetDrivesV1Beta1 and GetAllDrivesV1Beta1 expands root permissions",
func(check func(gjson.Result), resourcePermissions provider.ResourcePermissions) {
permissionService.On("GetPermissionByID", mock.Anything, mock.Anything).Return(&settingssvc.GetPermissionByIDResponse{
Permission: &v0.Permission{
@@ -518,7 +552,7 @@ var _ = Describe("Graph", func() {
Status: status.NewUnimplemented(ctx, fmt.Errorf("not supported"), "not supported"),
}, nil)
r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives", nil)
r := httptest.NewRequest(http.MethodGet, "/graph/v1beta1.0/me/drives?$expand=root($expand=permissions)", nil)
r = r.WithContext(ctx)
rr := httptest.NewRecorder()
svc.GetDrivesV1Beta1(rr, r)

View File

@@ -24,6 +24,7 @@ import (
settingssvc "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/settings/v0"
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
"github.com/opencloud-eu/opencloud/services/graph/pkg/identity"
"github.com/opencloud-eu/opencloud/services/graph/pkg/odata"
ocsettingssvc "github.com/opencloud-eu/opencloud/services/settings/pkg/service/v0"
"github.com/opencloud-eu/opencloud/services/settings/pkg/store/defaults"
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
@@ -53,7 +54,7 @@ func (g Graph) GetMe(w http.ResponseWriter, r *http.Request) {
return
}
exp, err := identity.GetExpandValues(odataReq.Query)
exp, err := odata.GetExpandValues(odataReq.Query)
if err != nil {
logger.Debug().Err(err).Interface("query", r.URL.Query()).Msg("could not get users: $expand error")
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, err.Error())
@@ -119,74 +120,85 @@ func (g Graph) fetchAppRoleAssignments(ctx context.Context, accountuuid string)
// GetUserDrive implements the Service interface.
func (g Graph) GetUserDrive(w http.ResponseWriter, r *http.Request) {
logger := g.logger.SubloggerWithRequestID(r.Context())
logger.Debug().Interface("query", r.URL.Query()).Msg("calling get user drive")
ctx := r.Context()
log := g.logger.SubloggerWithRequestID(ctx).With().Interface("query", r.URL.Query()).Logger()
log.Debug().Msg("calling get user drive")
webDavBaseURL, err := g.getWebDavBaseURL()
if err != nil {
log.Error().Err(err).Msg("could not get personal drive: error parsing webdav base url")
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
return
}
log = log.With().Str("url", webDavBaseURL.String()).Logger()
userID, err := url.PathUnescape(chi.URLParam(r, "userID"))
if err != nil {
logger.Debug().Err(err).Str("userID", chi.URLParam(r, "userID")).Msg("could not get drive: unescaping drive id failed")
log.Debug().Err(err).Str("userID", chi.URLParam(r, "userID")).Msg("could not get drive: unescaping drive id failed")
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "unescaping user id failed")
return
}
log = log.With().Str("userID", userID).Logger()
_, expandPermissions, err := parseDriveRequest(r)
if err != nil {
log.Debug().Err(err).Msg("could not get drives: error parsing odata request")
errorcode.RenderError(w, r, err)
return
}
if userID == "" {
u, ok := revactx.ContextGetUser(r.Context())
u, ok := revactx.ContextGetUser(ctx)
if !ok {
logger.Debug().Msg("could not get user: user not in context")
log.Debug().Msg("could not get user: user not in context")
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, "user not in context")
return
}
userID = u.GetId().GetOpaqueId()
}
logger.Debug().Str("userID", userID).Msg("calling list storage spaces with user and personal filter")
ctx := r.Context()
log.Debug().Msg("calling list storage spaces with user and personal filter")
filters := []*storageprovider.ListStorageSpacesRequest_Filter{listStorageSpacesTypeFilter("personal"), listStorageSpacesUserFilter(userID)}
res, err := g.ListStorageSpacesWithFilters(ctx, filters, true)
switch {
case err != nil:
logger.Error().Err(err).Msg("could not get drive: transport error")
log.Error().Err(err).Msg("could not get drive: transport error")
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
return
case res.Status.Code != cs3rpc.Code_CODE_OK:
if res.Status.Code == cs3rpc.Code_CODE_NOT_FOUND {
// the client is doing a lookup for a specific space, therefore we need to return
// not found to the caller
logger.Debug().Str("userID", userID).Msg("could not get personal drive for user: not found")
log.Debug().Msg("could not get personal drive for user: not found")
errorcode.ItemNotFound.Render(w, r, http.StatusNotFound, "drive not found")
return
}
logger.Debug().
Str("userID", userID).
log.Debug().
Str("grpcmessage", res.GetStatus().GetMessage()).
Msg("could not get personal drive for user: grpc error")
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, res.Status.Message)
return
}
webDavBaseURL, err := g.getWebDavBaseURL()
spaces, err := g.formatDrives(ctx, webDavBaseURL, res.StorageSpaces, APIVersion_1, expandPermissions)
if err != nil {
logger.Error().Err(err).Str("url", webDavBaseURL.String()).Msg("could not get personal drive: error parsing webdav base url")
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
return
}
spaces, err := g.formatDrives(ctx, webDavBaseURL, res.StorageSpaces, APIVersion_1)
if err != nil {
logger.Debug().Err(err).Msg("could not get personal drive: error parsing grpc response")
log.Debug().Err(err).Msg("could not get personal drive: error parsing grpc response")
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
return
}
switch num := len(spaces); {
case num == 0:
logger.Debug().Str("userID", userID).Msg("could not get personal drive: no drive returned from storage")
log.Debug().Msg("could not get personal drive: no drive returned from storage")
errorcode.ItemNotFound.Render(w, r, http.StatusNotFound, "no drive returned from storage")
return
case num == 1:
render.Status(r, http.StatusOK)
render.JSON(w, r, spaces[0])
default:
logger.Debug().Int("number", num).Msg("could not get personal drive: expected to find a single drive but fetched more")
log.Debug().Int("number", num).Msg("could not get personal drive: expected to find a single drive but fetched more")
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, "could not get personal drive: expected to find a single drive but fetched more")
return
}
@@ -301,7 +313,7 @@ func (g Graph) GetUsers(w http.ResponseWriter, r *http.Request) {
users = finalUsers
}
exp, err := identity.GetExpandValues(odataReq.Query)
exp, err := odata.GetExpandValues(odataReq.Query)
if err != nil {
logger.Debug().Err(err).Interface("query", r.URL.Query()).Msg("could not get users: $expand error")
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, err.Error())
@@ -449,7 +461,7 @@ func (g Graph) GetUser(w http.ResponseWriter, r *http.Request) {
return
}
exp, err := identity.GetExpandValues(odataReq.Query)
exp, err := odata.GetExpandValues(odataReq.Query)
if err != nil {
logger.Debug().Err(err).Interface("query", r.URL.Query()).Msg("could not get users: $expand error")
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, err.Error())
@@ -466,6 +478,8 @@ func (g Graph) GetUser(w http.ResponseWriter, r *http.Request) {
listDrives := slices.Contains(exp, "drives")
listDrive := slices.Contains(exp, "drive")
expandDrivePermissions := slices.Contains(exp, "drive.root.permissions")
expandDrivesPermissions := slices.Contains(exp, "drives.root.permissions")
// do we need to list all or only the personal drive
filters := []*storageprovider.ListStorageSpacesRequest_Filter{}
@@ -526,7 +540,13 @@ func (g Graph) GetUser(w http.ResponseWriter, r *http.Request) {
user.Drive = &libregraph.Drive{}
}
for _, sp := range lspr.GetStorageSpaces() {
d, err := g.cs3StorageSpaceToDrive(r.Context(), wdu, sp, APIVersion_1)
expandPermissions := false
if sp.GetSpaceType() == "personal" && sp.GetOwner().GetId().GetOpaqueId() != user.GetId() {
expandPermissions = expandDrivePermissions
} else {
expandPermissions = expandDrivesPermissions
}
d, err := g.cs3StorageSpaceToDrive(r.Context(), wdu, sp, APIVersion_1, expandPermissions)
if err != nil {
logger.Debug().Err(err).Interface("id", sp.Id).Msg("error converting space to drive")
continue
@@ -1023,7 +1043,7 @@ func (g Graph) searchOCMAcceptedUsers(ctx context.Context, odataReq *godata.GoDa
if err != nil {
return nil, errorcode.New(errorcode.GeneralException, err.Error())
}
term, err := identity.GetSearchValues(odataReq.Query)
term, err := odata.GetSearchValues(odataReq.Query)
if err != nil {
return nil, errorcode.New(errorcode.InvalidRequest, err.Error())
}