github.com/aidoskuneen/adk-node@v0.0.0-20220315131952-2e32567cb7f4/adkgo-node/version_check.go (about)

     1  // Copyright 2021 The adkgo Authors
     2  // This file is part of adkgo.
     3  //
     4  // adkgo is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // adkgo is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with adkgo. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package main
    18  
    19  import (
    20  	"encoding/json"
    21  	"errors"
    22  	"fmt"
    23  	"io/ioutil"
    24  	"net/http"
    25  	"regexp"
    26  	"strings"
    27  
    28  	"github.com/aidoskuneen/adk-node/log"
    29  	"github.com/jedisct1/go-minisign"
    30  	"gopkg.in/urfave/cli.v1"
    31  )
    32  
    33  var gethPubKeys []string = []string{
    34  	//@holiman, minisign public key FB1D084D39BAEC24
    35  	"RWQk7Lo5TQgd+wxBNZM+Zoy+7UhhMHaWKzqoes9tvSbFLJYZhNTbrIjx",
    36  	//minisign public key 138B1CA303E51687
    37  	"RWSHFuUDoxyLEzjszuWZI1xStS66QTyXFFZG18uDfO26CuCsbckX1e9J",
    38  	//minisign public key FD9813B2D2098484
    39  	"RWSEhAnSshOY/b+GmaiDkObbCWefsAoavjoLcPjBo1xn71yuOH5I+Lts",
    40  }
    41  
    42  type vulnJson struct {
    43  	Name        string
    44  	Uid         string
    45  	Summary     string
    46  	Description string
    47  	Links       []string
    48  	Introduced  string
    49  	Fixed       string
    50  	Published   string
    51  	Severity    string
    52  	Check       string
    53  	CVE         string
    54  }
    55  
    56  func versionCheck(ctx *cli.Context) error {
    57  	url := ctx.String(VersionCheckUrlFlag.Name)
    58  	version := ctx.String(VersionCheckVersionFlag.Name)
    59  	log.Info("Checking vulnerabilities", "version", version, "url", url)
    60  	return checkCurrent(url, version)
    61  }
    62  
    63  func checkCurrent(url, current string) error {
    64  	var (
    65  		data []byte
    66  		sig  []byte
    67  		err  error
    68  	)
    69  	if data, err = fetch(url); err != nil {
    70  		return fmt.Errorf("could not retrieve data: %w", err)
    71  	}
    72  	if sig, err = fetch(fmt.Sprintf("%v.minisig", url)); err != nil {
    73  		return fmt.Errorf("could not retrieve signature: %w", err)
    74  	}
    75  	if err = verifySignature(gethPubKeys, data, sig); err != nil {
    76  		return err
    77  	}
    78  	var vulns []vulnJson
    79  	if err = json.Unmarshal(data, &vulns); err != nil {
    80  		return err
    81  	}
    82  	allOk := true
    83  	for _, vuln := range vulns {
    84  		r, err := regexp.Compile(vuln.Check)
    85  		if err != nil {
    86  			return err
    87  		}
    88  		if r.MatchString(current) {
    89  			allOk = false
    90  			fmt.Printf("## Vulnerable to %v (%v)\n\n", vuln.Uid, vuln.Name)
    91  			fmt.Printf("Severity: %v\n", vuln.Severity)
    92  			fmt.Printf("Summary : %v\n", vuln.Summary)
    93  			fmt.Printf("Fixed in: %v\n", vuln.Fixed)
    94  			if len(vuln.CVE) > 0 {
    95  				fmt.Printf("CVE: %v\n", vuln.CVE)
    96  			}
    97  			if len(vuln.Links) > 0 {
    98  				fmt.Printf("References:\n")
    99  				for _, ref := range vuln.Links {
   100  					fmt.Printf("\t- %v\n", ref)
   101  				}
   102  			}
   103  			fmt.Println()
   104  		}
   105  	}
   106  	if allOk {
   107  		fmt.Println("No vulnerabilities found")
   108  	}
   109  	return nil
   110  }
   111  
   112  // fetch makes an HTTP request to the given url and returns the response body
   113  func fetch(url string) ([]byte, error) {
   114  	if filep := strings.TrimPrefix(url, "file://"); filep != url {
   115  		return ioutil.ReadFile(filep)
   116  	}
   117  	res, err := http.Get(url)
   118  	if err != nil {
   119  		return nil, err
   120  	}
   121  	defer res.Body.Close()
   122  	body, err := ioutil.ReadAll(res.Body)
   123  	if err != nil {
   124  		return nil, err
   125  	}
   126  	return body, nil
   127  }
   128  
   129  // verifySignature checks that the sigData is a valid signature of the given
   130  // data, for pubkey GethPubkey
   131  func verifySignature(pubkeys []string, data, sigdata []byte) error {
   132  	sig, err := minisign.DecodeSignature(string(sigdata))
   133  	if err != nil {
   134  		return err
   135  	}
   136  	// find the used key
   137  	var key *minisign.PublicKey
   138  	for _, pubkey := range pubkeys {
   139  		pub, err := minisign.NewPublicKey(pubkey)
   140  		if err != nil {
   141  			// our pubkeys should be parseable
   142  			return err
   143  		}
   144  		if pub.KeyId != sig.KeyId {
   145  			continue
   146  		}
   147  		key = &pub
   148  		break
   149  	}
   150  	if key == nil {
   151  		log.Info("Signing key not trusted", "keyid", keyID(sig.KeyId), "error", err)
   152  		return errors.New("signature could not be verified")
   153  	}
   154  	if ok, err := key.Verify(data, sig); !ok || err != nil {
   155  		log.Info("Verification failed error", "keyid", keyID(key.KeyId), "error", err)
   156  		return errors.New("signature could not be verified")
   157  	}
   158  	return nil
   159  }
   160  
   161  // keyID turns a binary minisign key ID into a hex string.
   162  // Note: key IDs are printed in reverse byte order.
   163  func keyID(id [8]byte) string {
   164  	var rev [8]byte
   165  	for i := range id {
   166  		rev[len(rev)-1-i] = id[i]
   167  	}
   168  	return fmt.Sprintf("%X", rev)
   169  }