mirror of
https://github.com/ipfs/kubo.git
synced 2025-06-28 08:47:42 +08:00
namesys: differentiate between validation errors
License: MIT Signed-off-by: Dirk McCormick <dirkmdev@gmail.com>
This commit is contained in:
@ -2,6 +2,7 @@ package namesys
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -21,7 +22,62 @@ import (
|
||||
ci "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto"
|
||||
)
|
||||
|
||||
func TestValidation(t *testing.T) {
|
||||
func testValidatorCase(t *testing.T, priv ci.PrivKey, kbook pstore.KeyBook, ns string, key string, val []byte, eol time.Time, exp error) {
|
||||
validChecker := NewIpnsRecordValidator(kbook)
|
||||
|
||||
p := path.Path("/ipfs/QmfM2r8seH2GiRaC4esTjeraXEachRt8ZsSeGaWTPLyMoG")
|
||||
entry, err := CreateRoutingEntryData(priv, p, 1, eol)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
data := val
|
||||
if data == nil {
|
||||
data, err = proto.Marshal(entry)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
rec := &record.ValidationRecord{
|
||||
Namespace: ns,
|
||||
Key: key,
|
||||
Value: data,
|
||||
}
|
||||
|
||||
err = validChecker.Func(rec)
|
||||
if err != exp {
|
||||
params := fmt.Sprintf("namespace: %s\nkey: %s\neol: %s\n", ns, key, eol)
|
||||
if exp == nil {
|
||||
t.Fatalf("Unexpected error %s for params %s", err, params)
|
||||
} else if err == nil {
|
||||
t.Fatalf("Expected error %s but there was no error for params %s", exp, params)
|
||||
} else {
|
||||
t.Fatalf("Expected error %s but got %s for params %s", exp, err, params)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidator(t *testing.T) {
|
||||
ts := time.Now()
|
||||
|
||||
priv, id, _, _ := genKeys(t)
|
||||
priv2, id2, _, _ := genKeys(t)
|
||||
kbook := pstore.NewPeerstore()
|
||||
kbook.AddPubKey(id, priv.GetPublic())
|
||||
emptyKbook := pstore.NewPeerstore()
|
||||
|
||||
testValidatorCase(t, priv, kbook, "ipns", string(id), nil, ts.Add(time.Hour), nil)
|
||||
testValidatorCase(t, priv, kbook, "ipns", string(id), nil, ts.Add(time.Hour*-1), ErrExpiredRecord)
|
||||
testValidatorCase(t, priv, kbook, "ipns", string(id), []byte("bad data"), ts.Add(time.Hour), ErrBadRecord)
|
||||
testValidatorCase(t, priv, kbook, "ipns", "bad key", nil, ts.Add(time.Hour), ErrKeyFormat)
|
||||
testValidatorCase(t, priv, emptyKbook, "ipns", string(id), nil, ts.Add(time.Hour), ErrPublicKeyNotFound)
|
||||
testValidatorCase(t, priv2, kbook, "ipns", string(id2), nil, ts.Add(time.Hour), ErrPublicKeyNotFound)
|
||||
testValidatorCase(t, priv2, kbook, "ipns", string(id), nil, ts.Add(time.Hour), ErrSignature)
|
||||
testValidatorCase(t, priv, kbook, "", string(id), nil, ts.Add(time.Hour), ErrInvalidPath)
|
||||
testValidatorCase(t, priv, kbook, "wrong", string(id), nil, ts.Add(time.Hour), ErrInvalidPath)
|
||||
}
|
||||
|
||||
func TestResolverValidation(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
rid := testutil.RandIdentityOrFatal(t)
|
||||
dstore := dssync.MutexWrap(ds.NewMapDatastore())
|
||||
|
@ -147,7 +147,9 @@ func (r *routingResolver) resolveOnce(ctx context.Context, name string) (path.Pa
|
||||
return "", err
|
||||
}
|
||||
|
||||
// use the routing system to get the name.
|
||||
// Use the routing system to get the name.
|
||||
// Note that the DHT will call the ipns validator when retrieving
|
||||
// the value, which in turn verifies the ipns record signature
|
||||
_, ipnsKey := IpnsKeysForID(pid)
|
||||
val, err := r.routing.GetValue(ctx, ipnsKey)
|
||||
if err != nil {
|
||||
|
@ -42,11 +42,13 @@ func selectRecord(recs []*pb.IpnsEntry, vals [][]byte) (int, error) {
|
||||
} else if r.GetSequence() == bestSeq {
|
||||
rt, err := u.ParseRFC3339(string(r.GetValidity()))
|
||||
if err != nil {
|
||||
log.Errorf("failed to parse ipns record EOL %s", r.GetValidity())
|
||||
continue
|
||||
}
|
||||
|
||||
bestt, err := u.ParseRFC3339(string(recs[besti].GetValidity()))
|
||||
if err != nil {
|
||||
log.Errorf("failed to parse ipns record EOL %s", recs[besti].GetValidity())
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,18 @@ var ErrInvalidPath = errors.New("record path invalid")
|
||||
// signature verification
|
||||
var ErrSignature = errors.New("record signature verification failed")
|
||||
|
||||
// ErrBadRecord should be returned when an ipns record cannot be unmarshalled
|
||||
var ErrBadRecord = errors.New("record could not be unmarshalled")
|
||||
|
||||
// ErrKeyFormat should be returned when an ipns record key is
|
||||
// incorrectly formatted (not a peer ID)
|
||||
var ErrKeyFormat = errors.New("record key could not be parsed into peer ID")
|
||||
|
||||
// ErrPublicKeyNotFound should be returned when the public key
|
||||
// corresponding to the ipns record path cannot be retrieved
|
||||
// from the peer store
|
||||
var ErrPublicKeyNotFound = errors.New("public key not found in peer store")
|
||||
|
||||
// NewIpnsRecordValidator returns a ValidChecker for IPNS records
|
||||
// The validator function will get a public key from the KeyBook
|
||||
// to verify the record's signature
|
||||
@ -44,19 +56,19 @@ func NewIpnsRecordValidator(kbook pstore.KeyBook) *record.ValidChecker {
|
||||
entry := new(pb.IpnsEntry)
|
||||
err := proto.Unmarshal(r.Value, entry)
|
||||
if err != nil {
|
||||
return err
|
||||
return ErrBadRecord
|
||||
}
|
||||
|
||||
// Get the public key defined by the ipns path
|
||||
pid, err := peer.IDFromString(r.Key)
|
||||
if err != nil {
|
||||
log.Debugf("failed to parse ipns record key %s into public key hash", r.Key)
|
||||
return ErrSignature
|
||||
log.Debugf("failed to parse ipns record key %s into peer ID", r.Key)
|
||||
return ErrKeyFormat
|
||||
}
|
||||
pubk := kbook.PubKey(pid)
|
||||
if pubk == nil {
|
||||
log.Debugf("public key with hash %s not found in peer store", pid)
|
||||
return ErrSignature
|
||||
return ErrPublicKeyNotFound
|
||||
}
|
||||
|
||||
// Check the ipns record signature with the public key
|
||||
|
Reference in New Issue
Block a user