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 }