Skip to content

Commit

Permalink
add filter by sharetype in the ocs API
Browse files Browse the repository at this point in the history
  • Loading branch information
David Christofas committed Sep 28, 2021
1 parent 48d4872 commit 89dcba4
Show file tree
Hide file tree
Showing 8 changed files with 269 additions and 136 deletions.
5 changes: 5 additions & 0 deletions changelog/unreleased/sharetype-filter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Enhancement: Add a share types filter to the OCS API

Added a filter to the OCS API to filter the received shares by type.

https://github.com/cs3org/reva/pull/2050
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,36 @@ func (h *Handler) listSharesWithMe(w http.ResponseWriter, r *http.Request) {
}
}

lrsRes, err := client.ListReceivedShares(ctx, &collaboration.ListReceivedSharesRequest{})
filters := []*collaboration.Filter{}
var shareTypes []string
shareTypesParam := r.URL.Query().Get("share_types")
if shareTypesParam != "" {
shareTypes = strings.Split(shareTypesParam, ",")
}
for _, s := range shareTypes {
if s == "" {
continue
}
shareType, err := strconv.Atoi(strings.TrimSpace(s))
if err != nil {
response.WriteOCSError(w, r, response.MetaBadRequest.StatusCode, "invalid share type", err)
return
}
switch shareType {
case int(conversions.ShareTypeUser):
filters = append(filters, share.UserGranteeFilter())
case int(conversions.ShareTypeGroup):
filters = append(filters, share.GroupGranteeFilter())
}
}

if len(shareTypes) != 0 && len(filters) == 0 {
// If a share_types filter was set for anything other than user or group shares just return an empty response
response.WriteOCSSuccess(w, r, []*conversions.ShareData{})
return
}

lrsRes, err := client.ListReceivedShares(ctx, &collaboration.ListReceivedSharesRequest{Filters: filters})
if err != nil {
response.WriteOCSError(w, r, response.MetaServerError.StatusCode, "error sending a grpc ListReceivedShares request", err)
return
Expand Down Expand Up @@ -693,25 +722,47 @@ func (h *Handler) listSharesWithOthers(w http.ResponseWriter, r *http.Request) {
}
}

shareTypes := strings.Split(r.URL.Query().Get("share_types"), ",")
var shareTypes []string
shareTypesParam := r.URL.Query().Get("share_types")
if shareTypesParam != "" {
shareTypes = strings.Split(shareTypesParam, ",")
}

listPublicShares := len(shareTypes) == 0 // if no share_types filter was set we want to list all share by default
listUserShares := len(shareTypes) == 0 // if no share_types filter was set we want to list all share by default
for _, s := range shareTypes {
if s == "" {
continue
}
shareType, err := strconv.Atoi(strings.TrimSpace(s))
if err != nil && s != "" {
if err != nil {
response.WriteOCSError(w, r, response.MetaBadRequest.StatusCode, "invalid share type", err)
return
}
if s == "" || shareType == int(conversions.ShareTypeUser) || shareType == int(conversions.ShareTypeGroup) {
userShares, status, err := h.listUserShares(r, filters)
h.logProblems(status, err, "could not listUserShares")
shares = append(shares, userShares...)
}
if s == "" || shareType == int(conversions.ShareTypePublicLink) {
publicShares, status, err := h.listPublicShares(r, linkFilters)
h.logProblems(status, err, "could not listPublicShares")
shares = append(shares, publicShares...)

switch shareType {
case int(conversions.ShareTypeUser):
listUserShares = true
filters = append(filters, share.UserGranteeFilter())
case int(conversions.ShareTypeGroup):
listUserShares = true
filters = append(filters, share.GroupGranteeFilter())
case int(conversions.ShareTypePublicLink):
listPublicShares = true
}
}

if listPublicShares {
publicShares, status, err := h.listPublicShares(r, linkFilters)
h.logProblems(status, err, "could not listPublicShares")
shares = append(shares, publicShares...)
}
if listUserShares {
userShares, status, err := h.listUserShares(r, filters)
h.logProblems(status, err, "could not listUserShares")
shares = append(shares, userShares...)
}

response.WriteOCSSuccess(w, r, shares)
}

Expand Down
63 changes: 24 additions & 39 deletions pkg/share/manager/json/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,21 +268,15 @@ func (m *mgr) get(ctx context.Context, ref *collaboration.ShareReference) (s *co

// check if we are the owner
user := ctxpkg.ContextMustGetUser(ctx)
if utils.UserEqual(user.Id, s.Owner) || utils.UserEqual(user.Id, s.Creator) {
if share.IsCreatedByUser(s, user) {
return s, nil
}

// or the grantee
if s.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_USER && utils.UserEqual(user.Id, s.Grantee.GetUserId()) {
if share.IsGrantedToUser(s, user) {
return s, nil
} else if s.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_GROUP {
// check if all user groups match this share; TODO(labkode): filter shares created by us.
for _, g := range user.Groups {
if g == s.Grantee.GetGroupId().OpaqueId {
return s, nil
}
}
}

// we return not found to not disclose information
return nil, errtypes.NotFound(ref.String())
}
Expand All @@ -302,7 +296,7 @@ func (m *mgr) Unshare(ctx context.Context, ref *collaboration.ShareReference) er
user := ctxpkg.ContextMustGetUser(ctx)
for i, s := range m.model.Shares {
if sharesEqual(ref, s) {
if utils.UserEqual(user.Id, s.Owner) || utils.UserEqual(user.Id, s.Creator) {
if share.IsCreatedByUser(s, user) {
m.model.Shares[len(m.model.Shares)-1], m.model.Shares[i] = m.model.Shares[i], m.model.Shares[len(m.model.Shares)-1]
m.model.Shares = m.model.Shares[:len(m.model.Shares)-1]
if err := m.model.Save(); err != nil {
Expand Down Expand Up @@ -336,7 +330,7 @@ func (m *mgr) UpdateShare(ctx context.Context, ref *collaboration.ShareReference
user := ctxpkg.ContextMustGetUser(ctx)
for i, s := range m.model.Shares {
if sharesEqual(ref, s) {
if utils.UserEqual(user.Id, s.Owner) || utils.UserEqual(user.Id, s.Creator) {
if share.IsCreatedByUser(s, user) {
now := time.Now().UnixNano()
m.model.Shares[i].Permissions = p
m.model.Shares[i].Mtime = &typespb.Timestamp{
Expand All @@ -360,19 +354,16 @@ func (m *mgr) ListShares(ctx context.Context, filters []*collaboration.Filter) (
defer m.Unlock()
user := ctxpkg.ContextMustGetUser(ctx)
for _, s := range m.model.Shares {
if utils.UserEqual(user.Id, s.Owner) || utils.UserEqual(user.Id, s.Creator) {
if share.IsCreatedByUser(s, user) {
// no filter we return earlier
if len(filters) == 0 {
ss = append(ss, s)
} else {
// check filters
// TODO(labkode): add the rest of filters.
for _, f := range filters {
if f.Type == collaboration.Filter_TYPE_RESOURCE_ID {
if utils.ResourceIDEqual(s.ResourceId, f.GetResourceId()) {
ss = append(ss, s)
}
}
continue
}
// check filters
for _, f := range filters {
if share.MatchesFilter(s, f) {
ss = append(ss, s)
}
}
}
Expand All @@ -387,20 +378,21 @@ func (m *mgr) ListReceivedShares(ctx context.Context, filters []*collaboration.F
defer m.Unlock()
user := ctxpkg.ContextMustGetUser(ctx)
for _, s := range m.model.Shares {
if utils.UserEqual(user.Id, s.Owner) || utils.UserEqual(user.Id, s.Creator) {
// omit shares created by me
if share.IsCreatedByUser(s, user) || !share.IsGrantedToUser(s, user) {
// omit shares created by the user or shares the user can't access
continue
}
if s.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_USER && utils.UserEqual(user.Id, s.Grantee.GetUserId()) {

if len(filters) == 0 {
rs := m.convert(ctx, s)
rss = append(rss, rs)
} else if s.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_GROUP {
// check if all user groups match this share; TODO(labkode): filter shares created by us.
for _, g := range user.Groups {
if g == s.Grantee.GetGroupId().OpaqueId {
rs := m.convert(ctx, s)
rss = append(rss, rs)
}
continue
}

for _, f := range filters {
if share.MatchesFilter(s, f) {
rs := m.convert(ctx, s)
rss = append(rss, rs)
}
}
}
Expand Down Expand Up @@ -432,16 +424,9 @@ func (m *mgr) getReceived(ctx context.Context, ref *collaboration.ShareReference
user := ctxpkg.ContextMustGetUser(ctx)
for _, s := range m.model.Shares {
if sharesEqual(ref, s) {
if s.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_USER && utils.UserEqual(user.Id, s.Grantee.GetUserId()) {
if share.IsGrantedToUser(s, user) {
rs := m.convert(ctx, s)
return rs, nil
} else if s.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_GROUP {
for _, g := range user.Groups {
if s.Grantee.GetGroupId().OpaqueId == g {
rs := m.convert(ctx, s)
return rs, nil
}
}
}
}
}
Expand Down
54 changes: 23 additions & 31 deletions pkg/share/manager/memory/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ func (m *manager) get(ctx context.Context, ref *collaboration.ShareReference) (s

// check if we are the owner
user := ctxpkg.ContextMustGetUser(ctx)
if utils.UserEqual(user.Id, s.Owner) || utils.UserEqual(user.Id, s.Creator) {
if share.IsCreatedByUser(s, user) {
return s, nil
}

Expand All @@ -171,7 +171,7 @@ func (m *manager) Unshare(ctx context.Context, ref *collaboration.ShareReference
user := ctxpkg.ContextMustGetUser(ctx)
for i, s := range m.shares {
if sharesEqual(ref, s) {
if utils.UserEqual(user.Id, s.Owner) || utils.UserEqual(user.Id, s.Creator) {
if share.IsCreatedByUser(s, user) {
m.shares[len(m.shares)-1], m.shares[i] = m.shares[i], m.shares[len(m.shares)-1]
m.shares = m.shares[:len(m.shares)-1]
return nil
Expand Down Expand Up @@ -201,7 +201,7 @@ func (m *manager) UpdateShare(ctx context.Context, ref *collaboration.ShareRefer
user := ctxpkg.ContextMustGetUser(ctx)
for i, s := range m.shares {
if sharesEqual(ref, s) {
if utils.UserEqual(user.Id, s.Owner) || utils.UserEqual(user.Id, s.Creator) {
if share.IsCreatedByUser(s, user) {
now := time.Now().UnixNano()
m.shares[i].Permissions = p
m.shares[i].Mtime = &typespb.Timestamp{
Expand All @@ -221,19 +221,17 @@ func (m *manager) ListShares(ctx context.Context, filters []*collaboration.Filte
defer m.lock.Unlock()
user := ctxpkg.ContextMustGetUser(ctx)
for _, s := range m.shares {
if utils.UserEqual(user.Id, s.Owner) || utils.UserEqual(user.Id, s.Creator) {
if share.IsCreatedByUser(s, user) {
// no filter we return earlier
if len(filters) == 0 {
ss = append(ss, s)
} else {
// check filters
// TODO(labkode): add the rest of filters.
for _, f := range filters {
if f.Type == collaboration.Filter_TYPE_RESOURCE_ID {
if utils.ResourceIDEqual(s.ResourceId, f.GetResourceId()) {
ss = append(ss, s)
}
}
continue
}
// check filters
// TODO(labkode): add the rest of filters.
for _, f := range filters {
if share.MatchesFilter(s, f) {
ss = append(ss, s)
}
}
}
Expand All @@ -248,20 +246,21 @@ func (m *manager) ListReceivedShares(ctx context.Context, filters []*collaborati
defer m.lock.Unlock()
user := ctxpkg.ContextMustGetUser(ctx)
for _, s := range m.shares {
if utils.UserEqual(user.Id, s.Owner) || utils.UserEqual(user.Id, s.Creator) {
// omit shares created by me
if share.IsCreatedByUser(s, user) || !share.IsGrantedToUser(s, user) {
// omit shares created by the user or shares the user can't access
continue
}
if s.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_USER && utils.UserEqual(user.Id, s.Grantee.GetUserId()) {

if len(filters) == 0 {
rs := m.convert(ctx, s)
rss = append(rss, rs)
} else if s.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_GROUP {
// check if all user groups match this share; TODO(labkode): filter shares created by us.
for _, g := range user.Groups {
if g == s.Grantee.GetGroupId().OpaqueId {
rs := m.convert(ctx, s)
rss = append(rss, rs)
}
continue
}

for _, f := range filters {
if share.MatchesFilter(s, f) {
rs := m.convert(ctx, s)
rss = append(rss, rs)
}
}
}
Expand Down Expand Up @@ -293,16 +292,9 @@ func (m *manager) getReceived(ctx context.Context, ref *collaboration.ShareRefer
user := ctxpkg.ContextMustGetUser(ctx)
for _, s := range m.shares {
if sharesEqual(ref, s) {
if s.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_USER && utils.UserEqual(user.Id, s.Grantee.GetUserId()) {
if share.IsGrantedToUser(s, user) {
rs := m.convert(ctx, s)
return rs, nil
} else if s.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_GROUP {
for _, g := range user.Groups {
if s.Grantee.GetGroupId().OpaqueId == g {
rs := m.convert(ctx, s)
return rs, nil
}
}
}
}
}
Expand Down
35 changes: 35 additions & 0 deletions pkg/share/share.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ package share
import (
"context"

userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/cs3org/reva/pkg/utils"
)

// Manager is the interface that manipulates shares.
Expand Down Expand Up @@ -82,3 +84,36 @@ func ResourceIDFilter(id *provider.ResourceId) *collaboration.Filter {
},
}
}

// IsCreatedByUser checks if the user is the owner or creator of the share.
func IsCreatedByUser(share *collaboration.Share, user *userv1beta1.User) bool {
return utils.UserEqual(user.Id, share.Owner) || utils.UserEqual(user.Id, share.Creator)
}

// IsGrantedToUser checks if the user is a grantee of the share. Either by a user grant or by a group grant.
func IsGrantedToUser(share *collaboration.Share, user *userv1beta1.User) bool {
if share.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_USER && utils.UserEqual(user.Id, share.Grantee.GetUserId()) {
return true
}
if share.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_GROUP {
// check if any of the user's group is the grantee of the share
for _, g := range user.Groups {
if g == share.Grantee.GetGroupId().OpaqueId {
return true
}
}
}
return false
}

// MatchesFilter tests if the share passes the filter.
func MatchesFilter(share *collaboration.Share, filter *collaboration.Filter) bool {
switch filter.Type {
case collaboration.Filter_TYPE_RESOURCE_ID:
return utils.ResourceIDEqual(share.ResourceId, filter.GetResourceId())
case collaboration.Filter_TYPE_GRANTEE_TYPE:
return share.Grantee.Type == filter.GetGranteeType()
default:
return false
}
}
Loading

0 comments on commit 89dcba4

Please sign in to comment.