├── .github
├── ISSUE_TEMPLATE
│ ├── config.yml
│ ├── feature_request.md
│ └── issue-report.md
├── dependabot.yml
├── release.yml
└── workflows
│ ├── build-test.yml
│ ├── codeql-analysis.yml
│ ├── dep-auto-merge.yml
│ ├── dockerhub-push.yml
│ ├── lint-test.yml
│ ├── release-binary.yml
│ └── release-test.yml
├── .gitignore
├── .goreleaser.yml
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── cmd
├── cvemap
│ └── main.go
└── integration-test
│ ├── main.go
│ ├── run.sh
│ ├── server.go
│ └── test-data.json
├── go.mod
├── go.sum
├── pkg
├── runner
│ ├── banner.go
│ ├── options.go
│ ├── runner.go
│ └── util.go
├── service
│ └── cvemap.go
├── testutils
│ └── util.go
└── types
│ └── types.go
└── static
└── cvemap.png
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 |
3 | contact_links:
4 | - name: Ask an question / advise on using cvemap
5 | url: https://github.com/projectdiscovery/cvemap/discussions/categories/q-a
6 | about: Ask a question or request support for using cvemap
7 |
8 | - name: Share idea / feature to discuss for cvemap
9 | url: https://github.com/projectdiscovery/cvemap/discussions/categories/ideas
10 | about: Share idea / feature to discuss for cvemap
11 |
12 | - name: Connect with PD Team (Discord)
13 | url: https://discord.gg/projectdiscovery
14 | about: Connect with PD Team for direct communication
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Request feature to implement in this project
4 | labels: 'Type: Enhancement'
5 | ---
6 |
7 |
13 |
14 | ### Please describe your feature request:
15 |
16 |
17 | ### Describe the use case of this feature:
18 |
19 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/issue-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Issue report
3 | about: Create a report to help us to improve the project
4 | labels: 'Type: Bug'
5 |
6 | ---
7 |
8 |
13 |
14 |
15 |
16 | ### cvemap version:
17 |
18 |
19 |
20 |
21 | ### Current Behavior:
22 |
23 |
24 | ### Expected Behavior:
25 |
26 |
27 | ### Steps To Reproduce:
28 |
33 |
34 |
35 | ### Anything else:
36 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 |
9 | # Maintain dependencies for go modules
10 | - package-ecosystem: "gomod"
11 | directory: "/"
12 | schedule:
13 | interval: "weekly"
14 | target-branch: "main"
15 | commit-message:
16 | prefix: "chore"
17 | include: "scope"
18 | labels:
19 | - "Type: Maintenance"
20 | groups:
21 | modules:
22 | patterns: ["github.com/projectdiscovery/*"]
23 |
24 | # # Maintain dependencies for docker
25 | # - package-ecosystem: "docker"
26 | # directory: "/"
27 | # schedule:
28 | # interval: "weekly"
29 | # target-branch: "dev"
30 | # commit-message:
31 | # prefix: "chore"
32 | # include: "scope"
33 | # labels:
34 | # - "Type: Maintenance"
35 | #
36 | # # Maintain dependencies for GitHub Actions
37 | # - package-ecosystem: "github-actions"
38 | # directory: "/"
39 | # schedule:
40 | # interval: "weekly"
41 | # target-branch: "dev"
42 | # commit-message:
43 | # prefix: "chore"
44 | # include: "scope"
45 | # labels:
46 | # - "Type: Maintenance"
47 |
--------------------------------------------------------------------------------
/.github/release.yml:
--------------------------------------------------------------------------------
1 | changelog:
2 | exclude:
3 | authors:
4 | - dependabot
5 | categories:
6 | - title: 🎉 New Features
7 | labels:
8 | - "Type: Enhancement"
9 | - title: 🐞 Bugs Fixes
10 | labels:
11 | - "Type: Bug"
12 | - title: 🔨 Maintenance
13 | labels:
14 | - "Type: Maintenance"
15 | - title: Other Changes
16 | labels:
17 | - "*"
--------------------------------------------------------------------------------
/.github/workflows/build-test.yml:
--------------------------------------------------------------------------------
1 | name: 🔨 Build Test
2 |
3 | on:
4 | pull_request:
5 | paths:
6 | - '**.go'
7 | - '**.mod'
8 | workflow_dispatch:
9 |
10 | jobs:
11 | build:
12 | name: Test Builds
13 | runs-on: ${{ matrix.os }}
14 | strategy:
15 | matrix:
16 | os: [ubuntu-latest, windows-latest, macOS-latest]
17 | go-version: [1.21.x]
18 | steps:
19 | - name: Set up Go
20 | uses: actions/setup-go@v4
21 | with:
22 | go-version: ${{ matrix.go-version }}
23 |
24 | - name: Check out code
25 | uses: actions/checkout@v3
26 |
27 | - name: Build
28 | run: go build .
29 | working-directory: cmd/cvemap/
30 |
31 | - name: Test
32 | run: go test ./...
33 | working-directory: .
34 |
35 | - name: Integration Tests Linux, macOS
36 | if: runner.os == 'Linux' || runner.os == 'macOS'
37 | env:
38 | GH_ACTION: true
39 | run: bash run.sh
40 | working-directory: cmd/integration-test/
41 |
42 | - name: Integration Tests Windows
43 | if: runner.os == 'Windows'
44 | env:
45 | GH_ACTION: true
46 | MSYS_NO_PATHCONV: true
47 | run: bash run.sh
48 | working-directory: cmd/integration-test/
49 |
50 | - name: Race Condition Tests
51 | if: github.actor != 'dependabot[bot]'
52 | run: go run -race . -id CVE-1999-0027
53 | working-directory: cmd/cvemap/
54 | env:
55 | PDCP_API_KEY: "${{ secrets.PDCP_API_KEY }}"
56 | PDCP_API_SERVER: https://api.projectdiscovery.io
57 | DEBUG: true
58 |
59 | # - name: Test Example Code
60 | # run: go run .
61 | # working-directory: examples/
62 |
63 |
64 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | name: 🚨 CodeQL Analysis
2 |
3 | on:
4 | workflow_dispatch:
5 | pull_request:
6 | branches:
7 | - dev
8 |
9 | jobs:
10 | analyze:
11 | name: Analyze
12 | runs-on: ubuntu-latest
13 | permissions:
14 | actions: read
15 | contents: read
16 | security-events: write
17 |
18 | strategy:
19 | fail-fast: false
20 | matrix:
21 | language: [ 'go' ]
22 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
23 |
24 | steps:
25 | - name: Checkout repository
26 | uses: actions/checkout@v3
27 |
28 | # Initializes the CodeQL tools for scanning.
29 | - name: Initialize CodeQL
30 | uses: github/codeql-action/init@v2
31 | with:
32 | languages: ${{ matrix.language }}
33 |
34 | - name: Autobuild
35 | uses: github/codeql-action/autobuild@v2
36 |
37 | - name: Perform CodeQL Analysis
38 | uses: github/codeql-action/analyze@v2
--------------------------------------------------------------------------------
/.github/workflows/dep-auto-merge.yml:
--------------------------------------------------------------------------------
1 | name: 🤖 dep auto merge
2 |
3 | on:
4 | pull_request:
5 | branches:
6 | - main
7 | workflow_dispatch:
8 |
9 | permissions:
10 | pull-requests: write
11 | issues: write
12 | repository-projects: write
13 |
14 | jobs:
15 | automerge:
16 | runs-on: ubuntu-latest
17 | if: github.actor == 'dependabot[bot]'
18 | steps:
19 | - uses: actions/checkout@v3
20 | with:
21 | token: ${{ secrets.DEPENDABOT_PAT }}
22 |
23 | - uses: ahmadnassri/action-dependabot-auto-merge@v2
24 | with:
25 | github-token: ${{ secrets.DEPENDABOT_PAT }}
26 | target: all
--------------------------------------------------------------------------------
/.github/workflows/dockerhub-push.yml:
--------------------------------------------------------------------------------
1 | name: 🌥 Docker Push
2 |
3 | on:
4 | workflow_run:
5 | workflows: ["🎉 Release Binary"]
6 | types:
7 | - completed
8 | workflow_dispatch:
9 |
10 | jobs:
11 | docker:
12 | runs-on: ubuntu-latest-16-cores
13 | steps:
14 | - name: Git Checkout
15 | uses: actions/checkout@v3
16 |
17 | - name: Get Github tag
18 | id: meta
19 | run: |
20 | curl --silent "https://api.github.com/repos/projectdiscovery/cvemap/releases/latest" | jq -r .tag_name | xargs -I {} echo TAG={} >> $GITHUB_OUTPUT
21 |
22 | - name: Set up QEMU
23 | uses: docker/setup-qemu-action@v2
24 |
25 | - name: Set up Docker Buildx
26 | uses: docker/setup-buildx-action@v2
27 |
28 | - name: Login to DockerHub
29 | uses: docker/login-action@v2
30 | with:
31 | username: ${{ secrets.DOCKER_USERNAME }}
32 | password: ${{ secrets.DOCKER_TOKEN }}
33 |
34 | - name: Build and push
35 | uses: docker/build-push-action@v4
36 | with:
37 | context: .
38 | platforms: linux/amd64,linux/arm64,linux/arm
39 | push: true
40 | tags: projectdiscovery/cvemap:latest,projectdiscovery/cvemap:${{ steps.meta.outputs.TAG }}
--------------------------------------------------------------------------------
/.github/workflows/lint-test.yml:
--------------------------------------------------------------------------------
1 | name: 🙏🏻 Lint Test
2 |
3 | on:
4 | pull_request:
5 | paths:
6 | - '**.go'
7 | - '**.mod'
8 | workflow_dispatch:
9 |
10 | jobs:
11 | lint:
12 | name: Lint Test
13 | runs-on: ubuntu-latest
14 | steps:
15 | - name: Checkout code
16 | uses: actions/checkout@v3
17 |
18 | - name: "Set up Go"
19 | uses: actions/setup-go@v4
20 | with:
21 | go-version: 1.21.x
22 |
23 | - name: Run golangci-lint
24 | uses: golangci/golangci-lint-action@v3.6.0
25 | with:
26 | version: latest
27 | args: --timeout 5m
28 | working-directory: .
--------------------------------------------------------------------------------
/.github/workflows/release-binary.yml:
--------------------------------------------------------------------------------
1 | name: 🎉 Release Binary
2 | on:
3 | push:
4 | tags:
5 | - '*'
6 | workflow_dispatch:
7 |
8 | jobs:
9 | release:
10 | runs-on: ubuntu-latest-16-cores
11 | steps:
12 | - name: "Check out code"
13 | uses: actions/checkout@v3
14 | with:
15 | fetch-depth: 0
16 |
17 | - name: "Set up Go"
18 | uses: actions/setup-go@v4
19 | with:
20 | go-version: 1.21.x
21 |
22 | - name: "Create release on GitHub"
23 | uses: goreleaser/goreleaser-action@v4
24 | with:
25 | args: "release --clean"
26 | version: latest
27 | workdir: .
28 | env:
29 | GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
30 | SLACK_WEBHOOK: "${{ secrets.RELEASE_SLACK_WEBHOOK }}"
31 | DISCORD_WEBHOOK_ID: "${{ secrets.DISCORD_WEBHOOK_ID }}"
32 | DISCORD_WEBHOOK_TOKEN: "${{ secrets.DISCORD_WEBHOOK_TOKEN }}"
--------------------------------------------------------------------------------
/.github/workflows/release-test.yml:
--------------------------------------------------------------------------------
1 | name: 🔨 Release Test
2 |
3 | on:
4 | pull_request:
5 | paths:
6 | - '**.go'
7 | - '**.mod'
8 | - '**.yml'
9 | workflow_dispatch:
10 |
11 | jobs:
12 | release-test:
13 | runs-on: ubuntu-latest-16-cores
14 | steps:
15 | - name: "Check out code"
16 | uses: actions/checkout@v3
17 | with:
18 | fetch-depth: 0
19 |
20 | - name: Set up Go
21 | uses: actions/setup-go@v4
22 | with:
23 | go-version: 1.21.x
24 |
25 | - name: release test
26 | uses: goreleaser/goreleaser-action@v4
27 | with:
28 | args: "release --clean --snapshot"
29 | version: latest
30 | workdir: .
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # If you prefer the allow list template instead of the deny list, see community template:
2 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
3 | #
4 | # Binaries for programs and plugins
5 | *.exe
6 | *.exe~
7 | *.dll
8 | *.so
9 | *.dylib
10 |
11 | # Test binary, built with `go test -c`
12 | *.test
13 |
14 | # Output of the go coverage tool, specifically when used with LiteIDE
15 | *.out
16 |
17 | # Dependency directories (remove the comment below to include it)
18 | # vendor/
19 |
20 | # Go workspace file
21 | go.work
22 | /cvemap
23 | /cmd/cvemap/cvemap
24 |
--------------------------------------------------------------------------------
/.goreleaser.yml:
--------------------------------------------------------------------------------
1 | before:
2 | hooks:
3 | - go mod tidy
4 |
5 | builds:
6 | - env:
7 | - CGO_ENABLED=0
8 | goos:
9 | - windows
10 | - linux
11 | - darwin
12 | goarch:
13 | - amd64
14 | - 386
15 | - arm
16 | - arm64
17 |
18 | ignore:
19 | - goos: darwin
20 | goarch: '386'
21 | - goos: windows
22 | goarch: 'arm'
23 | - goos: windows
24 | goarch: 'arm64'
25 |
26 | binary: '{{ .ProjectName }}'
27 | main: cmd/cvemap/main.go
28 |
29 | archives:
30 | - format: zip
31 | name_template: '{{ .ProjectName }}_{{ .Version }}_{{ if eq .Os "darwin" }}macOS{{ else }}{{ .Os }}{{ end }}_{{ .Arch }}'
32 |
33 | checksum:
34 | algorithm: sha256
35 |
36 | announce:
37 | slack:
38 | enabled: true
39 | channel: '#release'
40 | username: GoReleaser
41 | message_template: 'New Release: {{ .ProjectName }} {{.Tag}} is published! Check it out at {{ .ReleaseURL }}'
42 |
43 | discord:
44 | enabled: true
45 | message_template: '**New Release: {{ .ProjectName }} {{.Tag}}** is published! Check it out at {{ .ReleaseURL }}'
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | # Base
2 | FROM golang:1.22.5-alpine AS builder
3 | RUN apk add --no-cache build-base
4 | WORKDIR /app
5 | COPY . /app
6 | RUN go mod download
7 | RUN go build ./cmd/cvemap
8 |
9 | # Release
10 | FROM alpine:3.18.2
11 | RUN apk -U upgrade --no-cache \
12 | && apk add --no-cache bind-tools ca-certificates
13 | COPY --from=builder /app/cvemap /usr/local/bin/
14 |
15 | ENTRYPOINT ["cvemap"]
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 ProjectDiscovery
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # Go parameters
2 | GOCMD=go
3 | GOBUILD=$(GOCMD) build
4 | GOMOD=$(GOCMD) mod
5 | GOTEST=$(GOCMD) test
6 | GOFLAGS := -v
7 | # This should be disabled if the binary uses pprof
8 | LDFLAGS := -s -w
9 |
10 | ifneq ($(shell go env GOOS),darwin)
11 | LDFLAGS := -extldflags "-static"
12 | endif
13 |
14 | all: build
15 | build:
16 | $(GOBUILD) $(GOFLAGS) -ldflags '$(LDFLAGS)' -o "cvemap" cmd/cvemap/main.go
17 | integration:
18 | cd cmd/integration-test; bash run.sh
19 | tidy:
20 | $(GOMOD) tidy
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
153 |
154 | **cvemap** is made with ❤️ by the [projectdiscovery](https://projectdiscovery.io) team and distributed under [MIT License](LICENSE).
155 |
156 |
157 |

--------------------------------------------------------------------------------
/cmd/cvemap/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/projectdiscovery/cvemap/pkg/runner"
5 | "github.com/projectdiscovery/gologger"
6 | )
7 |
8 | func main() {
9 | options := runner.ParseOptions()
10 | runner, err := runner.New(options)
11 | if err != nil {
12 | gologger.Fatal().Msgf("Could not create runner: %s\n", err)
13 | }
14 | runner.Run()
15 | }
16 |
--------------------------------------------------------------------------------
/cmd/integration-test/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "fmt"
6 | "os"
7 | "strings"
8 |
9 | "github.com/logrusorgru/aurora"
10 | "github.com/pkg/errors"
11 | "github.com/projectdiscovery/cvemap/pkg/testutils"
12 | )
13 |
14 | var (
15 | xPDCPHeaderTestKey = "test-67291d9a-0aa6-49b1-b249-2b9d4b45bcea"
16 | debug = os.Getenv("DEBUG") == "true"
17 | success = aurora.Green("[✓]").String()
18 | failed = aurora.Red("[✘]").String()
19 | currentCvemapBinary = flag.String("current", "", "Current Branch Cvemap Binary")
20 | )
21 |
22 | func main() {
23 | flag.Parse()
24 | SetupMockServer()
25 | os.Setenv("CVEMAP_API_URL", "http://localhost:8080/api/v1")
26 | os.Setenv("PDCP_API_KEY", xPDCPHeaderTestKey)
27 | if err := runIntegrationTests(); err != nil {
28 | fmt.Println("Error running integration tests:", err)
29 | }
30 | }
31 |
32 | var testCases = map[string]testutils.TestCase{
33 | "Get By cve_id": &CveIDTestCase{},
34 | }
35 |
36 | type CveIDTestCase struct{}
37 |
38 | func (c *CveIDTestCase) Execute() error {
39 | currentOutput, err := testutils.RunCvemapBinaryAndGetResults(*currentCvemapBinary, debug, []string{"-id", "CVE-1999-0027", "-j", "-silent"})
40 | if err != nil {
41 | return errors.Wrap(err, "could not run cvemap test")
42 | }
43 | if len(currentOutput) == 0 {
44 | return errors.New("no output from cvemap")
45 | }
46 | if strings.Contains(strings.Join(currentOutput, ""), `"cve_id": "CVE-1999-0027"`) {
47 | return nil
48 | }
49 | return errors.New("cve_id not found in output")
50 | }
51 |
52 | func runIntegrationTests() error {
53 |
54 | for testName, testcase := range testCases {
55 | if err := testcase.Execute(); err != nil {
56 | fmt.Fprintf(os.Stderr, "%s Test \"%s\" failed: %s\n", failed, testName, err)
57 | } else {
58 | fmt.Printf("%s Test \"%s\" passed!\n", success, testName)
59 | }
60 | }
61 | return nil
62 | }
63 |
--------------------------------------------------------------------------------
/cmd/integration-test/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # reading os type from arguments
4 | CURRENT_OS=$1
5 |
6 | if [ "${CURRENT_OS}" == "windows-latest" ];then
7 | extension=.exe
8 | fi
9 |
10 | echo "::group::Building integration-test binary"
11 | go build -o integration-test$extension
12 | echo "::endgroup::"
13 |
14 | echo "::group::Building cvemap binary from current branch"
15 | go build -o cvemap$extension ../cvemap
16 | echo "::endgroup::"
17 |
18 |
19 | echo 'Starting cvemap integration test'
20 | ./integration-test$extension -current cvemap$extension
21 |
--------------------------------------------------------------------------------
/cmd/integration-test/server.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "net/http"
7 | "os"
8 |
9 | "github.com/projectdiscovery/cvemap/pkg/types"
10 | )
11 |
12 | var cveData *types.CVEBulkData
13 |
14 | func SetupMockServer() {
15 | var err error
16 | // Load data from the JSON file
17 | cveData, err = loadData("test-data.json")
18 | if err != nil {
19 | fmt.Println("Error loading data:", err)
20 | return
21 | }
22 | // Setup HTTP server
23 | http.HandleFunc("/api/v1/cves", RequireAPIKey(http.HandlerFunc(handleRequest)))
24 |
25 | go func() {
26 | // Start the server on port 8080
27 | fmt.Println("Cvemap test server listening on 8080...")
28 | if err := http.ListenAndServe(":8080", nil); err != nil {
29 | fmt.Println("Error starting server:", err)
30 | }
31 | }()
32 | }
33 |
34 | // RequireAPIKey is a middleware that checks for the X-PDCP-Key header.
35 | func RequireAPIKey(next http.HandlerFunc) http.HandlerFunc {
36 | return func(w http.ResponseWriter, r *http.Request) {
37 | apiKey := r.Header.Get("X-PDCP-Key")
38 | if apiKey != xPDCPHeaderTestKey {
39 | http.Error(w, "Unauthorized: X-PDCP-Key header is required", http.StatusUnauthorized)
40 | return
41 | }
42 | next(w, r)
43 | }
44 | }
45 |
46 | // handleRequest handles HTTP requests.
47 | func handleRequest(w http.ResponseWriter, r *http.Request) {
48 | // Handle the case where "cve_id" is a query parameter
49 | cveID := r.URL.Query().Get("cve_id")
50 | if cveID == "" {
51 | http.NotFound(w, r)
52 | }
53 | for _, data := range cveData.Cves {
54 | if data.CveID == cveID {
55 | // Return the data corresponding to the given CVE ID
56 | if err := json.NewEncoder(w).Encode(cveData); err != nil {
57 | http.Error(w, err.Error(), http.StatusInternalServerError)
58 | }
59 | return
60 | }
61 | }
62 | http.NotFound(w, r)
63 | }
64 |
65 | // LoadData loads data from a JSON file into a slice of CVEData.
66 | func loadData(filename string) (*types.CVEBulkData, error) {
67 | file, err := os.Open(filename)
68 | if err != nil {
69 | return nil, err
70 | }
71 | defer file.Close()
72 |
73 | var data types.CVEBulkData
74 | decoder := json.NewDecoder(file)
75 | if err := decoder.Decode(&data); err != nil {
76 | return nil, err
77 | }
78 |
79 | return &data, nil
80 | }
81 |
--------------------------------------------------------------------------------
/cmd/integration-test/test-data.json:
--------------------------------------------------------------------------------
1 | {
2 | "result_count": 1,
3 | "total_results": 1,
4 | "cves": [
5 | {
6 | "cpe": {
7 | "cpe": "cpe:2.3:o:sgi:irix:*:*:*:*:*:*:*:*",
8 | "vendor": "sgi",
9 | "product": "irix"
10 | },
11 | "epss": {
12 | "epss_score": 0.00064,
13 | "epss_percentile": 0.26181
14 | },
15 | "cve_id": "CVE-1999-0027",
16 | "is_oss": false,
17 | "is_poc": false,
18 | "assignee": "cve@mitre.org",
19 | "severity": "high",
20 | "hackerone": {
21 | "rank": 6320,
22 | "count": 0
23 | },
24 | "is_remote": false,
25 | "reference": [
26 | "https://exchange.xforce.ibmcloud.com/vulnerabilities/CVE-1999-0027",
27 | "https://github.com/Kuromesi/Py4CSKG"
28 | ],
29 | "cvss_score": 7.2,
30 | "updated_at": "2022-08-17T07:15:08.580",
31 | "weaknesses": [
32 | {
33 | "cwe_id": "CWE-119",
34 | "cwe_name": "Improper Restriction of Operations within the Bounds of a Memory Buffer"
35 | }
36 | ],
37 | "age_in_days": 9682,
38 | "is_template": false,
39 | "vuln_status": "modified",
40 | "cvss_metrics": {
41 | "cvss2": {
42 | "score": 7.2,
43 | "vector": "CVSS:2.0/AV:L/AC:L/Au:N/C:C/I:C/A:C",
44 | "severity": "high"
45 | }
46 | },
47 | "is_exploited": false,
48 | "published_at": "1997-07-16T04:00:00.000",
49 | "vulnerable_cpe": [
50 | "cpe:2.3:o:sgi:irix:*:*:*:*:*:*:*:*"
51 | ],
52 | "cve_description": "root privileges via buffer overflow in eject command on SGI IRIX systems.",
53 | "vendor_advisory": ""
54 | }
55 | ]
56 | }
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/projectdiscovery/cvemap
2 |
3 | go 1.21
4 |
5 | require (
6 | github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203
7 | github.com/jedib0t/go-pretty/v6 v6.6.7
8 | github.com/logrusorgru/aurora v2.0.3+incompatible
9 | github.com/pkg/errors v0.9.1
10 | github.com/projectdiscovery/goflags v0.1.71
11 | github.com/projectdiscovery/gologger v1.1.43
12 | github.com/projectdiscovery/retryablehttp-go v1.0.98
13 | github.com/projectdiscovery/utils v0.4.9
14 | )
15 |
16 | require (
17 | aead.dev/minisign v0.2.1 // indirect
18 | github.com/Masterminds/semver/v3 v3.2.1 // indirect
19 | github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057 // indirect
20 | github.com/Mzack9999/go-http-digest-auth-client v0.6.1-0.20220414142836-eb8883508809 // indirect
21 | github.com/VividCortex/ewma v1.2.0 // indirect
22 | github.com/akrylysov/pogreb v0.10.2 // indirect
23 | github.com/alecthomas/chroma/v2 v2.14.0 // indirect
24 | github.com/andybalholm/brotli v1.1.0 // indirect
25 | github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
26 | github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
27 | github.com/aymerick/douceur v0.2.0 // indirect
28 | github.com/bits-and-blooms/bitset v1.13.0 // indirect
29 | github.com/bits-and-blooms/bloom/v3 v3.6.0 // indirect
30 | github.com/charmbracelet/glamour v0.8.0 // indirect
31 | github.com/charmbracelet/lipgloss v0.13.0 // indirect
32 | github.com/charmbracelet/x/ansi v0.3.2 // indirect
33 | github.com/cheggaaa/pb/v3 v3.1.5 // indirect
34 | github.com/cloudflare/circl v1.3.7 // indirect
35 | github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 // indirect
36 | github.com/dimchansky/utfbom v1.1.1 // indirect
37 | github.com/dlclark/regexp2 v1.11.4 // indirect
38 | github.com/docker/go-units v0.5.0 // indirect
39 | github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
40 | github.com/fatih/color v1.16.0 // indirect
41 | github.com/gaissmai/bart v0.9.5 // indirect
42 | github.com/go-ole/go-ole v1.2.6 // indirect
43 | github.com/golang/protobuf v1.5.3 // indirect
44 | github.com/golang/snappy v0.0.4 // indirect
45 | github.com/google/go-github/v30 v30.1.0 // indirect
46 | github.com/google/go-querystring v1.1.0 // indirect
47 | github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
48 | github.com/google/uuid v1.3.1 // indirect
49 | github.com/gorilla/css v1.0.1 // indirect
50 | github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
51 | github.com/json-iterator/go v1.1.12 // indirect
52 | github.com/klauspost/compress v1.17.5 // indirect
53 | github.com/klauspost/pgzip v1.2.6 // indirect
54 | github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
55 | github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
56 | github.com/mattn/go-colorable v0.1.13 // indirect
57 | github.com/mattn/go-isatty v0.0.20 // indirect
58 | github.com/mattn/go-runewidth v0.0.16 // indirect
59 | github.com/mholt/archiver/v3 v3.5.1 // indirect
60 | github.com/microcosm-cc/bluemonday v1.0.27 // indirect
61 | github.com/miekg/dns v1.1.58 // indirect
62 | github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7 // indirect
63 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
64 | github.com/modern-go/reflect2 v1.0.2 // indirect
65 | github.com/muesli/reflow v0.3.0 // indirect
66 | github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a // indirect
67 | github.com/nwaples/rardecode v1.1.3 // indirect
68 | github.com/pierrec/lz4/v4 v4.1.21 // indirect
69 | github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
70 | github.com/projectdiscovery/blackrock v0.0.1 // indirect
71 | github.com/projectdiscovery/fastdialer v0.3.0 // indirect
72 | github.com/projectdiscovery/hmap v0.0.77 // indirect
73 | github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983 // indirect
74 | github.com/projectdiscovery/networkpolicy v0.1.1 // indirect
75 | github.com/projectdiscovery/retryabledns v1.0.94 // indirect
76 | github.com/refraction-networking/utls v1.6.7 // indirect
77 | github.com/rivo/uniseg v0.4.7 // indirect
78 | github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect
79 | github.com/shirou/gopsutil/v3 v3.23.7 // indirect
80 | github.com/shoenig/go-m1cpu v0.1.6 // indirect
81 | github.com/syndtr/goleveldb v1.0.0 // indirect
82 | github.com/tidwall/btree v1.7.0 // indirect
83 | github.com/tidwall/buntdb v1.3.0 // indirect
84 | github.com/tidwall/gjson v1.17.0 // indirect
85 | github.com/tidwall/grect v0.1.4 // indirect
86 | github.com/tidwall/match v1.1.1 // indirect
87 | github.com/tidwall/pretty v1.2.1 // indirect
88 | github.com/tidwall/rtred v0.1.2 // indirect
89 | github.com/tidwall/tinyqueue v0.1.1 // indirect
90 | github.com/tklauser/go-sysconf v0.3.12 // indirect
91 | github.com/tklauser/numcpus v0.6.1 // indirect
92 | github.com/ulikunitz/xz v0.5.11 // indirect
93 | github.com/weppos/publicsuffix-go v0.30.2-0.20230730094716-a20f9abcc222 // indirect
94 | github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
95 | github.com/yuin/goldmark v1.7.4 // indirect
96 | github.com/yuin/goldmark-emoji v1.0.3 // indirect
97 | github.com/yusufpapurcu/wmi v1.2.4 // indirect
98 | github.com/zcalusic/sysinfo v1.0.2 // indirect
99 | github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248 // indirect
100 | github.com/zmap/zcrypto v0.0.0-20231219022726-a1f61fb1661c // indirect
101 | go.etcd.io/bbolt v1.3.8 // indirect
102 | go.uber.org/multierr v1.11.0 // indirect
103 | golang.org/x/crypto v0.31.0 // indirect
104 | golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect
105 | golang.org/x/mod v0.17.0 // indirect
106 | golang.org/x/net v0.33.0 // indirect
107 | golang.org/x/oauth2 v0.16.0 // indirect
108 | golang.org/x/sync v0.11.0 // indirect
109 | golang.org/x/sys v0.30.0 // indirect
110 | golang.org/x/term v0.29.0 // indirect
111 | golang.org/x/text v0.22.0 // indirect
112 | golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
113 | google.golang.org/appengine v1.6.8 // indirect
114 | google.golang.org/protobuf v1.33.0 // indirect
115 | gopkg.in/djherbis/times.v1 v1.3.0 // indirect
116 | gopkg.in/yaml.v3 v3.0.1 // indirect
117 | )
118 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | aead.dev/minisign v0.2.0/go.mod h1:zdq6LdSd9TbuSxchxwhpA9zEb9YXcVGoE8JakuiGaIQ=
2 | aead.dev/minisign v0.2.1 h1:Z+7HA9dsY/eGycYj6kpWHpcJpHtjAwGiJFvbiuO9o+M=
3 | aead.dev/minisign v0.2.1/go.mod h1:oCOjeA8VQNEbuSCFaaUXKekOusa/mll6WtMoO5JY4M4=
4 | cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
5 | github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
6 | github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
7 | github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057 h1:KFac3SiGbId8ub47e7kd2PLZeACxc1LkiiNoDOFRClE=
8 | github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057/go.mod h1:iLB2pivrPICvLOuROKmlqURtFIEsoJZaMidQfCG1+D4=
9 | github.com/Mzack9999/go-http-digest-auth-client v0.6.1-0.20220414142836-eb8883508809 h1:ZbFL+BDfBqegi+/Ssh7im5+aQfBRx6it+kHnC7jaDU8=
10 | github.com/Mzack9999/go-http-digest-auth-client v0.6.1-0.20220414142836-eb8883508809/go.mod h1:upgc3Zs45jBDnBT4tVRgRcgm26ABpaP7MoTSdgysca4=
11 | github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g=
12 | github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow=
13 | github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4=
14 | github.com/akrylysov/pogreb v0.10.2 h1:e6PxmeyEhWyi2AKOBIJzAEi4HkiC+lKyCocRGlnDi78=
15 | github.com/akrylysov/pogreb v0.10.2/go.mod h1:pNs6QmpQ1UlTJKDezuRWmaqkgUE2TuU0YTWyqJZ7+lI=
16 | github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE=
17 | github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
18 | github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E=
19 | github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I=
20 | github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
21 | github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
22 | github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
23 | github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
24 | github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
25 | github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
26 | github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
27 | github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
28 | github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
29 | github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
30 | github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
31 | github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
32 | github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
33 | github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
34 | github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE=
35 | github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
36 | github.com/bits-and-blooms/bloom/v3 v3.6.0 h1:dTU0OVLJSoOhz9m68FTXMFfA39nR8U/nTCs1zb26mOI=
37 | github.com/bits-and-blooms/bloom/v3 v3.6.0/go.mod h1:VKlUSvp0lFIYqxJjzdnSsZEw4iHb1kOL2tfHTgyJBHg=
38 | github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
39 | github.com/charmbracelet/glamour v0.8.0 h1:tPrjL3aRcQbn++7t18wOpgLyl8wrOHUEDS7IZ68QtZs=
40 | github.com/charmbracelet/glamour v0.8.0/go.mod h1:ViRgmKkf3u5S7uakt2czJ272WSg2ZenlYEZXT2x7Bjw=
41 | github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw=
42 | github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY=
43 | github.com/charmbracelet/x/ansi v0.3.2 h1:wsEwgAN+C9U06l9dCVMX0/L3x7ptvY1qmjMwyfE6USY=
44 | github.com/charmbracelet/x/ansi v0.3.2/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
45 | github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a h1:G99klV19u0QnhiizODirwVksQB91TJKV/UaTnACcG30=
46 | github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
47 | github.com/cheggaaa/pb/v3 v3.1.5 h1:QuuUzeM2WsAqG2gMqtzaWithDJv0i+i6UlnwSCI4QLk=
48 | github.com/cheggaaa/pb/v3 v3.1.5/go.mod h1:CrxkeghYTXi1lQBEI7jSn+3svI3cuc19haAj6jM60XI=
49 | github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
50 | github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
51 | github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
52 | github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 h1:ox2F0PSMlrAAiAdknSRMDrAr8mfxPCfSZolH+/qQnyQ=
53 | github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08/go.mod h1:pCxVEbcm3AMg7ejXyorUXi6HQCzOIBf7zEDVPtw0/U4=
54 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
55 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
56 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
57 | github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
58 | github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
59 | github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
60 | github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
61 | github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
62 | github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
63 | github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY=
64 | github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
65 | github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
66 | github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203 h1:XBBHcIb256gUJtLmY22n99HaZTz+r2Z51xUPi01m3wg=
67 | github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203/go.mod h1:E1jcSv8FaEny+OP/5k9UxZVw9YFWGj7eI4KR/iOBqCg=
68 | github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
69 | github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
70 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
71 | github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
72 | github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
73 | github.com/gaissmai/bart v0.9.5 h1:vy+r4Px6bjZ+v2QYXAsg63vpz9IfzdW146A8Cn4GPIo=
74 | github.com/gaissmai/bart v0.9.5/go.mod h1:KHeYECXQiBjTzQz/om2tqn3sZF1J7hw9m6z41ftj3fg=
75 | github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
76 | github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
77 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
78 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
79 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
80 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
81 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
82 | github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
83 | github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
84 | github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
85 | github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
86 | github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
87 | github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
88 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
89 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
90 | github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
91 | github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
92 | github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
93 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
94 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
95 | github.com/google/go-github/v30 v30.1.0 h1:VLDx+UolQICEOKu2m4uAoMti1SxuEBAl7RSEG16L+Oo=
96 | github.com/google/go-github/v30 v30.1.0/go.mod h1:n8jBpHl45a/rlBUtRJMOG4GhNADUQFEufcolZ95JfU8=
97 | github.com/google/go-github/v50 v50.2.0/go.mod h1:VBY8FB6yPIjrtKhozXv4FQupxKLS6H4m6xFZlT43q8Q=
98 | github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
99 | github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
100 | github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
101 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
102 | github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
103 | github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
104 | github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
105 | github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
106 | github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
107 | github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
108 | github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
109 | github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
110 | github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
111 | github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
112 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
113 | github.com/jedib0t/go-pretty/v6 v6.6.7 h1:m+LbHpm0aIAPLzLbMfn8dc3Ht8MW7lsSO4MPItz/Uuo=
114 | github.com/jedib0t/go-pretty/v6 v6.6.7/go.mod h1:YwC5CE4fJ1HFUDeivSV1r//AmANFHyqczZk+U6BDALU=
115 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
116 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
117 | github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
118 | github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
119 | github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
120 | github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
121 | github.com/klauspost/compress v1.17.5 h1:d4vBd+7CHydUqpFBgUEKkSdtSugf9YFmSkvUYPquI5E=
122 | github.com/klauspost/compress v1.17.5/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
123 | github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
124 | github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
125 | github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
126 | github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
127 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
128 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
129 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
130 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
131 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
132 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
133 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
134 | github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
135 | github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
136 | github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
137 | github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
138 | github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
139 | github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
140 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
141 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
142 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
143 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
144 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
145 | github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
146 | github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
147 | github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
148 | github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo=
149 | github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
150 | github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
151 | github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
152 | github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
153 | github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
154 | github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7 h1:yRZGarbxsRytL6EGgbqK2mCY+Lk5MWKQYKJT2gEglhc=
155 | github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7/go.mod h1:bO02GTIPCMQFTEvE5h4DjYB58bCoZ35XLeBf0buTDdM=
156 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
157 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
158 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
159 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
160 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
161 | github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8=
162 | github.com/mreiferson/go-httpclient v0.0.0-20201222173833-5e475fde3a4d/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8=
163 | github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
164 | github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
165 | github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a h1:2MaM6YC3mGu54x+RKAA6JiFFHlHDY1UbkxqppT7wYOg=
166 | github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a/go.mod h1:hxSnBBYLK21Vtq/PHd0S2FYCxBXzBua8ov5s1RobyRQ=
167 | github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
168 | github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc=
169 | github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
170 | github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
171 | github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
172 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
173 | github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
174 | github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
175 | github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
176 | github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
177 | github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
178 | github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
179 | github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
180 | github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
181 | github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
182 | github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
183 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
184 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
185 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
186 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
187 | github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
188 | github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
189 | github.com/projectdiscovery/blackrock v0.0.1 h1:lHQqhaaEFjgf5WkuItbpeCZv2DUIE45k0VbGJyft6LQ=
190 | github.com/projectdiscovery/blackrock v0.0.1/go.mod h1:ANUtjDfaVrqB453bzToU+YB4cUbvBRpLvEwoWIwlTss=
191 | github.com/projectdiscovery/fastdialer v0.3.0 h1:/wMptjdsrAU/wiaA/U3lSgYGaYCGJH6xm0mLei6oMxk=
192 | github.com/projectdiscovery/fastdialer v0.3.0/go.mod h1:Q0YLArvpx9GAfY/NcTPMCA9qZuVOGnuVoNYWzKBwxdQ=
193 | github.com/projectdiscovery/goflags v0.1.71 h1:CmgHQUEo2VCUOypIsSvIa4YlpzIQSIg2bmfyQXYoe48=
194 | github.com/projectdiscovery/goflags v0.1.71/go.mod h1:ikxJf0Jy7tQe13LpvTp0tanRAnqqYIlQlJaikSHnhY8=
195 | github.com/projectdiscovery/gologger v1.1.43 h1:26DOeBUK2xus/UpM8jzHfNqEU5tWams3VGBtjJtI02I=
196 | github.com/projectdiscovery/gologger v1.1.43/go.mod h1:993FxohnjVo34dSgE3bw+L4TOCDNQfQ5zNbK0YhYrEw=
197 | github.com/projectdiscovery/hmap v0.0.77 h1:pI7pmW+CN19LAkMsSFKC0K1SK1+sonto2hwte/7eOaQ=
198 | github.com/projectdiscovery/hmap v0.0.77/go.mod h1:LkV8r/enq9G9HnY2YzMpU4CCmFz3dstOlhmeaObVQfk=
199 | github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983 h1:ZScLodGSezQVwsQDtBSMFp72WDq0nNN+KE/5DHKY5QE=
200 | github.com/projectdiscovery/machineid v0.0.0-20240226150047-2e2c51e35983/go.mod h1:3G3BRKui7nMuDFAZKR/M2hiOLtaOmyukT20g88qRQjI=
201 | github.com/projectdiscovery/networkpolicy v0.1.1 h1:iv9gECukD5KAZp98KVh+T3TEPTkY6dr3sKsdbh9XyZU=
202 | github.com/projectdiscovery/networkpolicy v0.1.1/go.mod h1:/Hg2ieLewSe/BagFF+UYXAQo3NwmVMq16MSAl492XkU=
203 | github.com/projectdiscovery/retryabledns v1.0.94 h1:MvxtRcmvxhxikxT7p/E40hcYRWRiL5fg/JQ8bpBaz+0=
204 | github.com/projectdiscovery/retryabledns v1.0.94/go.mod h1:croGTyMM4yNlrSWA/X7xNe3c0c7mDmCdbm8goLd8Bak=
205 | github.com/projectdiscovery/retryablehttp-go v1.0.98 h1:7wNj+vmx0z9FaQhtX/YRAMv4/1idj+bmFF07QvvEnIo=
206 | github.com/projectdiscovery/retryablehttp-go v1.0.98/go.mod h1:ZS4sDlqTP2YbydUcjqXECdb3AIFvrT466OvcZjN3GlY=
207 | github.com/projectdiscovery/utils v0.4.9 h1:GzYKy5iiCWEZZPGxrtgTOnRTZYiIAiCditGufp0nhGU=
208 | github.com/projectdiscovery/utils v0.4.9/go.mod h1:/68d0OHGgYF4aW4X7kS1qlFlYOnZxgtFDN85iH732JI=
209 | github.com/refraction-networking/utls v1.6.7 h1:zVJ7sP1dJx/WtVuITug3qYUq034cDq9B2MR1K67ULZM=
210 | github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0=
211 | github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
212 | github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
213 | github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
214 | github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
215 | github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA=
216 | github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
217 | github.com/shirou/gopsutil/v3 v3.23.7 h1:C+fHO8hfIppoJ1WdsVm1RoI0RwXoNdfTK7yWXV0wVj4=
218 | github.com/shirou/gopsutil/v3 v3.23.7/go.mod h1:c4gnmoRC0hQuaLqvxnx1//VXQ0Ms/X9UnJF8pddY5z4=
219 | github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
220 | github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
221 | github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
222 | github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
223 | github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
224 | github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
225 | github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
226 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
227 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
228 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
229 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
230 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
231 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
232 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
233 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
234 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
235 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
236 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
237 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
238 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
239 | github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
240 | github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
241 | github.com/tidwall/assert v0.1.0 h1:aWcKyRBUAdLoVebxo95N7+YZVTFF/ASTr7BN4sLP6XI=
242 | github.com/tidwall/assert v0.1.0/go.mod h1:QLYtGyeqse53vuELQheYl9dngGCJQ+mTtlxcktb+Kj8=
243 | github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI=
244 | github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY=
245 | github.com/tidwall/buntdb v1.3.0 h1:gdhWO+/YwoB2qZMeAU9JcWWsHSYU3OvcieYgFRS0zwA=
246 | github.com/tidwall/buntdb v1.3.0/go.mod h1:lZZrZUWzlyDJKlLQ6DKAy53LnG7m5kHyrEHvvcDmBpU=
247 | github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
248 | github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM=
249 | github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
250 | github.com/tidwall/grect v0.1.4 h1:dA3oIgNgWdSspFzn1kS4S/RDpZFLrIxAZOdJKjYapOg=
251 | github.com/tidwall/grect v0.1.4/go.mod h1:9FBsaYRaR0Tcy4UwefBX/UDcDcDy9V5jUcxHzv2jd5Q=
252 | github.com/tidwall/lotsa v1.0.2 h1:dNVBH5MErdaQ/xd9s769R31/n2dXavsQ0Yf4TMEHHw8=
253 | github.com/tidwall/lotsa v1.0.2/go.mod h1:X6NiU+4yHA3fE3Puvpnn1XMDrFZrE9JO2/w+UMuqgR8=
254 | github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
255 | github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
256 | github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
257 | github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
258 | github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
259 | github.com/tidwall/rtred v0.1.2 h1:exmoQtOLvDoO8ud++6LwVsAMTu0KPzLTUrMln8u1yu8=
260 | github.com/tidwall/rtred v0.1.2/go.mod h1:hd69WNXQ5RP9vHd7dqekAz+RIdtfBogmglkZSRxCHFQ=
261 | github.com/tidwall/tinyqueue v0.1.1 h1:SpNEvEggbpyN5DIReaJ2/1ndroY8iyEGxPYxoSaymYE=
262 | github.com/tidwall/tinyqueue v0.1.1/go.mod h1:O/QNHwrnjqr6IHItYrzoHAKYhBkLI67Q096fQP5zMYw=
263 | github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
264 | github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
265 | github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
266 | github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
267 | github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
268 | github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
269 | github.com/twmb/murmur3 v1.1.6/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ=
270 | github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
271 | github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
272 | github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
273 | github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
274 | github.com/weppos/publicsuffix-go v0.13.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
275 | github.com/weppos/publicsuffix-go v0.30.2-0.20230730094716-a20f9abcc222 h1:h2JizvZl9aIj6za9S5AyrkU+OzIS4CetQthH/ejO+lg=
276 | github.com/weppos/publicsuffix-go v0.30.2-0.20230730094716-a20f9abcc222/go.mod h1:s41lQh6dIsDWIC1OWh7ChWJXLH0zkJ9KHZVqA7vHyuQ=
277 | github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
278 | github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
279 | github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU=
280 | github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g=
281 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
282 | github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
283 | github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg=
284 | github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
285 | github.com/yuin/goldmark-emoji v1.0.3 h1:aLRkLHOuBR2czCY4R8olwMjID+tENfhyFDMCRhbIQY4=
286 | github.com/yuin/goldmark-emoji v1.0.3/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U=
287 | github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
288 | github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
289 | github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
290 | github.com/zcalusic/sysinfo v1.0.2 h1:nwTTo2a+WQ0NXwo0BGRojOJvJ/5XKvQih+2RrtWqfxc=
291 | github.com/zcalusic/sysinfo v1.0.2/go.mod h1:kluzTYflRWo6/tXVMJPdEjShsbPpsFRyy+p1mBQPC30=
292 | github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE=
293 | github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248 h1:Nzukz5fNOBIHOsnP+6I79kPx3QhLv8nBy2mfFhBRq30=
294 | github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE=
295 | github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is=
296 | github.com/zmap/zcertificate v0.0.1/go.mod h1:q0dlN54Jm4NVSSuzisusQY0hqDWvu92C+TWveAxiVWk=
297 | github.com/zmap/zcrypto v0.0.0-20201128221613-3719af1573cf/go.mod h1:aPM7r+JOkfL+9qSB4KbYjtoEzJqUK50EXkkJabeNJDQ=
298 | github.com/zmap/zcrypto v0.0.0-20201211161100-e54a5822fb7e/go.mod h1:aPM7r+JOkfL+9qSB4KbYjtoEzJqUK50EXkkJabeNJDQ=
299 | github.com/zmap/zcrypto v0.0.0-20231219022726-a1f61fb1661c h1:U1b4THKcgOpJ+kILupuznNwPiURtwVW3e9alJvji9+s=
300 | github.com/zmap/zcrypto v0.0.0-20231219022726-a1f61fb1661c/go.mod h1:GSDpFDD4TASObxvfZfvpZZ3OWHIUHMlhVWlkOe4ewVk=
301 | github.com/zmap/zlint/v3 v3.0.0/go.mod h1:paGwFySdHIBEMJ61YjoqT4h7Ge+fdYG4sUQhnTb1lJ8=
302 | go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA=
303 | go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
304 | go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
305 | go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
306 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
307 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
308 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
309 | golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
310 | golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
311 | golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
312 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
313 | golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
314 | golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
315 | golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
316 | golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
317 | golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
318 | golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
319 | golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA=
320 | golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
321 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
322 | golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
323 | golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
324 | golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
325 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
326 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
327 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
328 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
329 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
330 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
331 | golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
332 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
333 | golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
334 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
335 | golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
336 | golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
337 | golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
338 | golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
339 | golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
340 | golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
341 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
342 | golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw=
343 | golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ=
344 | golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o=
345 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
346 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
347 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
348 | golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
349 | golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
350 | golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
351 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
352 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
353 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
354 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
355 | golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
356 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
357 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
358 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
359 | golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
360 | golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
361 | golang.org/x/sys v0.0.0-20210228012217-479acdf4ea46/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
362 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
363 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
364 | golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
365 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
366 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
367 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
368 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
369 | golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
370 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
371 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
372 | golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
373 | golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
374 | golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
375 | golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
376 | golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
377 | golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
378 | golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
379 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
380 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
381 | golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
382 | golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
383 | golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
384 | golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
385 | golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
386 | golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
387 | golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
388 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
389 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
390 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
391 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
392 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
393 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
394 | golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
395 | golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
396 | golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
397 | golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
398 | golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
399 | golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
400 | golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
401 | golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
402 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
403 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
404 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
405 | golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
406 | golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
407 | golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
408 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
409 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
410 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
411 | google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
412 | google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
413 | google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
414 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
415 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
416 | google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
417 | google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
418 | google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
419 | google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
420 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
421 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
422 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
423 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
424 | gopkg.in/djherbis/times.v1 v1.3.0 h1:uxMS4iMtH6Pwsxog094W0FYldiNnfY/xba00vq6C2+o=
425 | gopkg.in/djherbis/times.v1 v1.3.0/go.mod h1:AQlg6unIsrsCEdQYhTzERy542dz6SFdQFZFv6mUY0P8=
426 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
427 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
428 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
429 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
430 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
431 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
432 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
433 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
434 |
--------------------------------------------------------------------------------
/pkg/runner/banner.go:
--------------------------------------------------------------------------------
1 | package runner
2 |
3 | import (
4 | "github.com/projectdiscovery/gologger"
5 | "github.com/projectdiscovery/utils/auth/pdcp"
6 | updateutils "github.com/projectdiscovery/utils/update"
7 | )
8 |
9 | const banner = `
10 |
11 | ______ _____ ____ ___ ____ ____
12 | / ___/ | / / _ \/ __ \__ \/ __ \/ __ \
13 | / /__ | |/ / __/ / / / / / /_/ / /_/ /
14 | \___/ |___/\___/_/ /_/ /_/\__,_/ .___/
15 | /_/
16 |
17 | `
18 |
19 | // Version is the current version
20 | const Version = `v0.0.7`
21 |
22 | // showBanner is used to show the banner to the user
23 | func showBanner() {
24 | gologger.Print().Msgf("%s\n", banner)
25 | gologger.Print().Msgf("\t\tprojectdiscovery.io\n\n")
26 | }
27 |
28 | // GetUpdateCallback returns a callback function that updates proxify
29 | func GetUpdateCallback() func() {
30 | return func() {
31 | showBanner()
32 | updateutils.GetUpdateToolCallback("cvemap", Version)()
33 | }
34 | }
35 |
36 | // AuthWithPDCP is used to authenticate with PDCP
37 | func AuthWithPDCP() {
38 | showBanner()
39 | pdcp.CheckNValidateCredentials("cvemap")
40 | }
41 |
--------------------------------------------------------------------------------
/pkg/runner/options.go:
--------------------------------------------------------------------------------
1 | package runner
2 |
3 | import "github.com/projectdiscovery/goflags"
4 |
5 | type Options struct {
6 | PdcpAuth string
7 | CveIds goflags.StringSlice
8 | CweIds goflags.StringSlice
9 | Vendor goflags.StringSlice
10 | Product goflags.StringSlice
11 | Eproduct goflags.StringSlice
12 | Severity goflags.StringSlice
13 | CvssScore goflags.StringSlice
14 | //cvssMetrics goflags.StringSlice
15 | EpssPercentile goflags.StringSlice
16 | //year goflags.StringSlice
17 | Assignees goflags.StringSlice
18 | Reference goflags.StringSlice
19 | //vulnType goflags.StringSlice
20 | IncludeColumns []string
21 | ExcludeColumns []string
22 | TableHeaders []string
23 | ListId bool
24 | EpssScore string
25 | Cpe string
26 | VulnStatus string
27 | Age string
28 | Kev string
29 | //trending bool
30 | Hackerone string
31 | HasNucleiTemplate string
32 | HasPoc string
33 | Search string
34 | RemotlyExploitable string
35 | EnablePageKeys bool
36 | Json bool
37 | Limit int
38 | Offset int
39 | Version bool
40 | DisableUpdateCheck bool
41 | Silent bool
42 | Verbose bool
43 | Debug bool
44 | HealthCheck bool
45 | HTTPProxy string
46 | Output string
47 | }
48 |
--------------------------------------------------------------------------------
/pkg/runner/runner.go:
--------------------------------------------------------------------------------
1 | package runner
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "io"
7 | "net/http"
8 | "net/url"
9 | "os"
10 | "strconv"
11 | "strings"
12 | "sync"
13 |
14 | "github.com/eiannone/keyboard"
15 | "github.com/jedib0t/go-pretty/v6/table"
16 | "github.com/projectdiscovery/cvemap/pkg/service"
17 | "github.com/projectdiscovery/cvemap/pkg/types"
18 | "github.com/projectdiscovery/goflags"
19 | "github.com/projectdiscovery/gologger"
20 | "github.com/projectdiscovery/gologger/levels"
21 | "github.com/projectdiscovery/utils/auth/pdcp"
22 | "github.com/projectdiscovery/utils/env"
23 | fileutil "github.com/projectdiscovery/utils/file"
24 | sliceutil "github.com/projectdiscovery/utils/slice"
25 | updateutils "github.com/projectdiscovery/utils/update"
26 | urlutil "github.com/projectdiscovery/utils/url"
27 | )
28 |
29 | var (
30 | PDCPApiKey = ""
31 | DEFAULT_FEILD_CHAR_LIMIT = env.GetEnvOrDefault("DEFAULT_FEILD_CHAR_LIMIT", 20)
32 | )
33 |
34 | func init() {
35 | pch := pdcp.PDCPCredHandler{}
36 | if os.Getenv("PDCP_API_KEY") != "" {
37 | PDCPApiKey = os.Getenv("PDCP_API_KEY")
38 | } else if creds, err := pch.GetCreds(); err == nil {
39 | PDCPApiKey = creds.APIKey
40 | }
41 | }
42 |
43 | var (
44 | defaultHeaders = []string{"ID", "CVSS", "Severity", "EPSS", "Product", "Age", "Template"}
45 |
46 | headerMap = map[string]string{
47 | "id": "id",
48 | "cwe": "cwe",
49 | "epss": "epss",
50 | "cvss": "cvss",
51 | "severity": "severity",
52 | "vendor": "vendor",
53 | "product": "product",
54 | "vstatus": "vstatus",
55 | "assignee": "assignee",
56 | "age": "age",
57 | "kev": "kev",
58 | "template": "template",
59 | "poc": "poc",
60 | "rank": "rank",
61 | "reports": "reports",
62 | }
63 |
64 | allowedHeader = goflags.AllowdTypes{
65 | "": goflags.EnumVariable(-1),
66 | "cwe": goflags.EnumVariable(0),
67 | "epss": goflags.EnumVariable(1),
68 | "product": goflags.EnumVariable(2),
69 | "vendor": goflags.EnumVariable(3),
70 | "vstatus": goflags.EnumVariable(4),
71 | "assignee": goflags.EnumVariable(5),
72 | "age": goflags.EnumVariable(6),
73 | "kev": goflags.EnumVariable(7),
74 | "template": goflags.EnumVariable(8),
75 | "poc": goflags.EnumVariable(9),
76 | }
77 | allowedHeaderString = allowedHeader.String()
78 |
79 | allowedVstatus = goflags.AllowdTypes{
80 | "": goflags.EnumVariable(-1),
81 | "new": goflags.EnumVariable(0),
82 | "confirmed": goflags.EnumVariable(1),
83 | "unconfirmed": goflags.EnumVariable(2),
84 | "modified": goflags.EnumVariable(3),
85 | "rejected": goflags.EnumVariable(4),
86 | "unknown": goflags.EnumVariable(5),
87 | }
88 |
89 | maxLimit = 300
90 | )
91 |
92 | func ParseOptions() *Options {
93 | var options Options
94 |
95 | flagset := goflags.NewFlagSet()
96 | flagset.SetDescription(`Navigate the CVE jungle with ease.`)
97 |
98 | flagset.CreateGroup("config", "Config",
99 | flagset.DynamicVar(&options.PdcpAuth, "auth", "true", "configure projectdiscovery cloud (pdcp) api key"),
100 | flagset.StringVarP(&options.HTTPProxy, "proxy", "http-proxy", "", "http proxy to use (eg http://127.0.0.1:8080)"),
101 | )
102 |
103 | flagset.CreateGroup("OPTIONS", "options",
104 | // currently only one cve id is supported
105 | flagset.StringSliceVar(&options.CveIds, "id", nil, "cve to list for given id", goflags.FileCommaSeparatedStringSliceOptions),
106 | flagset.StringSliceVarP(&options.CweIds, "cwe-id", "cwe", nil, "cve to list for given cwe id", goflags.CommaSeparatedStringSliceOptions),
107 | flagset.StringSliceVarP(&options.Vendor, "vendor", "v", nil, "cve to list for given vendor", goflags.CommaSeparatedStringSliceOptions),
108 | flagset.StringSliceVarP(&options.Product, "product", "p", nil, "cve to list for given product", goflags.CommaSeparatedStringSliceOptions),
109 | flagset.StringSliceVar(&options.Eproduct, "eproduct", nil, "cves to exclude based on products", goflags.CommaSeparatedStringSliceOptions),
110 | flagset.StringSliceVarP(&options.Severity, "severity", "s", nil, "cve to list for given severity", goflags.CommaSeparatedStringSliceOptions),
111 | flagset.StringSliceVarP(&options.CvssScore, "cvss-score", "cs", nil, "cve to list for given cvss score", goflags.CommaSeparatedStringSliceOptions),
112 | flagset.StringVarP(&options.Cpe, "cpe", "c", "", "cve to list for given cpe"),
113 | flagset.StringVarP(&options.EpssScore, "epss-score", "es", "", "cve to list for given epss score"),
114 | flagset.StringSliceVarP(&options.EpssPercentile, "epss-percentile", "ep", nil, "cve to list for given epss percentile", goflags.CommaSeparatedStringSliceOptions),
115 | flagset.StringVar(&options.Age, "age", "", "cve to list published by given age in days"),
116 | flagset.StringSliceVarP(&options.Assignees, "assignee", "a", nil, "cve to list for given publisher assignee", goflags.CommaSeparatedStringSliceOptions),
117 | //flagset.StringSliceVarP(&options.vulnType, "type", "vt", nil, "cve to list for given vulnerability type", goflags.CommaSeparatedStringSliceOptions),
118 | flagset.EnumVarP(&options.VulnStatus, "vstatus", "vs", goflags.EnumVariable(-1), strings.Replace(fmt.Sprintf("cve to list for given vulnerability status in cli output. supported: %s", allowedVstatus.String()), " ,", "", -1), allowedVstatus),
119 | )
120 |
121 | flagset.CreateGroup("update", "Update",
122 | flagset.CallbackVarP(GetUpdateCallback(), "update", "up", "update cvemap to latest version"),
123 | flagset.BoolVarP(&options.DisableUpdateCheck, "disable-update-check", "duc", false, "disable automatic cvemap update check"),
124 | )
125 |
126 | flagset.CreateGroup("FILTER", "filter",
127 | flagset.StringVarP(&options.Search, "search", "q", "", "search in cve data"),
128 | flagset.DynamicVarP(&options.Kev, "kev", "k", "true", "display cves marked as exploitable vulnerabilities by cisa"),
129 | flagset.DynamicVarP(&options.HasNucleiTemplate, "template", "t", "true", "display cves that has public nuclei templates"),
130 | flagset.DynamicVar(&options.HasPoc, "poc", "true", "display cves that has public published poc"),
131 | flagset.DynamicVarP(&options.Hackerone, "hackerone", "h1", "true", "display cves reported on hackerone"),
132 | flagset.DynamicVarP(&options.RemotlyExploitable, "remote", "re", "true", "display remotely exploitable cves (AV:N & PR:N | PR:L)"),
133 | )
134 |
135 | flagset.CreateGroup("OUTPUT", "output",
136 | flagset.EnumSliceVarP(&options.IncludeColumns, "field", "f", []goflags.EnumVariable{goflags.EnumVariable(-1)}, strings.Replace(fmt.Sprintf("fields to display in cli output. supported: %s", allowedHeaderString), " ,", "", -1), allowedHeader),
137 | flagset.EnumSliceVarP(&options.ExcludeColumns, "exclude", "fe", []goflags.EnumVariable{goflags.EnumVariable(-1)}, strings.Replace(fmt.Sprintf("fields to exclude from cli output. supported: %s", allowedHeaderString), " ,", "", -1), allowedHeader),
138 | flagset.BoolVarP(&options.ListId, "list-id", "lsi", false, "list only the cve ids in the output"),
139 | flagset.IntVarP(&options.Limit, "limit", "l", 50, "limit the number of results to display"),
140 | flagset.IntVar(&options.Offset, "offset", 0, "offset the results to display"),
141 | flagset.BoolVarP(&options.Json, "json", "j", false, "return output in json format"),
142 | flagset.StringVarP(&options.Output, "output", "o", "", "output to file"),
143 | // experimental
144 | flagset.BoolVarP(&options.EnablePageKeys, "enable-page-keys", "epk", false, "enable page keys to navigate results"),
145 | )
146 |
147 | flagset.CreateGroup("DEBUG", "debug",
148 | flagset.BoolVar(&options.Version, "version", false, "Version"),
149 | flagset.BoolVar(&options.Silent, "silent", false, "Silent"),
150 | flagset.BoolVar(&options.Verbose, "verbose", false, "Verbose"),
151 | flagset.BoolVar(&options.Debug, "debug", false, "Debug"),
152 | flagset.BoolVarP(&options.HealthCheck, "health-check", "hc", false, "run diagnostic check up"),
153 | )
154 |
155 | if err := flagset.Parse(); err != nil {
156 | gologger.Fatal().Msgf("Error parsing flags: %s\n", err)
157 | }
158 | if !options.Debug {
159 | options.Debug = env.GetEnvOrDefault("DEBUG", false)
160 | }
161 | if options.Version {
162 | gologger.Info().Msgf("Current Version: %s\n", Version)
163 | os.Exit(0)
164 | }
165 |
166 | if options.HealthCheck {
167 | showBanner()
168 | gologger.Print().Msgf("%s\n", DoHealthCheck(options))
169 | os.Exit(0)
170 | }
171 |
172 | // api key hierarchy: cli flag > env var > .pdcp/credential file
173 | if options.PdcpAuth == "true" {
174 | AuthWithPDCP()
175 | } else if len(options.PdcpAuth) == 36 {
176 | PDCPApiKey = options.PdcpAuth
177 | ph := pdcp.PDCPCredHandler{}
178 | if _, err := ph.GetCreds(); err == pdcp.ErrNoCreds {
179 | apiServer := env.GetEnvOrDefault("PDCP_API_SERVER", pdcp.DefaultApiServer)
180 | if validatedCreds, err := ph.ValidateAPIKey(PDCPApiKey, apiServer, "cvemap"); err == nil {
181 | _ = ph.SaveCreds(validatedCreds)
182 | }
183 | }
184 | }
185 |
186 | if options.Limit > maxLimit {
187 | options.Limit = maxLimit
188 | }
189 |
190 | if fileutil.HasStdin() {
191 | // Read from stdin
192 | bin, err := io.ReadAll(os.Stdin)
193 | if err != nil {
194 | gologger.Fatal().Msgf("couldn't read stdin: %s\n", err)
195 | }
196 | stdinStr := strings.TrimSpace(string(bin))
197 | if stdinStr != "" {
198 | options.CveIds = append(options.CveIds, strings.Split(stdinStr, "\n")...)
199 | }
200 | }
201 |
202 | // make fields case insensitive
203 | for i, cveId := range options.CveIds {
204 | options.CveIds[i] = strings.ToUpper(cveId)
205 | }
206 | for i, cweId := range options.CweIds {
207 | options.CweIds[i] = strings.ToUpper(cweId)
208 | }
209 | for i, severity := range options.Severity {
210 | options.Severity[i] = strings.ToLower(severity)
211 | }
212 | for i, vendor := range options.Vendor {
213 | options.Vendor[i] = strings.ToLower(vendor)
214 | }
215 | for i, product := range options.Product {
216 | options.Product[i] = strings.ToLower(product)
217 | }
218 | for i, eproduct := range options.Eproduct {
219 | options.Eproduct[i] = strings.ToLower(eproduct)
220 | }
221 | return &options
222 | }
223 |
224 | type Runner struct {
225 | Options *Options
226 | CvemapService *service.Cvemap
227 | }
228 |
229 | func New(options *Options) (*Runner, error) {
230 | serviceOpts := &service.Options{
231 | ApiKey: PDCPApiKey,
232 | Debug: options.Debug,
233 | }
234 | if options.HTTPProxy != "" {
235 | proxyURL, parseErr := url.Parse(options.HTTPProxy)
236 | if parseErr != nil {
237 | return nil, parseErr
238 | }
239 | serviceOpts.HttpClient = &http.Client{
240 | Transport: &http.Transport{
241 | Proxy: http.ProxyURL(proxyURL)}}
242 | }
243 | CvemapService, err := service.NewCvemap(serviceOpts)
244 | if err != nil {
245 | return nil, err
246 | }
247 | r := &Runner{
248 | Options: options,
249 | CvemapService: CvemapService,
250 | }
251 | return r, nil
252 | }
253 |
254 | func (r *Runner) Run() {
255 | if r.Options.Silent {
256 | gologger.DefaultLogger.SetMaxLevel(levels.LevelSilent)
257 | } else if r.Options.Verbose {
258 | gologger.DefaultLogger.SetMaxLevel(levels.LevelVerbose)
259 | }
260 |
261 | // Show the user the banner
262 | showBanner()
263 |
264 | if !r.Options.DisableUpdateCheck {
265 | latestVersion, err := updateutils.GetToolVersionCallback("cvemap", Version)()
266 | if err != nil {
267 | if r.Options.Verbose {
268 | gologger.Error().Msgf("cvemap version check failed: %v", err.Error())
269 | }
270 | } else {
271 | gologger.Info().Msgf("Current cvemap version %v %v", Version, updateutils.GetVersionDescription(Version, latestVersion))
272 | }
273 | }
274 |
275 | // on default, enable kev
276 | if isDefaultRun(r.Options) {
277 | r.Options.Kev = "true"
278 | }
279 |
280 | parseHeaders(r.Options)
281 |
282 | if r.Options.EnablePageKeys && len(r.Options.CveIds) == 0 {
283 | r.processWithPageKeyEvents()
284 | } else {
285 | _ = r.process()
286 | }
287 | }
288 |
289 | func (r *Runner) GetCves() (*types.CVEBulkData, error) {
290 | if len(r.Options.CveIds) > 0 {
291 | return r.CvemapService.GetCvesByIds(r.Options.CveIds)
292 | }
293 | if r.Options.Search != "" {
294 | query := constructQueryByOptions(*r.Options)
295 | if r.Options.Debug {
296 | gologger.Print().Msgf("constructed query: %s\n", query)
297 | }
298 | return r.CvemapService.GetCvesBySearchString(query, r.Options.Limit, r.Options.Offset)
299 | }
300 | return r.CvemapService.GetCvesByFilters(constructQueryParams(r.Options))
301 | }
302 |
303 | func (r *Runner) process() *types.CVEBulkData {
304 | var cvesResp *types.CVEBulkData
305 | var err error
306 | cvesResp, err = r.GetCves()
307 | if err != nil {
308 | gologger.Fatal().Msgf("Error getting CVEs: %s\n", err)
309 | return nil
310 | }
311 |
312 | if r.Options.Json {
313 | outputJson(cvesResp.Cves)
314 | return cvesResp
315 | }
316 |
317 | if r.Options.Output != "" {
318 | writeToFile(r.Options.Output, cvesResp.Cves)
319 | }
320 |
321 | nPages := cvesResp.TotalResults / r.Options.Limit
322 | if cvesResp.TotalResults%r.Options.Limit > 0 {
323 | nPages++
324 | }
325 | currentPage := (r.Options.Offset / r.Options.Limit) + 1
326 | if len(r.Options.CveIds) == 0 && (r.Options.Verbose || r.Options.EnablePageKeys) {
327 | gologger.Print().Msgf("\n Limit: %v Page: %v TotalPages: %v TotalResults: %v\n", r.Options.Limit, currentPage, nPages, cvesResp.TotalResults)
328 | }
329 |
330 | if r.Options.ListId {
331 | for _, cve := range cvesResp.Cves {
332 | fmt.Println(cve.CveID)
333 | }
334 | return cvesResp
335 | }
336 |
337 | // limit headers to 10, otherwise it will be too wide
338 | if len(r.Options.TableHeaders) > 10 {
339 | r.Options.TableHeaders = r.Options.TableHeaders[:10]
340 | }
341 |
342 | headers, rows := generateTableData(cvesResp.Cves, r.Options.TableHeaders)
343 |
344 | renderTable(headers, rows)
345 |
346 | if r.Options.EnablePageKeys {
347 | pageString := ""
348 | if currentPage > 1 {
349 | pageString += " ◀ "
350 | }
351 | if currentPage < nPages {
352 | pageString += " ▶"
353 | }
354 | gologger.Print().Msgf("%s", pageString)
355 | }
356 | return cvesResp
357 | }
358 |
359 | func (r *Runner) processWithPageKeyEvents() {
360 | cveResp := r.process()
361 | // wait for user input
362 | err := keyboard.Open()
363 | if err != nil {
364 | panic(err)
365 | }
366 | defer keyboard.Close()
367 | waitGroup := sync.WaitGroup{}
368 | waitGroup.Add(1)
369 |
370 | go func() {
371 | for {
372 | _, key, err := keyboard.GetKey()
373 | if err != nil {
374 | panic(err)
375 | }
376 |
377 | if key == keyboard.KeyEsc || key == keyboard.KeyCtrlC {
378 | waitGroup.Done()
379 | break
380 | }
381 |
382 | switch key {
383 | case keyboard.KeyArrowRight:
384 | if r.Options.Offset+r.Options.Limit < cveResp.TotalResults {
385 | r.Options.Offset += r.Options.Limit
386 | clearScreen()
387 | cveResp = r.process()
388 | }
389 | case keyboard.KeyArrowLeft:
390 | if r.Options.Offset-r.Options.Limit >= 0 {
391 | r.Options.Offset -= r.Options.Limit
392 | clearScreen()
393 | cveResp = r.process()
394 | }
395 | }
396 | }
397 | }()
398 |
399 | waitGroup.Wait()
400 | }
401 |
402 | func parseHeaders(options *Options) {
403 | // construct headers
404 | headers := make([]string, 0)
405 |
406 | if options.Hackerone == "true" {
407 | defaultHeaders = []string{"ID", "CVSS", "Severity", "EPSS", "Rank", "Reports", "Age", "Product", "Template"}
408 | }
409 |
410 | options.IncludeColumns = getValidHeaders(options.IncludeColumns)
411 | options.ExcludeColumns = getValidHeaders(options.ExcludeColumns)
412 |
413 | options.IncludeColumns = append(defaultHeaders, options.IncludeColumns...)
414 | // case insensitive contains check
415 | contains := func(array []string, element string) bool {
416 | for _, e := range array {
417 | if strings.EqualFold(e, element) {
418 | return true
419 | }
420 | }
421 | return false
422 | }
423 | // add headers to display
424 | for _, header := range options.IncludeColumns {
425 | if !contains(options.ExcludeColumns, header) && !contains(headers, header) {
426 | headers = append(headers, header)
427 | }
428 | }
429 | options.TableHeaders = headers
430 | }
431 |
432 | func renderTable(headers []string, rows [][]interface{}) {
433 | // Create a table for displaying CVE data with the specified headers
434 | t := table.NewWriter()
435 | t.SetOutputMirror(os.Stdout)
436 |
437 | // Append the specified headers to the table
438 | headerRow := make([]interface{}, len(headers))
439 | for i, header := range headers {
440 | headerRow[i] = header
441 | }
442 | t.AppendHeader(headerRow)
443 | // Loop through the retrieved CVE data and add rows to the table
444 | for _, row := range rows {
445 | t.AppendRow(row)
446 | }
447 | // t.SetColumnConfigs([]table.ColumnConfig{
448 | // {Number: 5, WidthMax: 20},
449 | // })
450 | // Set table options and render it
451 | t.SetStyle(table.StyleRounded)
452 | t.Render()
453 | }
454 |
455 | func generateTableData(cves []types.CVEData, headers []string) ([]string, [][]interface{}) {
456 | dataRows := make([][]interface{}, len(cves))
457 | for r, cve := range cves {
458 | dataRows[r] = getRow(headers, cve)
459 | }
460 | return headers, dataRows
461 | }
462 |
463 | func getRow(headers []string, cve types.CVEData) []interface{} {
464 | row := make([]interface{}, len(headers))
465 | for i, header := range headers {
466 | switch strings.ToLower(header) {
467 | case "id":
468 | row[i] = getCellValueByLimit(cve.CveID)
469 | case "epss":
470 | row[i] = getCellValueByLimit(cve.Epss.Score)
471 | case "cvss":
472 | row[i] = ""
473 | if cve.CvssMetrics != nil {
474 | row[i] = getCellValueByLimit(getLatestVersionCVSSScore(*cve.CvssMetrics))
475 | }
476 | case "severity":
477 | row[i] = getCellValueByLimit(strings.ToTitle(cve.Severity))
478 | case "cwe":
479 | row[i] = ""
480 | if len(cve.Weaknesses) > 0 {
481 | row[i] = getCellValueByLimit(cve.Weaknesses[0].CWEID)
482 | }
483 | case "vendor":
484 | row[i] = ""
485 | if cve.Cpe != nil {
486 | row[i] = getCellValueByLimit(*cve.Cpe.Vendor)
487 | }
488 | case "product":
489 | row[i] = ""
490 | if cve.Cpe != nil {
491 | row[i] = getCellValueByLimit(*cve.Cpe.Product)
492 | }
493 | case "vstatus":
494 | row[i] = getCellValueByLimit(strings.ToUpper(cve.VulnStatus))
495 | case "assignee":
496 | row[i] = ""
497 | if len(cve.Assignee) > 0 {
498 | row[i] = getCellValueByLimit(cve.Assignee)
499 | }
500 | case "age":
501 | row[i] = ""
502 | if cve.AgeInDays > 0 {
503 | row[i] = getCellValueByLimit(cve.AgeInDays)
504 | }
505 | case "kev":
506 | row[i] = getCellValueByLimit(strings.ToUpper(strconv.FormatBool(cve.IsKev)))
507 | case "template":
508 | if cve.IsTemplate {
509 | row[i] = "✅"
510 | } else {
511 | row[i] = "❌"
512 | }
513 | case "poc":
514 | row[i] = getCellValueByLimit(strings.ToUpper(strconv.FormatBool(cve.IsPoc)))
515 | case "rank":
516 | row[i] = ""
517 | if cve.Hackerone.Rank > 0 {
518 | row[i] = getCellValueByLimit(cve.Hackerone.Rank)
519 | }
520 | case "reports":
521 | row[i] = getCellValueByLimit(cve.Hackerone.Count)
522 |
523 | default:
524 | row[i] = ""
525 | }
526 | }
527 | return row
528 | }
529 |
530 | func getCellValueByLimit(cell interface{}) string {
531 | if cell == nil {
532 | return ""
533 | }
534 | cellValue := fmt.Sprintf("%v", cell)
535 | if len(cellValue) > DEFAULT_FEILD_CHAR_LIMIT {
536 | cellValue = cellValue[:DEFAULT_FEILD_CHAR_LIMIT] + "..."
537 | }
538 | return cellValue
539 | }
540 |
541 | func outputJson(cve []types.CVEData) {
542 | json, err := json.MarshalIndent(cve, "", " ")
543 | if err != nil {
544 | gologger.Error().Msgf("Error marshalling json: %s\n", err)
545 | return
546 | }
547 | gologger.Silent().Msgf("%s\n", string(json))
548 | }
549 |
550 | func writeToFile(filename string, cves []types.CVEData) {
551 | file, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
552 | if err != nil {
553 | gologger.Fatal().Msgf("failed to open or create file: %v", err)
554 | }
555 | defer file.Close()
556 | json, err := json.MarshalIndent(cves, "", " ")
557 | if err != nil {
558 | gologger.Error().Msgf("Error marshalling json: %s\n", err)
559 | }
560 | // Write to the file
561 | _, err = file.WriteString(string(json))
562 | if err != nil {
563 | gologger.Fatal().Msgf("failed to write to file: %v", err)
564 | }
565 | }
566 |
567 | func constructQueryParams(opts *Options) string {
568 | queryParams := urlutil.NewOrderedParams()
569 | if len(opts.Severity) > 0 {
570 | addQueryParams(queryParams, "severity", opts.Severity)
571 | }
572 | if len(opts.Assignees) > 0 {
573 | addQueryParams(queryParams, "assignee", opts.Assignees)
574 | }
575 | if len(opts.CvssScore) > 0 {
576 | var cvsKey string
577 | for _, cvssScore := range opts.CvssScore {
578 | cvsKey = "cvss_score"
579 | if cvssScore[0] == '>' {
580 | cvsKey = "cvss_score_gte"
581 | cvssScore = strings.TrimSpace(cvssScore[1:])
582 | } else if cvssScore[0] == '<' {
583 | cvsKey = "cvss_score_lte"
584 | cvssScore = strings.TrimSpace(cvssScore[1:])
585 | }
586 | queryParams.Add(cvsKey, cvssScore)
587 | }
588 | }
589 |
590 | if len(opts.Age) > 0 {
591 | ageKey := "age_in_days"
592 | if opts.Age[0] == '>' {
593 | ageKey = "age_in_days_gte"
594 | opts.Age = strings.TrimSpace(opts.Age[1:])
595 | } else if opts.Age[0] == '<' {
596 | ageKey = "age_in_days_lte"
597 | opts.Age = strings.TrimSpace(opts.Age[1:])
598 | }
599 | queryParams.Add(ageKey, opts.Age)
600 | }
601 | if len(opts.VulnStatus) > 0 {
602 | queryParams.Add("vuln_status", strings.ToLower(opts.VulnStatus))
603 | }
604 | if len(opts.Reference) > 0 {
605 | addQueryParams(queryParams, "reference", opts.Reference)
606 | }
607 | if len(opts.EpssScore) > 0 {
608 | epssKey := "epss.epss_score"
609 | if opts.EpssScore[0] == '>' {
610 | epssKey = "epss.epss_score_gte"
611 | opts.EpssScore = strings.TrimSpace(opts.EpssScore[1:])
612 | } else if opts.EpssScore[0] == '<' {
613 | epssKey = "epss.epss_score_lte"
614 | opts.EpssScore = strings.TrimSpace(opts.EpssScore[1:])
615 | }
616 | queryParams.Add(epssKey, opts.EpssScore)
617 | }
618 | if len(opts.EpssPercentile) > 0 {
619 | var epKey string
620 | for _, ep := range opts.EpssPercentile {
621 | epKey = "epss.epss_percentile"
622 | if ep[0] == '>' {
623 | epKey = "epss.epss_percentile_gte"
624 | ep = strings.TrimSpace(ep[1:])
625 | } else if ep[0] == '<' {
626 | epKey = "epss.epss_percentile_lte"
627 | ep = strings.TrimSpace(ep[1:])
628 | }
629 | queryParams.Add(epKey, ep)
630 | }
631 | }
632 | if len(opts.CweIds) > 0 {
633 | addQueryParams(queryParams, "weaknesses.$.cwe_id", opts.CweIds)
634 | }
635 | if len(opts.Cpe) > 0 {
636 | queryParams.Add("cpe.cpe", opts.Cpe)
637 | }
638 | if len(opts.Product) > 0 {
639 | addQueryParams(queryParams, "cpe.product", opts.Product)
640 | }
641 | if len(opts.Eproduct) > 0 {
642 | addQueryParams(queryParams, "cpe.product_ne", opts.Eproduct)
643 | }
644 | if len(opts.Vendor) > 0 {
645 | addQueryParams(queryParams, "cpe.vendor", opts.Vendor)
646 | }
647 | if opts.Kev == "true" {
648 | queryParams.Add("is_exploited", "true")
649 | } else if opts.Kev == "false" {
650 | queryParams.Add("is_exploited", "false")
651 | }
652 | if opts.HasNucleiTemplate == "true" {
653 | queryParams.Add("is_template", "true")
654 | } else if opts.HasNucleiTemplate == "false" {
655 | queryParams.Add("is_template", "false")
656 | }
657 | if opts.HasPoc == "true" {
658 | queryParams.Add("is_poc", "true")
659 | } else if opts.HasPoc == "false" {
660 | queryParams.Add("is_poc", "false")
661 | }
662 | if opts.RemotlyExploitable == "true" {
663 | queryParams.Add("is_remote", "true")
664 | }
665 | subQuery := ""
666 | if opts.Hackerone == "true" {
667 | subQuery = "hackerone.rank_gte=1"
668 | subQuery += "&sort_asc=hackerone.rank"
669 | } else {
670 | subQuery = "sort_desc=cve_id"
671 | }
672 | if opts.Limit > 0 {
673 | if len(subQuery) > 0 {
674 | subQuery += "&"
675 | }
676 | subQuery += fmt.Sprintf("limit=%d", opts.Limit)
677 | }
678 | if opts.Offset >= 0 {
679 | if len(subQuery) > 0 {
680 | subQuery += "&"
681 | }
682 | subQuery += fmt.Sprintf("offset=%d", opts.Offset)
683 | }
684 | query := queryParams.Encode()
685 | if len(opts.CweIds) == 1 {
686 | if len(query) > 0 && len(subQuery) > 0 {
687 | query += "&"
688 | }
689 | return query + subQuery
690 | }
691 | if len(query) > 0 && len(subQuery) > 0 {
692 | query = "&" + query
693 | }
694 | return subQuery + query
695 | }
696 |
697 | func constructQueryByOptions(opts Options) string {
698 | query := opts.Search
699 | if len(opts.Vendor) > 0 {
700 | query = fmt.Sprintf("%s cpe.vendor:%s", query, strings.Join(opts.Vendor, ","))
701 | }
702 | if len(opts.Product) > 0 {
703 | query = fmt.Sprintf("%s cpe.product:%s", query, strings.Join(opts.Product, ","))
704 | }
705 | if len(opts.Eproduct) > 0 {
706 | query = fmt.Sprintf("%s cpe.product_ne:%s", query, strings.Join(opts.Eproduct, ","))
707 | }
708 | if len(opts.Severity) > 0 {
709 | query = fmt.Sprintf("%s severity:%s", query, strings.Join(opts.Severity, ","))
710 | }
711 | if len(opts.CvssScore) > 0 {
712 | var cvsKey string
713 | for _, cvssScore := range opts.CvssScore {
714 | cvsKey = "cvss_score"
715 | if cvssScore[0] == '>' {
716 | cvsKey = "cvss_score_gte"
717 | cvssScore = strings.TrimSpace(cvssScore[1:])
718 | } else if cvssScore[0] == '<' {
719 | cvsKey = "cvss_score_lte"
720 | cvssScore = strings.TrimSpace(cvssScore[1:])
721 | }
722 | query = fmt.Sprintf("%s %s:%s", query, cvsKey, cvssScore)
723 | }
724 | }
725 | if len(opts.EpssScore) > 0 {
726 | epssKey := "epss.epss_score"
727 | if opts.EpssScore[0] == '>' {
728 | epssKey = "epss.epss_score_gte"
729 | opts.EpssScore = strings.TrimSpace(opts.EpssScore[1:])
730 | } else if opts.EpssScore[0] == '<' {
731 | epssKey = "epss.epss_score_lte"
732 | opts.EpssScore = strings.TrimSpace(opts.EpssScore[1:])
733 | }
734 | query = fmt.Sprintf("%s %s:%s", query, epssKey, opts.EpssScore)
735 | }
736 | if len(opts.EpssPercentile) > 0 {
737 | var epKey string
738 | for _, ep := range opts.EpssPercentile {
739 | epKey = "epss.epss_percentile"
740 | if ep[0] == '>' {
741 | epKey = "epss.epss_percentile_gte"
742 | ep = strings.TrimSpace(ep[1:])
743 | } else if ep[0] == '<' {
744 | epKey = "epss.epss_percentile_lte"
745 | ep = strings.TrimSpace(ep[1:])
746 | }
747 | query = fmt.Sprintf("%s %s:%s", query, epKey, ep)
748 | }
749 | }
750 | if len(opts.Cpe) > 0 {
751 | query = fmt.Sprintf(`%s cpe.cpe:"%s"`, query, opts.Cpe)
752 | }
753 | if len(opts.CweIds) > 0 {
754 | query = fmt.Sprintf("%s %s:%s", query, "weaknesses.$.cwe_id", strings.Join(opts.CweIds, ","))
755 | }
756 | if len(opts.Age) > 0 {
757 | ageKey := "age_in_days"
758 | if opts.Age[0] == '>' {
759 | ageKey = "age_in_days_gte"
760 | opts.Age = strings.TrimSpace(opts.Age[1:])
761 | } else if opts.Age[0] == '<' {
762 | ageKey = "age_in_days_lte"
763 | opts.Age = strings.TrimSpace(opts.Age[1:])
764 | }
765 | query = fmt.Sprintf("%s %s:%s", query, ageKey, opts.Age)
766 | }
767 | if len(opts.Assignees) > 0 {
768 | query = fmt.Sprintf("%s assignee:%s", query, strings.Join(opts.Assignees, ","))
769 | }
770 | if len(opts.VulnStatus) > 0 {
771 | query = fmt.Sprintf("%s vuln_status:%s", query, strings.ToLower(opts.VulnStatus))
772 | }
773 | if opts.Kev == "true" {
774 | query = fmt.Sprintf("%s is_exploited:true", query)
775 | } else if opts.Kev == "false" {
776 | query = fmt.Sprintf("%s is_exploited:false", query)
777 | }
778 | if opts.HasNucleiTemplate == "true" {
779 | query = fmt.Sprintf("%s is_template:true", query)
780 | } else if opts.HasNucleiTemplate == "false" {
781 | query = fmt.Sprintf("%s is_template:false", query)
782 | }
783 | if opts.HasPoc == "true" {
784 | query = fmt.Sprintf("%s is_poc:true", query)
785 | } else if opts.HasPoc == "false" {
786 | query = fmt.Sprintf("%s is_poc:false", query)
787 | }
788 | if opts.Hackerone == "true" {
789 | query = fmt.Sprintf("%s hackerone.rank_gte:1 sort_asc:hackerone.rank", query)
790 | } else {
791 | query = fmt.Sprintf("%s sort_desc:cve_id", query)
792 | }
793 | if opts.RemotlyExploitable == "true" {
794 | query = fmt.Sprintf("%s is_remote:true", query)
795 | }
796 |
797 | parts := strings.Split(query, " ")
798 | parts = sliceutil.PruneEmptyStrings(parts)
799 | parts = sliceutil.Dedupe(parts)
800 | query = strings.Join(parts, " ")
801 | return query
802 | }
803 |
804 | func addQueryParams(queryParams *urlutil.OrderedParams, key string, values []string) *urlutil.OrderedParams {
805 | if len(values) > 0 {
806 | for _, value := range values {
807 | queryParams.Add(key, value)
808 | }
809 | }
810 | return queryParams
811 | }
812 |
813 | func getValidHeaders(keys []string) []string {
814 | headers := []string{}
815 | for _, hk := range keys {
816 | if v, ok := headerMap[hk]; ok {
817 | headers = append(headers, v)
818 | }
819 | }
820 | return headers
821 | }
822 |
--------------------------------------------------------------------------------
/pkg/runner/util.go:
--------------------------------------------------------------------------------
1 | package runner
2 |
3 | import (
4 | "fmt"
5 | "net"
6 | "os"
7 | "os/exec"
8 | "runtime"
9 | "strings"
10 |
11 | "github.com/projectdiscovery/cvemap/pkg/types"
12 | fileutil "github.com/projectdiscovery/utils/file"
13 | )
14 |
15 | func DoHealthCheck(opts Options) string {
16 | var test strings.Builder
17 | test.WriteString(fmt.Sprintf("Version: %s\n", Version))
18 | test.WriteString(fmt.Sprintf("Operating System: %s\n", runtime.GOOS))
19 | test.WriteString(fmt.Sprintf("Architecture: %s\n", runtime.GOARCH))
20 | test.WriteString(fmt.Sprintf("Go Version: %s\n", runtime.Version()))
21 | test.WriteString(fmt.Sprintf("Compiler: %s\n", runtime.Compiler))
22 |
23 | var testResult string
24 | c4, err := net.Dial("tcp4", "cve.projectdiscovery.io:443")
25 | if err == nil && c4 != nil {
26 | c4.Close()
27 | }
28 | testResult = "Ok"
29 | if err != nil {
30 | testResult = fmt.Sprintf("Ko (%s)", err)
31 | }
32 | test.WriteString(fmt.Sprintf("IPv4 connectivity to cve.projectdiscovery.io:443 => %s\n", testResult))
33 |
34 | u4, err := net.Dial("udp4", "cve.projectdiscovery.io:53")
35 | if err == nil && u4 != nil {
36 | u4.Close()
37 | }
38 | testResult = "Ok"
39 | if err != nil {
40 | testResult = fmt.Sprintf("Ko (%s)", err)
41 | }
42 | test.WriteString(fmt.Sprintf("IPv4 UDP connectivity to cve.projectdiscovery.io:53 => %s\n", testResult))
43 | return test.String()
44 | }
45 |
46 | func getLatestVersionCVSSScore(cvss types.CvssMetrics) float64 {
47 | var highestScore float64
48 | if cvss.Cvss2 != nil {
49 | highestScore = cvss.Cvss2.Score
50 | }
51 | if cvss.Cvss30 != nil {
52 | highestScore = cvss.Cvss30.Score
53 | }
54 | if cvss.Cvss31 != nil {
55 | highestScore = cvss.Cvss31.Score
56 | }
57 | return highestScore
58 | }
59 |
60 | func isDefaultRun(opts *Options) bool {
61 | options := len(opts.CveIds) == 0 && len(opts.CweIds) == 0 && len(opts.Vendor) == 0 && len(opts.Product) == 0 && len(opts.Severity) == 0 && len(opts.CvssScore) == 0 && len(opts.EpssPercentile) == 0 && len(opts.Assignees) == 0 && len(opts.Reference) == 0 && opts.EpssScore == "" && opts.Cpe == "" && opts.VulnStatus == "" && opts.Age == ""
62 | filters := opts.Kev == "" && opts.Hackerone == "" && opts.HasNucleiTemplate == "" && opts.HasPoc == "" && opts.RemotlyExploitable == "" && opts.Search == ""
63 | return options && filters && !fileutil.HasStdin()
64 | }
65 |
66 | // clearScreen clears the terminal screen
67 | func clearScreen() {
68 | var cmd *exec.Cmd
69 | if runtime.GOOS == "windows" {
70 | cmd = exec.Command("cls")
71 | } else {
72 | cmd = exec.Command("clear")
73 | }
74 | cmd.Stdout = os.Stdout
75 | _ = cmd.Run()
76 | }
77 |
--------------------------------------------------------------------------------
/pkg/service/cvemap.go:
--------------------------------------------------------------------------------
1 | package service
2 |
3 | import (
4 | "bytes"
5 | "encoding/json"
6 | "fmt"
7 | "net/http"
8 | "net/url"
9 | "strings"
10 |
11 | "github.com/projectdiscovery/cvemap/pkg/types"
12 | "github.com/projectdiscovery/gologger"
13 | "github.com/projectdiscovery/retryablehttp-go"
14 | "github.com/projectdiscovery/utils/env"
15 | errorutil "github.com/projectdiscovery/utils/errors"
16 | )
17 |
18 | const xPDCPHeaderKey = "X-PDCP-Key"
19 |
20 | var (
21 | BaseUrl = env.GetEnvOrDefault("CVEMAP_API_URL", "https://cve.projectdiscovery.io/api/v1")
22 | ErrUnAuthorized = errorutil.New(`unauthorized: 401 (get your free api key from https://cloud.projectdiscovery.io)`)
23 | )
24 |
25 | type Cvemap struct {
26 | opts *Options
27 | client *retryablehttp.Client
28 | }
29 |
30 | type Options struct {
31 | // ApiKey is the api key for the cvemap api
32 | ApiKey string
33 | // RetryableHttpOptions contains options for the http client (optional)
34 | RetryableHttpOptions *retryablehttp.Options
35 | // HttpClient is the http client to use (optional)
36 | HttpClient *http.Client
37 | // Debug is a flag that enables debugging output
38 | Debug bool
39 | }
40 |
41 | func NewCvemap(opts *Options) (*Cvemap, error) {
42 | if opts == nil {
43 | return nil, fmt.Errorf("Options cannot be nil")
44 | }
45 | if opts.ApiKey == "" {
46 | return nil, fmt.Errorf("api key cannot be empty")
47 | }
48 | clientOpts := retryablehttp.DefaultOptionsSingle
49 | if opts.RetryableHttpOptions != nil {
50 | clientOpts = *opts.RetryableHttpOptions
51 | }
52 | if opts.HttpClient != nil {
53 | clientOpts.HttpClient = opts.HttpClient
54 | }
55 | httpClient := retryablehttp.NewClient(clientOpts)
56 |
57 | return &Cvemap{
58 | opts: opts,
59 | client: httpClient,
60 | }, nil
61 | }
62 |
63 | func (c *Cvemap) GetCvesByIds(cveIds []string) (*types.CVEBulkData, error) {
64 | url := fmt.Sprintf("%s/cves", BaseUrl)
65 | // send only 100 cve ids max
66 | if len(cveIds) > 100 {
67 | cveIds = cveIds[:100]
68 | }
69 | var cveIdList types.CVEIdList
70 | cveIdList.Cves = append(cveIdList.Cves, cveIds...)
71 | reqData, err := json.Marshal(cveIdList)
72 | if err != nil {
73 | return nil, err
74 | }
75 | // Send an HTTP POST request
76 | req, err := retryablehttp.NewRequest("POST", url, bytes.NewBuffer(reqData))
77 | if err != nil {
78 | return nil, err
79 | }
80 | req.Header.Set("Content-Type", "application/json")
81 | req.Header.Set(xPDCPHeaderKey, c.opts.ApiKey)
82 |
83 | response, err := c.doRequest(req)
84 | if err != nil {
85 | return nil, err
86 | }
87 | defer response.Body.Close()
88 | // Check the response status code
89 | if response.StatusCode != http.StatusOK {
90 | return nil, errorutil.New("unexpected status code: %d", response.StatusCode)
91 | }
92 | var cvesInBulk types.CVEBulkData
93 | // Decode the JSON response into an array of CVEData structs
94 | err = json.NewDecoder(response.Body).Decode(&cvesInBulk)
95 | if err != nil {
96 | return nil, err
97 | }
98 | return &cvesInBulk, nil
99 | }
100 |
101 | func (c *Cvemap) GetCvesByFilters(encodedParams string) (*types.CVEBulkData, error) {
102 | url := fmt.Sprintf("%s/cves?%s", BaseUrl, encodedParams)
103 | // Send an HTTP GET request
104 | response, err := c.makeGetRequest(url)
105 | if err != nil {
106 | return nil, err
107 | }
108 | defer response.Body.Close()
109 | // Check the response status code
110 | if response.StatusCode != http.StatusOK {
111 | return nil, errorutil.New("unexpected status code: %d", response.StatusCode)
112 | }
113 | // Create a variable to store the response data
114 | var cvesInBulk types.CVEBulkData
115 | // Decode the JSON response into an array of CVEData structs
116 | err = json.NewDecoder(response.Body).Decode(&cvesInBulk)
117 | if err != nil {
118 | return nil, err
119 | }
120 | return &cvesInBulk, nil
121 | }
122 |
123 | func (c *Cvemap) GetCvesBySearchString(query string, limit, offset int) (*types.CVEBulkData, error) {
124 | u, err := url.Parse(fmt.Sprintf("%s/cves/search", BaseUrl))
125 | if err != nil {
126 | return nil, err
127 | }
128 | // Construct query parameters
129 | q := u.Query()
130 | q.Set("q", query)
131 | q.Set("limit", fmt.Sprintf("%v", limit))
132 | q.Set("offset", fmt.Sprintf("%v", offset))
133 | u.RawQuery = q.Encode()
134 | response, err := c.makeGetRequest(u.String())
135 | if err != nil {
136 | return nil, err
137 | }
138 | defer response.Body.Close()
139 | // Check the response status code
140 | if response.StatusCode != http.StatusOK {
141 | return nil, errorutil.New("unexpected status code: %d", response.StatusCode)
142 | }
143 | // Create a variable to store the response data
144 | var cvesInBulk types.CVEBulkData
145 | // Decode the JSON response into an array of CVEData structs
146 | err = json.NewDecoder(response.Body).Decode(&cvesInBulk)
147 | if err != nil {
148 | return nil, err
149 | }
150 | return &cvesInBulk, nil
151 | }
152 |
153 | // all the root level fields are supported
154 | func (c *Cvemap) GetCvesForSpecificFields(fields []string, encodedParams string, limit, offset int) (*types.CVEBulkData, error) {
155 | url := fmt.Sprintf("%s/cves?fields=%s&%s&limit=%v&offset=%v", BaseUrl, strings.Join(fields, ","), encodedParams, limit, offset)
156 | // Send an HTTP GET request
157 | response, err := c.makeGetRequest(url)
158 | if err != nil {
159 | return nil, err
160 | }
161 | defer response.Body.Close()
162 | // Check the response status code
163 | if response.StatusCode != http.StatusOK {
164 | return nil, errorutil.New("unexpected status code: %d", response.StatusCode)
165 | }
166 | // Create a variable to store the response data
167 | var cvesInBulk types.CVEBulkData
168 | // Decode the JSON response into an array of CVEData structs
169 | err = json.NewDecoder(response.Body).Decode(&cvesInBulk)
170 | if err != nil {
171 | return nil, err
172 | }
173 | return &cvesInBulk, nil
174 | }
175 |
176 | func (c *Cvemap) makeGetRequest(url string) (*http.Response, error) {
177 | req, err := retryablehttp.NewRequest("GET", url, nil)
178 | if err != nil {
179 | gologger.Fatal().Msgf("Error creating request: %s\n", err)
180 | }
181 | req.Header.Set(xPDCPHeaderKey, c.opts.ApiKey)
182 | return c.doRequest(req)
183 | }
184 |
185 | func (c *Cvemap) doRequest(req *retryablehttp.Request) (*http.Response, error) {
186 | if c.opts.Debug {
187 | // dump request
188 | dump, err := req.Dump()
189 | if err != nil {
190 | gologger.Fatal().Msgf("Error dumping request: %s\n", err)
191 | }
192 | gologger.Print().Msgf("%s\n", string(dump))
193 | }
194 | resp, err := c.client.Do(req)
195 |
196 | if err == nil && resp.StatusCode != http.StatusOK {
197 | if resp.StatusCode == http.StatusUnauthorized {
198 | return nil, ErrUnAuthorized
199 | }
200 | if c.opts.Debug {
201 | var errResp types.ErrorMessage
202 | err = json.NewDecoder(resp.Body).Decode(&errResp)
203 | if err == nil {
204 | return nil, errorutil.New("error %d: %s\n", resp.StatusCode, errResp.Message)
205 | }
206 | }
207 | }
208 | return resp, err
209 | }
210 |
--------------------------------------------------------------------------------
/pkg/testutils/util.go:
--------------------------------------------------------------------------------
1 | package testutils
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "os/exec"
7 | "strings"
8 | )
9 |
10 | // RunCvemapßBinaryAndGetResults returns a list of the results
11 | func RunCvemapBinaryAndGetResults(cvemapBinary string, debug bool, args []string) ([]string, error) {
12 | cmd := exec.Command("bash", "-c")
13 | cmdLine := fmt.Sprintf(`./%s `, cvemapBinary)
14 | cmdLine += strings.Join(args, " ")
15 | if debug {
16 | os.Setenv("DEBUG", "1")
17 | cmd.Stderr = os.Stderr
18 | }
19 | cmd.Args = append(cmd.Args, cmdLine)
20 | data, err := cmd.Output()
21 | if err != nil {
22 | return nil, err
23 | }
24 | parts := []string{}
25 | items := strings.Split(string(data), "\n")
26 | for _, i := range items {
27 | if i != "" {
28 | parts = append(parts, i)
29 | }
30 | }
31 | return parts, nil
32 | }
33 |
34 | // TestCase is a single integration test case
35 | type TestCase interface {
36 | // Execute executes a test case and returns any errors if occurred
37 | Execute() error
38 | }
39 |
--------------------------------------------------------------------------------
/pkg/types/types.go:
--------------------------------------------------------------------------------
1 | package types
2 |
3 | import "time"
4 |
5 | type CVEBulkData struct {
6 | ResultCount int `json:"result_count"`
7 | TotalResults int `json:"total_results"`
8 | Cves []CVEData `json:"cves"`
9 | }
10 |
11 | type CVEData struct {
12 | CveID string `json:"cve_id,omitempty"`
13 | CveDescription string `json:"cve_description,omitempty"`
14 | Severity string `json:"severity,omitempty"`
15 | CvssScore float64 `json:"cvss_score,omitempty"`
16 | CvssMetrics *CvssMetrics `json:"cvss_metrics,omitempty"`
17 | Weaknesses []struct {
18 | CWEID string `json:"cwe_id"`
19 | CWEName string `json:"cwe_name,omitempty"`
20 | } `json:"weaknesses,omitempty"`
21 | Epss struct {
22 | Score float64 `json:"epss_score"`
23 | Percentile float64 `json:"epss_percentile"`
24 | } `json:"epss,omitempty"`
25 | Cpe *OutputCpe `json:"cpe,omitempty"`
26 | Reference []string `json:"reference,omitempty"`
27 | Poc []struct {
28 | URL string `json:"url"`
29 | Source string `json:"source"`
30 | AddedAt string `json:"added_at"`
31 | } `json:"poc,omitempty"`
32 | VendorAdvisory *string `json:"vendor_advisory,omitempty"`
33 | Patch []string `json:"patch_url,omitempty"`
34 | IsTemplate bool `json:"is_template"`
35 | NucleiTemplates *NucleiTemplates `json:"nuclei_templates,omitempty"`
36 | IsKev bool `json:"is_exploited"`
37 | Kev *KevObject `json:"kev,omitempty"`
38 | Assignee string `json:"assignee,omitempty"`
39 | PublishedAt string `json:"published_at,omitempty"`
40 | UpdatedAt string `json:"updated_at,omitempty"`
41 | Hackerone struct {
42 | Rank int `json:"rank"`
43 | Count int `json:"count"`
44 | } `json:"hackerone,omitempty"`
45 | AgeInDays int `json:"age_in_days"`
46 | VulnStatus string `json:"vuln_status,omitempty"`
47 | IsPoc bool `json:"is_poc"`
48 | IsRemote bool `json:"is_remote"`
49 | IsOss bool `json:"is_oss"`
50 | VulnerableCPE []string `json:"vulnerable_cpe,omitempty"`
51 | Shodan *OutputShodanData `json:"shodan,omitempty"`
52 | OSS *OSS `json:"oss,omitempty"`
53 | }
54 |
55 | type CvssMetrics struct {
56 | Cvss2 *Cvss2 `json:"cvss2,omitempty"`
57 | Cvss30 *Cvss30 `json:"cvss30,omitempty"`
58 | Cvss31 *Cvss31 `json:"cvss31,omitempty"`
59 | }
60 |
61 | type Cvss2 struct {
62 | Score float64 `json:"score"`
63 | Vector string `json:"vector"`
64 | Severity string `json:"severity"`
65 | }
66 |
67 | type Cvss30 struct {
68 | Score float64 `json:"score"`
69 | Vector string `json:"vector"`
70 | Severity string `json:"severity"`
71 | }
72 |
73 | type Cvss31 struct {
74 | Score float64 `json:"score"`
75 | Vector string `json:"vector"`
76 | Severity string `json:"severity"`
77 | }
78 |
79 | type NucleiTemplates struct {
80 | TemplateIssue string `json:"template_issue,omitempty"`
81 | TemplateIssueType string `json:"template_issue_type,omitempty"`
82 | TemplatePath string `json:"template_path,omitempty"`
83 | TemplatePR string `json:"template_pr,omitempty"`
84 | TemplateURL string `json:"template_url,omitempty"`
85 | CreatedAt *time.Time `json:"created_at,omitempty"`
86 | UpdatedAt *time.Time `json:"updated_at,omitempty"`
87 | }
88 |
89 | type OSS struct {
90 | AllLanguages map[string]int `json:"all_languages,omitempty"`
91 | Description string `json:"description,omitempty"`
92 | Forks int `json:"forks,omitempty"`
93 | Language string `json:"language,omitempty"`
94 | Stars int `json:"stars,omitempty"`
95 | Subscribers int `json:"subscribers,omitempty"`
96 | Topics []string `json:"topics,omitempty"`
97 | PushedAt CustomTime `json:"pushed_at,omitempty"`
98 | CreatedAt CustomTime `json:"created_at,omitempty"`
99 | UpdatedAt CustomTime `json:"updated_at,omitempty"`
100 | URL string `json:"url,omitempty"`
101 | }
102 |
103 | type CustomTime struct {
104 | time.Time
105 | }
106 |
107 | func (ct *CustomTime) UnmarshalJSON(b []byte) error {
108 | s := string(b)
109 | if s == "null" {
110 | return nil
111 | }
112 | t, err := time.Parse(`"2006-01-02 15:04:05 -0700 MST"`, s)
113 | if err != nil {
114 | return err
115 | }
116 | ct.Time = t
117 | return nil
118 | }
119 |
120 | type OutputCpe struct {
121 | Cpe *string `json:"cpe,omitempty"`
122 | Vendor *string `json:"vendor,omitempty"`
123 | Product *string `json:"product,omitempty"`
124 | Platform *string `json:"framework,omitempty"`
125 | }
126 |
127 | type KevObject struct {
128 | AddedDate string `json:"added_date"`
129 | DueDate string `json:"due_date"`
130 | KnownRansomwareCampaignUse bool `json:"known_ransomware_campaign_use"`
131 | }
132 |
133 | type OutputShodanData struct {
134 | Count int `json:"count"`
135 | Query []string `json:"query"`
136 | }
137 |
138 | type ErrorMessage struct {
139 | Message string `json:"message"`
140 | }
141 |
142 | type CVEIdList struct {
143 | Cves []string `json:"cves"`
144 | }
145 |
--------------------------------------------------------------------------------
/static/cvemap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/projectdiscovery/cvemap/0ec6ce6c5d9b2740566a7fa52a35483c744b2cb2/static/cvemap.png
--------------------------------------------------------------------------------