mirror of
https://github.com/ipfs/kubo.git
synced 2025-06-29 01:12:24 +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 (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -21,7 +22,62 @@ import (
|
|||||||
ci "gx/ipfs/QmaPbCnUMBohSGo3KnxEa2bHqyJVVeEEcwtqJAYxerieBo/go-libp2p-crypto"
|
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()
|
ctx := context.Background()
|
||||||
rid := testutil.RandIdentityOrFatal(t)
|
rid := testutil.RandIdentityOrFatal(t)
|
||||||
dstore := dssync.MutexWrap(ds.NewMapDatastore())
|
dstore := dssync.MutexWrap(ds.NewMapDatastore())
|
||||||
|
@ -147,7 +147,9 @@ func (r *routingResolver) resolveOnce(ctx context.Context, name string) (path.Pa
|
|||||||
return "", err
|
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)
|
_, ipnsKey := IpnsKeysForID(pid)
|
||||||
val, err := r.routing.GetValue(ctx, ipnsKey)
|
val, err := r.routing.GetValue(ctx, ipnsKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -42,11 +42,13 @@ func selectRecord(recs []*pb.IpnsEntry, vals [][]byte) (int, error) {
|
|||||||
} else if r.GetSequence() == bestSeq {
|
} else if r.GetSequence() == bestSeq {
|
||||||
rt, err := u.ParseRFC3339(string(r.GetValidity()))
|
rt, err := u.ParseRFC3339(string(r.GetValidity()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Errorf("failed to parse ipns record EOL %s", r.GetValidity())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
bestt, err := u.ParseRFC3339(string(recs[besti].GetValidity()))
|
bestt, err := u.ParseRFC3339(string(recs[besti].GetValidity()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Errorf("failed to parse ipns record EOL %s", recs[besti].GetValidity())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,18 @@ var ErrInvalidPath = errors.New("record path invalid")
|
|||||||
// signature verification
|
// signature verification
|
||||||
var ErrSignature = errors.New("record signature verification failed")
|
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
|
// NewIpnsRecordValidator returns a ValidChecker for IPNS records
|
||||||
// The validator function will get a public key from the KeyBook
|
// The validator function will get a public key from the KeyBook
|
||||||
// to verify the record's signature
|
// to verify the record's signature
|
||||||
@ -44,19 +56,19 @@ func NewIpnsRecordValidator(kbook pstore.KeyBook) *record.ValidChecker {
|
|||||||
entry := new(pb.IpnsEntry)
|
entry := new(pb.IpnsEntry)
|
||||||
err := proto.Unmarshal(r.Value, entry)
|
err := proto.Unmarshal(r.Value, entry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return ErrBadRecord
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the public key defined by the ipns path
|
// Get the public key defined by the ipns path
|
||||||
pid, err := peer.IDFromString(r.Key)
|
pid, err := peer.IDFromString(r.Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("failed to parse ipns record key %s into public key hash", r.Key)
|
log.Debugf("failed to parse ipns record key %s into peer ID", r.Key)
|
||||||
return ErrSignature
|
return ErrKeyFormat
|
||||||
}
|
}
|
||||||
pubk := kbook.PubKey(pid)
|
pubk := kbook.PubKey(pid)
|
||||||
if pubk == nil {
|
if pubk == nil {
|
||||||
log.Debugf("public key with hash %s not found in peer store", pid)
|
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
|
// Check the ipns record signature with the public key
|
||||||
|
Reference in New Issue
Block a user