Skip to content

Commit 80b0c9a

Browse files
authored
fix(transfer): Don't allow unknown fields during json unmarshalling. (#6428)
* fix(transfer): Don't allow unknown fields during json unmarshalling. Use json's DisallowUnknownFields flag on the decoder to control error emission for uknown fields. Implement Unmarshaller interface for both version of the ics20 packet data. * docs: expand on recursion protection.
1 parent 45c7eea commit 80b0c9a

File tree

2 files changed

+64
-18
lines changed

2 files changed

+64
-18
lines changed

modules/apps/transfer/keeper/relay_test.go

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,15 +1088,6 @@ func (suite *KeeperTestSuite) TestPacketForwardsCompatibility() {
10881088
expError error
10891089
expAckError error
10901090
}{
1091-
{
1092-
"success: new field v2",
1093-
func() {
1094-
jsonString := fmt.Sprintf(`{"tokens":[{"denom": {"base": "atom", "trace": []},"amount":"100"}],"sender":"%s","receiver":"%s", "new_field":"value"}`, suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String())
1095-
packetData = []byte(jsonString)
1096-
},
1097-
nil,
1098-
nil,
1099-
},
11001091
{
11011092
"success: no new field with memo v2",
11021093
func() {
@@ -1124,24 +1115,22 @@ func (suite *KeeperTestSuite) TestPacketForwardsCompatibility() {
11241115
ibcerrors.ErrInvalidType,
11251116
},
11261117
{
1127-
"failure: missing field v2",
1118+
"failure: new field v2",
11281119
func() {
1129-
jsonString := fmt.Sprintf(`{"tokens":[{"denom": {"trace": []},"amount":"100"}],"sender":"%s","receiver":"%s"}`, suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String())
1120+
jsonString := fmt.Sprintf(`{"tokens":[{"denom": {"base": "atom", "trace": []},"amount":"100"}],"sender":"%s","receiver":"%s", "new_field":"value"}`, suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String())
11301121
packetData = []byte(jsonString)
11311122
},
1132-
types.ErrInvalidDenomForTransfer,
1123+
ibcerrors.ErrInvalidType,
11331124
ibcerrors.ErrInvalidType,
11341125
},
11351126
{
1136-
"success: new field",
1127+
"failure: missing field v2",
11371128
func() {
1138-
path.EndpointA.ChannelConfig.Version = types.V1
1139-
path.EndpointB.ChannelConfig.Version = types.V1
1140-
jsonString := fmt.Sprintf(`{"denom":"denom","amount":"100","sender":"%s","receiver":"%s","memo":"memo","new_field":"value"}`, suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String())
1129+
jsonString := fmt.Sprintf(`{"tokens":[{"denom": {"trace": []},"amount":"100"}],"sender":"%s","receiver":"%s"}`, suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String())
11411130
packetData = []byte(jsonString)
11421131
},
1143-
nil,
1144-
nil,
1132+
types.ErrInvalidDenomForTransfer,
1133+
ibcerrors.ErrInvalidType,
11451134
},
11461135
{
11471136
"success: no new field with memo",
@@ -1175,6 +1164,17 @@ func (suite *KeeperTestSuite) TestPacketForwardsCompatibility() {
11751164
ibcerrors.ErrInvalidType,
11761165
ibcerrors.ErrInvalidType,
11771166
},
1167+
{
1168+
"failure: new field",
1169+
func() {
1170+
path.EndpointA.ChannelConfig.Version = types.V1
1171+
path.EndpointB.ChannelConfig.Version = types.V1
1172+
jsonString := fmt.Sprintf(`{"denom":"denom","amount":"100","sender":"%s","receiver":"%s","memo":"memo","new_field":"value"}`, suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String())
1173+
packetData = []byte(jsonString)
1174+
},
1175+
ibcerrors.ErrInvalidType,
1176+
ibcerrors.ErrInvalidType,
1177+
},
11781178
{
11791179
"failure: missing field",
11801180
func() {
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package types
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
)
7+
8+
// UnmarshalJSON implements the Unmarshaller interface for FungibleTokenPacketDataV2.
9+
func (ftpd *FungibleTokenPacketDataV2) UnmarshalJSON(bz []byte) error {
10+
// Recursion protection. We cannot unmarshal into FungibleTokenPacketData directly
11+
// else UnmarshalJSON is going to get invoked again, ad infinum. Create an alias
12+
// and unmarshal into that, instead.
13+
type ftpdAlias FungibleTokenPacketDataV2
14+
15+
d := json.NewDecoder(bytes.NewReader(bz))
16+
// Raise errors during decoding if unknown fields are encountered.
17+
d.DisallowUnknownFields()
18+
19+
var alias ftpdAlias
20+
if err := d.Decode(&alias); err != nil {
21+
return err
22+
}
23+
24+
*ftpd = FungibleTokenPacketDataV2(alias)
25+
return nil
26+
}
27+
28+
// UnmarshalJSON implements the Unmarshaller interface for FungibleTokenPacketData.
29+
func (ftpd *FungibleTokenPacketData) UnmarshalJSON(bz []byte) error {
30+
// Recursion protection. We cannot unmarshal into FungibleTokenPacketData directly
31+
// else UnmarshalJSON is going to get invoked again, ad infinum. Create an alias
32+
// and unmarshal into that, instead.
33+
type ftpdAlias FungibleTokenPacketData
34+
35+
d := json.NewDecoder(bytes.NewReader(bz))
36+
// Raise errors during decoding if unknown fields are encountered.
37+
d.DisallowUnknownFields()
38+
39+
var alias ftpdAlias
40+
if err := d.Decode(&alias); err != nil {
41+
return err
42+
}
43+
44+
*ftpd = FungibleTokenPacketData(alias)
45+
return nil
46+
}

0 commit comments

Comments
 (0)