@cryptotaxi247 / kubo / commits / 56ae2fd0a

routing: record validation into record/

This commit moves the record validation/verification from dht/ into the new record/ packaage. Validator object -- which is merely a map of ValidatorFuncs -- with a VerifyRecord cc @whyrusleeping

Juan Batiz-Benet committed Jan 17, 2015 at 03:52 UTC 56ae2fd0a82f7bfc424f3987b44ea478292b87e6
6 files changed +89 -74
core/core.go
+1 -1
@@ -436,6 +436,6 @@ func constructPeerHost(ctx context.Context, cfg *config.Config, id peer.ID, ps p
436
437 func constructDHTRouting(ctx context.Context, host p2phost.Host, ds datastore.ThreadSafeDatastore) (*dht.IpfsDHT, error) {
438 dhtRouting := dht.NewDHT(ctx, host, ds)
439 - dhtRouting.Validators[IpnsValidatorTag] = namesys.ValidateIpnsRecord
439 + dhtRouting.Validator[IpnsValidatorTag] = namesys.ValidateIpnsRecord
440 return dhtRouting, nil
441 }
routing/dht/dht.go
+3 -4
@@ -54,8 +54,7 @@ type IpfsDHT struct {
54 birth time.Time // When this peer started up
55 diaglock sync.Mutex // lock to make diagnostics work better
56
57 - // record validator funcs
58 - Validators map[string]ValidatorFunc
57 + Validator record.Validator // record validator funcs
58
59 ctxgroup.ContextGroup
60 }
@@ -81,8 +80,8 @@ func NewDHT(ctx context.Context, h host.Host, dstore ds.ThreadSafeDatastore) *Ip
80 dht.routingTable = kb.NewRoutingTable(20, kb.ConvertPeerID(dht.self), time.Minute, dht.peerstore)
81 dht.birth = time.Now()
82
84 - dht.Validators = make(map[string]ValidatorFunc)
85 - dht.Validators["pk"] = ValidatePublicKeyRecord
83 + dht.Validator = make(record.Validator)
84 + dht.Validator["pk"] = record.ValidatePublicKeyRecord
85
86 if doPinging {
87 dht.Children().Add(1)
routing/dht/dht_test.go
+3 -3
@@ -38,7 +38,7 @@ func setupDHT(ctx context.Context, t *testing.T) *IpfsDHT {
38 dss := dssync.MutexWrap(ds.NewMapDatastore())
39 d := NewDHT(ctx, h, dss)
40
41 - d.Validators["v"] = func(u.Key, []byte) error {
41 + d.Validator["v"] = func(u.Key, []byte) error {
42 return nil
43 }
44 return d
@@ -142,8 +142,8 @@ func TestValueGetSet(t *testing.T) {
142 vf := func(u.Key, []byte) error {
143 return nil
144 }
145 - dhtA.Validators["v"] = vf
146 - dhtB.Validators["v"] = vf
145 + dhtA.Validator["v"] = vf
146 + dhtB.Validator["v"] = vf
147
148 connect(t, ctx, dhtA, dhtB)
149
routing/dht/records.go
+3 -66
@@ -1,33 +1,17 @@
1 package dht
2
3 import (
4 - "bytes"
5 - "errors"
4 "fmt"
7 - "strings"
5
6 "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
7
8 ci "github.com/jbenet/go-ipfs/p2p/crypto"
12 - "github.com/jbenet/go-ipfs/p2p/peer"
9 + peer "github.com/jbenet/go-ipfs/p2p/peer"
10 pb "github.com/jbenet/go-ipfs/routing/dht/pb"
14 - record "github.com/jbenet/go-ipfs/routing/record"
11 u "github.com/jbenet/go-ipfs/util"
12 ctxutil "github.com/jbenet/go-ipfs/util/ctx"
13 )
14
19 -// ValidatorFunc is a function that is called to validate a given
20 -// type of DHTRecord.
21 -type ValidatorFunc func(u.Key, []byte) error
22 -
23 -// ErrBadRecord is returned any time a dht record is found to be
24 -// incorrectly formatted or signed.
25 -var ErrBadRecord = errors.New("bad dht record")
26 -
27 -// ErrInvalidRecordType is returned if a DHTRecord keys prefix
28 -// is not found in the Validator map of the DHT.
29 -var ErrInvalidRecordType = errors.New("invalid record keytype")
30 -
15 // KeyForPublicKey returns the key used to retrieve public keys
16 // from the dht.
17 func KeyForPublicKey(id peer.ID) u.Key {
@@ -123,7 +107,7 @@ func (dht *IpfsDHT) verifyRecordLocally(r *pb.Record) error {
107 return fmt.Errorf("do not have public key for %s", p)
108 }
109
126 - return dht.verifyRecord(r, pk)
110 + return dht.Validator.VerifyRecord(r, pk)
111 }
112
113 // verifyRecordOnline verifies a record, searching the DHT for the public key
@@ -140,52 +124,5 @@ func (dht *IpfsDHT) verifyRecordOnline(ctx context.Context, r *pb.Record) error
124 return err
125 }
126
143 - return dht.verifyRecord(r, pk)
144 -}
145 -
146 -// TODO: make this an independent exported function.
147 -// it might be useful for users to have access to.
148 -func (dht *IpfsDHT) verifyRecord(r *pb.Record, pk ci.PubKey) error {
149 - // First, validate the signature
150 - blob := record.RecordBlobForSig(r)
151 - ok, err := pk.Verify(blob, r.GetSignature())
152 - if err != nil {
153 - log.Error("Signature verify failed.")
154 - return err
155 - }
156 - if !ok {
157 - log.Error("dht found a forged record! (ignored)")
158 - return ErrBadRecord
159 - }
160 -
161 - // Now, check validity func
162 - parts := strings.Split(r.GetKey(), "/")
163 - if len(parts) < 3 {
164 - log.Infof("Record key does not have validator: %s", u.Key(r.GetKey()))
165 - return nil
166 - }
167 -
168 - fnc, ok := dht.Validators[parts[1]]
169 - if !ok {
170 - log.Errorf("Unrecognized key prefix: %s", parts[1])
171 - return ErrInvalidRecordType
172 - }
173 -
174 - return fnc(u.Key(r.GetKey()), r.GetValue())
175 -}
176 -
177 -// ValidatePublicKeyRecord implements ValidatorFunc and
178 -// verifies that the passed in record value is the PublicKey
179 -// that matches the passed in key.
180 -func ValidatePublicKeyRecord(k u.Key, val []byte) error {
181 - keyparts := bytes.Split([]byte(k), []byte("/"))
182 - if len(keyparts) < 3 {
183 - return errors.New("invalid key")
184 - }
185 -
186 - pkh := u.Hash(val)
187 - if !bytes.Equal(keyparts[2], pkh) {
188 - return errors.New("public key does not match storage key")
189 - }
190 - return nil
127 + return dht.Validator.VerifyRecord(r, pk)
128 }
routing/record/record.go
+4
@@ -2,13 +2,17 @@ package record
2
3 import (
4 "bytes"
5 +
6 "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto"
7
8 ci "github.com/jbenet/go-ipfs/p2p/crypto"
9 pb "github.com/jbenet/go-ipfs/routing/dht/pb"
10 + eventlog "github.com/jbenet/go-ipfs/thirdparty/eventlog"
11 u "github.com/jbenet/go-ipfs/util"
12 )
13
14 +var log = eventlog.Logger("routing/record")
15 +
16 // MakePutRecord creates and signs a dht record for the given key/value pair
17 func MakePutRecord(sk ci.PrivKey, key u.Key, value []byte) (*pb.Record, error) {
18 record := new(pb.Record)
routing/record/validation.go new
+75
@@ -0,0 +1,75 @@
1 +package record
2 +
3 +import (
4 + "bytes"
5 + "errors"
6 + "strings"
7 +
8 + ci "github.com/jbenet/go-ipfs/p2p/crypto"
9 + pb "github.com/jbenet/go-ipfs/routing/dht/pb"
10 + u "github.com/jbenet/go-ipfs/util"
11 +)
12 +
13 +// ValidatorFunc is a function that is called to validate a given
14 +// type of DHTRecord.
15 +type ValidatorFunc func(u.Key, []byte) error
16 +
17 +// ErrBadRecord is returned any time a dht record is found to be
18 +// incorrectly formatted or signed.
19 +var ErrBadRecord = errors.New("bad dht record")
20 +
21 +// ErrInvalidRecordType is returned if a DHTRecord keys prefix
22 +// is not found in the Validator map of the DHT.
23 +var ErrInvalidRecordType = errors.New("invalid record keytype")
24 +
25 +// Validator is an object that helps ensure routing records are valid.
26 +// It is a collection of validator functions, each of which implements
27 +// its own notion of validity.
28 +type Validator map[string]ValidatorFunc
29 +
30 +// VerifyRecord checks a record and ensures it is still valid.
31 +// It runs needed validators
32 +func (v Validator) VerifyRecord(r *pb.Record, pk ci.PubKey) error {
33 + // First, validate the signature
34 + blob := RecordBlobForSig(r)
35 + ok, err := pk.Verify(blob, r.GetSignature())
36 + if err != nil {
37 + log.Error("Signature verify failed.")
38 + return err
39 + }
40 + if !ok {
41 + log.Error("dht found a forged record! (ignored)")
42 + return ErrBadRecord
43 + }
44 +
45 + // Now, check validity func
46 + parts := strings.Split(r.GetKey(), "/")
47 + if len(parts) < 3 {
48 + log.Infof("Record key does not have validator: %s", u.Key(r.GetKey()))
49 + return nil
50 + }
51 +
52 + fnc, ok := v[parts[1]]
53 + if !ok {
54 + log.Errorf("Unrecognized key prefix: %s", parts[1])
55 + return ErrInvalidRecordType
56 + }
57 +
58 + return fnc(u.Key(r.GetKey()), r.GetValue())
59 +}
60 +
61 +// ValidatePublicKeyRecord implements ValidatorFunc and
62 +// verifies that the passed in record value is the PublicKey
63 +// that matches the passed in key.
64 +func ValidatePublicKeyRecord(k u.Key, val []byte) error {
65 + keyparts := bytes.Split([]byte(k), []byte("/"))
66 + if len(keyparts) < 3 {
67 + return errors.New("invalid key")
68 + }
69 +
70 + pkh := u.Hash(val)
71 + if !bytes.Equal(keyparts[2], pkh) {
72 + return errors.New("public key does not match storage key")
73 + }
74 + return nil
75 +}