Skip to content

Commit

Permalink
Merge "[FAB-8006] Check for reserved fields in Json"
Browse files Browse the repository at this point in the history
  • Loading branch information
Jason Yellick authored and Gerrit Code Review committed Feb 14, 2018
2 parents 2057f74 + 0cf1756 commit 1033fcb
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 37 deletions.
54 changes: 29 additions & 25 deletions core/ledger/kvledger/txmgmt/statedb/statecouchdb/statecouchdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,15 @@ import (

var logger = flogging.MustGetLogger("statecouchdb")

const binaryWrapper = "valueBytes"
const (
binaryWrapper = "valueBytes"
idField = "_id"
revField = "_rev"
versionField = "~version"
deletedField = "_deleted"
)

const idField = "_id"
const revField = "_rev"
const versionField = "~version"
const deletedField = "_deleted"
var reservedFields = []string{idField, revField, versionField, deletedField}

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

// ValidateKey implements method in VersionedDB interface
func (vdb *VersionedDB) ValidateKey(key string) error {
// ValidateKeyValue implements method in VersionedDB interface
func (vdb *VersionedDB) ValidateKeyValue(key string, value []byte) error {
if !utf8.ValidString(key) {
return fmt.Errorf("Key should be a valid utf8 string: [%x]", key)
}
var jsonMap map[string]interface{}
err := json.Unmarshal([]byte(value), &jsonMap)
if err == nil {
// the value is a proper json and hence perform a check that this json does not contain reserved field
// if error is not nil then the value will be treated as a binary attachement.
return checkReservedFieldsNotUsed(jsonMap)
}
return nil
}

Expand Down Expand Up @@ -992,24 +1002,8 @@ func createCouchdbDocJSON(id, revision string, value []byte, version *version.He
}
}

// verify the version field was not included
if _, fieldFound := jsonMap[versionField]; fieldFound {
return nil, fmt.Errorf("The reserved field %s was found", versionField)
}

// verify the _id field was not included
if _, fieldFound := jsonMap[idField]; fieldFound {
return nil, fmt.Errorf("The reserved field %s was found", idField)
}

// verify the revision field was not included
if _, fieldFound := jsonMap[revField]; fieldFound {
return nil, fmt.Errorf("The reserved field %s was found", revField)
}

// verify the deleted field was not included
if _, fieldFound := jsonMap[deletedField]; fieldFound {
return nil, fmt.Errorf("The reserved field %s was found", deletedField)
if err := checkReservedFieldsNotUsed(jsonMap); err != nil {
return nil, err
}

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

}

// checkReservedFieldsNotUsed verifies that the reserve field was not included
func checkReservedFieldsNotUsed(jsonMap map[string]interface{}) error {
for _, fieldName := range reservedFields {
if _, fieldFound := jsonMap[fieldName]; fieldFound {
return fmt.Errorf("The reserved field %s was found", fieldName)
}
}
return nil
}

// removeJSONRevision removes the "_rev" if this is a JSON
func removeJSONRevision(jsonValue *[]byte) error {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package statecouchdb
import (
"archive/tar"
"bytes"
"fmt"
"log"
"os"
"testing"
Expand Down Expand Up @@ -196,14 +197,21 @@ func TestUtilityFunctions(t *testing.T) {
byteKeySupported := db.BytesKeySuppoted()
testutil.AssertEquals(t, byteKeySupported, false)

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

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

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

// TestInvalidJSONFields tests for invalid JSON fields
Expand Down
4 changes: 2 additions & 2 deletions core/ledger/kvledger/txmgmt/statedb/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ type VersionedDB interface {
// GetLatestSavePoint returns the height of the highest transaction upto which
// the state db is consistent
GetLatestSavePoint() (*version.Height, error)
// ValidateKey tests whether the key is supported by the db implementation.
// ValidateKeyValue tests whether the key and value is supported by the db implementation.
// For instance, leveldb supports any bytes for the key while the couchdb supports only valid utf-8 string
ValidateKey(key string) error
ValidateKeyValue(key string, value []byte) error
// BytesKeySuppoted returns true if the implementation (underlying db) supports the any bytes to be used as key.
// For instance, leveldb supports any bytes for the key while the couchdb supports only valid utf-8 string
BytesKeySuppoted() bool
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ func (vdb *versionedDB) Close() {
// do nothing because shared db is used
}

// ValidateKey implements method in VersionedDB interface
func (vdb *versionedDB) ValidateKey(key string) error {
// ValidateKeyValue implements method in VersionedDB interface
func (vdb *versionedDB) ValidateKeyValue(key string, value []byte) error {
return nil
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ func TestUtilityFunctions(t *testing.T) {
byteKeySupported := db.BytesKeySuppoted()
testutil.AssertEquals(t, byteKeySupported, true)

// ValidateKey should return nil for a valid key
validKey := db.ValidateKey("testKey")
testutil.AssertNil(t, validKey)
// ValidateKeyValue should return nil for a valid key and value
testutil.AssertNoError(t, db.ValidateKeyValue("testKey", []byte("testValue")), "leveldb should accept all key-values")
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func (s *lockBasedTxSimulator) SetState(ns string, key string, value []byte) err
if err := s.checkBeforeWrite(); err != nil {
return err
}
if err := s.helper.txmgr.db.ValidateKey(key); err != nil {
if err := s.helper.txmgr.db.ValidateKeyValue(key, value); err != nil {
return err
}
s.rwsetBuilder.AddToWriteSet(ns, key, value)
Expand Down Expand Up @@ -84,7 +84,7 @@ func (s *lockBasedTxSimulator) SetPrivateData(ns, coll, key string, value []byte
if err := s.checkBeforeWrite(); err != nil {
return err
}
if err := s.helper.txmgr.db.ValidateKey(key); err != nil {
if err := s.helper.txmgr.db.ValidateKeyValue(key, value); err != nil {
return err
}
s.writePerformed = true
Expand Down

0 comments on commit 1033fcb

Please sign in to comment.