Skip to content

Commit

Permalink
Merge pull request #568 from oasisprotocol/pro-wh/bugfix/chainutf8
Browse files Browse the repository at this point in the history
evmnfts, evmtokens: utf-8-clean strings from chain
  • Loading branch information
pro-wh authored Nov 17, 2023
2 parents 93ad10e + 50f26a2 commit 9e621ca
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 7 deletions.
15 changes: 10 additions & 5 deletions analyzer/evmnfts/evm_nfts.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,17 @@ func (p *processor) ProcessItem(ctx context.Context, batch *storage.QueryBatch,
staleNFT.Addr,
staleNFT.ID,
staleNFT.DownloadRound,
nftData.MetadataURI,
storage.SanitizeStringP(nftData.MetadataURI),
nftData.MetadataAccessed,
nftData.Metadata,
nftData.Name,
nftData.Description,
nftData.Image,
// Metadata has already gone through a round trip of JSON Unmarshal
// and Marshal, which should already make it safe for PostgreSQL. But
// for consistency, pass it through SanitizeString as well. This
// shouldn't have any effect, and if it does, it shouldn't affect the
// JSON syntax.
storage.SanitizeStringP(nftData.Metadata),
storage.SanitizeStringP(nftData.Name),
storage.SanitizeStringP(nftData.Description),
storage.SanitizeStringP(nftData.Image),
)
return nil
}
Expand Down
4 changes: 2 additions & 2 deletions analyzer/evmtokens/evm_tokens.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,8 @@ func (p *processor) ProcessItem(ctx context.Context, batch *storage.QueryBatch,
p.runtime,
staleToken.Addr,
tokenData.Type,
tokenData.Name,
tokenData.Symbol,
storage.SanitizeString(tokenData.Name),
storage.SanitizeString(tokenData.Symbol),
tokenData.Decimals,
totalSupply,
staleToken.DownloadRound,
Expand Down
42 changes: 42 additions & 0 deletions analyzer/runtime/evm/erc721_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package evm

import (
"encoding/json"
"testing"
"unicode/utf8"

"github.com/stretchr/testify/require"
)

func TestJSONRoundTrip(t *testing.T) {
for _, s := range []string{
// Invalid UTF-8.
"{\"a\": \"\xff\"}",
"{\"\xff\": \"a\"}",
// NUL bytes.
"{\"a\": \"\x00\"}",
"{\"\x00\": \"a\"}",
// Codepoint zero.
"{\"a\": \"\\u0000\"}",
"{\"\\u0000\": \"a\"}",
} {
var parsed any
err := json.Unmarshal([]byte(s), &parsed)
if err != nil {
// Erroring out while unmarshalling is fine.
t.Logf("%#v -> parsing: %v\n", s, err)
continue
}
roundTripBuf, err := json.Marshal(parsed)
if err != nil {
// Erroring out while marshalling is uncool, but not a showstopper.
t.Logf("%#v -> stringifying: %v\n", s, err)
continue
}
roundTrip := string(roundTripBuf)
// If it gets through the round trip, it'd better be clean.
require.True(t, utf8.ValidString(roundTrip), "%#v -> invalid UTF-8 %#v", s, roundTrip)
require.NotContains(t, roundTrip, 0x0, "%#v -> contains NUL byte %#v", s, roundTrip)
t.Logf("%#v -> %#v\n", s, roundTrip)
}
}
9 changes: 9 additions & 0 deletions storage/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"sync"

"github.com/jackc/pgx/v5"

"github.com/oasisprotocol/nexus/common"
)

type BatchItem struct {
Expand Down Expand Up @@ -128,3 +130,10 @@ type TargetStorage interface {
func SanitizeString(msg string) string {
return strings.ToValidUTF8(strings.ReplaceAll(msg, "\x00", "?"), "?")
}

func SanitizeStringP(msg *string) *string {
if msg == nil {
return nil
}
return common.Ptr(SanitizeString(*msg))
}

0 comments on commit 9e621ca

Please sign in to comment.