diff --git a/ipns/errors.go b/ipns/errors.go index ebcd4e263..d78aafffa 100644 --- a/ipns/errors.go +++ b/ipns/errors.go @@ -35,3 +35,10 @@ var ErrPublicKeyMismatch = errors.New("public key in record did not match expect // ErrBadRecord should be returned when an ipns record cannot be unmarshalled var ErrBadRecord = errors.New("record could not be unmarshalled") + +// 10 KiB limit defined in https://github.com/ipfs/specs/pull/319 +const MaxRecordSize int = 10 << (10 * 1) + +// ErrRecordSize should be returned when an ipns record is +// invalid due to being too big +var ErrRecordSize = errors.New("record exceeds allowed size limit") diff --git a/ipns/ipns.go b/ipns/ipns.go index fae3f6e2c..8782356cf 100644 --- a/ipns/ipns.go +++ b/ipns/ipns.go @@ -132,6 +132,11 @@ func createCborDataForIpnsEntry(e *pb.IpnsEntry) ([]byte, error) { // 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 + if entry.Size() > MaxRecordSize { + return ErrRecordSize + } + // Check the ipns record signature with the public key if entry.GetSignatureV2() == nil { // always error if no valid signature could be found diff --git a/ipns/validate_test.go b/ipns/validate_test.go index a0d7f7e02..0b38329fc 100644 --- a/ipns/validate_test.go +++ b/ipns/validate_test.go @@ -274,6 +274,26 @@ func TestSignatureV1Ignored(t *testing.T) { } } +func TestMaxSizeValidate(t *testing.T) { + goodeol := time.Now().Add(time.Hour) + + sk, pk, err := crypto.GenerateEd25519Key(rand.New(rand.NewSource(42))) + if err != nil { + t.Fatal(err) + } + + // Create record over the max size (value+other fields) + value := make([]byte, MaxRecordSize) + entry, err := Create(sk, value, 1, goodeol, 0) + if err != nil { + t.Fatal(err) + } + // Must fail with ErrRecordSize + if err := Validate(pk, entry); !errors.Is(err, ErrRecordSize) { + t.Fatal(err) + } +} + func TestCborDataCanonicalization(t *testing.T) { goodeol := time.Now().Add(time.Hour)