github.com/Hnampk/fabric@v2.1.1+incompatible/core/chaincode/platforms/node/platform.go (about)

     1  /*
     2  # Copyright IBM Corp. All Rights Reserved.
     3  #
     4  # SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package node
     8  
     9  import (
    10  	"archive/tar"
    11  	"bytes"
    12  	"compress/gzip"
    13  	"errors"
    14  	"fmt"
    15  	"net/url"
    16  	"os"
    17  	"path/filepath"
    18  	"regexp"
    19  	"strings"
    20  
    21  	pb "github.com/hyperledger/fabric-protos-go/peer"
    22  	"github.com/hyperledger/fabric/common/flogging"
    23  	"github.com/hyperledger/fabric/core/chaincode/platforms/util"
    24  )
    25  
    26  var logger = flogging.MustGetLogger("chaincode.platform.node")
    27  
    28  // Platform for chaincodes written in Go
    29  type Platform struct{}
    30  
    31  // Returns whether the given file or directory exists or not
    32  func pathExists(path string) (bool, error) {
    33  	_, err := os.Stat(path)
    34  	if err == nil {
    35  		return true, nil
    36  	}
    37  	if os.IsNotExist(err) {
    38  		return false, nil
    39  	}
    40  	return true, err
    41  }
    42  
    43  // Name returns the name of this platform
    44  func (p *Platform) Name() string {
    45  	return pb.ChaincodeSpec_NODE.String()
    46  }
    47  
    48  // ValidateSpec validates Go chaincodes
    49  func (p *Platform) ValidatePath(rawPath string) error {
    50  	path, err := url.Parse(rawPath)
    51  	if err != nil || path == nil {
    52  		return fmt.Errorf("invalid path: %s", err)
    53  	}
    54  
    55  	//Treat empty scheme as a local filesystem path
    56  	if path.Scheme == "" {
    57  		pathToCheck, err := filepath.Abs(rawPath)
    58  		if err != nil {
    59  			return fmt.Errorf("error obtaining absolute path of the chaincode: %s", err)
    60  		}
    61  
    62  		exists, err := pathExists(pathToCheck)
    63  		if err != nil {
    64  			return fmt.Errorf("error validating chaincode path: %s", err)
    65  		}
    66  		if !exists {
    67  			return fmt.Errorf("path to chaincode does not exist: %s", rawPath)
    68  		}
    69  	}
    70  	return nil
    71  }
    72  
    73  func (p *Platform) ValidateCodePackage(code []byte) error {
    74  	// FAB-2122: Scan the provided tarball to ensure it only contains source-code under
    75  	// the src folder.
    76  	//
    77  	// It should be noted that we cannot catch every threat with these techniques.  Therefore,
    78  	// the container itself needs to be the last line of defense and be configured to be
    79  	// resilient in enforcing constraints. However, we should still do our best to keep as much
    80  	// garbage out of the system as possible.
    81  	re := regexp.MustCompile(`^(/)?(src|META-INF)/.*`)
    82  	is := bytes.NewReader(code)
    83  	gr, err := gzip.NewReader(is)
    84  	if err != nil {
    85  		return fmt.Errorf("failure opening codepackage gzip stream: %s", err)
    86  	}
    87  	tr := tar.NewReader(gr)
    88  
    89  	var foundPackageJson = false
    90  	for {
    91  		header, err := tr.Next()
    92  		if err != nil {
    93  			// We only get here if there are no more entries to scan
    94  			break
    95  		}
    96  
    97  		// --------------------------------------------------------------------------------------
    98  		// Check name for conforming path
    99  		// --------------------------------------------------------------------------------------
   100  		if !re.MatchString(header.Name) {
   101  			return fmt.Errorf("illegal file detected in payload: \"%s\"", header.Name)
   102  		}
   103  		if header.Name == "src/package.json" {
   104  			foundPackageJson = true
   105  		}
   106  		// --------------------------------------------------------------------------------------
   107  		// Check that file mode makes sense
   108  		// --------------------------------------------------------------------------------------
   109  		// Acceptable flags:
   110  		//      ISREG      == 0100000
   111  		//      -rw-rw-rw- == 0666
   112  		//
   113  		// Anything else is suspect in this context and will be rejected
   114  		// --------------------------------------------------------------------------------------
   115  		if header.Mode&^0100666 != 0 {
   116  			return fmt.Errorf("illegal file mode detected for file %s: %o", header.Name, header.Mode)
   117  		}
   118  	}
   119  	if !foundPackageJson {
   120  		return fmt.Errorf("no package.json found at the root of the chaincode package")
   121  	}
   122  
   123  	return nil
   124  }
   125  
   126  // Generates a deployment payload by putting source files in src/$file entries in .tar.gz format
   127  func (p *Platform) GetDeploymentPayload(path string) ([]byte, error) {
   128  
   129  	var err error
   130  
   131  	// --------------------------------------------------------------------------------------
   132  	// Write out our tar package
   133  	// --------------------------------------------------------------------------------------
   134  	payload := bytes.NewBuffer(nil)
   135  	gw := gzip.NewWriter(payload)
   136  	tw := tar.NewWriter(gw)
   137  
   138  	folder := path
   139  	if folder == "" {
   140  		return nil, errors.New("ChaincodeSpec's path cannot be empty")
   141  	}
   142  
   143  	// trim trailing slash if it exists
   144  	if folder[len(folder)-1] == '/' {
   145  		folder = folder[:len(folder)-1]
   146  	}
   147  
   148  	logger.Debugf("Packaging node.js project from path %s", folder)
   149  
   150  	if err = util.WriteFolderToTarPackage(tw, folder, []string{"node_modules"}, nil, nil); err != nil {
   151  		logger.Errorf("Error writing folder to tar package %s", err)
   152  		return nil, fmt.Errorf("Error writing Chaincode package contents: %s", err)
   153  	}
   154  
   155  	// Write the tar file out
   156  	if err := tw.Close(); err != nil {
   157  		return nil, fmt.Errorf("Error writing Chaincode package contents: %s", err)
   158  	}
   159  
   160  	tw.Close()
   161  	gw.Close()
   162  
   163  	return payload.Bytes(), nil
   164  }
   165  
   166  func (p *Platform) GenerateDockerfile() (string, error) {
   167  	var buf []string
   168  
   169  	buf = append(buf, "FROM "+util.GetDockerImageFromConfig("chaincode.node.runtime"))
   170  	buf = append(buf, "ADD binpackage.tar /usr/local/src")
   171  
   172  	dockerFileContents := strings.Join(buf, "\n")
   173  
   174  	return dockerFileContents, nil
   175  }
   176  
   177  var buildScript = `
   178  set -e
   179  if [ -x /chaincode/build.sh ]; then
   180  	/chaincode/build.sh
   181  else
   182  	cp -R /chaincode/input/src/. /chaincode/output && cd /chaincode/output && npm install --production
   183  fi
   184  `
   185  
   186  func (p *Platform) DockerBuildOptions(path string) (util.DockerBuildOptions, error) {
   187  	return util.DockerBuildOptions{
   188  		Image: util.GetDockerImageFromConfig("chaincode.node.runtime"),
   189  		Cmd:   buildScript,
   190  	}, nil
   191  }