selectorvalidator.go 3.52 KB
Newer Older
1 2 3 4 5
package selectorvalidator

import (
	"errors"

6
	"github.com/ipfs/go-graphsync"
7 8 9 10 11
	ipld "github.com/ipld/go-ipld-prime"
	ipldfree "github.com/ipld/go-ipld-prime/impl/free"
	"github.com/ipld/go-ipld-prime/traversal"
	"github.com/ipld/go-ipld-prime/traversal/selector"
	"github.com/ipld/go-ipld-prime/traversal/selector/builder"
12
	"github.com/libp2p/go-libp2p-core/peer"
13 14 15 16 17 18 19 20
)

var (
	// ErrInvalidLimit means this type of recursive selector limit is not supported by default
	// -- to prevent DDOS attacks
	ErrInvalidLimit = errors.New("unsupported recursive selector limit")
)

21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
// SelectorValidator returns an OnRequestReceivedHook that only validates
// requests if their selector only has no recursions that are greater than
// maxAcceptedDepth
func SelectorValidator(maxAcceptedDepth int) graphsync.OnRequestReceivedHook {
	return func(p peer.ID, request graphsync.RequestData, hookActions graphsync.RequestReceivedHookActions) {
		err := ValidateMaxRecursionDepth(request.Selector(), maxAcceptedDepth)
		if err == nil {
			hookActions.ValidateRequest()
		}
	}
}

// ValidateMaxRecursionDepth examines the given selector node and verifies
// recursive selectors are limited to the given fixed depth
func ValidateMaxRecursionDepth(node ipld.Node, maxAcceptedDepth int) error {
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
	ssb := builder.NewSelectorSpecBuilder(ipldfree.NodeBuilder())

	// this selector is a selector for traversing selectors...
	// it traverses the various selector types looking for recursion limit fields
	// and matches them
	s, err := ssb.ExploreRecursive(selector.RecursionLimitNone(), ssb.ExploreFields(func(efsb builder.ExploreFieldsSpecBuilder) {
		efsb.Insert(selector.SelectorKey_ExploreRecursive, ssb.ExploreFields(func(efsb builder.ExploreFieldsSpecBuilder) {
			efsb.Insert(selector.SelectorKey_Limit, ssb.Matcher())
			efsb.Insert(selector.SelectorKey_Sequence, ssb.ExploreRecursiveEdge())
		}))
		efsb.Insert(selector.SelectorKey_ExploreFields, ssb.ExploreFields(func(efsb builder.ExploreFieldsSpecBuilder) {
			efsb.Insert(selector.SelectorKey_Fields, ssb.ExploreAll(ssb.ExploreRecursiveEdge()))
		}))
		efsb.Insert(selector.SelectorKey_ExploreUnion, ssb.ExploreAll(ssb.ExploreRecursiveEdge()))
		efsb.Insert(selector.SelectorKey_ExploreAll, ssb.ExploreFields(func(efsb builder.ExploreFieldsSpecBuilder) {
			efsb.Insert(selector.SelectorKey_Next, ssb.ExploreRecursiveEdge())
		}))
		efsb.Insert(selector.SelectorKey_ExploreIndex, ssb.ExploreFields(func(efsb builder.ExploreFieldsSpecBuilder) {
			efsb.Insert(selector.SelectorKey_Next, ssb.ExploreRecursiveEdge())
		}))
		efsb.Insert(selector.SelectorKey_ExploreRange, ssb.ExploreFields(func(efsb builder.ExploreFieldsSpecBuilder) {
			efsb.Insert(selector.SelectorKey_Next, ssb.ExploreRecursiveEdge())
		}))
		efsb.Insert(selector.SelectorKey_ExploreConditional, ssb.ExploreFields(func(efsb builder.ExploreFieldsSpecBuilder) {
			efsb.Insert(selector.SelectorKey_Next, ssb.ExploreRecursiveEdge())
		}))
	})).Selector()

	if err != nil {
		return err
	}

68
	return traversal.WalkMatching(node, s, func(progress traversal.Progress, visited ipld.Node) error {
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
		if visited.ReprKind() != ipld.ReprKind_Map || visited.Length() != 1 {
			return ErrInvalidLimit
		}
		kn, v, _ := visited.MapIterator().Next()
		kstr, _ := kn.AsString()
		switch kstr {
		case selector.SelectorKey_LimitDepth:
			maxDepthValue, err := v.AsInt()
			if err != nil {
				return ErrInvalidLimit
			}
			if maxDepthValue > maxAcceptedDepth {
				return ErrInvalidLimit
			}
			return nil
		case selector.SelectorKey_LimitNone:
			return ErrInvalidLimit
		default:
			return ErrInvalidLimit
		}
	})
}