From 33e3f0cd052bab0f57803a0a8aefaec69edf6613 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Wed, 10 May 2023 13:40:19 +0200 Subject: [PATCH] feat(ipns): helper ValidateWithPeerID and UnmarshalIpnsEntry (#294) --- gateway/handler_ipns_record.go | 6 ++---- ipns/ipns.go | 21 +++++++++++++++++++ ipns/validate_test.go | 38 ++++++++++++++++++++++++++++++++-- 3 files changed, 59 insertions(+), 6 deletions(-) diff --git a/gateway/handler_ipns_record.go b/gateway/handler_ipns_record.go index 9d4f93e06..73d9dabd5 100644 --- a/gateway/handler_ipns_record.go +++ b/gateway/handler_ipns_record.go @@ -10,9 +10,8 @@ import ( "time" "github.com/cespare/xxhash/v2" - "github.com/gogo/protobuf/proto" ipath "github.com/ipfs/boxo/coreiface/path" - ipns_pb "github.com/ipfs/boxo/ipns/pb" + "github.com/ipfs/boxo/ipns" "github.com/ipfs/go-cid" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" @@ -50,8 +49,7 @@ func (i *handler) serveIpnsRecord(ctx context.Context, w http.ResponseWriter, r return false } - var record ipns_pb.IpnsEntry - err = proto.Unmarshal(rawRecord, &record) + record, err := ipns.UnmarshalIpnsEntry(rawRecord) if err != nil { webError(w, err, http.StatusInternalServerError) return false diff --git a/ipns/ipns.go b/ipns/ipns.go index 87ddadb03..db92b39ff 100644 --- a/ipns/ipns.go +++ b/ipns/ipns.go @@ -130,6 +130,16 @@ func createCborDataForIpnsEntry(e *pb.IpnsEntry) ([]byte, error) { return buf.Bytes(), nil } +// ValidateWithPeerID validates the given IPNS entry against the given peer ID. +func ValidateWithPeerID(pid peer.ID, entry *pb.IpnsEntry) error { + pk, err := ExtractPublicKey(pid, entry) + if err != nil { + return err + } + + return Validate(pk, entry) +} + // Validates validates the given IPNS entry against the given public key. func Validate(pk ic.PubKey, entry *pb.IpnsEntry) error { // Make sure max size is respected @@ -287,6 +297,17 @@ func EmbedPublicKey(pk ic.PubKey, entry *pb.IpnsEntry) error { return nil } +// UnmarshalIpnsEntry unmarshalls an IPNS entry from a slice of bytes. +func UnmarshalIpnsEntry(data []byte) (*pb.IpnsEntry, error) { + var entry pb.IpnsEntry + err := proto.Unmarshal(data, &entry) + if err != nil { + return nil, err + } + + return &entry, nil +} + // ExtractPublicKey extracts a public key matching `pid` from the IPNS record, // if possible. // diff --git a/ipns/validate_test.go b/ipns/validate_test.go index e75d0aee7..1b24ec492 100644 --- a/ipns/validate_test.go +++ b/ipns/validate_test.go @@ -19,6 +19,7 @@ import ( pstore "github.com/libp2p/go-libp2p/core/peerstore" "github.com/libp2p/go-libp2p/p2p/host/peerstore/pstoremem" "github.com/multiformats/go-multicodec" + "github.com/stretchr/testify/assert" ) func testValidatorCase(t *testing.T, priv crypto.PrivKey, kbook pstore.KeyBook, key string, val []byte, eol time.Time, exp error) { @@ -143,8 +144,6 @@ func TestEmbeddedPubKeyValidate(t *testing.T) { } func TestPeerIDPubKeyValidate(t *testing.T) { - t.Skip("disabled until libp2p/go-libp2p-crypto#51 is fixed") - goodeol := time.Now().Add(time.Hour) kbook, err := pstoremem.NewPeerstore() if err != nil { @@ -413,3 +412,38 @@ func genKeys(t *testing.T) (crypto.PrivKey, peer.ID, string) { return priv, pid, ipnsKey } + +func TestValidateWithPeerID(t *testing.T) { + path := []byte("/ipfs/bafkreifjjcie6lypi6ny7amxnfftagclbuxndqonfipmb64f2km2devei4") + eol := time.Now().Add(time.Hour) + + rnd := rand.New(rand.NewSource(42)) + + sk, pk, err := crypto.GenerateEd25519Key(rnd) + assert.NoError(t, err) + + pid, err := peer.IDFromPublicKey(pk) + assert.NoError(t, err) + + entry, err := Create(sk, path, 1, eol, 0) + assert.NoError(t, err) + + t.Run("valid peer ID", func(t *testing.T) { + t.Parallel() + err = ValidateWithPeerID(pid, entry) + assert.NoError(t, err) + }) + + t.Run("invalid peer ID", func(t *testing.T) { + t.Parallel() + + _, pk2, err := crypto.GenerateEd25519Key(rnd) + assert.NoError(t, err) + + pid2, err := peer.IDFromPublicKey(pk2) + assert.NoError(t, err) + + err = ValidateWithPeerID(pid2, entry) + assert.ErrorIs(t, err, ErrSignature) + }) +}