records.go 1.64 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
package dht

import (
	"bytes"
	"errors"
	"strings"

	"code.google.com/p/goprotobuf/proto"
	"github.com/jbenet/go-ipfs/peer"
	pb "github.com/jbenet/go-ipfs/routing/dht/pb"
	u "github.com/jbenet/go-ipfs/util"
)

type ValidatorFunc func(u.Key, []byte) error

var ErrBadRecord = errors.New("bad dht record")
var ErrInvalidRecordType = errors.New("invalid record keytype")

// creates and signs a dht record for the given key/value pair
func (dht *IpfsDHT) makePutRecord(key u.Key, value []byte) (*pb.Record, error) {
	record := new(pb.Record)

Jeromy's avatar
Jeromy committed
23
	record.Key = proto.String(string(key))
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
	record.Value = value
	record.Author = proto.String(string(dht.self.ID()))
	blob := bytes.Join([][]byte{[]byte(key), value, []byte(dht.self.ID())}, []byte{})
	sig, err := dht.self.PrivKey().Sign(blob)
	if err != nil {
		return nil, err
	}
	record.Signature = sig
	return record, nil
}

func (dht *IpfsDHT) verifyRecord(r *pb.Record) error {
	// First, validate the signature
	p, err := dht.peerstore.Get(peer.ID(r.GetAuthor()))
	if err != nil {
		return err
	}
Jeromy's avatar
Jeromy committed
41
	k := u.Key(r.GetKey())
42

Jeromy's avatar
Jeromy committed
43
	blob := bytes.Join([][]byte{[]byte(k),
44
		r.GetValue(),
Jeromy's avatar
Jeromy committed
45
		[]byte(r.GetAuthor())}, []byte{})
46 47 48

	ok, err := p.PubKey().Verify(blob, r.GetSignature())
	if err != nil {
Jeromy's avatar
Jeromy committed
49
		log.Error("Signature verify failed.")
50 51 52 53 54 55 56 57 58
		return err
	}

	if !ok {
		return ErrBadRecord
	}

	// Now, check validity func
	parts := strings.Split(r.GetKey(), "/")
Jeromy's avatar
Jeromy committed
59 60
	if len(parts) < 3 {
		log.Errorf("Record had bad key: %s", u.Key(r.GetKey()))
61 62 63
		return ErrBadRecord
	}

Jeromy's avatar
Jeromy committed
64
	fnc, ok := dht.Validators[parts[1]]
65
	if !ok {
Jeromy's avatar
Jeromy committed
66
		log.Errorf("Unrecognized key prefix: %s", parts[1])
67 68 69 70 71
		return ErrInvalidRecordType
	}

	return fnc(u.Key(r.GetKey()), r.GetValue())
}