-
Notifications
You must be signed in to change notification settings - Fork 38
/
Copy pathselectorvalidator.go
92 lines (82 loc) · 3.57 KB
/
selectorvalidator.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package selectorvalidator
import (
"errors"
ipld "github.com/ipld/go-ipld-prime"
basicnode "github.com/ipld/go-ipld-prime/node/basic"
"github.com/ipld/go-ipld-prime/traversal"
"github.com/ipld/go-ipld-prime/traversal/selector"
"github.com/ipld/go-ipld-prime/traversal/selector/builder"
"github.com/libp2p/go-libp2p-core/peer"
"github.com/ipfs/go-graphsync"
)
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")
)
var maxDepthSelector selector.Selector
func init() {
ssb := builder.NewSelectorSpecBuilder(basicnode.Prototype.Map)
// this selector is a selector for traversing selectors...
// it traverses the various selector types looking for recursion limit fields
// and matches them
maxDepthSelector, _ = 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()
}
// 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.OnIncomingRequestHook {
return func(p peer.ID, request graphsync.RequestData, hookActions graphsync.IncomingRequestHookActions) {
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 {
return traversal.WalkMatching(node, maxDepthSelector, func(progress traversal.Progress, visited ipld.Node) error {
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
}
})
}