From 71109c5a54ad7442426a6a7c94f1ab549d1ec6ae Mon Sep 17 00:00:00 2001 From: Angelo De Caro Date: Wed, 16 Nov 2022 13:51:41 +0100 Subject: [PATCH] Revert "keys are sanitised directly by orion, no need for extra sanitization (#431)" (#433) Signed-off-by: Angelo De Caro --- integration/orion/cars/views/transfer.go | 8 ++-- platform/orion/core/generic/session.go | 61 +++++++++--------------- platform/orion/driver/sm.go | 4 +- platform/orion/services/db/orion.go | 15 +++++- platform/orion/services/otx/loaded.go | 20 +++----- platform/orion/transaction.go | 4 +- 6 files changed, 51 insertions(+), 61 deletions(-) diff --git a/integration/orion/cars/views/transfer.go b/integration/orion/cars/views/transfer.go index 1616cee31..22cdbf18b 100644 --- a/integration/orion/cars/views/transfer.go +++ b/integration/orion/cars/views/transfer.go @@ -137,7 +137,7 @@ func (f *BuyerFlow) Call(context view.Context) (interface{}, error) { func buyerValidateTransaction(loadedTx *otx.LoadedTransaction, buyerID, dmvID string) error { newCarRec := &states.CarRecord{} var newCarACL *types.AccessControl - writes, _ := loadedTx.Writes() + writes := loadedTx.Writes() for _, dw := range writes { switch { case strings.HasPrefix(dw.Key, states.CarRecordKeyPrefix): @@ -202,7 +202,7 @@ func (f *DMVFlow) Call(context view.Context) (interface{}, error) { tx.SetNamespace("cars") // Sets the namespace where the state should be stored if err = dmvValidateTransaction(tx, loadedTx, me); err != nil { - return nil, errors.Wrap(err, "error during dmv validate transaction") + return nil, errors.Wrap(err, "error during buyer validate transaction") } if err = loadedTx.Commit(); err != nil { @@ -216,7 +216,7 @@ func (f *DMVFlow) Call(context view.Context) (interface{}, error) { func dmvValidateTransaction(tx *otx.Transaction, loadedTx *otx.LoadedTransaction, dmvID string) error { carRec := &states.CarRecord{} - reads, _ := loadedTx.Reads() + reads := loadedTx.Reads() for _, dr := range reads { recordBytes, err := tx.Get(dr.Key) if err != nil { @@ -234,7 +234,7 @@ func dmvValidateTransaction(tx *otx.Transaction, loadedTx *otx.LoadedTransaction newCarRec := &states.CarRecord{} var newCarACL *types.AccessControl - writes, _ := loadedTx.Writes() + writes := loadedTx.Writes() for _, dw := range writes { switch { case strings.HasPrefix(dw.Key, states.CarRecordKeyPrefix): diff --git a/platform/orion/core/generic/session.go b/platform/orion/core/generic/session.go index ff680d4f1..502df11a1 100644 --- a/platform/orion/core/generic/session.go +++ b/platform/orion/core/generic/session.go @@ -7,7 +7,8 @@ SPDX-License-Identifier: Apache-2.0 package generic import ( - "encoding/hex" + "encoding/base64" + "net/url" "strings" "time" @@ -28,7 +29,7 @@ type DataTx struct { } func (d *DataTx) Put(db string, key string, bytes []byte, a driver.AccessControl) error { - key = toOrionKey(key) + key = sanitizeKey(key) var ac *types.AccessControl if a != nil { var ok bool @@ -44,7 +45,7 @@ func (d *DataTx) Put(db string, key string, bytes []byte, a driver.AccessControl } func (d *DataTx) Get(db string, key string) ([]byte, error) { - key = toOrionKey(key) + key = sanitizeKey(key) r, _, err := d.dataTx.Get(db, key) if err != nil { return nil, errors.Wrapf(err, "failed getting data") @@ -58,7 +59,7 @@ func (d *DataTx) Commit(sync bool) (string, error) { } func (d *DataTx) Delete(db string, key string) error { - key = toOrionKey(key) + key = sanitizeKey(key) return d.dataTx.Delete(db, key) } @@ -96,44 +97,36 @@ func (l *LoadedDataTx) CoSignAndClose() ([]byte, error) { return proto.Marshal(env) } -func (l *LoadedDataTx) Reads() (map[string][]*driver.DataRead, error) { +func (l *LoadedDataTx) Reads() map[string][]*driver.DataRead { res := map[string][]*driver.DataRead{} source := l.loadedDataTx.Reads() for s, reads := range source { newReads := make([]*driver.DataRead, len(reads)) for i, read := range reads { - k, err := fromOrionKey(read.Key) - if err != nil { - return nil, errors.WithMessagef(err, "failed to decode read key [%s]", read.Key) - } newReads[i] = &driver.DataRead{ - Key: k, + Key: read.Key, } } res[s] = newReads } - return res, nil + return res } -func (l *LoadedDataTx) Writes() (map[string][]*driver.DataWrite, error) { +func (l *LoadedDataTx) Writes() map[string][]*driver.DataWrite { res := map[string][]*driver.DataWrite{} source := l.loadedDataTx.Writes() for s, writes := range source { newWrites := make([]*driver.DataWrite, len(writes)) for i, write := range writes { - k, err := fromOrionKey(write.Key) - if err != nil { - return nil, errors.WithMessagef(err, "failed to decode write key [%s]", write.Key) - } newWrites[i] = &driver.DataWrite{ - Key: k, + Key: write.Key, Value: write.Value, Acl: write.Acl, } } res[s] = newWrites } - return res, nil + return res } func (l *LoadedDataTx) MustSignUsers() []string { @@ -259,32 +252,24 @@ func (s *SessionManager) NewSession(id string) (driver.Session, error) { return &Session{s: session}, err } -// toOrionKey makes sure that each component in the key can be correctly be url escaped -func toOrionKey(key string) string { - key = strings.ReplaceAll(key, string(rune(0)), "~") +// sanitizeKey makes sure that each component in the key can be correctly be url escaped +func sanitizeKey(key string) string { + escaped := false components := strings.Split(key, "~") - b := strings.Builder{} - for i := 0; i < len(components); i++ { - b.WriteString(hex.EncodeToString([]byte(components[i]))) - if i < len(components)-1 { - b.WriteRune('~') + for i, c := range components { + cc := url.PathEscape(c) + if c != cc { + components[i] = base64.StdEncoding.EncodeToString([]byte(c)) + escaped = true } } - if strings.HasSuffix(key, "~") { - b.WriteRune('~') + if !escaped { + return key } - return b.String() -} -func fromOrionKey(key string) (string, error) { - components := strings.Split(key, "~") b := strings.Builder{} for i := 0; i < len(components); i++ { - decoded, err := hex.DecodeString(components[i]) - if err != nil { - return "", errors.Wrapf(err, "failed to decode [%s]", key) - } - b.WriteString(string(decoded)) + b.WriteString(components[i]) if i < len(components)-1 { b.WriteRune('~') } @@ -292,5 +277,5 @@ func fromOrionKey(key string) (string, error) { if strings.HasSuffix(key, "~") { b.WriteRune('~') } - return b.String(), nil + return b.String() } diff --git a/platform/orion/driver/sm.go b/platform/orion/driver/sm.go index 2707b3a2c..0e9857daa 100644 --- a/platform/orion/driver/sm.go +++ b/platform/orion/driver/sm.go @@ -37,8 +37,8 @@ type LoadedDataTx interface { ID() string Commit() error CoSignAndClose() ([]byte, error) - Reads() (map[string][]*DataRead, error) - Writes() (map[string][]*DataWrite, error) + Reads() map[string][]*DataRead + Writes() map[string][]*DataWrite MustSignUsers() []string SignedUsers() []string } diff --git a/platform/orion/services/db/orion.go b/platform/orion/services/db/orion.go index daf442be0..02c824ee5 100644 --- a/platform/orion/services/db/orion.go +++ b/platform/orion/services/db/orion.go @@ -7,6 +7,8 @@ SPDX-License-Identifier: Apache-2.0 package db import ( + "encoding/base64" + "strings" "sync" "github.com/hyperledger-labs/fabric-smart-client/pkg/utils/proto" @@ -282,7 +284,18 @@ func (db *Orion) Discard() error { } func dbKey(namespace, key string) string { - return namespace + keys.NamespaceSeparator + key + k := orionKey(namespace + keys.NamespaceSeparator + key) + components := strings.Split(k, "~") + var b strings.Builder + for _, component := range components { + b.WriteString(base64.StdEncoding.EncodeToString([]byte(component))) + b.WriteString("~") + } + return b.String() +} + +func orionKey(key string) string { + return strings.ReplaceAll(key, string(rune(0)), "~") } func (db *Orion) versionedValue(txn *orion.Transaction, dbKey string) (*dbproto.VersionedValue, error) { diff --git a/platform/orion/services/otx/loaded.go b/platform/orion/services/otx/loaded.go index 95cd40913..952659e58 100644 --- a/platform/orion/services/otx/loaded.go +++ b/platform/orion/services/otx/loaded.go @@ -70,28 +70,20 @@ func (lt *LoadedTransaction) CoSignAndClose() ([]byte, error) { return t.CoSignAndClose() } -func (lt *LoadedTransaction) Reads() ([]*orion.DataRead, error) { +func (lt *LoadedTransaction) Reads() []*orion.DataRead { t, err := lt.getLoadedDataTx() if err != nil { - return nil, err - } - reads, err := t.Reads() - if err != nil { - return nil, err + return nil } - return reads[lt.Namespace], nil + return t.Reads()[lt.Namespace] } -func (lt *LoadedTransaction) Writes() ([]*orion.DataWrite, error) { +func (lt *LoadedTransaction) Writes() []*orion.DataWrite { t, err := lt.getLoadedDataTx() if err != nil { - return nil, err - } - writes, err := t.Writes() - if err != nil { - return nil, err + return nil } - return writes[lt.Namespace], nil + return t.Writes()[lt.Namespace] } func (lt *LoadedTransaction) MustSignUsers() []string { diff --git a/platform/orion/transaction.go b/platform/orion/transaction.go index d3a861020..cab48be1b 100644 --- a/platform/orion/transaction.go +++ b/platform/orion/transaction.go @@ -138,11 +138,11 @@ func (t *LoadedTransaction) CoSignAndClose() ([]byte, error) { return t.loadedDataTx.CoSignAndClose() } -func (t *LoadedTransaction) Reads() (map[string][]*driver.DataRead, error) { +func (t *LoadedTransaction) Reads() map[string][]*DataRead { return t.loadedDataTx.Reads() } -func (t *LoadedTransaction) Writes() (map[string][]*driver.DataWrite, error) { +func (t *LoadedTransaction) Writes() map[string][]*DataWrite { return t.loadedDataTx.Writes() }