Skip to content

Commit 0aa53d7

Browse files
committed
Enhance validation of chaincode names/versions in LCCC
This CR ensures chaincode names and versions only consist of the allowable characters. Chaincode names should only consist of alphanumerics, '_', and '-' while versions can also include '.' . It also fixes the GetInstalledChaincodes query logic to account for the fact that '.' is allowed in versions. Finally, this CR reworks some of the test case logic for install, deploy, and upgrade to allow for easier addition of standard test cases for those functions. https://jira.hyperledger.org/browse/FAB-2922 Change-Id: I4ac29ed619eb91d2a04f4896546443ae81da432c Signed-off-by: Will Lahti <[email protected]>
1 parent c08a043 commit 0aa53d7

File tree

3 files changed

+244
-238
lines changed

3 files changed

+244
-238
lines changed

core/common/ccprovider/ccprovider.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,9 @@ func GetInstalledChaincodes() (*pb.ChaincodeQueryResponse, error) {
122122
var ccInfoArray []*pb.ChaincodeInfo
123123

124124
for _, file := range files {
125-
fileNameArray := strings.Split(file.Name(), ".")
125+
// split at first period as chaincode versions can contain periods while
126+
// chaincode names cannot
127+
fileNameArray := strings.SplitN(file.Name(), ".", 2)
126128

127129
// check that length is 2 as expected, otherwise skip to next cc file
128130
if len(fileNameArray) == 2 {

core/scc/lccc/lccc.go

+80-68
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,8 @@ package lccc
1818

1919
import (
2020
"fmt"
21+
"regexp"
2122
"sort"
22-
"strconv"
23-
"strings"
2423

2524
"github.com/golang/protobuf/proto"
2625
"github.com/hyperledger/fabric/common/cauthdsl"
@@ -74,8 +73,8 @@ const (
7473
//GETINSTALLEDCHAINCODES gets the installed chaincodes on a peer
7574
GETINSTALLEDCHAINCODES = "getinstalledchaincodes"
7675

77-
//characters used in chaincodenamespace
78-
specialChars = "/:[]${}"
76+
allowedCharsChaincodeName = "[A-Za-z0-9_-]+"
77+
allowedCharsVersion = "[A-Za-z0-9_.-]+"
7978
)
8079

8180
//---------- the LCCC -----------------
@@ -164,37 +163,44 @@ func (f InvalidChainNameErr) Error() string {
164163
type InvalidChaincodeNameErr string
165164

166165
func (f InvalidChaincodeNameErr) Error() string {
167-
return fmt.Sprintf("invalid chain code name %s", string(f))
166+
return fmt.Sprintf("invalid chaincode name %s", string(f))
168167
}
169168

170-
//MarshallErr error marshaling/unmarshalling
171-
type MarshallErr string
169+
//EmptyChaincodeNameErr trying to upgrade to same version of Chaincode
170+
type EmptyChaincodeNameErr string
172171

173-
func (m MarshallErr) Error() string {
174-
return fmt.Sprintf("error while marshalling %s", string(m))
172+
func (f EmptyChaincodeNameErr) Error() string {
173+
return fmt.Sprint("chaincode name not provided")
175174
}
176175

177-
//IdenticalVersionErr trying to upgrade to same version of Chaincode
178-
type IdenticalVersionErr string
179-
180-
func (f IdenticalVersionErr) Error() string {
181-
return fmt.Sprintf("chain code with the same version exists %s", string(f))
182-
}
183-
184-
//InvalidVersionErr trying to upgrade to same version of Chaincode
176+
//InvalidVersionErr invalid version error
185177
type InvalidVersionErr string
186178

187179
func (f InvalidVersionErr) Error() string {
188-
return fmt.Sprintf("invalid version %s", string(f))
180+
return fmt.Sprintf("invalid chaincode version %s", string(f))
189181
}
190182

191-
//EmptyVersionErr trying to upgrade to same version of Chaincode
183+
//EmptyVersionErr empty version error
192184
type EmptyVersionErr string
193185

194186
func (f EmptyVersionErr) Error() string {
195187
return fmt.Sprintf("version not provided for chaincode %s", string(f))
196188
}
197189

190+
//MarshallErr error marshaling/unmarshalling
191+
type MarshallErr string
192+
193+
func (m MarshallErr) Error() string {
194+
return fmt.Sprintf("error while marshalling %s", string(m))
195+
}
196+
197+
//IdenticalVersionErr trying to upgrade to same version of Chaincode
198+
type IdenticalVersionErr string
199+
200+
func (f IdenticalVersionErr) Error() string {
201+
return fmt.Sprintf("chaincode with the same version exists %s", string(f))
202+
}
203+
198204
//-------------- helper functions ------------------
199205
//create the chaincode on the given chain
200206
func (lccc *LifeCycleSysCC) createChaincode(stub shim.ChaincodeStubInterface, chainname string, ccname string, version string, cccode []byte, policy []byte, escc []byte, vscc []byte) (*ccprovider.ChaincodeData, error) {
@@ -338,35 +344,60 @@ func (lccc *LifeCycleSysCC) isValidChainName(chainname string) bool {
338344
return true
339345
}
340346

341-
//check validity of chaincode name
342-
func (lccc *LifeCycleSysCC) isValidChaincodeName(chaincodename string) bool {
343-
//TODO we probably need more checks
344-
if chaincodename == "" {
345-
return false
347+
// isValidChaincodeName checks the validity of chaincode name. Chaincode names
348+
// should never be blank and should only consist of alphanumerics, '_', and '-'
349+
func (lccc *LifeCycleSysCC) isValidChaincodeName(chaincodeName string) error {
350+
if chaincodeName == "" {
351+
return EmptyChaincodeNameErr("")
352+
}
353+
354+
if !isValidCCNameOrVersion(chaincodeName, allowedCharsChaincodeName) {
355+
return InvalidChaincodeNameErr(chaincodeName)
356+
}
357+
358+
return nil
359+
}
360+
361+
// isValidChaincodeVersion checks the validity of chaincode version. Versions
362+
// should never be blank and should only consist of alphanumerics, '_', '-',
363+
// and '.'
364+
func (lccc *LifeCycleSysCC) isValidChaincodeVersion(chaincodeName string, version string) error {
365+
if version == "" {
366+
return EmptyVersionErr(chaincodeName)
367+
}
368+
369+
if !isValidCCNameOrVersion(version, allowedCharsVersion) {
370+
return InvalidVersionErr(version)
346371
}
347372

348-
//do not allow special characters in chaincode name
349-
if strings.ContainsAny(chaincodename, specialChars) {
373+
return nil
374+
}
375+
376+
func isValidCCNameOrVersion(ccNameOrVersion string, regExp string) bool {
377+
re, _ := regexp.Compile(regExp)
378+
379+
matched := re.FindString(ccNameOrVersion)
380+
if len(matched) != len(ccNameOrVersion) {
350381
return false
351382
}
352383

353384
return true
354385
}
355386

356-
//this implements "install" Invoke transaction
387+
// executeInstall implements the "install" Invoke transaction
357388
func (lccc *LifeCycleSysCC) executeInstall(stub shim.ChaincodeStubInterface, depSpec []byte) error {
358389
cds, err := utils.GetChaincodeDeploymentSpec(depSpec)
359390

360391
if err != nil {
361392
return err
362393
}
363394

364-
if !lccc.isValidChaincodeName(cds.ChaincodeSpec.ChaincodeId.Name) {
365-
return InvalidChaincodeNameErr(cds.ChaincodeSpec.ChaincodeId.Name)
395+
if err = lccc.isValidChaincodeName(cds.ChaincodeSpec.ChaincodeId.Name); err != nil {
396+
return err
366397
}
367398

368-
if cds.ChaincodeSpec.ChaincodeId.Version == "" {
369-
return EmptyVersionErr(cds.ChaincodeSpec.ChaincodeId.Name)
399+
if err = lccc.isValidChaincodeVersion(cds.ChaincodeSpec.ChaincodeId.Name, cds.ChaincodeSpec.ChaincodeId.Version); err != nil {
400+
return err
370401
}
371402

372403
if err = ccprovider.PutChaincodeIntoFS(cds); err != nil {
@@ -376,16 +407,20 @@ func (lccc *LifeCycleSysCC) executeInstall(stub shim.ChaincodeStubInterface, dep
376407
return err
377408
}
378409

379-
//this implements "deploy" Invoke transaction
410+
// executeDeploy implements the "instantiate" Invoke transaction
380411
func (lccc *LifeCycleSysCC) executeDeploy(stub shim.ChaincodeStubInterface, chainname string, depSpec []byte, policy []byte, escc []byte, vscc []byte) error {
381412
cds, err := utils.GetChaincodeDeploymentSpec(depSpec)
382413

383414
if err != nil {
384415
return err
385416
}
386417

387-
if !lccc.isValidChaincodeName(cds.ChaincodeSpec.ChaincodeId.Name) {
388-
return InvalidChaincodeNameErr(cds.ChaincodeSpec.ChaincodeId.Name)
418+
if err = lccc.isValidChaincodeName(cds.ChaincodeSpec.ChaincodeId.Name); err != nil {
419+
return err
420+
}
421+
422+
if err = lccc.isValidChaincodeVersion(cds.ChaincodeSpec.ChaincodeId.Name, cds.ChaincodeSpec.ChaincodeId.Version); err != nil {
423+
return err
389424
}
390425

391426
if err = lccc.acl(stub, chainname, cds); err != nil {
@@ -397,40 +432,12 @@ func (lccc *LifeCycleSysCC) executeDeploy(stub shim.ChaincodeStubInterface, chai
397432
return ExistsErr(cds.ChaincodeSpec.ChaincodeId.Name)
398433
}
399434

400-
if cds.ChaincodeSpec.ChaincodeId.Version == "" {
401-
return EmptyVersionErr(cds.ChaincodeSpec.ChaincodeId.Name)
402-
}
403-
404435
_, err = lccc.createChaincode(stub, chainname, cds.ChaincodeSpec.ChaincodeId.Name, cds.ChaincodeSpec.ChaincodeId.Version, depSpec, policy, escc, vscc)
405436

406437
return err
407438
}
408439

409-
func (lccc *LifeCycleSysCC) getUpgradeVersion(cd *ccprovider.ChaincodeData, cds *pb.ChaincodeDeploymentSpec) (string, error) {
410-
if cd.Version == cds.ChaincodeSpec.ChaincodeId.Version {
411-
return "", IdenticalVersionErr(cds.ChaincodeSpec.ChaincodeId.Name)
412-
}
413-
414-
if cds.ChaincodeSpec.ChaincodeId.Version != "" {
415-
return cds.ChaincodeSpec.ChaincodeId.Version, nil
416-
}
417-
418-
//user did not specifcy Version. the previous version better be a number
419-
v, err := strconv.ParseInt(cd.Version, 10, 32)
420-
421-
//This should never happen as long we don't expose version as version is computed internally
422-
//so panic till we find a need to relax
423-
if err != nil {
424-
return "", InvalidVersionErr(cd.Version)
425-
}
426-
427-
// replace the ChaincodeDeploymentSpec using the next version
428-
newVersion := fmt.Sprintf("%d", (v + 1))
429-
430-
return newVersion, nil
431-
}
432-
433-
//this implements "upgrade" Invoke transaction
440+
// executeUpgrade implements the "upgrade" Invoke transaction.
434441
func (lccc *LifeCycleSysCC) executeUpgrade(stub shim.ChaincodeStubInterface, chainName string, depSpec []byte, policy []byte, escc []byte, vscc []byte) ([]byte, error) {
435442
cds, err := utils.GetChaincodeDeploymentSpec(depSpec)
436443
if err != nil {
@@ -442,8 +449,12 @@ func (lccc *LifeCycleSysCC) executeUpgrade(stub shim.ChaincodeStubInterface, cha
442449
}
443450

444451
chaincodeName := cds.ChaincodeSpec.ChaincodeId.Name
445-
if !lccc.isValidChaincodeName(chaincodeName) {
446-
return nil, InvalidChaincodeNameErr(chaincodeName)
452+
if err = lccc.isValidChaincodeName(chaincodeName); err != nil {
453+
return nil, err
454+
}
455+
456+
if err = lccc.isValidChaincodeVersion(chaincodeName, cds.ChaincodeSpec.ChaincodeId.Version); err != nil {
457+
return nil, err
447458
}
448459

449460
// check for existence of chaincode
@@ -452,11 +463,12 @@ func (lccc *LifeCycleSysCC) executeUpgrade(stub shim.ChaincodeStubInterface, cha
452463
return nil, NotFoundErr(chainName)
453464
}
454465

455-
ver, err := lccc.getUpgradeVersion(cd, cds)
456-
if err != nil {
457-
return nil, err
466+
if cd.Version == cds.ChaincodeSpec.ChaincodeId.Version {
467+
return nil, IdenticalVersionErr(cds.ChaincodeSpec.ChaincodeId.Name)
458468
}
459469

470+
ver := cds.ChaincodeSpec.ChaincodeId.Version
471+
460472
newCD, err := lccc.upgradeChaincode(stub, chainName, chaincodeName, ver, depSpec, policy, escc, vscc)
461473
if err != nil {
462474
return nil, err

0 commit comments

Comments
 (0)