// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package worker is used to fetch and create issues for CVEs that are
// potential Go vulnerabilities.
package worker

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"path"
	"strings"

	"github.com/go-git/go-git/v5"
	"github.com/go-git/go-git/v5/plumbing/filemode"
	"github.com/go-git/go-git/v5/plumbing/object"
	"golang.org/x/vuln/internal/cveschema"
	"golang.org/x/vuln/internal/derrors"
	"golang.org/x/vuln/internal/report"
)

// Run clones the CVEProject/cvelist repository and compares the files to the
// existing triaged-cve-list.
func Run(dirpath string, triaged map[string]string) (err error) {
	defer derrors.Wrap(&err, "Run(triaged)")
	var repo *git.Repository
	if dirpath != "" {
		repo, err = openRepo(dirpath)
	} else {
		repo, err = cloneRepo(cvelistRepoURL)
	}
	if err != nil {
		return err
	}
	root, err := getRepoRoot(repo)
	if err != nil {
		return err
	}
	if err := createIssuesToTriage(repo, root, triaged); err != nil {
		return err
	}
	return nil
}

// createIssuesToTriage creates GitHub issues to be triaged by the Go security
// team.
// TODO: Create GitHub issues. At the moment, this just prints the number of
// issues to be created.
func createIssuesToTriage(r *git.Repository, t *object.Tree, triaged map[string]string) (err error) {
	defer derrors.Wrap(&err, "createIssuesToTriage(r, t, triaged)")
	log.Printf("Finding new Go vulnerabilities from CVE list...")
	cves, issues, err := walkRepo(r, t, "", triaged)
	if err != nil {
		return err
	}
	// TODO: log CVE states in a CVE record.
	// TODO: create GitHub issues.

	var numRefs int
	for _, issue := range issues {
		if issue.AdditionalInfo.Reason == reasonReferenceData {
			numRefs += 1
		}
	}
	log.Printf("Found %d new issues from %d CVEs (%d based on reference data)",
		len(issues), len(cves), numRefs)
	return nil
}

// walkRepo looks at the files in t, recursively, and check if it is a CVE that
// needs to be manually triaged.
func walkRepo(r *git.Repository, t *object.Tree, dirpath string, triaged map[string]string) (newCVEs map[string]bool, newIssues []*GoVulnIssue, err error) {
	defer derrors.Wrap(&err, "walkRepo(r, t, %q, triaged)", dirpath)
	newCVEs = map[string]bool{}
	for _, e := range t.Entries {
		fp := path.Join(dirpath, e.Name)
		if !strings.HasPrefix(fp, "202") {
			continue
		}
		switch e.Mode {
		case filemode.Dir:
			t2, err := r.TreeObject(e.Hash)
			if err != nil {
				return nil, nil, err
			}
			cves, issues, err := walkRepo(r, t2, fp, triaged)
			if err != nil {
				return nil, nil, err
			}
			for c := range cves {
				newCVEs[c] = true
			}
			newIssues = append(newIssues, issues...)
		default:
			if !strings.HasPrefix(e.Name, "CVE-") {
				continue
			}
			cveID := strings.TrimSuffix(e.Name, ".json")
			if _, ok := triaged[cveID]; ok {
				continue
			}
			newCVEs[cveID] = true
			c, err := parseCVE(r, e)
			if err != nil {
				return nil, nil, err
			}
			issue, err := cveToIssue(c)
			if err != nil {
				return nil, nil, err
			}
			if issue != nil {
				log.Printf("New CVE to triage: %q (%q)\n", cveID, issue.Report.Module)
				newIssues = append(newIssues, issue)
			}
		}
	}
	return newCVEs, newIssues, nil
}

// parseCVEJSON parses a CVE file following the CVE JSON format:
// https://github.com/CVEProject/automation-working-group/blob/master/cve_json_schema/DRAFT-JSON-file-format-v4.md
func parseCVE(r *git.Repository, e object.TreeEntry) (_ *cveschema.CVE, err error) {
	defer derrors.Wrap(&err, "parseCVE(r, e)")
	blob, err := r.BlobObject(e.Hash)
	if err != nil {
		return nil, fmt.Errorf("r.BlobObject: %v", err)
	}
	src, err := blob.Reader()
	if err != nil {
		return nil, fmt.Errorf("blob.Reader: %v", err)
	}
	defer func() {
		cerr := src.Close()
		if err == nil {
			err = cerr
		}
	}()
	var c cveschema.CVE
	d := json.NewDecoder(src)
	if err := d.Decode(&c); err != nil {
		return nil, fmt.Errorf("d.Decode: %v", err)
	}
	if err != nil {
		return nil, err
	}
	return &c, nil
}

const goGitHubRepo = "github.com/golang/go"

// cveToIssue creates a GoVulnIssue from a c *cveschema.CVE.
func cveToIssue(c *cveschema.CVE) (_ *GoVulnIssue, err error) {
	defer derrors.Wrap(&err, "cveToIssue(%q)", c.CVEDataMeta.ID)
	if isPendingCVE(c) {
		return nil, nil
	}
	switch c.DataVersion {
	case "4.0":
		return cveToIssueV4(c)
	default:
		// TODO(https://golang.org/issue/49289): Add support for v5.0.
		log.Printf("Unxpected data_version for CVE %q: %q (skipping)", c.CVEDataMeta.ID, c.DataVersion)
		return nil, nil
	}
}

func cveToIssueV4(c *cveschema.CVE) (_ *GoVulnIssue, err error) {
	mp, err := modulePathFromCVE(c)
	if err != nil {
		return nil, err
	}
	if mp == "" {
		return nil, nil
	}
	var links report.Links
	for _, r := range c.References.ReferenceData {
		if links.Commit == "" && strings.Contains(r.URL, "/commit/") {
			links.Commit = r.URL
		} else if links.PR == "" && strings.Contains(r.URL, "/pull/") {
			links.PR = r.URL
		} else {
			links.Context = append(links.Context, r.URL)
		}
	}
	var cwe string
	for _, pt := range c.Problemtype.ProblemtypeData {
		for _, d := range pt.Description {
			if strings.Contains(d.Value, "CWE") {
				cwe = d.Value
			}
		}
	}
	r := report.Report{
		Module:      mp,
		Links:       links,
		CVE:         c.CVEDataMeta.ID,
		Description: description(c),
	}
	if mp == goGitHubRepo {
		r.Stdlib = true
	}
	info := AdditionalInfo{
		Products: products(c),
		CWE:      cwe,
		Reason:   reasonReferenceData,
	}
	return &GoVulnIssue{Report: r, AdditionalInfo: info}, nil
}

// isPendingCVE reports if the CVE is still waiting on information and not
// ready to be triaged.
func isPendingCVE(c *cveschema.CVE) bool {
	return c.CVEDataMeta.STATE == cveschema.StateReserved
}

var vcsHostsWithThreeElementRepoName = map[string]bool{
	"bitbucket.org": true,
	"gitea.com":     true,
	"gitee.com":     true,
	"github.com":    true,
	"gitlab.com":    true,
	"golang.org":    true,
}

// modulePathFromCVE returns a Go module path for a CVE, if we can determine
// what it is.
func modulePathFromCVE(c *cveschema.CVE) (_ string, err error) {
	defer derrors.Wrap(&err, "modulePathFromCVE(c)")
	for _, r := range c.References.ReferenceData {
		if r.URL == "" {
			continue
		}
		for host := range vcsHostsWithThreeElementRepoName {
			if !strings.Contains(r.URL, host) {
				continue
			}
			refURL, err := url.Parse(r.URL)
			if err != nil {
				return "", fmt.Errorf("url.Parse(%q): %v", r.URL, err)
			}
			u := refURL.Host + refURL.Path
			parts := strings.Split(u, "/")
			if len(parts) < 3 {
				continue
			}
			mod := strings.Join(parts[0:3], "/")
			r, err := http.DefaultClient.Get(fmt.Sprintf("https://pkg.go.dev/%s", mod))
			if err != nil {
				return "", err
			}
			if r.StatusCode == http.StatusOK {
				return mod, nil
			}
		}
	}
	return "", nil
}

const reasonReferenceData = "This CVE was identified as a go vuln because a Go module path was found in reference data."

// GoVulnIssue represents a GitHub issue to be created about a Go
// vulnerability.
type GoVulnIssue struct {
	AdditionalInfo AdditionalInfo
	Report         report.Report
}

// AdditionalInfo contains additional information about the CVE not captured by
// report.Report.
type AdditionalInfo struct {
	CWE      string
	Products []*cveschema.ProductDataItem
	Reason   string
}

func description(c *cveschema.CVE) string {
	var ds []string
	for _, d := range c.Description.DescriptionData {
		ds = append(ds, d.Value)
	}
	return strings.Join(ds, "| \n ")
}

func products(c *cveschema.CVE) []*cveschema.ProductDataItem {
	var pds []*cveschema.ProductDataItem
	for _, v := range c.Affects.Vendor.VendorData {
		for _, pd := range v.Product.ProductData {
			pds = append(pds, &pd)
		}
	}
	return pds
}
