36533f7c3f
Fixes for new geth version
127 lines
2.8 KiB
Go
127 lines
2.8 KiB
Go
package ipns
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
|
|
pb "github.com/ipfs/go-ipns/pb"
|
|
|
|
proto "github.com/gogo/protobuf/proto"
|
|
logging "github.com/ipfs/go-log"
|
|
ic "github.com/libp2p/go-libp2p-crypto"
|
|
peer "github.com/libp2p/go-libp2p-peer"
|
|
pstore "github.com/libp2p/go-libp2p-peerstore"
|
|
record "github.com/libp2p/go-libp2p-record"
|
|
)
|
|
|
|
var log = logging.Logger("ipns")
|
|
|
|
var _ record.Validator = Validator{}
|
|
|
|
// RecordKey returns the libp2p record key for a given peer ID.
|
|
func RecordKey(pid peer.ID) string {
|
|
return "/ipns/" + string(pid)
|
|
}
|
|
|
|
// Validator is an IPNS record validator that satisfies the libp2p record
|
|
// validator interface.
|
|
type Validator struct {
|
|
// KeyBook, if non-nil, will be used to lookup keys for validating IPNS
|
|
// records.
|
|
KeyBook pstore.KeyBook
|
|
}
|
|
|
|
// Validate validates an IPNS record.
|
|
func (v Validator) Validate(key string, value []byte) error {
|
|
ns, pidString, err := record.SplitKey(key)
|
|
if err != nil || ns != "ipns" {
|
|
return ErrInvalidPath
|
|
}
|
|
|
|
// Parse the value into an IpnsEntry
|
|
entry := new(pb.IpnsEntry)
|
|
err = proto.Unmarshal(value, entry)
|
|
if err != nil {
|
|
return ErrBadRecord
|
|
}
|
|
|
|
// Get the public key defined by the ipns path
|
|
pid, err := peer.IDFromString(pidString)
|
|
if err != nil {
|
|
log.Debugf("failed to parse ipns record key %s into peer ID", pidString)
|
|
return ErrKeyFormat
|
|
}
|
|
|
|
pubk, err := v.getPublicKey(pid, entry)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return Validate(pubk, entry)
|
|
}
|
|
|
|
func (v Validator) getPublicKey(pid peer.ID, entry *pb.IpnsEntry) (ic.PubKey, error) {
|
|
switch pk, err := ExtractPublicKey(pid, entry); err {
|
|
case peer.ErrNoPublicKey:
|
|
case nil:
|
|
return pk, nil
|
|
default:
|
|
return nil, err
|
|
}
|
|
|
|
if v.KeyBook == nil {
|
|
log.Debugf("public key with hash %s not found in IPNS record and no peer store provided", pid)
|
|
return nil, ErrPublicKeyNotFound
|
|
}
|
|
|
|
pubk := v.KeyBook.PubKey(pid)
|
|
if pubk == nil {
|
|
log.Debugf("public key with hash %s not found in peer store", pid)
|
|
return nil, ErrPublicKeyNotFound
|
|
}
|
|
return pubk, nil
|
|
}
|
|
|
|
// Select selects the best record by checking which has the highest sequence
|
|
// number and latest EOL.
|
|
//
|
|
// This function returns an error if any of the records fail to parse. Validate
|
|
// your records first!
|
|
func (v Validator) Select(k string, vals [][]byte) (int, error) {
|
|
var recs []*pb.IpnsEntry
|
|
for _, v := range vals {
|
|
e := new(pb.IpnsEntry)
|
|
if err := proto.Unmarshal(v, e); err != nil {
|
|
return -1, err
|
|
}
|
|
recs = append(recs, e)
|
|
}
|
|
|
|
return selectRecord(recs, vals)
|
|
}
|
|
|
|
func selectRecord(recs []*pb.IpnsEntry, vals [][]byte) (int, error) {
|
|
switch len(recs) {
|
|
case 0:
|
|
return -1, errors.New("no usable records in given set")
|
|
case 1:
|
|
return 0, nil
|
|
}
|
|
|
|
var i int
|
|
for j := 1; j < len(recs); j++ {
|
|
cmp, err := Compare(recs[i], recs[j])
|
|
if err != nil {
|
|
return -1, err
|
|
}
|
|
if cmp == 0 {
|
|
cmp = bytes.Compare(vals[i], vals[j])
|
|
}
|
|
if cmp < 0 {
|
|
i = j
|
|
}
|
|
}
|
|
|
|
return i, nil
|
|
}
|