bitbucket.org/Aishee/synsec@v0.0.0-20210414005726-236fc01a153d/pkg/cwhub/download.go (about)

     1  package cwhub
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/sha256"
     6  	"path/filepath"
     7  
     8  	//"errors"
     9  	"github.com/pkg/errors"
    10  
    11  	//"errors"
    12  	"fmt"
    13  	"io"
    14  	"io/ioutil"
    15  	"net/http"
    16  	"os"
    17  	"strings"
    18  
    19  	"bitbucket.org/Aishee/synsec/pkg/csconfig"
    20  	"bitbucket.org/Aishee/synsec/pkg/types"
    21  	log "github.com/sirupsen/logrus"
    22  	"gopkg.in/yaml.v2"
    23  )
    24  
    25  func UpdateHubIdx(hub *csconfig.Hub) error {
    26  
    27  	bidx, err := DownloadHubIdx(hub)
    28  	if err != nil {
    29  		return errors.Wrap(err, "failed to download index")
    30  	}
    31  	ret, err := LoadPkgIndex(bidx)
    32  	if err != nil {
    33  		if !errors.Is(err, ReferenceMissingError) {
    34  			return errors.Wrap(err, "failed to read index")
    35  		}
    36  	}
    37  	hubIdx = ret
    38  	if err, _ := LocalSync(hub); err != nil {
    39  		return errors.Wrap(err, "failed to sync")
    40  	}
    41  	return nil
    42  }
    43  
    44  func DownloadHubIdx(hub *csconfig.Hub) ([]byte, error) {
    45  	log.Debugf("fetching index from branch %s (%s)", HubBranch, fmt.Sprintf(RawFileURLTemplate, HubBranch, HubIndexFile))
    46  	req, err := http.NewRequest("GET", fmt.Sprintf(RawFileURLTemplate, HubBranch, HubIndexFile), nil)
    47  	if err != nil {
    48  		return nil, errors.Wrap(err, "failed to build request for hub index")
    49  	}
    50  	resp, err := http.DefaultClient.Do(req)
    51  	if err != nil {
    52  		return nil, errors.Wrap(err, "failed http request for hub index")
    53  	}
    54  	if resp.StatusCode != 200 {
    55  		return nil, fmt.Errorf("bad http code %d while requesting %s", resp.StatusCode, req.URL.String())
    56  	}
    57  	defer resp.Body.Close()
    58  	body, err := ioutil.ReadAll(resp.Body)
    59  	if err != nil {
    60  		return nil, errors.Wrap(err, "failed to read request answer for hub index")
    61  	}
    62  	file, err := os.OpenFile(hub.HubIndexFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
    63  
    64  	if err != nil {
    65  		return nil, errors.Wrap(err, "while opening hub index file")
    66  	}
    67  	defer file.Close()
    68  
    69  	wsize, err := file.WriteString(string(body))
    70  	if err != nil {
    71  		return nil, errors.Wrap(err, "while writting hub index file")
    72  	}
    73  	log.Infof("Wrote new %d bytes index to %s", wsize, hub.HubIndexFile)
    74  	return body, nil
    75  }
    76  
    77  //DownloadLatest will download the latest version of Item to the tdir directory
    78  func DownloadLatest(hub *csconfig.Hub, target Item, overwrite bool) (Item, error) {
    79  	var err error
    80  
    81  	log.Debugf("Downloading %s %s", target.Type, target.Name)
    82  	if target.Type == COLLECTIONS {
    83  		var tmp = [][]string{target.Parsers, target.PostOverflows, target.Scenarios, target.Collections}
    84  		for idx, ptr := range tmp {
    85  			ptrtype := ItemTypes[idx]
    86  			for _, p := range ptr {
    87  				if val, ok := hubIdx[ptrtype][p]; ok {
    88  					log.Debugf("Download %s sub-item : %s %s", target.Name, ptrtype, p)
    89  					//recurse as it's a collection
    90  					if ptrtype == COLLECTIONS {
    91  						log.Tracef("collection, recurse")
    92  						hubIdx[ptrtype][p], err = DownloadLatest(hub, val, overwrite)
    93  						if err != nil {
    94  							return target, errors.Wrap(err, fmt.Sprintf("while downloading %s", val.Name))
    95  						}
    96  					}
    97  					item, err := DownloadItem(hub, val, overwrite)
    98  					if err != nil {
    99  						return target, errors.Wrap(err, fmt.Sprintf("while downloading %s", val.Name))
   100  					}
   101  
   102  					// We need to enable an item when it has been added to a collection since latest release of the collection.
   103  					// We check if val.Downloaded is false because maybe the item has been disabled by the user.
   104  					if !item.Installed && !val.Downloaded {
   105  						if item, err = EnableItem(hub, item); err != nil {
   106  							return target, errors.Wrapf(err, "enabling '%s'", item.Name)
   107  						}
   108  					}
   109  					hubIdx[ptrtype][p] = item
   110  				} else {
   111  					return target, fmt.Errorf("required %s %s of %s doesn't exist, abort", ptrtype, p, target.Name)
   112  				}
   113  			}
   114  		}
   115  		target, err = DownloadItem(hub, target, overwrite)
   116  		if err != nil {
   117  			return target, fmt.Errorf("failed to download item : %s", err)
   118  		}
   119  	} else {
   120  		return DownloadItem(hub, target, overwrite)
   121  	}
   122  	return target, nil
   123  }
   124  
   125  func DownloadItem(hub *csconfig.Hub, target Item, overwrite bool) (Item, error) {
   126  
   127  	var tdir = hub.HubDir
   128  	var dataFolder = hub.DataDir
   129  	/*if user didn't --force, don't overwrite local, tainted, up-to-date files*/
   130  	if !overwrite {
   131  		if target.Tainted {
   132  			log.Debugf("%s : tainted, not updated", target.Name)
   133  			return target, nil
   134  		}
   135  		if target.UpToDate {
   136  			log.Debugf("%s : up-to-date, not updated", target.Name)
   137  			return target, nil
   138  		}
   139  	}
   140  	req, err := http.NewRequest("GET", fmt.Sprintf(RawFileURLTemplate, HubBranch, target.RemotePath), nil)
   141  	if err != nil {
   142  		return target, errors.Wrap(err, fmt.Sprintf("while downloading %s", req.URL.String()))
   143  	}
   144  	resp, err := http.DefaultClient.Do(req)
   145  	if err != nil {
   146  		return target, errors.Wrap(err, fmt.Sprintf("while downloading %s", req.URL.String()))
   147  	}
   148  	if resp.StatusCode != 200 {
   149  		return target, fmt.Errorf("bad http code %d for %s", resp.StatusCode, req.URL.String())
   150  	}
   151  	defer resp.Body.Close()
   152  	body, err := ioutil.ReadAll(resp.Body)
   153  	if err != nil {
   154  		return target, errors.Wrap(err, fmt.Sprintf("while reading %s", req.URL.String()))
   155  	}
   156  	h := sha256.New()
   157  	if _, err := h.Write([]byte(body)); err != nil {
   158  		return target, errors.Wrap(err, fmt.Sprintf("while hashing %s", target.Name))
   159  	}
   160  	meow := fmt.Sprintf("%x", h.Sum(nil))
   161  	if meow != target.Versions[target.Version].Digest {
   162  		log.Errorf("Downloaded version doesn't match index, please 'hub update'")
   163  		log.Debugf("got %s, expected %s", meow, target.Versions[target.Version].Digest)
   164  		return target, fmt.Errorf("invalid download hash for %s", target.Name)
   165  	}
   166  	//all good, install
   167  	//check if parent dir exists
   168  	tmpdirs := strings.Split(tdir+"/"+target.RemotePath, "/")
   169  	parent_dir := strings.Join(tmpdirs[:len(tmpdirs)-1], "/")
   170  
   171  	/*ensure that target file is within target dir*/
   172  	finalPath, err := filepath.Abs(tdir + "/" + target.RemotePath)
   173  	if err != nil {
   174  		return target, errors.Wrapf(err, "Abs error on %s", tdir+"/"+target.RemotePath)
   175  	}
   176  	if !strings.HasPrefix(finalPath, tdir) {
   177  		return target, fmt.Errorf("path %s escapes %s, abort", target.RemotePath, tdir)
   178  	}
   179  	/*check dir*/
   180  	if _, err = os.Stat(parent_dir); os.IsNotExist(err) {
   181  		log.Debugf("%s doesn't exist, create", parent_dir)
   182  		if err := os.MkdirAll(parent_dir, os.ModePerm); err != nil {
   183  			return target, errors.Wrap(err, "while creating parent directories")
   184  		}
   185  	}
   186  	/*check actual file*/
   187  	if _, err = os.Stat(finalPath); !os.IsNotExist(err) {
   188  		log.Warningf("%s : overwrite", target.Name)
   189  		log.Debugf("target: %s/%s", tdir, target.RemotePath)
   190  	} else {
   191  		log.Infof("%s : OK", target.Name)
   192  	}
   193  
   194  	f, err := os.OpenFile(tdir+"/"+target.RemotePath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
   195  	if err != nil {
   196  		return target, errors.Wrap(err, "while opening file")
   197  	}
   198  	defer f.Close()
   199  	_, err = f.WriteString(string(body))
   200  	if err != nil {
   201  		return target, errors.Wrap(err, "while writting file")
   202  	}
   203  	target.Downloaded = true
   204  	target.Tainted = false
   205  	target.UpToDate = true
   206  
   207  	dec := yaml.NewDecoder(bytes.NewReader(body))
   208  	for {
   209  		data := &types.DataSet{}
   210  		err = dec.Decode(data)
   211  		if err != nil {
   212  			if err == io.EOF {
   213  				break
   214  			} else {
   215  				return target, errors.Wrap(err, "while reading file")
   216  			}
   217  		}
   218  		err = types.GetData(data.Data, dataFolder)
   219  		if err != nil {
   220  			return target, errors.Wrap(err, "while getting data")
   221  		}
   222  	}
   223  	hubIdx[target.Type][target.Name] = target
   224  	return target, nil
   225  }