fix binary encoding stupid encoding bug that just guessed a slice length and if we were to go above it it would just panic.

for example: https://github.com/bitvora/wot-relay/issues/16
This commit is contained in:
fiatjaf 2024-09-08 11:48:07 -03:00
parent e175e634c8
commit 7787a4fcf7
4 changed files with 89 additions and 27 deletions

View File

@ -1,13 +1,16 @@
package binary
import (
"encoding/base64"
"encoding/binary"
"encoding/hex"
"encoding/json"
"fmt"
"testing"
"github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/test_common"
"github.com/stretchr/testify/require"
)
func TestBinaryPartialGet(t *testing.T) {
@ -40,22 +43,44 @@ func TestBinaryPartialGet(t *testing.T) {
}
}
func TestBinaryEncodeBackwardsCompatible(t *testing.T) {
for i, jevt := range test_common.NormalEvents {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
b64bevt := test_common.BinaryEventsBase64[i]
bevt, err := base64.StdEncoding.DecodeString(b64bevt)
require.NoError(t, err)
pevt := &nostr.Event{}
err = json.Unmarshal([]byte(jevt), pevt)
require.NoError(t, err)
encoded, err := Marshal(pevt)
require.NoError(t, err)
require.Equal(t, bevt, encoded)
})
}
}
func TestBinaryEncode(t *testing.T) {
for _, jevt := range test_common.NormalEvents {
pevt := &nostr.Event{}
if err := json.Unmarshal([]byte(jevt), pevt); err != nil {
t.Fatalf("failed to decode normal json: %s", err)
}
bevt, err := Marshal(pevt)
if err != nil {
t.Fatalf("failed to encode binary: %s", err)
}
evt := &nostr.Event{}
if err := Unmarshal(bevt, evt); err != nil {
t.Fatalf("error unmarshalling binary: %s", err)
}
checkParsedCorrectly(t, pevt, jevt)
checkParsedCorrectly(t, evt, jevt)
for i, jevt := range test_common.NormalEvents {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
pevt := &nostr.Event{}
if err := json.Unmarshal([]byte(jevt), pevt); err != nil {
t.Fatalf("failed to decode normal json: %s", err)
}
bevt, err := Marshal(pevt)
if err != nil {
t.Fatalf("failed to encode binary: %s", err)
}
evt := &nostr.Event{}
if err := Unmarshal(bevt, evt); err != nil {
t.Fatalf("error unmarshalling binary: %s", err)
}
checkParsedCorrectly(t, pevt, jevt)
checkParsedCorrectly(t, evt, jevt)
})
}
}

View File

View File

@ -74,35 +74,30 @@ func Marshal(evt *nostr.Event) ([]byte, error) {
}
copy(buf[136:], content)
curr := 136 + len(content)
if tagCount := len(evt.Tags); tagCount > MaxTagCount {
return nil, fmt.Errorf("can't encode too many tags: %d, max is %d", tagCount, MaxTagCount)
} else {
binary.BigEndian.PutUint16(buf[curr:curr+2], uint16(tagCount))
binary.BigEndian.PutUint16(buf[136+len(content):136+len(content)+2], uint16(tagCount))
}
curr++
buf = buf[0 : 136+len(content)+2]
for _, tag := range evt.Tags {
curr++
if itemCount := len(tag); itemCount > MaxTagItemCount {
return nil, fmt.Errorf("can't encode a tag with so many items: %d, max is %d", itemCount, MaxTagItemCount)
} else {
buf[curr] = uint8(itemCount)
buf = append(buf, uint8(itemCount))
}
for _, item := range tag {
curr++
itemb := []byte(item)
itemSize := len(itemb)
if itemSize > MaxTagItemSize {
return nil, fmt.Errorf("tag item is too large: %d, max is %d", itemSize, MaxTagItemSize)
}
binary.BigEndian.PutUint16(buf[curr:curr+2], uint16(itemSize))
itemEnd := curr + 2 + itemSize
copy(buf[curr+2:itemEnd], itemb)
curr = itemEnd
buf = binary.BigEndian.AppendUint16(buf, uint16(itemSize))
buf = append(buf, itemb...)
buf = append(buf, 0)
}
}
buf = buf[0 : curr+1]
return buf, nil
}

File diff suppressed because one or more lines are too long