Skip to content

Commit 0cf1756

Browse files
committed
[FAB-8006] Check for reserved fields in Json
This CR adds a check during simulation for the presence of reserved fields in the JSON that a chaincode writes via PutState function. Change-Id: If91e090fbb835446cb3a081456098e2870965a16 Signed-off-by: manish <manish.sethi@gmail.com>
1 parent 0cb7692 commit 0cf1756

File tree

6 files changed

+48
-37
lines changed

6 files changed

+48
-37
lines changed

core/ledger/kvledger/txmgmt/statedb/statecouchdb/statecouchdb.go

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,15 @@ import (
3030

3131
var logger = flogging.MustGetLogger("statecouchdb")
3232

33-
const binaryWrapper = "valueBytes"
33+
const (
34+
binaryWrapper = "valueBytes"
35+
idField = "_id"
36+
revField = "_rev"
37+
versionField = "~version"
38+
deletedField = "_deleted"
39+
)
3440

35-
const idField = "_id"
36-
const revField = "_rev"
37-
const versionField = "~version"
38-
const deletedField = "_deleted"
41+
var reservedFields = []string{idField, revField, versionField, deletedField}
3942

4043
// querySkip is implemented for future use by query paging
4144
// currently defaulted to 0 and is not used
@@ -234,11 +237,18 @@ func (vdb *VersionedDB) Close() {
234237
// no need to close db since a shared couch instance is used
235238
}
236239

237-
// ValidateKey implements method in VersionedDB interface
238-
func (vdb *VersionedDB) ValidateKey(key string) error {
240+
// ValidateKeyValue implements method in VersionedDB interface
241+
func (vdb *VersionedDB) ValidateKeyValue(key string, value []byte) error {
239242
if !utf8.ValidString(key) {
240243
return fmt.Errorf("Key should be a valid utf8 string: [%x]", key)
241244
}
245+
var jsonMap map[string]interface{}
246+
err := json.Unmarshal([]byte(value), &jsonMap)
247+
if err == nil {
248+
// the value is a proper json and hence perform a check that this json does not contain reserved field
249+
// if error is not nil then the value will be treated as a binary attachement.
250+
return checkReservedFieldsNotUsed(jsonMap)
251+
}
242252
return nil
243253
}
244254

@@ -992,24 +1002,8 @@ func createCouchdbDocJSON(id, revision string, value []byte, version *version.He
9921002
}
9931003
}
9941004

995-
// verify the version field was not included
996-
if _, fieldFound := jsonMap[versionField]; fieldFound {
997-
return nil, fmt.Errorf("The reserved field %s was found", versionField)
998-
}
999-
1000-
// verify the _id field was not included
1001-
if _, fieldFound := jsonMap[idField]; fieldFound {
1002-
return nil, fmt.Errorf("The reserved field %s was found", idField)
1003-
}
1004-
1005-
// verify the revision field was not included
1006-
if _, fieldFound := jsonMap[revField]; fieldFound {
1007-
return nil, fmt.Errorf("The reserved field %s was found", revField)
1008-
}
1009-
1010-
// verify the deleted field was not included
1011-
if _, fieldFound := jsonMap[deletedField]; fieldFound {
1012-
return nil, fmt.Errorf("The reserved field %s was found", deletedField)
1005+
if err := checkReservedFieldsNotUsed(jsonMap); err != nil {
1006+
return nil, err
10131007
}
10141008

10151009
// add the version
@@ -1040,6 +1034,16 @@ func createCouchdbDocJSON(id, revision string, value []byte, version *version.He
10401034

10411035
}
10421036

1037+
// checkReservedFieldsNotUsed verifies that the reserve field was not included
1038+
func checkReservedFieldsNotUsed(jsonMap map[string]interface{}) error {
1039+
for _, fieldName := range reservedFields {
1040+
if _, fieldFound := jsonMap[fieldName]; fieldFound {
1041+
return fmt.Errorf("The reserved field %s was found", fieldName)
1042+
}
1043+
}
1044+
return nil
1045+
}
1046+
10431047
// removeJSONRevision removes the "_rev" if this is a JSON
10441048
func removeJSONRevision(jsonValue *[]byte) error {
10451049

core/ledger/kvledger/txmgmt/statedb/statecouchdb/statecouchdb_test.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package statecouchdb
1919
import (
2020
"archive/tar"
2121
"bytes"
22+
"fmt"
2223
"log"
2324
"os"
2425
"testing"
@@ -196,14 +197,21 @@ func TestUtilityFunctions(t *testing.T) {
196197
byteKeySupported := db.BytesKeySuppoted()
197198
testutil.AssertEquals(t, byteKeySupported, false)
198199

199-
// ValidateKey should return nil for a valid key
200-
err = db.ValidateKey("testKey")
200+
// ValidateKeyValue should return nil for a valid key and value
201+
err = db.ValidateKeyValue("testKey", []byte("Some random bytes"))
201202
testutil.AssertNil(t, err)
202203

203204
// ValidateKey should return an error for an invalid key
204-
err = db.ValidateKey(string([]byte{0xff, 0xfe, 0xfd}))
205+
err = db.ValidateKeyValue(string([]byte{0xff, 0xfe, 0xfd}), []byte("Some random bytes"))
205206
testutil.AssertError(t, err, "ValidateKey should have thrown an error for an invalid utf-8 string")
206207

208+
// ValidateKey should return an error for a json value that already contains one of the reserved fields
209+
for _, reservedField := range reservedFields {
210+
testVal := fmt.Sprintf(`{"%s":"dummyVal"}`, reservedField)
211+
err = db.ValidateKeyValue("testKey", []byte(testVal))
212+
testutil.AssertError(t, err, fmt.Sprintf(
213+
"ValidateKey should have thrown an error for a json value %s, as contains one of the rserved fields", testVal))
214+
}
207215
}
208216

209217
// TestInvalidJSONFields tests for invalid JSON fields

core/ledger/kvledger/txmgmt/statedb/statedb.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ type VersionedDB interface {
4242
// GetLatestSavePoint returns the height of the highest transaction upto which
4343
// the state db is consistent
4444
GetLatestSavePoint() (*version.Height, error)
45-
// ValidateKey tests whether the key is supported by the db implementation.
45+
// ValidateKeyValue tests whether the key and value is supported by the db implementation.
4646
// For instance, leveldb supports any bytes for the key while the couchdb supports only valid utf-8 string
47-
ValidateKey(key string) error
47+
ValidateKeyValue(key string, value []byte) error
4848
// BytesKeySuppoted returns true if the implementation (underlying db) supports the any bytes to be used as key.
4949
// For instance, leveldb supports any bytes for the key while the couchdb supports only valid utf-8 string
5050
BytesKeySuppoted() bool

core/ledger/kvledger/txmgmt/statedb/stateleveldb/stateleveldb.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ func (vdb *versionedDB) Close() {
6868
// do nothing because shared db is used
6969
}
7070

71-
// ValidateKey implements method in VersionedDB interface
72-
func (vdb *versionedDB) ValidateKey(key string) error {
71+
// ValidateKeyValue implements method in VersionedDB interface
72+
func (vdb *versionedDB) ValidateKeyValue(key string, value []byte) error {
7373
return nil
7474
}
7575

core/ledger/kvledger/txmgmt/statedb/stateleveldb/stateleveldb_test.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,6 @@ func TestUtilityFunctions(t *testing.T) {
127127
byteKeySupported := db.BytesKeySuppoted()
128128
testutil.AssertEquals(t, byteKeySupported, true)
129129

130-
// ValidateKey should return nil for a valid key
131-
validKey := db.ValidateKey("testKey")
132-
testutil.AssertNil(t, validKey)
130+
// ValidateKeyValue should return nil for a valid key and value
131+
testutil.AssertNoError(t, db.ValidateKeyValue("testKey", []byte("testValue")), "leveldb should accept all key-values")
133132
}

core/ledger/kvledger/txmgmt/txmgr/lockbasedtxmgr/lockbased_tx_simulator.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func (s *lockBasedTxSimulator) SetState(ns string, key string, value []byte) err
5454
if err := s.checkBeforeWrite(); err != nil {
5555
return err
5656
}
57-
if err := s.helper.txmgr.db.ValidateKey(key); err != nil {
57+
if err := s.helper.txmgr.db.ValidateKeyValue(key, value); err != nil {
5858
return err
5959
}
6060
s.rwsetBuilder.AddToWriteSet(ns, key, value)
@@ -84,7 +84,7 @@ func (s *lockBasedTxSimulator) SetPrivateData(ns, coll, key string, value []byte
8484
if err := s.checkBeforeWrite(); err != nil {
8585
return err
8686
}
87-
if err := s.helper.txmgr.db.ValidateKey(key); err != nil {
87+
if err := s.helper.txmgr.db.ValidateKeyValue(key, value); err != nil {
8888
return err
8989
}
9090
s.writePerformed = true

0 commit comments

Comments
 (0)