Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit 04fd12b

Browse files
authored
static key for mapping, allow to set only state namespace (#70)
* const key for mapping * owner extension refactoring
1 parent a1cf54a commit 04fd12b

15 files changed

Lines changed: 184 additions & 47 deletions

File tree

extensions/owner/modifier.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package owner
22

33
import (
4+
"fmt"
5+
46
"github.com/pkg/errors"
7+
58
"github.com/s7techlab/cckit/router"
69
)
710

@@ -13,10 +16,10 @@ var (
1316
// Only allow access from chain code owner
1417
func Only(next router.HandlerFunc, pos ...int) router.HandlerFunc {
1518
return func(c router.Context) (interface{}, error) {
16-
invokerIsOwner, err := IsInvoker(c)
17-
if invokerIsOwner && err == nil {
19+
err := IsTxCreator(c)
20+
if err == nil {
1821
return next(c)
1922
}
20-
return nil, ErrOwnerOnly
23+
return nil, fmt.Errorf(`%s: %w`, err, ErrOwnerOnly)
2124
}
2225
}

extensions/owner/owner.go

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
package owner
33

44
import (
5-
"github.com/pkg/errors"
5+
"errors"
6+
"fmt"
7+
68
"github.com/s7techlab/cckit/identity"
79
r "github.com/s7techlab/cckit/router"
810
)
@@ -16,6 +18,9 @@ var (
1618

1719
// ErrOwnerAlreadySetted owner already setted
1820
ErrOwnerAlreadySetted = errors.New(`owner already setted`)
21+
22+
// ErrMSPIdentifierNotEqual occurs when tx creator and cc owner certificate did not match
23+
ErrMSPIdentifierNotEqual = errors.New(`msp identifier not equal`)
1924
)
2025

2126
func IsSetted(c r.Context) (bool, error) {
@@ -49,6 +54,7 @@ func SetFromCreator(c r.Context) (*identity.Entry, error) {
4954
if err != nil {
5055
return nil, err
5156
}
57+
5258
return identityEntry, c.State().Insert(OwnerStateKey, identityEntry)
5359
}
5460

@@ -69,11 +75,11 @@ func SetFromArgs(c r.Context) (*identity.Entry, error) {
6975
return Get(c)
7076
}
7177

72-
// Insert
78+
// Insert information about owner to chaincode state
7379
func Insert(c r.Context, mspID string, cert []byte) (*identity.Entry, error) {
7480

7581
if ownerSetted, err := IsSetted(c); err != nil {
76-
return nil, errors.Wrap(err, `check owner is set`)
82+
return nil, fmt.Errorf(`check owner is set: %w`, err)
7783
} else if ownerSetted {
7884
return nil, ErrOwnerAlreadySetted
7985
}
@@ -85,15 +91,15 @@ func Insert(c r.Context, mspID string, cert []byte) (*identity.Entry, error) {
8591

8692
identityEntry, err := identity.CreateEntry(id)
8793
if err != nil {
88-
return nil, errors.Wrap(err, `create owner entry`)
94+
return nil, fmt.Errorf(`create owner entry: %w`, err)
8995
}
9096
return identityEntry, c.State().Insert(OwnerStateKey, identityEntry)
9197
}
9298

9399
// IsInvokerOr checks tx creator and compares with owner of another identity
94100
func IsInvokerOr(c r.Context, allowedTo ...identity.Identity) (bool, error) {
95-
if isOwner, err := IsInvoker(c); isOwner || err != nil {
96-
return isOwner, err
101+
if err := IsTxCreator(c); err == nil {
102+
return true, nil
97103
}
98104
if len(allowedTo) == 0 {
99105
return false, nil
@@ -111,7 +117,7 @@ func IsInvokerOr(c r.Context, allowedTo ...identity.Identity) (bool, error) {
111117
return false, nil
112118
}
113119

114-
// IdentityFromState
120+
// IdentityEntryFromState returns identity.Entry with chaincode owner certificate
115121
func IdentityEntryFromState(c r.Context) (identity.Entry, error) {
116122
res, err := c.State().Get(OwnerStateKey, &identity.Entry{})
117123
if err != nil {
@@ -121,16 +127,35 @@ func IdentityEntryFromState(c r.Context) (identity.Entry, error) {
121127
return res.(identity.Entry), nil
122128
}
123129

124-
// IsInvoker checks than tx creator is chain code owner
125-
func IsInvoker(c r.Context) (bool, error) {
126-
invoker, err := identity.FromStub(c.Stub())
127-
if err != nil {
130+
// Deprecated: IsInvoker checks than tx creator is chain code owner
131+
// use IsTxCreator
132+
func IsInvoker(ctx r.Context) (bool, error) {
133+
if err := IsTxCreator(ctx); err != nil {
128134
return false, err
129135
}
130-
ownerEntry, err := IdentityEntryFromState(c)
136+
137+
return true, nil
138+
}
139+
140+
// IsTxCreator returns error if owner identity (msp_id + certificate) did not match tx creator identity
141+
func IsTxCreator(ctx r.Context) error {
142+
invoker, err := identity.FromStub(ctx.Stub())
143+
if err != nil {
144+
return err
145+
}
146+
147+
ownerEntry, err := IdentityEntryFromState(ctx)
131148
if err != nil {
132-
return false, err
149+
return err
150+
}
151+
152+
if ownerEntry.GetMSPID() != invoker.GetMSPIdentifier() {
153+
return fmt.Errorf(`%s : %w`, ErrMSPIdentifierNotEqual, ErrOwnerOnly)
154+
}
155+
156+
if err = identity.CertEqual(invoker, ownerEntry); err != nil {
157+
return fmt.Errorf(`%s : %w`, err, ErrOwnerOnly)
133158
}
134159

135-
return ownerEntry.MSPId == invoker.MspID && ownerEntry.Subject == invoker.GetSubject(), nil
160+
return nil
136161
}

identity/cert_identity.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ package identity
33
import (
44
"crypto/x509"
55
"encoding/pem"
6+
"fmt"
67
"time"
78

89
"github.com/golang/protobuf/proto"
910
"github.com/hyperledger/fabric-chaincode-go/pkg/cid"
1011
"github.com/hyperledger/fabric-chaincode-go/shim"
1112
protomsp "github.com/hyperledger/fabric-protos-go/msp"
1213
"github.com/hyperledger/fabric/msp"
13-
"github.com/pkg/errors"
1414
)
1515

1616
// New creates CertIdentity struct from an mspID and certificate
@@ -23,18 +23,18 @@ func New(mspID string, certPEM []byte) (ci *CertIdentity, err error) {
2323
}
2424

2525
// FromStub creates Identity interface from tx creator mspID and certificate (stub.GetCreator)
26-
func FromStub(stub shim.ChaincodeStubInterface) (ci *CertIdentity, err error) {
26+
func FromStub(stub shim.ChaincodeStubInterface) (*CertIdentity, error) {
2727
clientIdentity, err := cid.New(stub)
2828
if err != nil {
29-
return nil, errors.Wrap(err, `client identity from stub`)
29+
return nil, fmt.Errorf(`client identity from stub: %w`, err)
3030
}
3131
mspID, err := clientIdentity.GetMSPID()
3232
if err != nil {
33-
return
33+
return nil, err
3434
}
3535
cert, err := clientIdentity.GetX509Certificate()
3636
if err != nil {
37-
return
37+
return nil, err
3838
}
3939
return &CertIdentity{mspID, cert}, nil
4040
}
@@ -56,6 +56,7 @@ func (ci CertIdentity) GetID() string {
5656
}
5757

5858
// Deprecated: GetMSPID returns invoker's membership service provider id
59+
// Use GetMSPIdentifier()
5960
func (ci CertIdentity) GetMSPID() string {
6061
return ci.MspID
6162
}

identity/entry.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ func (e Entry) GetIdentityEntry() Entry {
8989
// CreateEntry creates IdentityEntry structure from an identity interface
9090
func CreateEntry(i Identity) (g *Entry, err error) {
9191
return &Entry{
92-
MSPId: i.GetMSPID(),
92+
MSPId: i.GetMSPIdentifier(),
9393
Subject: i.GetSubject(),
9494
Issuer: i.GetIssuer(),
9595
PEM: i.GetPEM(),

identity/equal.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package identity
2+
3+
import (
4+
"errors"
5+
)
6+
7+
var (
8+
ErrSubjectNotEqual = errors.New(`certificate subject not equal`)
9+
ErrIssuerNotEqual = errors.New(`certificate issuer not equal`)
10+
)
11+
12+
type (
13+
SubjectIssuer interface {
14+
GetSubject() string
15+
GetIssuer() string
16+
}
17+
)
18+
19+
// CertEqual checks certificate equality
20+
func CertEqual(cert1, cert2 SubjectIssuer) error {
21+
22+
if cert1 == nil || cert2 == nil {
23+
return errors.New(`certificate empty`)
24+
}
25+
if cert1.GetSubject() != cert2.GetSubject() {
26+
return ErrSubjectNotEqual
27+
}
28+
29+
if cert1.GetIssuer() != cert2.GetIssuer() {
30+
return ErrIssuerNotEqual
31+
}
32+
33+
return nil
34+
}

identity/identity.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ type Identity interface {
1414
// Deprecated: GetMSPID msp identifier. Use GetMspIdentifier instead
1515
GetMSPID() string
1616

17-
// GetSubject string representation of X.509 cert subject
17+
// GetSubject string representation of X.509 cert subject
1818
GetSubject() string
19-
// GetIssuer string representation of X.509 cert issuer
19+
// GetIssuer string representation of X.509 cert issuer
2020
GetIssuer() string
2121

2222
// GetPublicKey *rsa.PublicKey or *dsa.PublicKey or *ecdsa.PublicKey:

router/request.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package router
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
)
7+
8+
var ErrInvalidRequest = errors.New(`invalid request`)
9+
10+
type (
11+
Validator interface {
12+
Validate() error
13+
}
14+
)
15+
16+
// ValidateRequest use Validator interface and create error, allow to use error.Is(ErrInvalidRequest)
17+
func ValidateRequest(request Validator) error {
18+
if err := request.Validate(); err != nil {
19+
return fmt.Errorf(`%s: %w`, err.Error(), ErrInvalidRequest)
20+
}
21+
22+
return nil
23+
}

state/mapping/mapping_test.go

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ var (
3232

3333
Owner = identitytestdata.Certificates[0].MustIdentity(`SOME_MSP`)
3434
)
35-
var _ = Describe(`Mapping`, func() {
35+
var _ = Describe(`State mapping in chaincode`, func() {
3636

3737
BeforeSuite(func() {
3838

@@ -162,23 +162,14 @@ var _ = Describe(`Mapping`, func() {
162162
It("Allow to insert entry once more time", func() {
163163
expectcc.ResponseOk(compositeIDCC.Invoke(`create`, create1))
164164
})
165-
166-
It("Check entry keying", func() {
167-
168-
})
169-
170165
})
171166

172167
Describe(`Entity with complex id`, func() {
173168

174-
ent1 := &schema.EntityWithComplexId{Id: &schema.EntityComplexId{
175-
IdPart1: []string{`aaa`, `bb`},
176-
IdPart2: `ccc`,
177-
IdPart3: testcc.MustTime(`2020-01-28T17:00:00Z`),
178-
}}
169+
ent1 := testdata.CreateEntityWithComplextId[0]
179170

180171
It("Allow to add data to chaincode state", func() {
181-
expectcc.ResponseOk(complexIDCC.Invoke(`entityInsert`, ent1))
172+
expectcc.ResponseOk(complexIDCC.From(Owner).Invoke(`entityInsert`, ent1))
182173
keys := expectcc.PayloadIs(complexIDCC.From(Owner).Invoke(
183174
`debugStateKeys`, `EntityWithComplexId`), &[]string{}).([]string)
184175
Expect(len(keys)).To(Equal(1))
@@ -380,7 +371,7 @@ var _ = Describe(`Mapping`, func() {
380371
}
381372

382373
It("Disallow to get config before set", func() {
383-
expectcc.ResponseError(configCC.Invoke(`configGet`), `state entry not found: Config | config`)
374+
expectcc.ResponseError(configCC.Invoke(`configGet`), `state entry not found: Config`)
384375
})
385376

386377
It("Allow to set config", func() {

state/mapping/state_mapping.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ func (smm StateMappings) GetByNamespace(namespace state.Key) (StateMapper, error
126126
return m, nil
127127
}
128128
}
129-
return nil, fmt.Errorf(`%s: %s`, ErrStateMappingNotFound, namespace)
129+
return nil, fmt.Errorf(`namespace=%s: %w`, namespace, ErrStateMappingNotFound)
130130
}
131131

132132
func (smm StateMappings) GetBySchema(schema interface{}) (StateMapper, error) {

state/mapping/state_mapping_opt.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,21 @@ const (
1616
TimestampKeyLayout = `2006-01-02`
1717
)
1818

19-
// WithStateNamespace sets namespace for mapping
20-
func WithStateNamespace(namespace state.Key) StateMappingOpt {
19+
// WithNamespace sets namespace for mapping
20+
func WithNamespace(namespace state.Key) StateMappingOpt {
2121
return func(sm *StateMapping, smm StateMappings) {
2222
sm.namespace = namespace
2323
}
2424
}
2525

2626
// WithStaticPKey set static key for all instances of mapped entry
27-
func WithStaticPKey(key state.Key) StateMappingOpt {
27+
func WithConstPKey(keys ...state.Key) StateMappingOpt {
2828
return func(sm *StateMapping, smm StateMappings) {
29+
key := state.Key{}
30+
for _, k := range keys {
31+
key = key.Append(k)
32+
}
33+
2934
sm.primaryKeyer = func(_ interface{}) (state.Key, error) {
3035
return key, nil
3136
}
@@ -108,7 +113,7 @@ func PKeySchema(pkeySchema interface{}) StateMappingOpt {
108113
//add mapping for schema identifier
109114
smm.Add(
110115
pkeySchema,
111-
WithStateNamespace(namespace),
116+
WithNamespace(namespace),
112117
PKeyAttr(attrs...),
113118
KeyerFor(sm.schema))
114119
}
@@ -140,7 +145,7 @@ func PKeyComplexId(pkeySchema interface{}) StateMappingOpt {
140145
return func(sm *StateMapping, smm StateMappings) {
141146
sm.primaryKeyer = attrsKeyer([]string{`Id`})
142147
smm.Add(pkeySchema,
143-
WithStateNamespace(SchemaNamespace(sm.schema)),
148+
WithNamespace(SchemaNamespace(sm.schema)),
144149
PKeyAttr(attrsFrom(pkeySchema)...),
145150
KeyerFor(sm.schema))
146151
}

0 commit comments

Comments
 (0)