// Copyright 2023 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 osvutils provides utilities for working with Go OSV entries.
// It is separated from package osv because that package
// promises to only import from the standard library.
package osvutils

import (
	"errors"
	"fmt"
	"strings"

	"golang.org/x/vulndb/internal/derrors"
	"golang.org/x/vulndb/internal/idstr"
	"golang.org/x/vulndb/internal/osv"
	"golang.org/x/vulndb/internal/version"
)

// Validate errors if there are any problems with the OSV Entry.
// It is used to validate OSV entries before publishing them to the
// Go vulnerability database, and has stricter requirements than
// the general OSV format.
func Validate(e *osv.Entry) (err error) {
	derrors.Wrap(&err, "Validate(%s)", e.ID)
	return validate(e, true)
}

// ValidateExceptTimestamps errors if there are any problems with the
// OSV Entry, with the exception of the timestamps (published, modified and
// withdrawn) which are not checked.
// This is used to validate entries at CL submit time, before their timestamps
// are corrected.
func ValidateExceptTimestamps(e *osv.Entry) (err error) {
	derrors.Wrap(&err, "ValidateExceptTimestamps(%s)", e.ID)
	return validate(e, false)
}

var (
	// Errors for incorrect timestamps.
	errNoModified             = errors.New("modified time must be non-zero")
	errNoPublished            = errors.New("published time must be non-zero")
	errPublishedAfterModified = errors.New("published time cannot be after modified time")

	// Errors for missing fields.
	errNoID                = errors.New("id field is empty")
	errNoSchemaVersion     = errors.New("schema_version field is empty")
	errNoSummary           = errors.New("summary field is empty")
	errNoDetails           = errors.New("details field is empty")
	errNoAffected          = errors.New("affected field is empty")
	errNoReferences        = errors.New("references field is empty")
	errNoDatabaseSpecific  = errors.New("database_specific field is empty")
	errNoModule            = errors.New("affected field missing module path")
	errNotGoEcosystem      = errors.New("affected ecosystem is not Go")
	errNoRanges            = errors.New("affected field contains no ranges")
	errNoEcosystemSpecific = errors.New("affected field contains no ecosystem_specific field")
	errNoPackagePath       = errors.New("affected.ecosystem_specific.imports field has no package path")

	// Errors for invalid fields.
	errInvalidAlias           = errors.New("alias must be CVE or GHSA ID")
	errInvalidPkgsiteURL      = errors.New("database_specific.URL must be a link to https://pkg.go.dev/vuln/<Go id>")
	errInvalidPackagePath     = errors.New("package path must be prefixed by module path")
	errTooManyRanges          = errors.New("each module should have exactly one version range")
	errRangeTypeNotSemver     = errors.New("range type must be SEMVER")
	errNoRangeEvents          = errors.New("range must contain one or more events")
	errOutOfOrderRange        = errors.New("introduced and fixed versions must alternate")
	errUnsortedRange          = errors.New("range events must be in strictly ascending order")
	errNoIntroducedOrFixed    = errors.New("introduced or fixed must be set")
	errBothIntroducedAndFixed = errors.New("introduced and fixed cannot both be set in same event")
	errInvalidSemver          = errors.New("invalid or non-canonical semver version")
)

func validate(e *osv.Entry, checkTimestamps bool) (err error) {
	if checkTimestamps {
		switch {
		case e.Modified.IsZero():
			return errNoModified
		case e.Published.IsZero():
			return errNoPublished
		case e.Published.After(e.Modified.Time):
			return fmt.Errorf("%w (published=%s, modified=%s)", errPublishedAfterModified, e.Published, e.Modified)
		}
	}

	// Check for missing required fields.
	switch {
	case e.ID == "":
		return errNoID
	case e.SchemaVersion == "":
		return errNoSchemaVersion
	case e.Summary == "":
		return errNoSummary
	case e.Details == "" && !hasAdvisory(e):
		return errNoDetails
	case len(e.Affected) == 0:
		return errNoAffected
	case len(e.References) == 0:
		return errNoReferences
	case e.DatabaseSpecific == nil:
		return errNoDatabaseSpecific
	}

	for _, a := range e.Affected {
		if err := validateAffected(&a); err != nil {
			return err
		}
	}
	for _, alias := range e.Aliases {
		if !idstr.IsAliasType(alias) {
			return fmt.Errorf("%w (found alias %s)", errInvalidAlias, alias)
		}
	}

	return validateDatabaseSpecific(e.DatabaseSpecific)
}

func hasAdvisory(entry *osv.Entry) bool {
	for _, ref := range entry.References {
		if ref.Type == osv.ReferenceTypeAdvisory {
			return true
		}
	}
	return false
}

func validateAffected(a *osv.Affected) error {
	switch {
	case a.Module.Path == "":
		return errNoModule
	case a.Module.Ecosystem != osv.GoEcosystem:
		return errNotGoEcosystem
	}

	if err := ValidateRanges(a.Ranges); err != nil {
		return err
	}

	return validateEcosystemSpecific(a.EcosystemSpecific, a.Module.Path)
}

func ValidateRanges(ranges []osv.Range) error {
	switch {
	case len(ranges) == 0:
		return errNoRanges
	case len(ranges) > 1:
		return fmt.Errorf("%w (found %d ranges)", errTooManyRanges, len(ranges))
	}

	return validateRange(&ranges[0])
}

func validateRange(r *osv.Range) error {
	switch {
	case r.Type != osv.RangeTypeSemver:
		return fmt.Errorf("%w (found range type %q)",
			errRangeTypeNotSemver, r.Type)
	case len(r.Events) == 0:
		return errNoRangeEvents
	}

	// Check that all the events are valid and sorted in ascending order.
	prev, err := parseRangeEvent(&r.Events[0])
	if err != nil {
		return err
	}
	for _, event := range r.Events[1:] {
		current, err := parseRangeEvent(&event)
		if err != nil {
			return fmt.Errorf("invalid range event: %w", err)
		}
		// Introduced and fixed versions must alternate.
		if current.introduced == prev.introduced {
			return errOutOfOrderRange
		}
		if !less(prev.v, current.v) {
			return fmt.Errorf("%w (found %s>=%s)", errUnsortedRange, prev.v, current.v)
		}
		prev = current
	}

	return nil
}

func less(v, w string) bool {
	// Ensure that version 0 is always lowest.
	if v == "0" {
		return true
	}
	if w == "0" {
		return false
	}
	return version.Before(v, w)
}

type event struct {
	v          string
	introduced bool
}

func parseRangeEvent(e *osv.RangeEvent) (*event, error) {
	introduced, fixed := e.Introduced, e.Fixed

	var v string
	var isIntroduced bool
	switch {
	case introduced == "" && fixed == "":
		return nil, errNoIntroducedOrFixed
	case introduced != "" && fixed != "":
		return nil, errBothIntroducedAndFixed
	case introduced == "0":
		return &event{v: "0", introduced: true}, nil
	case introduced != "":
		v = introduced
		isIntroduced = true
	case fixed != "":
		v = fixed
		isIntroduced = false
	}

	if !version.IsValid(v) || v != version.Canonical(v) {
		return nil, fmt.Errorf("%w (found %s)", errInvalidSemver, v)
	}

	return &event{v: v, introduced: isIntroduced}, nil
}

func validateEcosystemSpecific(es *osv.EcosystemSpecific, module string) error {
	if es == nil {
		return errNoEcosystemSpecific
	}

	for _, pkg := range es.Packages {
		if pkg.Path == "" {
			return errNoPackagePath
		}
		// Package path must be prefixed by module path unless it is
		// in the Go standard library or toolchain.
		if (module != osv.GoStdModulePath && module != osv.GoCmdModulePath) &&
			!strings.HasPrefix(pkg.Path, module) {
			return fmt.Errorf("%w (found module=%q, package=%q)", errInvalidPackagePath, module, pkg.Path)
		}
	}

	return nil
}

func validateDatabaseSpecific(d *osv.DatabaseSpecific) error {
	if !idstr.IsGoAdvisory(d.URL) {
		return fmt.Errorf("%w (found URL %q)", errInvalidPkgsiteURL, d.URL)
	}
	return nil
}
