diff --git a/gateway/handler_ipns_record.go b/gateway/handler_ipns_record.go index 9d4f93e06e..73d9dabd52 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 87ddadb034..db92b39ffe 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 e75d0aee7e..48fa0ec788 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.Nil(t, err) + + pid, err := peer.IDFromPublicKey(pk) + assert.Nil(t, err) + + entry, err := Create(sk, path, 1, eol, 0) + assert.Nil(t, err) + + t.Run("valid peer ID", func(t *testing.T) { + t.Parallel() + err = ValidateWithPeerID(pid, entry) + assert.Nil(t, err) + }) + + t.Run("invalid peer ID", func(t *testing.T) { + t.Parallel() + + _, pk2, err := crypto.GenerateEd25519Key(rnd) + assert.Nil(t, err) + + pid2, err := peer.IDFromPublicKey(pk2) + assert.Nil(t, err) + + err = ValidateWithPeerID(pid2, entry) + assert.NotNil(t, err) + }) +}