From 7fb63d7e43d96809c679617bebed4dbb4fde3fc5 Mon Sep 17 00:00:00 2001 From: Jeromy Date: Wed, 25 Feb 2015 14:56:26 -0800 Subject: [PATCH] move signing options into a validation checker struct --- core/commands/dht.go | 2 +- core/core.go | 2 +- namesys/publisher.go | 10 ++++++-- routing/dht/dht.go | 2 +- routing/dht/dht_test.go | 16 +++++++++---- routing/dht/routing.go | 7 +++++- routing/mock/centralized_client.go | 2 +- routing/offline/offline.go | 4 ++-- routing/record/validation.go | 33 ++++++++++++++++++++++++--- routing/routing.go | 2 +- routing/supernode/client.go | 2 +- routing/supernode/server.go | 2 +- test/integration/grandcentral_test.go | 2 +- 13 files changed, 65 insertions(+), 21 deletions(-) diff --git a/core/commands/dht.go b/core/commands/dht.go index cef5a63fe..5b2b3bf44 100644 --- a/core/commands/dht.go +++ b/core/commands/dht.go @@ -508,7 +508,7 @@ PutValue will store the given key value pair in the dht. go func() { defer close(events) - err := dht.PutValue(ctx, key, []byte(data), true) + err := dht.PutValue(ctx, key, []byte(data)) if err != nil { notif.PublishQueryEvent(ctx, ¬if.QueryEvent{ Type: notif.QueryError, diff --git a/core/core.go b/core/core.go index c8a201e43..45767728b 100644 --- a/core/core.go +++ b/core/core.go @@ -488,7 +488,7 @@ func startListening(ctx context.Context, host p2phost.Host, cfg *config.Config) func constructDHTRouting(ctx context.Context, host p2phost.Host, dstore ds.ThreadSafeDatastore) (routing.IpfsRouting, error) { dhtRouting := dht.NewDHT(ctx, host, dstore) - dhtRouting.Validator[IpnsValidatorTag] = namesys.ValidateIpnsRecord + dhtRouting.Validator[IpnsValidatorTag] = namesys.IpnsRecordValidator return dhtRouting, nil } diff --git a/namesys/publisher.go b/namesys/publisher.go index 126069d96..cb7456cb9 100644 --- a/namesys/publisher.go +++ b/namesys/publisher.go @@ -13,6 +13,7 @@ import ( pb "github.com/jbenet/go-ipfs/namesys/internal/pb" ci "github.com/jbenet/go-ipfs/p2p/crypto" routing "github.com/jbenet/go-ipfs/routing" + record "github.com/jbenet/go-ipfs/routing/record" u "github.com/jbenet/go-ipfs/util" ) @@ -62,7 +63,7 @@ func (p *ipnsPublisher) Publish(ctx context.Context, k ci.PrivKey, value u.Key) log.Debugf("Storing pubkey at: %s", namekey) // Store associated public key timectx, _ := context.WithDeadline(ctx, time.Now().Add(time.Second*10)) - err = p.routing.PutValue(timectx, namekey, pkbytes, false) + err = p.routing.PutValue(timectx, namekey, pkbytes) if err != nil { return err } @@ -72,7 +73,7 @@ func (p *ipnsPublisher) Publish(ctx context.Context, k ci.PrivKey, value u.Key) log.Debugf("Storing ipns entry at: %s", ipnskey) // Store ipns entry at "/ipns/"+b58(h(pubkey)) timectx, _ = context.WithDeadline(ctx, time.Now().Add(time.Second*10)) - err = p.routing.PutValue(timectx, ipnskey, data, true) + err = p.routing.PutValue(timectx, ipnskey, data) if err != nil { return err } @@ -105,6 +106,11 @@ func ipnsEntryDataForSig(e *pb.IpnsEntry) []byte { []byte{}) } +var IpnsRecordValidator = &record.ValidChecker{ + Func: ValidateIpnsRecord, + Sign: true, +} + // ValidateIpnsRecord implements ValidatorFunc and verifies that the // given 'val' is an IpnsEntry and that that entry is valid. func ValidateIpnsRecord(k u.Key, val []byte) error { diff --git a/routing/dht/dht.go b/routing/dht/dht.go index 6e5e6456e..324b80fb6 100644 --- a/routing/dht/dht.go +++ b/routing/dht/dht.go @@ -84,7 +84,7 @@ func NewDHT(ctx context.Context, h host.Host, dstore ds.ThreadSafeDatastore) *Ip dht.birth = time.Now() dht.Validator = make(record.Validator) - dht.Validator["pk"] = record.ValidatePublicKeyRecord + dht.Validator["pk"] = record.PublicKeyValidator if doPinging { dht.Children().Add(1) diff --git a/routing/dht/dht_test.go b/routing/dht/dht_test.go index 862693418..4b48ccc65 100644 --- a/routing/dht/dht_test.go +++ b/routing/dht/dht_test.go @@ -41,8 +41,11 @@ func setupDHT(ctx context.Context, t *testing.T) *IpfsDHT { dss := dssync.MutexWrap(ds.NewMapDatastore()) d := NewDHT(ctx, h, dss) - d.Validator["v"] = func(u.Key, []byte) error { - return nil + d.Validator["v"] = &record.ValidChecker{ + Func: func(u.Key, []byte) error { + return nil + }, + Sign: false, } return d } @@ -139,8 +142,11 @@ func TestValueGetSet(t *testing.T) { defer dhtA.host.Close() defer dhtB.host.Close() - vf := func(u.Key, []byte) error { - return nil + vf := &record.ValidChecker{ + Func: func(u.Key, []byte) error { + return nil + }, + Sign: false, } dhtA.Validator["v"] = vf dhtB.Validator["v"] = vf @@ -148,7 +154,7 @@ func TestValueGetSet(t *testing.T) { connect(t, ctx, dhtA, dhtB) ctxT, _ := context.WithTimeout(ctx, time.Second) - dhtA.PutValue(ctxT, "/v/hello", []byte("world"), false) + dhtA.PutValue(ctxT, "/v/hello", []byte("world")) ctxT, _ = context.WithTimeout(ctx, time.Second*2) val, err := dhtA.GetValue(ctxT, "/v/hello") diff --git a/routing/dht/routing.go b/routing/dht/routing.go index 3f548e21d..28ee8f03a 100644 --- a/routing/dht/routing.go +++ b/routing/dht/routing.go @@ -29,13 +29,18 @@ var asyncQueryBuffer = 10 // PutValue adds value corresponding to given Key. // This is the top level "Store" operation of the DHT -func (dht *IpfsDHT) PutValue(ctx context.Context, key u.Key, value []byte, sign bool) error { +func (dht *IpfsDHT) PutValue(ctx context.Context, key u.Key, value []byte) error { log.Debugf("PutValue %s", key) sk, err := dht.getOwnPrivateKey() if err != nil { return err } + sign, err := dht.Validator.IsSigned(key) + if err != nil { + return err + } + rec, err := record.MakePutRecord(sk, key, value, sign) if err != nil { log.Debug("Creation of record failed!") diff --git a/routing/mock/centralized_client.go b/routing/mock/centralized_client.go index cbcff3ab0..6a550bfaa 100644 --- a/routing/mock/centralized_client.go +++ b/routing/mock/centralized_client.go @@ -22,7 +22,7 @@ type client struct { } // FIXME(brian): is this method meant to simulate putting a value into the network? -func (c *client) PutValue(ctx context.Context, key u.Key, val []byte, sign bool) error { +func (c *client) PutValue(ctx context.Context, key u.Key, val []byte) error { log.Debugf("PutValue: %s", key) return c.datastore.Put(key.DsKey(), val) } diff --git a/routing/offline/offline.go b/routing/offline/offline.go index 33c57d336..15049f16d 100644 --- a/routing/offline/offline.go +++ b/routing/offline/offline.go @@ -35,8 +35,8 @@ type offlineRouting struct { sk ci.PrivKey } -func (c *offlineRouting) PutValue(ctx context.Context, key u.Key, val []byte, sign bool) error { - rec, err := record.MakePutRecord(c.sk, key, val, sign) +func (c *offlineRouting) PutValue(ctx context.Context, key u.Key, val []byte) error { + rec, err := record.MakePutRecord(c.sk, key, val, false) if err != nil { return err } diff --git a/routing/record/validation.go b/routing/record/validation.go index 4c6db584f..380bdea4c 100644 --- a/routing/record/validation.go +++ b/routing/record/validation.go @@ -25,7 +25,12 @@ var ErrInvalidRecordType = errors.New("invalid record keytype") // Validator is an object that helps ensure routing records are valid. // It is a collection of validator functions, each of which implements // its own notion of validity. -type Validator map[string]ValidatorFunc +type Validator map[string]*ValidChecker + +type ValidChecker struct { + Func ValidatorFunc + Sign bool +} // VerifyRecord checks a record and ensures it is still valid. // It runs needed validators @@ -37,13 +42,30 @@ func (v Validator) VerifyRecord(r *pb.Record) error { return nil } - fnc, ok := v[parts[1]] + val, ok := v[parts[1]] if !ok { log.Infof("Unrecognized key prefix: %s", parts[1]) return ErrInvalidRecordType } - return fnc(u.Key(r.GetKey()), r.GetValue()) + return val.Func(u.Key(r.GetKey()), r.GetValue()) +} + +func (v Validator) IsSigned(k u.Key) (bool, error) { + // Now, check validity func + parts := strings.Split(string(k), "/") + if len(parts) < 3 { + log.Infof("Record key does not have validator: %s", k) + return false, nil + } + + val, ok := v[parts[1]] + if !ok { + log.Infof("Unrecognized key prefix: %s", parts[1]) + return false, ErrInvalidRecordType + } + + return val.Sign, nil } // ValidatePublicKeyRecord implements ValidatorFunc and @@ -62,6 +84,11 @@ func ValidatePublicKeyRecord(k u.Key, val []byte) error { return nil } +var PublicKeyValidator = &ValidChecker{ + Func: ValidatePublicKeyRecord, + Sign: false, +} + func CheckRecordSig(r *pb.Record, pk ci.PubKey) error { blob := RecordBlobForSig(r) good, err := pk.Verify(blob, r.Signature) diff --git a/routing/routing.go b/routing/routing.go index d0acbb077..be400a520 100644 --- a/routing/routing.go +++ b/routing/routing.go @@ -21,7 +21,7 @@ type IpfsRouting interface { // Basic Put/Get // PutValue adds value corresponding to given Key. - PutValue(context.Context, u.Key, []byte, bool) error + PutValue(context.Context, u.Key, []byte) error // GetValue searches for the value corresponding to given Key. GetValue(context.Context, u.Key) ([]byte, error) diff --git a/routing/supernode/client.go b/routing/supernode/client.go index fbba8dfee..09fa90ef6 100644 --- a/routing/supernode/client.go +++ b/routing/supernode/client.go @@ -59,7 +59,7 @@ func (c *Client) FindProvidersAsync(ctx context.Context, k u.Key, max int) <-cha return ch } -func (c *Client) PutValue(ctx context.Context, k u.Key, v []byte, sign bool) error { +func (c *Client) PutValue(ctx context.Context, k u.Key, v []byte) error { defer log.EventBegin(ctx, "putValue", &k).Done() r, err := makeRecord(c.peerstore, c.local, k, v) if err != nil { diff --git a/routing/supernode/server.go b/routing/supernode/server.go index 315730858..1132039a1 100644 --- a/routing/supernode/server.go +++ b/routing/supernode/server.go @@ -204,7 +204,7 @@ func providerKey(k util.Key) datastore.Key { func verify(ps peer.Peerstore, r *dhtpb.Record) error { v := make(record.Validator) - v["pk"] = record.ValidatePublicKeyRecord + v["pk"] = record.PublicKeyValidator p := peer.ID(r.GetAuthor()) pk := ps.PubKey(p) if pk == nil { diff --git a/test/integration/grandcentral_test.go b/test/integration/grandcentral_test.go index 5d4186c61..4d7655b26 100644 --- a/test/integration/grandcentral_test.go +++ b/test/integration/grandcentral_test.go @@ -168,7 +168,7 @@ func RunSupernodePutRecordGetRecord(conf testutil.LatencyConfig) error { k := util.Key("key") note := []byte("a note from putter") - if err := putter.Routing.PutValue(ctx, k, note, false); err != nil { + if err := putter.Routing.PutValue(ctx, k, note); err != nil { return fmt.Errorf("failed to put value: %s", err) }