From c0a5528aaffa911984a9fd24a956fcc39d480afe Mon Sep 17 00:00:00 2001
From: sandeep <8293321+ehsandeep@users.noreply.github.com>
Date: Tue, 23 Jan 2024 16:47:37 +0530
Subject: [PATCH] initial release
---
.github/ISSUE_TEMPLATE/config.yml | 14 +
.github/ISSUE_TEMPLATE/feature_request.md | 18 +
.github/ISSUE_TEMPLATE/issue-report.md | 36 +
.github/dependabot.yml | 45 ++
.github/release.yml | 17 +
.github/workflows/build-test.yml | 63 ++
.github/workflows/codeql-analysis.yml | 38 +
.github/workflows/dep-auto-merge.yml | 26 +
.github/workflows/dockerhub-push.yml | 40 +
.github/workflows/lint-test.yml | 28 +
.github/workflows/release-binary.yml | 32 +
.github/workflows/release-test.yml | 30 +
.gitignore | 21 +
.goreleaser.yml | 45 ++
LICENSE | 21 +
README.md | 153 ++++
cmd/cvemap/main.go | 8 +
cmd/integration-test/main.go | 62 ++
cmd/integration-test/run.sh | 20 +
cmd/integration-test/server.go | 80 ++
cmd/integration-test/test-data.json | 56 ++
go.mod | 104 +++
go.sum | 388 ++++++++++
runner/banner.go | 40 +
runner/options.go | 43 ++
runner/runner.go | 865 ++++++++++++++++++++++
runner/testutils/util.go | 38 +
runner/types.go | 143 ++++
runner/util.go | 41 +
static/cvemap.png | Bin 0 -> 1471774 bytes
30 files changed, 2515 insertions(+)
create mode 100644 .github/ISSUE_TEMPLATE/config.yml
create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md
create mode 100644 .github/ISSUE_TEMPLATE/issue-report.md
create mode 100644 .github/dependabot.yml
create mode 100644 .github/release.yml
create mode 100644 .github/workflows/build-test.yml
create mode 100644 .github/workflows/codeql-analysis.yml
create mode 100644 .github/workflows/dep-auto-merge.yml
create mode 100644 .github/workflows/dockerhub-push.yml
create mode 100644 .github/workflows/lint-test.yml
create mode 100644 .github/workflows/release-binary.yml
create mode 100644 .github/workflows/release-test.yml
create mode 100644 .gitignore
create mode 100644 .goreleaser.yml
create mode 100644 LICENSE
create mode 100644 README.md
create mode 100644 cmd/cvemap/main.go
create mode 100644 cmd/integration-test/main.go
create mode 100644 cmd/integration-test/run.sh
create mode 100644 cmd/integration-test/server.go
create mode 100644 cmd/integration-test/test-data.json
create mode 100644 go.mod
create mode 100644 go.sum
create mode 100644 runner/banner.go
create mode 100644 runner/options.go
create mode 100644 runner/runner.go
create mode 100644 runner/testutils/util.go
create mode 100644 runner/types.go
create mode 100644 runner/util.go
create mode 100644 static/cvemap.png
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000..9db7326
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,14 @@
+blank_issues_enabled: false
+
+contact_links:
+ - name: Ask an question / advise on using cvemap
+ url: https://github.com/projectdiscovery/cvemap/discussions/categories/q-a
+ about: Ask a question or request support for using cvemap
+
+ - name: Share idea / feature to discuss for cvemap
+ url: https://github.com/projectdiscovery/cvemap/discussions/categories/ideas
+ about: Share idea / feature to discuss for cvemap
+
+ - name: Connect with PD Team (Discord)
+ url: https://discord.gg/projectdiscovery
+ about: Connect with PD Team for direct communication
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..a44c78a
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,18 @@
+---
+name: Feature request
+about: Request feature to implement in this project
+labels: 'Type: Enhancement'
+---
+
+
+
+### Please describe your feature request:
+
+
+### Describe the use case of this feature:
+
diff --git a/.github/ISSUE_TEMPLATE/issue-report.md b/.github/ISSUE_TEMPLATE/issue-report.md
new file mode 100644
index 0000000..1cad67e
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/issue-report.md
@@ -0,0 +1,36 @@
+---
+name: Issue report
+about: Create a report to help us to improve the project
+labels: 'Type: Bug'
+
+---
+
+
+
+
+
+### cvemap version:
+
+
+
+
+### Current Behavior:
+
+
+### Expected Behavior:
+
+
+### Steps To Reproduce:
+
+
+
+### Anything else:
+
\ No newline at end of file
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..f9ecf8d
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,45 @@
+# To get started with Dependabot version updates, you'll need to specify which
+# package ecosystems to update and where the package manifests are located.
+# Please see the documentation for all configuration options:
+# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
+
+version: 2
+updates:
+
+ # Maintain dependencies for go modules
+ - package-ecosystem: "gomod"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ target-branch: "main"
+ commit-message:
+ prefix: "chore"
+ include: "scope"
+ labels:
+ - "Type: Maintenance"
+ allow:
+ - dependency-name: "github.com/projectdiscovery/*"
+
+# # Maintain dependencies for docker
+# - package-ecosystem: "docker"
+# directory: "/"
+# schedule:
+# interval: "weekly"
+# target-branch: "dev"
+# commit-message:
+# prefix: "chore"
+# include: "scope"
+# labels:
+# - "Type: Maintenance"
+#
+# # Maintain dependencies for GitHub Actions
+# - package-ecosystem: "github-actions"
+# directory: "/"
+# schedule:
+# interval: "weekly"
+# target-branch: "dev"
+# commit-message:
+# prefix: "chore"
+# include: "scope"
+# labels:
+# - "Type: Maintenance"
\ No newline at end of file
diff --git a/.github/release.yml b/.github/release.yml
new file mode 100644
index 0000000..596ba07
--- /dev/null
+++ b/.github/release.yml
@@ -0,0 +1,17 @@
+changelog:
+ exclude:
+ authors:
+ - dependabot
+ categories:
+ - title: 🎉 New Features
+ labels:
+ - "Type: Enhancement"
+ - title: 🐞 Bugs Fixes
+ labels:
+ - "Type: Bug"
+ - title: 🔨 Maintenance
+ labels:
+ - "Type: Maintenance"
+ - title: Other Changes
+ labels:
+ - "*"
\ No newline at end of file
diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml
new file mode 100644
index 0000000..8bd137d
--- /dev/null
+++ b/.github/workflows/build-test.yml
@@ -0,0 +1,63 @@
+name: 🔨 Build Test
+
+on:
+ pull_request:
+ paths:
+ - '**.go'
+ - '**.mod'
+ workflow_dispatch:
+
+jobs:
+ build:
+ name: Test Builds
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ os: [ubuntu-latest, windows-latest, macOS-latest]
+ go-version: [1.21.x]
+ steps:
+ - name: Set up Go
+ uses: actions/setup-go@v4
+ with:
+ go-version: ${{ matrix.go-version }}
+
+ - name: Check out code
+ uses: actions/checkout@v3
+
+ - name: Build
+ run: go build .
+ working-directory: cmd/cvemap/
+
+ - name: Test
+ run: go test ./...
+ working-directory: .
+
+ - name: Integration Tests Linux, macOS
+ if: runner.os == 'Linux' || runner.os == 'macOS'
+ env:
+ GH_ACTION: true
+ run: bash run.sh
+ working-directory: cmd/integration-test/
+
+ - name: Integration Tests Windows
+ if: runner.os == 'Windows'
+ env:
+ GH_ACTION: true
+ MSYS_NO_PATHCONV: true
+ run: bash run.sh
+ working-directory: cmd/integration-test/
+
+ - name: Race Condition Tests
+ if: github.actor != 'dependabot[bot]'
+ run: go run -race . -id CVE-1999-0027
+ working-directory: cmd/cvemap/
+ env:
+ PDCP_API_KEY: "${{ secrets.PDCP_API_KEY }}"
+ PDCP_API_SERVER: https://api.projectdiscovery.io
+ DEBUG: true
+
+ # - name: Test Example Code
+ # run: go run .
+ # working-directory: examples/
+
+
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
new file mode 100644
index 0000000..9f533f8
--- /dev/null
+++ b/.github/workflows/codeql-analysis.yml
@@ -0,0 +1,38 @@
+name: 🚨 CodeQL Analysis
+
+on:
+ workflow_dispatch:
+ pull_request:
+ branches:
+ - dev
+
+jobs:
+ analyze:
+ name: Analyze
+ runs-on: ubuntu-latest
+ permissions:
+ actions: read
+ contents: read
+ security-events: write
+
+ strategy:
+ fail-fast: false
+ matrix:
+ language: [ 'go' ]
+ # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v2
+ with:
+ languages: ${{ matrix.language }}
+
+ - name: Autobuild
+ uses: github/codeql-action/autobuild@v2
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v2
\ No newline at end of file
diff --git a/.github/workflows/dep-auto-merge.yml b/.github/workflows/dep-auto-merge.yml
new file mode 100644
index 0000000..fc26472
--- /dev/null
+++ b/.github/workflows/dep-auto-merge.yml
@@ -0,0 +1,26 @@
+name: 🤖 dep auto merge
+
+on:
+ pull_request:
+ branches:
+ - main
+ workflow_dispatch:
+
+permissions:
+ pull-requests: write
+ issues: write
+ repository-projects: write
+
+jobs:
+ automerge:
+ runs-on: ubuntu-latest
+ if: github.actor == 'dependabot[bot]'
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ token: ${{ secrets.DEPENDABOT_PAT }}
+
+ - uses: ahmadnassri/action-dependabot-auto-merge@v2
+ with:
+ github-token: ${{ secrets.DEPENDABOT_PAT }}
+ target: all
\ No newline at end of file
diff --git a/.github/workflows/dockerhub-push.yml b/.github/workflows/dockerhub-push.yml
new file mode 100644
index 0000000..1e9f341
--- /dev/null
+++ b/.github/workflows/dockerhub-push.yml
@@ -0,0 +1,40 @@
+name: 🌥 Docker Push
+
+on:
+ workflow_run:
+ workflows: ["🎉 Release Binary"]
+ types:
+ - completed
+ workflow_dispatch:
+
+jobs:
+ docker:
+ runs-on: ubuntu-latest-16-cores
+ steps:
+ - name: Git Checkout
+ uses: actions/checkout@v3
+
+ - name: Get Github tag
+ id: meta
+ run: |
+ curl --silent "https://api.github.com/repos/projectdiscovery/cvemap/releases/latest" | jq -r .tag_name | xargs -I {} echo TAG={} >> $GITHUB_OUTPUT
+
+ - name: Set up QEMU
+ uses: docker/setup-qemu-action@v2
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v2
+
+ - name: Login to DockerHub
+ uses: docker/login-action@v2
+ with:
+ username: ${{ secrets.DOCKER_USERNAME }}
+ password: ${{ secrets.DOCKER_TOKEN }}
+
+ - name: Build and push
+ uses: docker/build-push-action@v4
+ with:
+ context: .
+ platforms: linux/amd64,linux/arm64,linux/arm
+ push: true
+ tags: projectdiscovery/cvemap:latest,projectdiscovery/cvemap:${{ steps.meta.outputs.TAG }}
\ No newline at end of file
diff --git a/.github/workflows/lint-test.yml b/.github/workflows/lint-test.yml
new file mode 100644
index 0000000..57d31cf
--- /dev/null
+++ b/.github/workflows/lint-test.yml
@@ -0,0 +1,28 @@
+name: 🙏🏻 Lint Test
+
+on:
+ pull_request:
+ paths:
+ - '**.go'
+ - '**.mod'
+ workflow_dispatch:
+
+jobs:
+ lint:
+ name: Lint Test
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v3
+
+ - name: "Set up Go"
+ uses: actions/setup-go@v4
+ with:
+ go-version: 1.21.x
+
+ - name: Run golangci-lint
+ uses: golangci/golangci-lint-action@v3.6.0
+ with:
+ version: latest
+ args: --timeout 5m
+ working-directory: .
\ No newline at end of file
diff --git a/.github/workflows/release-binary.yml b/.github/workflows/release-binary.yml
new file mode 100644
index 0000000..b17ae06
--- /dev/null
+++ b/.github/workflows/release-binary.yml
@@ -0,0 +1,32 @@
+name: 🎉 Release Binary
+on:
+ push:
+ tags:
+ - '*'
+ workflow_dispatch:
+
+jobs:
+ release:
+ runs-on: ubuntu-latest-16-cores
+ steps:
+ - name: "Check out code"
+ uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+
+ - name: "Set up Go"
+ uses: actions/setup-go@v4
+ with:
+ go-version: 1.21.x
+
+ - name: "Create release on GitHub"
+ uses: goreleaser/goreleaser-action@v4
+ with:
+ args: "release --clean"
+ version: latest
+ workdir: .
+ env:
+ GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
+ SLACK_WEBHOOK: "${{ secrets.RELEASE_SLACK_WEBHOOK }}"
+ DISCORD_WEBHOOK_ID: "${{ secrets.DISCORD_WEBHOOK_ID }}"
+ DISCORD_WEBHOOK_TOKEN: "${{ secrets.DISCORD_WEBHOOK_TOKEN }}"
\ No newline at end of file
diff --git a/.github/workflows/release-test.yml b/.github/workflows/release-test.yml
new file mode 100644
index 0000000..3cc2909
--- /dev/null
+++ b/.github/workflows/release-test.yml
@@ -0,0 +1,30 @@
+name: 🔨 Release Test
+
+on:
+ pull_request:
+ paths:
+ - '**.go'
+ - '**.mod'
+ - '**.yml'
+ workflow_dispatch:
+
+jobs:
+ release-test:
+ runs-on: ubuntu-latest-16-cores
+ steps:
+ - name: "Check out code"
+ uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+
+ - name: Set up Go
+ uses: actions/setup-go@v4
+ with:
+ go-version: 1.21.x
+
+ - name: release test
+ uses: goreleaser/goreleaser-action@v4
+ with:
+ args: "release --clean --snapshot"
+ version: latest
+ workdir: .
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3b735ec
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,21 @@
+# If you prefer the allow list template instead of the deny list, see community template:
+# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
+#
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, built with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# Dependency directories (remove the comment below to include it)
+# vendor/
+
+# Go workspace file
+go.work
diff --git a/.goreleaser.yml b/.goreleaser.yml
new file mode 100644
index 0000000..a5a7834
--- /dev/null
+++ b/.goreleaser.yml
@@ -0,0 +1,45 @@
+before:
+ hooks:
+ - go mod tidy
+
+builds:
+- env:
+ - CGO_ENABLED=0
+ goos:
+ - windows
+ - linux
+ - darwin
+ goarch:
+ - amd64
+ - 386
+ - arm
+ - arm64
+
+ ignore:
+ - goos: darwin
+ goarch: '386'
+ - goos: windows
+ goarch: 'arm'
+ - goos: windows
+ goarch: 'arm64'
+
+ binary: '{{ .ProjectName }}'
+ main: cmd/cvemap/main.go
+
+archives:
+- format: zip
+ name_template: '{{ .ProjectName }}_{{ .Version }}_{{ if eq .Os "darwin" }}macOS{{ else }}{{ .Os }}{{ end }}_{{ .Arch }}'
+
+checksum:
+ algorithm: sha256
+
+announce:
+ slack:
+ enabled: true
+ channel: '#release'
+ username: GoReleaser
+ message_template: 'New Release: {{ .ProjectName }} {{.Tag}} is published! Check it out at {{ .ReleaseURL }}'
+
+ discord:
+ enabled: true
+ message_template: '**New Release: {{ .ProjectName }} {{.Tag}}** is published! Check it out at {{ .ReleaseURL }}'
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..822f480
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 ProjectDiscovery
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..2d33510
--- /dev/null
+++ b/README.md
@@ -0,0 +1,153 @@
+
+
+**cvemap** is made with ❤️ by the [projectdiscovery](https://projectdiscovery.io) team and distributed under [MIT License](LICENSE).
+
+
+
![Join Discord](https://raw.githubusercontent.com/projectdiscovery/nuclei-burp-plugin/main/static/join-discord.png)
\ No newline at end of file
diff --git a/cmd/cvemap/main.go b/cmd/cvemap/main.go
new file mode 100644
index 0000000..44f71ed
--- /dev/null
+++ b/cmd/cvemap/main.go
@@ -0,0 +1,8 @@
+package main
+
+import "github.com/projectdiscovery/cvemap/runner"
+
+func main() {
+ options := runner.ParseOptions()
+ runner.Run(*options)
+}
diff --git a/cmd/integration-test/main.go b/cmd/integration-test/main.go
new file mode 100644
index 0000000..61831a5
--- /dev/null
+++ b/cmd/integration-test/main.go
@@ -0,0 +1,62 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "os"
+ "strings"
+
+ "github.com/logrusorgru/aurora"
+ "github.com/pkg/errors"
+ "github.com/projectdiscovery/cvemap/runner/testutils"
+)
+
+var (
+ xPDCPHeaderTestKey = "test-67291d9a-0aa6-49b1-b249-2b9d4b45bcea"
+ debug = os.Getenv("DEBUG") == "true"
+ success = aurora.Green("[✓]").String()
+ failed = aurora.Red("[✘]").String()
+ currentCvemapBinary = flag.String("current", "", "Current Branch Cvemap Binary")
+)
+
+func main() {
+ flag.Parse()
+ SetupMockServer()
+ os.Setenv("CVEMAP_API_URL", "http://localhost:8080/api/v1")
+ os.Setenv("PDCP_API_KEY", xPDCPHeaderTestKey)
+ if err := runIntegrationTests(); err != nil {
+ fmt.Println("Error running integration tests:", err)
+ }
+}
+
+var testCases = map[string]testutils.TestCase{
+ "Get By cve_id": &CveIDTestCase{},
+}
+
+type CveIDTestCase struct{}
+
+func (c *CveIDTestCase) Execute() error {
+ currentOutput, err := testutils.RunCvemapBinaryAndGetResults(*currentCvemapBinary, debug, []string{"-id", "CVE-1999-0027", "-j", "-silent"})
+ if err != nil {
+ return errors.Wrap(err, "could not run cvemap test")
+ }
+ if len(currentOutput) == 0 {
+ return errors.New("no output from cvemap")
+ }
+ if strings.Contains(strings.Join(currentOutput, ""), `"cve_id": "CVE-1999-0027"`) {
+ return nil
+ }
+ return errors.New("cve_id not found in output")
+}
+
+func runIntegrationTests() error {
+
+ for testName, testcase := range testCases {
+ if err := testcase.Execute(); err != nil {
+ fmt.Fprintf(os.Stderr, "%s Test \"%s\" failed: %s\n", failed, testName, err)
+ } else {
+ fmt.Printf("%s Test \"%s\" passed!\n", success, testName)
+ }
+ }
+ return nil
+}
diff --git a/cmd/integration-test/run.sh b/cmd/integration-test/run.sh
new file mode 100644
index 0000000..488deca
--- /dev/null
+++ b/cmd/integration-test/run.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# reading os type from arguments
+CURRENT_OS=$1
+
+if [ "${CURRENT_OS}" == "windows-latest" ];then
+ extension=.exe
+fi
+
+echo "::group::Building integration-test binary"
+go build -o integration-test$extension
+echo "::endgroup::"
+
+echo "::group::Building cvemap binary from current branch"
+go build -o cvemap$extension ../cvemap
+echo "::endgroup::"
+
+
+echo 'Starting cvemap integration test'
+./integration-test$extension -current cvemap$extension
diff --git a/cmd/integration-test/server.go b/cmd/integration-test/server.go
new file mode 100644
index 0000000..f09c025
--- /dev/null
+++ b/cmd/integration-test/server.go
@@ -0,0 +1,80 @@
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "os"
+
+ "github.com/projectdiscovery/cvemap/runner"
+)
+
+var cveData *runner.CVEBulkData
+
+func SetupMockServer() {
+ var err error
+ // Load data from the JSON file
+ cveData, err = loadData("test-data.json")
+ if err != nil {
+ fmt.Println("Error loading data:", err)
+ return
+ }
+ // Setup HTTP server
+ http.HandleFunc("/api/v1/cves", RequireAPIKey(http.HandlerFunc(handleRequest)))
+
+ go func() {
+ // Start the server on port 8080
+ fmt.Println("Cvemap test server listening on 8080...")
+ if err := http.ListenAndServe(":8080", nil); err != nil {
+ fmt.Println("Error starting server:", err)
+ }
+ }()
+}
+
+// RequireAPIKey is a middleware that checks for the X-PDCP-Key header.
+func RequireAPIKey(next http.HandlerFunc) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ apiKey := r.Header.Get("X-PDCP-Key")
+ if apiKey != xPDCPHeaderTestKey {
+ http.Error(w, "Unauthorized: X-PDCP-Key header is required", http.StatusUnauthorized)
+ return
+ }
+ next(w, r)
+ }
+}
+
+// handleRequest handles HTTP requests.
+func handleRequest(w http.ResponseWriter, r *http.Request) {
+ // Handle the case where "cve_id" is a query parameter
+ cveID := r.URL.Query().Get("cve_id")
+ if cveID == "" {
+ http.NotFound(w, r)
+ }
+ for _, data := range cveData.Cves {
+ if data.CveID == cveID {
+ // Return the data corresponding to the given CVE ID
+ if err := json.NewEncoder(w).Encode(cveData); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ }
+ return
+ }
+ }
+ http.NotFound(w, r)
+}
+
+// LoadData loads data from a JSON file into a slice of CVEData.
+func loadData(filename string) (*runner.CVEBulkData, error) {
+ file, err := os.Open(filename)
+ if err != nil {
+ return nil, err
+ }
+ defer file.Close()
+
+ var data runner.CVEBulkData
+ decoder := json.NewDecoder(file)
+ if err := decoder.Decode(&data); err != nil {
+ return nil, err
+ }
+
+ return &data, nil
+}
diff --git a/cmd/integration-test/test-data.json b/cmd/integration-test/test-data.json
new file mode 100644
index 0000000..056693b
--- /dev/null
+++ b/cmd/integration-test/test-data.json
@@ -0,0 +1,56 @@
+{
+ "result_count": 1,
+ "total_results": 1,
+ "cves": [
+ {
+ "cpe": {
+ "cpe": "cpe:2.3:o:sgi:irix:*:*:*:*:*:*:*:*",
+ "vendor": "sgi",
+ "product": "irix"
+ },
+ "epss": {
+ "epss_score": 0.00064,
+ "epss_percentile": 0.26181
+ },
+ "cve_id": "CVE-1999-0027",
+ "is_oss": false,
+ "is_poc": false,
+ "assignee": "cve@mitre.org",
+ "severity": "high",
+ "hackerone": {
+ "rank": 6320,
+ "count": 0
+ },
+ "is_remote": false,
+ "reference": [
+ "https://exchange.xforce.ibmcloud.com/vulnerabilities/CVE-1999-0027",
+ "https://github.com/Kuromesi/Py4CSKG"
+ ],
+ "cvss_score": 7.2,
+ "updated_at": "2022-08-17T07:15:08.580",
+ "weaknesses": [
+ {
+ "cwe_id": "CWE-119",
+ "cwe_name": "Improper Restriction of Operations within the Bounds of a Memory Buffer"
+ }
+ ],
+ "age_in_days": 9682,
+ "is_template": false,
+ "vuln_status": "modified",
+ "cvss_metrics": {
+ "cvss2": {
+ "score": 7.2,
+ "vector": "CVSS:2.0/AV:L/AC:L/Au:N/C:C/I:C/A:C",
+ "severity": "high"
+ }
+ },
+ "is_exploited": false,
+ "published_at": "1997-07-16T04:00:00.000",
+ "vulnerable_cpe": [
+ "cpe:2.3:o:sgi:irix:*:*:*:*:*:*:*:*"
+ ],
+ "cve_description": "root privileges via buffer overflow in eject command on SGI IRIX systems.",
+ "vendor_advisory": ""
+ }
+ ]
+}
\ No newline at end of file
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..2e044c9
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,104 @@
+module github.com/projectdiscovery/cvemap
+
+go 1.21
+
+require (
+ github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203
+ github.com/jedib0t/go-pretty/v6 v6.4.7
+ github.com/logrusorgru/aurora v2.0.3+incompatible
+ github.com/pkg/errors v0.9.1
+ github.com/projectdiscovery/goflags v0.1.36
+ github.com/projectdiscovery/gologger v1.1.12
+ github.com/projectdiscovery/utils v0.0.74
+)
+
+require (
+ aead.dev/minisign v0.2.0 // indirect
+ github.com/Masterminds/semver/v3 v3.2.1 // indirect
+ github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057 // indirect
+ github.com/Mzack9999/go-http-digest-auth-client v0.6.1-0.20220414142836-eb8883508809 // indirect
+ github.com/VividCortex/ewma v1.2.0 // indirect
+ github.com/akrylysov/pogreb v0.10.1 // indirect
+ github.com/alecthomas/chroma v0.10.0 // indirect
+ github.com/andybalholm/brotli v1.0.6 // indirect
+ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
+ github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
+ github.com/aymerick/douceur v0.2.0 // indirect
+ github.com/charmbracelet/glamour v0.6.0 // indirect
+ github.com/cheggaaa/pb/v3 v3.1.4 // indirect
+ github.com/cloudflare/circl v1.3.7 // indirect
+ github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 // indirect
+ github.com/denisbrodbeck/machineid v1.0.1 // indirect
+ github.com/dimchansky/utfbom v1.1.1 // indirect
+ github.com/dlclark/regexp2 v1.8.1 // indirect
+ github.com/docker/go-units v0.5.0 // indirect
+ github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
+ github.com/fatih/color v1.15.0 // indirect
+ github.com/gaukas/godicttls v0.0.4 // indirect
+ github.com/golang/protobuf v1.5.3 // indirect
+ github.com/golang/snappy v0.0.4 // indirect
+ github.com/google/go-github/v30 v30.1.0 // indirect
+ github.com/google/go-querystring v1.1.0 // indirect
+ github.com/gorilla/css v1.0.1 // indirect
+ github.com/json-iterator/go v1.1.12 // indirect
+ github.com/klauspost/compress v1.16.7 // indirect
+ github.com/klauspost/pgzip v1.2.5 // indirect
+ github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
+ github.com/mattn/go-colorable v0.1.13 // indirect
+ github.com/mattn/go-isatty v0.0.19 // indirect
+ github.com/mattn/go-runewidth v0.0.15 // indirect
+ github.com/mholt/archiver/v3 v3.5.1 // indirect
+ github.com/microcosm-cc/bluemonday v1.0.26 // indirect
+ github.com/miekg/dns v1.1.57 // indirect
+ github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7 // indirect
+ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+ github.com/modern-go/reflect2 v1.0.2 // indirect
+ github.com/muesli/reflow v0.3.0 // indirect
+ github.com/muesli/termenv v0.15.1 // indirect
+ github.com/nwaples/rardecode v1.1.3 // indirect
+ github.com/olekukonko/tablewriter v0.0.5 // indirect
+ github.com/pierrec/lz4/v4 v4.1.2 // indirect
+ github.com/projectdiscovery/blackrock v0.0.1 // indirect
+ github.com/projectdiscovery/fastdialer v0.0.55 // indirect
+ github.com/projectdiscovery/hmap v0.0.35 // indirect
+ github.com/projectdiscovery/networkpolicy v0.0.7 // indirect
+ github.com/projectdiscovery/retryabledns v1.0.52 // indirect
+ github.com/projectdiscovery/retryablehttp-go v1.0.44 // indirect
+ github.com/quic-go/quic-go v0.37.7 // indirect
+ github.com/refraction-networking/utls v1.5.4 // indirect
+ github.com/rivo/uniseg v0.4.4 // indirect
+ github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect
+ github.com/syndtr/goleveldb v1.0.0 // indirect
+ github.com/tidwall/btree v1.4.3 // indirect
+ github.com/tidwall/buntdb v1.3.0 // indirect
+ github.com/tidwall/gjson v1.14.3 // indirect
+ github.com/tidwall/grect v0.1.4 // indirect
+ github.com/tidwall/match v1.1.1 // indirect
+ github.com/tidwall/pretty v1.2.0 // indirect
+ github.com/tidwall/rtred v0.1.2 // indirect
+ github.com/tidwall/tinyqueue v0.1.1 // indirect
+ github.com/ulikunitz/xz v0.5.11 // indirect
+ github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6 // indirect
+ github.com/weppos/publicsuffix-go v0.30.1-0.20230422193905-8fecedd899db // indirect
+ github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
+ github.com/yl2chen/cidranger v1.0.2 // indirect
+ github.com/yuin/goldmark v1.5.4 // indirect
+ github.com/yuin/goldmark-emoji v1.0.1 // indirect
+ github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248 // indirect
+ github.com/zmap/zcrypto v0.0.0-20230422215203-9a665e1e9968 // indirect
+ go.etcd.io/bbolt v1.3.7 // indirect
+ go.uber.org/multierr v1.11.0 // indirect
+ golang.org/x/crypto v0.18.0 // indirect
+ golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc // indirect
+ golang.org/x/mod v0.14.0 // indirect
+ golang.org/x/net v0.20.0 // indirect
+ golang.org/x/oauth2 v0.11.0 // indirect
+ golang.org/x/sys v0.16.0 // indirect
+ golang.org/x/term v0.16.0 // indirect
+ golang.org/x/text v0.14.0 // indirect
+ golang.org/x/tools v0.16.1 // indirect
+ google.golang.org/appengine v1.6.7 // indirect
+ google.golang.org/protobuf v1.31.0 // indirect
+ gopkg.in/djherbis/times.v1 v1.3.0 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..7c4ccd1
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,388 @@
+aead.dev/minisign v0.2.0 h1:kAWrq/hBRu4AARY6AlciO83xhNnW9UaC8YipS2uhLPk=
+aead.dev/minisign v0.2.0/go.mod h1:zdq6LdSd9TbuSxchxwhpA9zEb9YXcVGoE8JakuiGaIQ=
+cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
+github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
+github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
+github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057 h1:KFac3SiGbId8ub47e7kd2PLZeACxc1LkiiNoDOFRClE=
+github.com/Mzack9999/gcache v0.0.0-20230410081825-519e28eab057/go.mod h1:iLB2pivrPICvLOuROKmlqURtFIEsoJZaMidQfCG1+D4=
+github.com/Mzack9999/go-http-digest-auth-client v0.6.1-0.20220414142836-eb8883508809 h1:ZbFL+BDfBqegi+/Ssh7im5+aQfBRx6it+kHnC7jaDU8=
+github.com/Mzack9999/go-http-digest-auth-client v0.6.1-0.20220414142836-eb8883508809/go.mod h1:upgc3Zs45jBDnBT4tVRgRcgm26ABpaP7MoTSdgysca4=
+github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow=
+github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4=
+github.com/akrylysov/pogreb v0.10.1 h1:FqlR8VR7uCbJdfUob916tPM+idpKgeESDXOA1K0DK4w=
+github.com/akrylysov/pogreb v0.10.1/go.mod h1:pNs6QmpQ1UlTJKDezuRWmaqkgUE2TuU0YTWyqJZ7+lI=
+github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
+github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
+github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
+github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
+github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
+github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
+github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
+github.com/aymanbagabas/go-osc52 v1.0.3/go.mod h1:zT8H+Rk4VSabYN90pWyugflM3ZhpTZNC7cASDfUCdT4=
+github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
+github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
+github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
+github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
+github.com/bits-and-blooms/bitset v1.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5MS5JVb4c=
+github.com/bits-and-blooms/bitset v1.8.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
+github.com/bits-and-blooms/bloom/v3 v3.5.0 h1:AKDvi1V3xJCmSR6QhcBfHbCN4Vf8FfxeWkMNQfmAGhY=
+github.com/bits-and-blooms/bloom/v3 v3.5.0/go.mod h1:Y8vrn7nk1tPIlmLtW2ZPV+W7StdVMor6bC1xgpjMZFs=
+github.com/charmbracelet/glamour v0.6.0 h1:wi8fse3Y7nfcabbbDuwolqTqMQPMnVPeZhDM273bISc=
+github.com/charmbracelet/glamour v0.6.0/go.mod h1:taqWV4swIMMbWALc0m7AfE9JkPSU8om2538k9ITBxOc=
+github.com/cheggaaa/pb/v3 v3.1.4 h1:DN8j4TVVdKu3WxVwcRKu0sG00IIU6FewoABZzXbRQeo=
+github.com/cheggaaa/pb/v3 v3.1.4/go.mod h1:6wVjILNBaXMs8c21qRiaUM8BR82erfgau1DQ4iUXmSA=
+github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
+github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
+github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 h1:ox2F0PSMlrAAiAdknSRMDrAr8mfxPCfSZolH+/qQnyQ=
+github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08/go.mod h1:pCxVEbcm3AMg7ejXyorUXi6HQCzOIBf7zEDVPtw0/U4=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ=
+github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI=
+github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
+github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
+github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
+github.com/dlclark/regexp2 v1.8.1 h1:6Lcdwya6GjPUNsBct8Lg/yRPwMhABj269AAzdGSiR+0=
+github.com/dlclark/regexp2 v1.8.1/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
+github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
+github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY=
+github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
+github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
+github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203 h1:XBBHcIb256gUJtLmY22n99HaZTz+r2Z51xUPi01m3wg=
+github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203/go.mod h1:E1jcSv8FaEny+OP/5k9UxZVw9YFWGj7eI4KR/iOBqCg=
+github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
+github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
+github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
+github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk=
+github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI=
+github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
+github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
+github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
+github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-github/v30 v30.1.0 h1:VLDx+UolQICEOKu2m4uAoMti1SxuEBAl7RSEG16L+Oo=
+github.com/google/go-github/v30 v30.1.0/go.mod h1:n8jBpHl45a/rlBUtRJMOG4GhNADUQFEufcolZ95JfU8=
+github.com/google/go-github/v50 v50.1.0/go.mod h1:Ev4Tre8QoKiolvbpOSG3FIi4Mlon3S2Nt9W5JYqKiwA=
+github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
+github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
+github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
+github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
+github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
+github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
+github.com/hashicorp/golang-lru/v2 v2.0.6 h1:3xi/Cafd1NaoEnS/yDssIiuVeDVywU0QdFGl3aQaQHM=
+github.com/hashicorp/golang-lru/v2 v2.0.6/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/jedib0t/go-pretty/v6 v6.4.7 h1:lwiTJr1DEkAgzljsUsORmWsVn5MQjt1BPJdPCtJ6KXE=
+github.com/jedib0t/go-pretty/v6 v6.4.7/go.mod h1:Ndk3ase2CkQbXLLNf5QDHoYb6J9WtVfmHZu9n8rk2xs=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
+github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
+github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
+github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
+github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
+github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
+github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
+github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
+github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
+github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
+github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
+github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
+github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
+github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
+github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo=
+github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
+github.com/microcosm-cc/bluemonday v1.0.21/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM=
+github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58=
+github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs=
+github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM=
+github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk=
+github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7 h1:yRZGarbxsRytL6EGgbqK2mCY+Lk5MWKQYKJT2gEglhc=
+github.com/minio/selfupdate v0.6.1-0.20230907112617-f11e74f84ca7/go.mod h1:bO02GTIPCMQFTEvE5h4DjYB58bCoZ35XLeBf0buTDdM=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8=
+github.com/mreiferson/go-httpclient v0.0.0-20201222173833-5e475fde3a4d/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8=
+github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
+github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
+github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc=
+github.com/muesli/termenv v0.15.1 h1:UzuTb/+hhlBugQz28rpzey4ZuKcZ03MeKsoG7IJZIxs=
+github.com/muesli/termenv v0.15.1/go.mod h1:HeAQPTzpfs016yGtA4g00CsdYnVLJvxsS4ANqrZs2sQ=
+github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
+github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc=
+github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
+github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
+github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
+github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
+github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
+github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
+github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q=
+github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k=
+github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
+github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
+github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
+github.com/pierrec/lz4/v4 v4.1.2 h1:qvY3YFXRQE/XB8MlLzJH7mSzBs74eA2gg52YTk6jUPM=
+github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/projectdiscovery/blackrock v0.0.1 h1:lHQqhaaEFjgf5WkuItbpeCZv2DUIE45k0VbGJyft6LQ=
+github.com/projectdiscovery/blackrock v0.0.1/go.mod h1:ANUtjDfaVrqB453bzToU+YB4cUbvBRpLvEwoWIwlTss=
+github.com/projectdiscovery/fastdialer v0.0.55 h1:dcD3La9MsImgQMrBnG0/w5Mu8PRJu2TU1STycKSSodc=
+github.com/projectdiscovery/fastdialer v0.0.55/go.mod h1:DNP62sWCLp0YHXwhlo73iyZODpSZE7dVstt2GNAC7+A=
+github.com/projectdiscovery/goflags v0.1.36 h1:gElwVU9BJsUbxjyHqDTmlGsB8Br2DDxbfMQMXLYvYhg=
+github.com/projectdiscovery/goflags v0.1.36/go.mod h1:A+MLWJgGKZ2WUED0ZlW5EQ4mmJ/s71VnvY6KF5ThLaM=
+github.com/projectdiscovery/gologger v1.1.12 h1:uX/QkQdip4PubJjjG0+uk5DtyAi1ANPJUvpmimXqv4A=
+github.com/projectdiscovery/gologger v1.1.12/go.mod h1:DI8nywPLERS5mo8QEA9E7gd5HZ3Je14SjJBH3F5/kLw=
+github.com/projectdiscovery/hmap v0.0.35 h1:JkadBpuB/GttuS+O72E26y6RrC8Ox90iFunrI2/zvrc=
+github.com/projectdiscovery/hmap v0.0.35/go.mod h1:EXm6Z/e10GS0uK7qNLH2OcT0bIKq+T4ZDWxSzK0ho5U=
+github.com/projectdiscovery/networkpolicy v0.0.7 h1:AwHqBRXBqDQgnWzBMuoJtHBNEYBw+NFp/4qIK688x7o=
+github.com/projectdiscovery/networkpolicy v0.0.7/go.mod h1:CK0CnFoLF1Nou6mY7P4WODSAxhPN8g8g7XpapgEP8tI=
+github.com/projectdiscovery/retryabledns v1.0.52 h1:jJRIT5y7KYZvaZAAvlkxvkKkQzst6LvEeLDqRc3LeOM=
+github.com/projectdiscovery/retryabledns v1.0.52/go.mod h1:Ea478e6XNVAmfH4KwqtLNjkwdgkpVH1O3+FL2dKLNb8=
+github.com/projectdiscovery/retryablehttp-go v1.0.44 h1:hicCe2h6daHt4muPovmffZE3YKBqGioreO6EpIGZ87g=
+github.com/projectdiscovery/retryablehttp-go v1.0.44/go.mod h1:7ECXK2cH2/G4sstf8hacyrMdPPJ/3wCAO5tFPZ4iO4s=
+github.com/projectdiscovery/utils v0.0.74 h1:mrjRm1eF3ZLIikIpWF3Nzbar/twHHqhz9WSi9fqGQeA=
+github.com/projectdiscovery/utils v0.0.74/go.mod h1:4MBUFfZ9Mm96PiWUj2zJ99sx2AVOpZkGukC6O16+p+o=
+github.com/quic-go/quic-go v0.37.7 h1:AgKsQLZ1+YCwZd2GYhBUsJDYZwEkA5gENtAjb+MxONU=
+github.com/quic-go/quic-go v0.37.7/go.mod h1:YsbH1r4mSHPJcLF4k4zruUkLBqctEMBDR6VPvcYjIsU=
+github.com/refraction-networking/utls v1.5.4 h1:9k6EO2b8TaOGsQ7Pl7p9w6PUhx18/ZCeT0WNTZ7Uw4o=
+github.com/refraction-networking/utls v1.5.4/go.mod h1:SPuDbBmgLGp8s+HLNc83FuavwZCFoMmExj+ltUHiHUw=
+github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
+github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
+github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA=
+github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
+github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
+github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
+github.com/tidwall/assert v0.1.0 h1:aWcKyRBUAdLoVebxo95N7+YZVTFF/ASTr7BN4sLP6XI=
+github.com/tidwall/assert v0.1.0/go.mod h1:QLYtGyeqse53vuELQheYl9dngGCJQ+mTtlxcktb+Kj8=
+github.com/tidwall/btree v1.4.3 h1:Lf5U/66bk0ftNppOBjVoy/AIPBrLMkheBp4NnSNiYOo=
+github.com/tidwall/btree v1.4.3/go.mod h1:LGm8L/DZjPLmeWGjv5kFrY8dL4uVhMmzmmLYmsObdKE=
+github.com/tidwall/buntdb v1.3.0 h1:gdhWO+/YwoB2qZMeAU9JcWWsHSYU3OvcieYgFRS0zwA=
+github.com/tidwall/buntdb v1.3.0/go.mod h1:lZZrZUWzlyDJKlLQ6DKAy53LnG7m5kHyrEHvvcDmBpU=
+github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
+github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw=
+github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
+github.com/tidwall/grect v0.1.4 h1:dA3oIgNgWdSspFzn1kS4S/RDpZFLrIxAZOdJKjYapOg=
+github.com/tidwall/grect v0.1.4/go.mod h1:9FBsaYRaR0Tcy4UwefBX/UDcDcDy9V5jUcxHzv2jd5Q=
+github.com/tidwall/lotsa v1.0.2 h1:dNVBH5MErdaQ/xd9s769R31/n2dXavsQ0Yf4TMEHHw8=
+github.com/tidwall/lotsa v1.0.2/go.mod h1:X6NiU+4yHA3fE3Puvpnn1XMDrFZrE9JO2/w+UMuqgR8=
+github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
+github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
+github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
+github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
+github.com/tidwall/rtred v0.1.2 h1:exmoQtOLvDoO8ud++6LwVsAMTu0KPzLTUrMln8u1yu8=
+github.com/tidwall/rtred v0.1.2/go.mod h1:hd69WNXQ5RP9vHd7dqekAz+RIdtfBogmglkZSRxCHFQ=
+github.com/tidwall/tinyqueue v0.1.1 h1:SpNEvEggbpyN5DIReaJ2/1ndroY8iyEGxPYxoSaymYE=
+github.com/tidwall/tinyqueue v0.1.1/go.mod h1:O/QNHwrnjqr6IHItYrzoHAKYhBkLI67Q096fQP5zMYw=
+github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
+github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
+github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
+github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
+github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6 h1:TtyC78WMafNW8QFfv3TeP3yWNDG+uxNkk9vOrnDu6JA=
+github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6/go.mod h1:h8272+G2omSmi30fBXiZDMkmHuOgonplfKIKjQWzlfs=
+github.com/weppos/publicsuffix-go v0.13.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k=
+github.com/weppos/publicsuffix-go v0.30.1-0.20230422193905-8fecedd899db h1:/WcxBne+5CbtbgWd/sV2wbravmr4sT7y52ifQaCgoLs=
+github.com/weppos/publicsuffix-go v0.30.1-0.20230422193905-8fecedd899db/go.mod h1:aiQaH1XpzIfgrJq3S1iw7w+3EDbRP7mF5fmwUhWyRUs=
+github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
+github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
+github.com/yl2chen/cidranger v1.0.2 h1:lbOWZVCG1tCRX4u24kuM1Tb4nHqWkDxwLdoS+SevawU=
+github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+github.com/yuin/goldmark v1.5.2/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+github.com/yuin/goldmark v1.5.4 h1:2uY/xC0roWy8IBEGLgB1ywIoEJFGmRrX21YQcvGZzjU=
+github.com/yuin/goldmark v1.5.4/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+github.com/yuin/goldmark-emoji v1.0.1 h1:ctuWEyzGBwiucEqxzwe0SOYDXPAucOrE9NQC18Wa1os=
+github.com/yuin/goldmark-emoji v1.0.1/go.mod h1:2w1E6FEWLcDQkoTE+7HU6QF1F6SLlNGjRIBbIZQFqkQ=
+github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE=
+github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248 h1:Nzukz5fNOBIHOsnP+6I79kPx3QhLv8nBy2mfFhBRq30=
+github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE=
+github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is=
+github.com/zmap/zcertificate v0.0.1/go.mod h1:q0dlN54Jm4NVSSuzisusQY0hqDWvu92C+TWveAxiVWk=
+github.com/zmap/zcrypto v0.0.0-20201128221613-3719af1573cf/go.mod h1:aPM7r+JOkfL+9qSB4KbYjtoEzJqUK50EXkkJabeNJDQ=
+github.com/zmap/zcrypto v0.0.0-20201211161100-e54a5822fb7e/go.mod h1:aPM7r+JOkfL+9qSB4KbYjtoEzJqUK50EXkkJabeNJDQ=
+github.com/zmap/zcrypto v0.0.0-20230422215203-9a665e1e9968 h1:YOQ1vXEwE4Rnj+uQ/3oCuJk5wgVsvUyW+glsndwYuyA=
+github.com/zmap/zcrypto v0.0.0-20230422215203-9a665e1e9968/go.mod h1:xIuOvYCZX21S5Z9bK1BMrertTGX/F8hgAPw7ERJRNS0=
+github.com/zmap/zlint/v3 v3.0.0/go.mod h1:paGwFySdHIBEMJ61YjoqT4h7Ge+fdYG4sUQhnTb1lJ8=
+go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
+go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
+go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
+go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
+golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
+golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
+golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
+golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc h1:ao2WRsKSzW6KuUY9IWPwWahcHCgR0s52IfwutMfEbdM=
+golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
+golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
+golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
+golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I=
+golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU=
+golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
+golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210228012217-479acdf4ea46/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
+golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
+golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
+golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
+golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA=
+golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
+google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
+google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/djherbis/times.v1 v1.3.0 h1:uxMS4iMtH6Pwsxog094W0FYldiNnfY/xba00vq6C2+o=
+gopkg.in/djherbis/times.v1 v1.3.0/go.mod h1:AQlg6unIsrsCEdQYhTzERy542dz6SFdQFZFv6mUY0P8=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/runner/banner.go b/runner/banner.go
new file mode 100644
index 0000000..ce02bd4
--- /dev/null
+++ b/runner/banner.go
@@ -0,0 +1,40 @@
+package runner
+
+import (
+ "github.com/projectdiscovery/gologger"
+ "github.com/projectdiscovery/utils/auth/pdcp"
+ updateutils "github.com/projectdiscovery/utils/update"
+)
+
+const banner = `
+
+ ______ _____ ____ ___ ____ ____
+ / ___/ | / / _ \/ __ \__ \/ __ \/ __ \
+ / /__ | |/ / __/ / / / / / /_/ / /_/ /
+ \___/ |___/\___/_/ /_/ /_/\__,_/ .___/
+ /_/
+
+`
+
+// Version is the current version
+const Version = `v0.0.1`
+
+// showBanner is used to show the banner to the user
+func showBanner() {
+ gologger.Print().Msgf("%s\n", banner)
+ gologger.Print().Msgf("\t\tprojectdiscovery.io\n\n")
+}
+
+// GetUpdateCallback returns a callback function that updates proxify
+func GetUpdateCallback() func() {
+ return func() {
+ showBanner()
+ updateutils.GetUpdateToolCallback("cvemap", Version)()
+ }
+}
+
+// AuthWithPDCP is used to authenticate with PDCP
+func AuthWithPDCP() {
+ showBanner()
+ pdcp.CheckNValidateCredentials("cvemap")
+}
diff --git a/runner/options.go b/runner/options.go
new file mode 100644
index 0000000..b777b62
--- /dev/null
+++ b/runner/options.go
@@ -0,0 +1,43 @@
+package runner
+
+import "github.com/projectdiscovery/goflags"
+
+type Options struct {
+ PdcpAuth bool
+ CveIds goflags.StringSlice
+ CweIds goflags.StringSlice
+ Vendor goflags.StringSlice
+ Product goflags.StringSlice
+ Eproduct goflags.StringSlice
+ Severity goflags.StringSlice
+ CvssScore goflags.StringSlice
+ //cvssMetrics goflags.StringSlice
+ EpssPercentile goflags.StringSlice
+ //year goflags.StringSlice
+ Assignees goflags.StringSlice
+ Reference goflags.StringSlice
+ //vulnType goflags.StringSlice
+ IncludeColumns []string
+ ExcludeColumns []string
+ TableHeaders []string
+ ListId bool
+ EpssScore string
+ Cpe string
+ VulnStatus string
+ Age string
+ Kev string
+ //trending bool
+ Hackerone string
+ HasNucleiTemplate string
+ HasPoc string
+ Search string
+ RemotlyExploitable string
+ EnablePageKeys bool
+ Json bool
+ Limit int
+ Offset int
+ Version bool
+ DisableUpdateCheck bool
+ Silent bool
+ Verbose bool
+}
diff --git a/runner/runner.go b/runner/runner.go
new file mode 100644
index 0000000..1b4aff0
--- /dev/null
+++ b/runner/runner.go
@@ -0,0 +1,865 @@
+package runner
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/http/httputil"
+ "net/url"
+ "os"
+ "strconv"
+ "strings"
+ "sync"
+
+ "github.com/eiannone/keyboard"
+ "github.com/jedib0t/go-pretty/v6/table"
+ "github.com/projectdiscovery/goflags"
+ "github.com/projectdiscovery/gologger"
+ "github.com/projectdiscovery/gologger/levels"
+ "github.com/projectdiscovery/utils/auth/pdcp"
+ errorutil "github.com/projectdiscovery/utils/errors"
+ fileutil "github.com/projectdiscovery/utils/file"
+ sliceutil "github.com/projectdiscovery/utils/slice"
+ updateutils "github.com/projectdiscovery/utils/update"
+)
+
+const xPDCPKeyHeader = "X-PDCP-Key"
+
+var (
+ baseUrl = "https://cve.projectdiscovery.io/api/v1"
+ httpCleint = &http.Client{}
+ pdcpApiKey = ""
+ DEFAULT_FEILD_CHAR_LIMIT = 20
+)
+
+func init() {
+ if os.Getenv("CVEMAP_API_URL") != "" {
+ baseUrl = os.Getenv("CVEMAP_API_URL")
+ }
+ pch := pdcp.PDCPCredHandler{}
+ if os.Getenv("PDCP_API_KEY") != "" {
+ pdcpApiKey = os.Getenv("PDCP_API_KEY")
+ } else if creds, err := pch.GetCreds(); err == nil {
+ pdcpApiKey = creds.APIKey
+ }
+ if os.Getenv("DEFAULT_FEILD_CHAR_LIMIT") != "" {
+ DEFAULT_FEILD_CHAR_LIMIT, _ = strconv.Atoi(os.Getenv("DEFAULT_FEILD_CHAR_LIMIT"))
+ }
+}
+
+var (
+ defaultHeaders = []string{"ID", "CVSS", "Severity", "EPSS", "Product", "Age", "Template"}
+
+ headerMap = map[string]string{
+ "id": "id",
+ "cwe": "cwe",
+ "epss": "epss",
+ "cvss": "cvss",
+ "severity": "severity",
+ "vendor": "vendor",
+ "product": "product",
+ "vstatus": "vstatus",
+ "assignee": "assignee",
+ "age": "age",
+ "kev": "kev",
+ "template": "template",
+ "poc": "poc",
+ "rank": "rank",
+ "reports": "reports",
+ }
+
+ allowedHeader = goflags.AllowdTypes{
+ "": goflags.EnumVariable(-1),
+ "cwe": goflags.EnumVariable(0),
+ "epss": goflags.EnumVariable(1),
+ "product": goflags.EnumVariable(2),
+ "vendor": goflags.EnumVariable(3),
+ "vstatus": goflags.EnumVariable(4),
+ "assignee": goflags.EnumVariable(5),
+ "age": goflags.EnumVariable(6),
+ "kev": goflags.EnumVariable(7),
+ "template": goflags.EnumVariable(8),
+ "poc": goflags.EnumVariable(9),
+ }
+ allowedHeaderString = allowedHeader.String()
+
+ allowedVstatus = goflags.AllowdTypes{
+ "": goflags.EnumVariable(-1),
+ "new": goflags.EnumVariable(0),
+ "confirmed": goflags.EnumVariable(1),
+ "unconfirmed": goflags.EnumVariable(2),
+ "modified": goflags.EnumVariable(3),
+ "rejected": goflags.EnumVariable(4),
+ "unknown": goflags.EnumVariable(5),
+ }
+
+ maxLimit = 300
+)
+
+func ParseOptions() *Options {
+ var options Options
+
+ flagset := goflags.NewFlagSet()
+ flagset.SetDescription(`Navigate the CVE jungle with ease.`)
+
+ flagset.CreateGroup("config", "Config",
+ flagset.BoolVar(&options.PdcpAuth, "auth", false, "configure projectdiscovery cloud (pdcp) api key"),
+ )
+
+ flagset.CreateGroup("OPTIONS", "options",
+ // currently only one cve id is supported
+ flagset.StringSliceVar(&options.CveIds, "id", nil, "cve to list for given id", goflags.FileCommaSeparatedStringSliceOptions),
+ // flagset.StringSliceVarP(&options.cweIds, "cwe-id", "cwe", nil, "cve to list for given cwe id", goflags.CommaSeparatedStringSliceOptions),
+ flagset.StringSliceVarP(&options.Vendor, "vendor", "v", nil, "cve to list for given vendor", goflags.CommaSeparatedStringSliceOptions),
+ flagset.StringSliceVarP(&options.Product, "product", "p", nil, "cve to list for given product", goflags.CommaSeparatedStringSliceOptions),
+ flagset.StringSliceVar(&options.Eproduct, "eproduct", nil, "cves to exclude based on products", goflags.CommaSeparatedStringSliceOptions),
+ flagset.StringSliceVarP(&options.Severity, "severity", "s", nil, "cve to list for given severity", goflags.CommaSeparatedStringSliceOptions),
+ flagset.StringSliceVarP(&options.CvssScore, "cvss-score", "cs", nil, "cve to list for given cvss score", goflags.CommaSeparatedStringSliceOptions),
+ flagset.StringVarP(&options.Cpe, "cpe", "c", "", "cve to list for given cpe"),
+ flagset.StringVarP(&options.EpssScore, "epss-score", "es", "", "cve to list for given epss score"),
+ flagset.StringSliceVarP(&options.EpssPercentile, "epss-percentile", "ep", nil, "cve to list for given epss percentile", goflags.CommaSeparatedStringSliceOptions),
+ flagset.StringVar(&options.Age, "age", "", "cve to list published by given age in days"),
+ flagset.StringSliceVarP(&options.Assignees, "assignee", "a", nil, "cve to list for given publisher assignee", goflags.CommaSeparatedStringSliceOptions),
+ //flagset.StringSliceVarP(&options.vulnType, "type", "vt", nil, "cve to list for given vulnerability type", goflags.CommaSeparatedStringSliceOptions),
+ 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),
+ )
+
+ flagset.CreateGroup("update", "Update",
+ flagset.CallbackVarP(GetUpdateCallback(), "update", "up", "update cvemap to latest version"),
+ flagset.BoolVarP(&options.DisableUpdateCheck, "disable-update-check", "duc", false, "disable automatic cvemap update check"),
+ )
+
+ flagset.CreateGroup("FILTER", "filter",
+ flagset.StringVarP(&options.Search, "search", "q", "", "search in cve data"),
+ flagset.DynamicVarP(&options.Kev, "kev", "k", "true", "display cves marked as exploitable vulnerabilities by cisa"),
+ flagset.DynamicVarP(&options.HasNucleiTemplate, "template", "t", "true", "display cves that has public nuclei templates"),
+ flagset.DynamicVar(&options.HasPoc, "poc", "true", "display cves that has public published poc"),
+ flagset.DynamicVarP(&options.Hackerone, "hackerone", "h1", "true", "display cves reported on hackerone"),
+ flagset.DynamicVarP(&options.RemotlyExploitable, "remote", "re", "true", "display remotely exploitable cves (AV:N & PR:N | PR:L)"),
+ )
+
+ flagset.CreateGroup("OUTPUT", "output",
+ 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),
+ 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),
+ flagset.BoolVarP(&options.ListId, "list-id", "lsi", false, "list only the cve ids in the output"),
+ flagset.IntVarP(&options.Limit, "limit", "l", 50, "limit the number of results to display"),
+ flagset.IntVar(&options.Offset, "offset", 0, "offset the results to display"),
+ flagset.BoolVarP(&options.Json, "json", "j", false, "return output in json format"),
+ // experimental
+ flagset.BoolVarP(&options.EnablePageKeys, "enable-page-keys", "epk", false, "enable page keys to navigate results"),
+ )
+
+ flagset.CreateGroup("DEBUG", "debug",
+ flagset.BoolVar(&options.Version, "version", false, "Version"),
+ flagset.BoolVar(&options.Silent, "silent", false, "Silent"),
+ flagset.BoolVar(&options.Verbose, "verbose", false, "Verbose"),
+ )
+
+ if err := flagset.Parse(); err != nil {
+ gologger.Fatal().Msgf("Error parsing flags: %s\n", err)
+ }
+
+ if options.Limit > maxLimit {
+ options.Limit = maxLimit
+ }
+
+ if fileutil.HasStdin() {
+ // Read from stdin
+ bin, err := io.ReadAll(os.Stdin)
+ if err != nil {
+ gologger.Fatal().Msgf("couldn't read stdin: %s\n", err)
+ }
+ options.CveIds = append(options.CveIds, strings.Split(strings.TrimSpace(string(bin)), "\n")...)
+ }
+
+ return &options
+}
+
+func Run(options Options) {
+
+ if options.Version {
+ gologger.Info().Msgf("Current Version: %s\n", Version)
+ os.Exit(0)
+ }
+
+ if options.PdcpAuth {
+ AuthWithPDCP()
+ }
+
+ if options.Silent {
+ gologger.DefaultLogger.SetMaxLevel(levels.LevelSilent)
+ } else if options.Verbose {
+ gologger.DefaultLogger.SetMaxLevel(levels.LevelVerbose)
+ }
+
+ // Show the user the banner
+ showBanner()
+
+ if !options.DisableUpdateCheck {
+ latestVersion, err := updateutils.GetToolVersionCallback("cvemap", Version)()
+ if err != nil {
+ if options.Verbose {
+ gologger.Error().Msgf("cvemap version check failed: %v", err.Error())
+ }
+ } else {
+ gologger.Info().Msgf("Current cvemap version %v %v", Version, updateutils.GetVersionDescription(Version, latestVersion))
+ }
+ }
+
+ // on default, enable kev
+ if isDefaultRun(options) {
+ options.Kev = "true"
+ }
+
+ parseHeaders(&options)
+
+ if options.EnablePageKeys && len(options.CveIds) == 0 {
+ processWithPageKeyEvents(options)
+ } else {
+ _ = process(options)
+ }
+}
+
+func process(options Options) *CVEBulkData {
+ var cvesResp *CVEBulkData
+ var err error
+ cvesResp, err = getCves(options)
+ if err != nil {
+ gologger.Fatal().Msgf("Error getting CVEs: %s\n", err)
+ return nil
+ }
+
+ if options.Json {
+ outputJson(cvesResp.Cves)
+ return cvesResp
+ }
+
+ nPages := cvesResp.TotalResults / options.Limit
+ if cvesResp.TotalResults%options.Limit > 0 {
+ nPages++
+ }
+ currentPage := (options.Offset / options.Limit) + 1
+ if len(options.CveIds) == 0 && (options.Verbose || options.EnablePageKeys) {
+ gologger.Print().Msgf("\n Limit: %v Page: %v TotalPages: %v TotalResults: %v\n", options.Limit, currentPage, nPages, cvesResp.TotalResults)
+ }
+
+ if options.ListId {
+ for _, cve := range cvesResp.Cves {
+ fmt.Println(cve.CveID)
+ }
+ return cvesResp
+ }
+
+ // limit headers to 10, otherwise it will be too wide
+ if len(options.TableHeaders) > 10 {
+ options.TableHeaders = options.TableHeaders[:10]
+ }
+
+ headers, rows := generateTableData(cvesResp.Cves, options.TableHeaders)
+
+ renderTable(headers, rows)
+
+ if options.EnablePageKeys {
+ pageString := ""
+ if currentPage > 1 {
+ pageString += " ◀ "
+ }
+ if currentPage < nPages {
+ pageString += " ▶"
+ }
+ fmt.Print(pageString)
+ }
+ return cvesResp
+}
+
+func processWithPageKeyEvents(options Options) {
+ cveResp := process(options)
+
+ // wait for user input
+ err := keyboard.Open()
+ if err != nil {
+ panic(err)
+ }
+ defer keyboard.Close()
+ waitGroup := sync.WaitGroup{}
+ waitGroup.Add(1)
+
+ go func() {
+ for {
+ _, key, err := keyboard.GetKey()
+ if err != nil {
+ panic(err)
+ }
+
+ if key == keyboard.KeyEsc || key == keyboard.KeyCtrlC {
+ waitGroup.Done()
+ break
+ }
+
+ switch key {
+ case keyboard.KeyArrowRight:
+ if options.Offset+options.Limit < cveResp.TotalResults {
+ options.Offset += options.Limit
+ clearScreen()
+ cveResp = process(options)
+ }
+ case keyboard.KeyArrowLeft:
+ if options.Offset-options.Limit >= 0 {
+ options.Offset -= options.Limit
+ clearScreen()
+ cveResp = process(options)
+ }
+ }
+ }
+ }()
+
+ waitGroup.Wait()
+}
+
+func parseHeaders(options *Options) {
+ // construct headers
+ headers := make([]string, 0)
+
+ if options.Hackerone == "true" {
+ defaultHeaders = []string{"ID", "CVSS", "Severity", "Rank", "Reports", "Product", "Age", "Template"}
+ }
+
+ options.IncludeColumns = getValidHeaders(options.IncludeColumns)
+ options.ExcludeColumns = getValidHeaders(options.ExcludeColumns)
+
+ options.IncludeColumns = append(defaultHeaders, options.IncludeColumns...)
+ // case insensitive contains check
+ contains := func(array []string, element string) bool {
+ for _, e := range array {
+ if strings.EqualFold(e, element) {
+ return true
+ }
+ }
+ return false
+ }
+ // add headers to display
+ for _, header := range options.IncludeColumns {
+ if !contains(options.ExcludeColumns, header) && !contains(headers, header) {
+ headers = append(headers, header)
+ }
+ }
+ options.TableHeaders = headers
+}
+
+func renderTable(headers []string, rows [][]interface{}) {
+ // Create a table for displaying CVE data with the specified headers
+ t := table.NewWriter()
+ t.SetOutputMirror(os.Stdout)
+
+ // Append the specified headers to the table
+ headerRow := make([]interface{}, len(headers))
+ for i, header := range headers {
+ headerRow[i] = header
+ }
+ t.AppendHeader(headerRow)
+ // Loop through the retrieved CVE data and add rows to the table
+ for _, row := range rows {
+ t.AppendRow(row)
+ }
+ // t.SetColumnConfigs([]table.ColumnConfig{
+ // {Number: 5, WidthMax: 20},
+ // })
+ // Set table options and render it
+ t.SetStyle(table.StyleRounded)
+ t.Render()
+}
+
+func generateTableData(cves []CVEData, headers []string) ([]string, [][]interface{}) {
+ dataRows := make([][]interface{}, len(cves))
+ for r, cve := range cves {
+ dataRows[r] = getRow(headers, cve)
+ }
+ return headers, dataRows
+}
+
+func getRow(headers []string, cve CVEData) []interface{} {
+ row := make([]interface{}, len(headers))
+ for i, header := range headers {
+ switch strings.ToLower(header) {
+ case "id":
+ row[i] = getCellValueByLimit(cve.CveID)
+ case "epss":
+ row[i] = getCellValueByLimit(cve.Epss.Score)
+ case "cvss":
+ row[i] = ""
+ if cve.CvssMetrics != nil {
+ row[i] = getCellValueByLimit(getLatestVersionCVSSScore(*cve.CvssMetrics))
+ }
+ case "severity":
+ row[i] = getCellValueByLimit(strings.ToTitle(cve.Severity))
+ case "cwe":
+ row[i] = ""
+ if len(cve.Weaknesses) > 0 {
+ row[i] = getCellValueByLimit(cve.Weaknesses[0].CWEID)
+ }
+ case "vendor":
+ row[i] = ""
+ if cve.Cpe != nil {
+ row[i] = getCellValueByLimit(*cve.Cpe.Vendor)
+ }
+ case "product":
+ row[i] = ""
+ if cve.Cpe != nil {
+ row[i] = getCellValueByLimit(*cve.Cpe.Product)
+ }
+ case "vstatus":
+ row[i] = getCellValueByLimit(strings.ToUpper(cve.VulnStatus))
+ case "assignee":
+ row[i] = ""
+ if len(cve.Assignee) > 0 {
+ row[i] = getCellValueByLimit(cve.Assignee)
+ }
+ case "age":
+ row[i] = ""
+ if cve.AgeInDays > 0 {
+ row[i] = getCellValueByLimit(cve.AgeInDays)
+ }
+ case "kev":
+ row[i] = getCellValueByLimit(strings.ToUpper(strconv.FormatBool(cve.IsKev)))
+ case "template":
+ if cve.IsTemplate {
+ row[i] = "✅"
+ } else {
+ row[i] = "❌"
+ }
+ case "poc":
+ row[i] = getCellValueByLimit(strings.ToUpper(strconv.FormatBool(cve.IsPoc)))
+ case "rank":
+ row[i] = ""
+ if cve.Hackerone.Rank > 0 {
+ row[i] = getCellValueByLimit(cve.Hackerone.Rank)
+ }
+ case "reports":
+ row[i] = getCellValueByLimit(cve.Hackerone.Count)
+
+ default:
+ row[i] = ""
+ }
+ }
+ return row
+}
+
+func getCellValueByLimit(cell interface{}) string {
+ if cell == nil {
+ return ""
+ }
+ cellValue := fmt.Sprintf("%v", cell)
+ if len(cellValue) > DEFAULT_FEILD_CHAR_LIMIT {
+ cellValue = cellValue[:DEFAULT_FEILD_CHAR_LIMIT] + "..."
+ }
+ return cellValue
+}
+
+func getCves(options Options) (*CVEBulkData, error) {
+ if len(options.CveIds) > 0 {
+ return getCvesByIds(options.CveIds)
+ }
+ if options.Search != "" {
+ query := constructQueryByOptions(options)
+ return getCvesBySearchString(query, options.Limit, options.Offset)
+ }
+ return getCvesByFilters(constructQueryParams(options))
+}
+
+func getCvesByFilters(encodedParams string) (*CVEBulkData, error) {
+ url := fmt.Sprintf("%s/cves?%s", baseUrl, encodedParams)
+ // Send an HTTP GET request
+ response, err := makeGetRequest(url)
+ if err != nil {
+ return nil, err
+ }
+ defer response.Body.Close()
+ // Check the response status code
+ if response.StatusCode != http.StatusOK {
+ return nil, errorutil.New("unexpected status code: %d", response.StatusCode)
+ }
+ // Create a variable to store the response data
+ var cvesInBulk CVEBulkData
+ // Decode the JSON response into an array of CVEData structs
+ err = json.NewDecoder(response.Body).Decode(&cvesInBulk)
+ if err != nil {
+ return nil, err
+ }
+ return &cvesInBulk, nil
+}
+
+func getCvesByIds(cveIds []string) (*CVEBulkData, error) {
+ url := fmt.Sprintf("%s/cves", baseUrl)
+ // send only 100 cve ids max
+ if len(cveIds) > 100 {
+ cveIds = cveIds[:100]
+ }
+ var cveIdList CVEIdList
+ cveIdList.Cves = append(cveIdList.Cves, cveIds...)
+ reqData, err := json.Marshal(cveIdList)
+ if err != nil {
+ return nil, err
+ }
+ // Send an HTTP POST request
+ req, err := http.NewRequest("POST", url, bytes.NewBuffer(reqData))
+ if err != nil {
+ return nil, err
+ }
+ req.Header.Set("Content-Type", "application/json")
+ req.Header.Set(xPDCPKeyHeader, pdcpApiKey)
+
+ response, err := doRequest(req)
+ if err != nil {
+ return nil, err
+ }
+ defer response.Body.Close()
+ // Check the response status code
+ if response.StatusCode != http.StatusOK {
+ return nil, errorutil.New("unexpected status code: %d", response.StatusCode)
+ }
+ var cvesInBulk CVEBulkData
+ // Decode the JSON response into an array of CVEData structs
+ err = json.NewDecoder(response.Body).Decode(&cvesInBulk)
+ if err != nil {
+ return nil, err
+ }
+ return &cvesInBulk, nil
+}
+
+func getCvesBySearchString(query string, limit, offset int) (*CVEBulkData, error) {
+ u, err := url.Parse(fmt.Sprintf("%s/cves/search", baseUrl))
+ if err != nil {
+ return nil, err
+ }
+ // Construct query parameters
+ q := u.Query()
+ q.Set("q", query)
+ q.Set("limit", fmt.Sprintf("%v", limit))
+ q.Set("offset", fmt.Sprintf("%v", offset))
+ u.RawQuery = q.Encode()
+ response, err := makeGetRequest(u.String())
+ if err != nil {
+ return nil, err
+ }
+ defer response.Body.Close()
+ // Check the response status code
+ if response.StatusCode != http.StatusOK {
+ return nil, errorutil.New("unexpected status code: %d", response.StatusCode)
+ }
+ // Create a variable to store the response data
+ var cvesInBulk CVEBulkData
+ // Decode the JSON response into an array of CVEData structs
+ err = json.NewDecoder(response.Body).Decode(&cvesInBulk)
+ if err != nil {
+ return nil, err
+ }
+ return &cvesInBulk, nil
+}
+
+// all the root level fields are supported
+// func getCvesForSpecificFields(fields []string, encodedParams string, limit, offset int) (*CVEBulkData, error) {
+// url := fmt.Sprintf("%s/cves?fields=%s&%s&limit=%v&offset=%v", baseUrl, strings.Join(fields, ","), encodedParams, limit, offset)
+// // Send an HTTP GET request
+// response, err := makeGetRequest(url)
+// if err != nil {
+// return nil, err
+// }
+// defer response.Body.Close()
+// // Check the response status code
+// if response.StatusCode != http.StatusOK {
+// return nil, errorutil.New("unexpected status code: %d", response.StatusCode)
+// }
+// // Create a variable to store the response data
+// var cvesInBulk CVEBulkData
+// // Decode the JSON response into an array of CVEData structs
+// err = json.NewDecoder(response.Body).Decode(&cvesInBulk)
+// if err != nil {
+// return nil, err
+// }
+// return &cvesInBulk, nil
+// }
+
+var UNAUTHORIZEDERR = errorutil.New(`unexpected status code: 401 (get your free api key from https://cloud.projectdiscovery.io)`)
+
+func makeGetRequest(url string) (*http.Response, error) {
+ req, err := http.NewRequest("GET", url, nil)
+ if err != nil {
+ gologger.Fatal().Msgf("Error creating request: %s\n", err)
+ }
+ req.Header.Set(xPDCPKeyHeader, pdcpApiKey)
+ return doRequest(req)
+}
+
+func doRequest(req *http.Request) (*http.Response, error) {
+ if os.Getenv("DEBUG") == "true" {
+ // dump request
+ dump, err := httputil.DumpRequest(req, true)
+ if err != nil {
+ gologger.Fatal().Msgf("Error dumping request: %s\n", err)
+ }
+ fmt.Println(string(dump))
+ }
+ resp, err := httpCleint.Do(req)
+ if err == nil && resp.StatusCode == http.StatusUnauthorized {
+ var errResp ErrorMessage
+ _ = json.NewDecoder(resp.Body).Decode(&errResp)
+ if os.Getenv("DEBUG") == "true" {
+ gologger.Error().Msgf("unauthorized: %s\n", errResp.Message)
+ }
+ return nil, UNAUTHORIZEDERR
+ }
+ return resp, err
+}
+
+func outputJson(cve []CVEData) {
+ json, err := json.MarshalIndent(cve, "", " ")
+ if err != nil {
+ gologger.Error().Msgf("Error marshalling json: %s\n", err)
+ return
+ }
+ fmt.Println(string(json))
+}
+
+func constructQueryParams(opts Options) string {
+ queryParams := &url.Values{}
+ if len(opts.Severity) > 0 {
+ addQueryParams(queryParams, "severity", opts.Severity)
+ }
+ if len(opts.Assignees) > 0 {
+ addQueryParams(queryParams, "assignee", opts.Assignees)
+ }
+ if len(opts.CvssScore) > 0 {
+ var cvsKey string
+ for _, cvssScore := range opts.CvssScore {
+ cvsKey = "cvss_score"
+ if cvssScore[0] == '>' {
+ cvsKey = "cvss_score_gte"
+ cvssScore = strings.TrimSpace(cvssScore[1:])
+ } else if cvssScore[0] == '<' {
+ cvsKey = "cvss_score_lte"
+ cvssScore = strings.TrimSpace(cvssScore[1:])
+ }
+ queryParams.Add(cvsKey, cvssScore)
+ }
+ }
+
+ if len(opts.Age) > 0 {
+ ageKey := "age_in_days"
+ if opts.Age[0] == '>' {
+ ageKey = "age_in_days_gte"
+ opts.Age = strings.TrimSpace(opts.Age[1:])
+ } else if opts.Age[0] == '<' {
+ ageKey = "age_in_days_lte"
+ opts.Age = strings.TrimSpace(opts.Age[1:])
+ }
+ queryParams.Add(ageKey, opts.Age)
+ }
+ if len(opts.VulnStatus) > 0 {
+ queryParams.Add("vuln_status", strings.ToLower(opts.VulnStatus))
+ }
+ if len(opts.Reference) > 0 {
+ addQueryParams(queryParams, "reference", opts.Reference)
+ }
+ if len(opts.EpssScore) > 0 {
+ epssKey := "epss.epss_score"
+ if opts.EpssScore[0] == '>' {
+ epssKey = "epss.epss_score_gte"
+ opts.EpssScore = strings.TrimSpace(opts.EpssScore[1:])
+ } else if opts.EpssScore[0] == '<' {
+ epssKey = "epss.epss_score_lte"
+ opts.EpssScore = strings.TrimSpace(opts.EpssScore[1:])
+ }
+ queryParams.Add(epssKey, opts.EpssScore)
+ }
+ if len(opts.EpssPercentile) > 0 {
+ var epKey string
+ for _, ep := range opts.EpssPercentile {
+ epKey = "epss.epss_percentile"
+ if ep[0] == '>' {
+ epKey = "epss.epss_percentile_gte"
+ ep = strings.TrimSpace(ep[1:])
+ } else if ep[0] == '<' {
+ epKey = "epss.epss_percentile_lte"
+ ep = strings.TrimSpace(ep[1:])
+ }
+ queryParams.Add(epKey, ep)
+ }
+ }
+ if len(opts.CweIds) > 0 {
+ addQueryParams(queryParams, "cwe_id", opts.CweIds)
+ }
+ if len(opts.Cpe) > 0 {
+ queryParams.Add("cpe.cpe", opts.Cpe)
+ }
+ if len(opts.Product) > 0 {
+ addQueryParams(queryParams, "cpe.product", opts.Product)
+ }
+ if len(opts.Eproduct) > 0 {
+ addQueryParams(queryParams, "cpe.product_ne", opts.Eproduct)
+ }
+ if len(opts.Vendor) > 0 {
+ addQueryParams(queryParams, "cpe.vendor", opts.Vendor)
+ }
+ if opts.Kev == "true" {
+ queryParams.Add("is_exploited", "true")
+ } else if opts.Kev == "false" {
+ queryParams.Add("is_exploited", "false")
+ }
+ if opts.HasNucleiTemplate == "true" {
+ queryParams.Add("is_template", "true")
+ } else if opts.HasNucleiTemplate == "false" {
+ queryParams.Add("is_template", "false")
+ }
+ if opts.HasPoc == "true" {
+ queryParams.Add("is_poc", "true")
+ } else if opts.HasPoc == "false" {
+ queryParams.Add("is_poc", "false")
+ }
+ if opts.Hackerone == "true" {
+ queryParams.Add("hackerone.rank_gte", "1")
+ queryParams.Add("sort_asc", "hackerone.rank")
+ } else {
+ queryParams.Add("sort_desc", "cve_id")
+ }
+ if opts.RemotlyExploitable == "true" {
+ queryParams.Add("is_remote", "true")
+ }
+ if opts.Limit > 0 {
+ queryParams.Add("limit", strconv.Itoa(opts.Limit))
+ }
+ if opts.Offset >= 0 {
+ queryParams.Add("offset", strconv.Itoa(opts.Offset))
+ }
+ return queryParams.Encode()
+}
+
+func constructQueryByOptions(opts Options) string {
+ query := opts.Search
+ if len(opts.Vendor) > 0 {
+ query = fmt.Sprintf("%s cpe.vendor:%s", query, strings.Join(opts.Vendor, ","))
+ }
+ if len(opts.Product) > 0 {
+ query = fmt.Sprintf("%s cpe.product:%s", query, strings.Join(opts.Product, ","))
+ }
+ if len(opts.Eproduct) > 0 {
+ query = fmt.Sprintf("%s cpe.product_ne:%s", query, strings.Join(opts.Eproduct, ","))
+ }
+ if len(opts.Severity) > 0 {
+ query = fmt.Sprintf("%s severity:%s", query, strings.Join(opts.Severity, ","))
+ }
+ if len(opts.CvssScore) > 0 {
+ var cvsKey string
+ for _, cvssScore := range opts.CvssScore {
+ cvsKey = "cvss_score"
+ if cvssScore[0] == '>' {
+ cvsKey = "cvss_score_gte"
+ cvssScore = strings.TrimSpace(cvssScore[1:])
+ } else if cvssScore[0] == '<' {
+ cvsKey = "cvss_score_lte"
+ cvssScore = strings.TrimSpace(cvssScore[1:])
+ }
+ query = fmt.Sprintf("%s %s:%s", query, cvsKey, cvssScore)
+ }
+ }
+ if len(opts.EpssScore) > 0 {
+ epssKey := "epss.epss_score"
+ if opts.EpssScore[0] == '>' {
+ epssKey = "epss.epss_score_gte"
+ opts.EpssScore = strings.TrimSpace(opts.EpssScore[1:])
+ } else if opts.EpssScore[0] == '<' {
+ epssKey = "epss.epss_score_lte"
+ opts.EpssScore = strings.TrimSpace(opts.EpssScore[1:])
+ }
+ query = fmt.Sprintf("%s %s:%s", query, epssKey, opts.EpssScore)
+ }
+ if len(opts.EpssPercentile) > 0 {
+ var epKey string
+ for _, ep := range opts.EpssPercentile {
+ epKey = "epss.epss_percentile"
+ if ep[0] == '>' {
+ epKey = "epss.epss_percentile_gte"
+ ep = strings.TrimSpace(ep[1:])
+ } else if ep[0] == '<' {
+ epKey = "epss.epss_percentile_lte"
+ ep = strings.TrimSpace(ep[1:])
+ }
+ query = fmt.Sprintf("%s %s:%s", query, epKey, ep)
+ }
+ }
+ if len(opts.Cpe) > 0 {
+ query = fmt.Sprintf(`%s cpe.cpe:"%s"`, query, opts.Cpe)
+ }
+ if len(opts.CweIds) > 0 {
+ query = fmt.Sprintf("%s cwe_id:%s", query, strings.Join(opts.CweIds, ","))
+ }
+ if len(opts.Age) > 0 {
+ ageKey := "age_in_days"
+ if opts.Age[0] == '>' {
+ ageKey = "age_in_days_gte"
+ opts.Age = strings.TrimSpace(opts.Age[1:])
+ } else if opts.Age[0] == '<' {
+ ageKey = "age_in_days_lte"
+ opts.Age = strings.TrimSpace(opts.Age[1:])
+ }
+ query = fmt.Sprintf("%s %s:%s", query, ageKey, opts.Age)
+ }
+ if len(opts.Assignees) > 0 {
+ query = fmt.Sprintf("%s assignee:%s", query, strings.Join(opts.Assignees, ","))
+ }
+ if len(opts.VulnStatus) > 0 {
+ query = fmt.Sprintf("%s vuln_status:%s", query, strings.ToLower(opts.VulnStatus))
+ }
+ if opts.Kev == "true" {
+ query = fmt.Sprintf("%s is_exploited:true", query)
+ } else if opts.Kev == "false" {
+ query = fmt.Sprintf("%s is_exploited:false", query)
+ }
+ if opts.HasNucleiTemplate == "true" {
+ query = fmt.Sprintf("%s is_template:true", query)
+ } else if opts.HasNucleiTemplate == "false" {
+ query = fmt.Sprintf("%s is_template:false", query)
+ }
+ if opts.HasPoc == "true" {
+ query = fmt.Sprintf("%s is_poc:true", query)
+ } else if opts.HasPoc == "false" {
+ query = fmt.Sprintf("%s is_poc:false", query)
+ }
+ if opts.Hackerone == "true" {
+ query = fmt.Sprintf("%s hackerone.rank_gte:1 sort_asc:hackerone.rank", query)
+ } else {
+ query = fmt.Sprintf("%s sort_desc:cve_id", query)
+ }
+ if opts.RemotlyExploitable == "true" {
+ query = fmt.Sprintf("%s is_remote:true", query)
+ }
+
+ parts := strings.Split(query, " ")
+ parts = sliceutil.PruneEmptyStrings(parts)
+ parts = sliceutil.Dedupe(parts)
+ query = strings.Join(parts, " ")
+ if os.Getenv("DEBUG") == "true" {
+ fmt.Println("constructed query: ", query)
+ }
+ return query
+}
+
+func addQueryParams(queryParams *url.Values, key string, values []string) *url.Values {
+ if len(values) > 0 {
+ for _, value := range values {
+ queryParams.Add(key, value)
+ }
+ }
+ return queryParams
+}
+
+func getValidHeaders(keys []string) []string {
+ headers := []string{}
+ for _, hk := range keys {
+ if v, ok := headerMap[hk]; ok {
+ headers = append(headers, v)
+ }
+ }
+ return headers
+}
diff --git a/runner/testutils/util.go b/runner/testutils/util.go
new file mode 100644
index 0000000..0765d22
--- /dev/null
+++ b/runner/testutils/util.go
@@ -0,0 +1,38 @@
+package testutils
+
+import (
+ "fmt"
+ "os"
+ "os/exec"
+ "strings"
+)
+
+// RunCvemapßBinaryAndGetResults returns a list of the results
+func RunCvemapBinaryAndGetResults(cvemapBinary string, debug bool, args []string) ([]string, error) {
+ cmd := exec.Command("bash", "-c")
+ cmdLine := fmt.Sprintf(`./%s `, cvemapBinary)
+ cmdLine += strings.Join(args, " ")
+ if debug {
+ os.Setenv("DEBUG", "1")
+ cmd.Stderr = os.Stderr
+ }
+ cmd.Args = append(cmd.Args, cmdLine)
+ data, err := cmd.Output()
+ if err != nil {
+ return nil, err
+ }
+ parts := []string{}
+ items := strings.Split(string(data), "\n")
+ for _, i := range items {
+ if i != "" {
+ parts = append(parts, i)
+ }
+ }
+ return parts, nil
+}
+
+// TestCase is a single integration test case
+type TestCase interface {
+ // Execute executes a test case and returns any errors if occurred
+ Execute() error
+}
diff --git a/runner/types.go b/runner/types.go
new file mode 100644
index 0000000..89b05cf
--- /dev/null
+++ b/runner/types.go
@@ -0,0 +1,143 @@
+package runner
+
+import "time"
+
+type CVEBulkData struct {
+ ResultCount int `json:"result_count"`
+ TotalResults int `json:"total_results"`
+ Cves []CVEData `json:"cves"`
+}
+
+type CVEData struct {
+ CveID string `json:"cve_id,omitempty"`
+ CveDescription string `json:"cve_description,omitempty"`
+ Severity string `json:"severity,omitempty"`
+ CvssScore float64 `json:"cvss_score,omitempty"`
+ CvssMetrics *CvssMetrics `json:"cvss_metrics,omitempty"`
+ Weaknesses []struct {
+ CWEID string `json:"cwe_id"`
+ CWEName string `json:"cwe_name,omitempty"`
+ } `json:"weaknesses,omitempty"`
+ Epss struct {
+ Score float64 `json:"epss_score"`
+ Percentile float64 `json:"epss_percentile"`
+ } `json:"epss,omitempty"`
+ Cpe *OutputCpe `json:"cpe,omitempty"`
+ Reference []string `json:"reference,omitempty"`
+ Poc []struct {
+ URL string `json:"url"`
+ Source string `json:"source"`
+ AddedAt string `json:"added_at"`
+ } `json:"poc,omitempty"`
+ VendorAdvisory *string `json:"vendor_advisory,omitempty"`
+ Patch []string `json:"patch_url,omitempty"`
+ IsTemplate bool `json:"is_template"`
+ NucleiTemplates *NucleiTemplates `json:"nuclei_templates,omitempty"`
+ IsKev bool `json:"is_exploited"`
+ Kev *KevObject `json:"kev,omitempty"`
+ Assignee string `json:"assignee,omitempty"`
+ PublishedAt string `json:"published_at,omitempty"`
+ UpdatedAt string `json:"updated_at,omitempty"`
+ Hackerone struct {
+ Rank int `json:"rank"`
+ Count int `json:"count"`
+ } `json:"hackerone,omitempty"`
+ AgeInDays int `json:"age_in_days,omitempty"`
+ VulnStatus string `json:"vuln_status,omitempty"`
+ IsPoc bool `json:"is_poc"`
+ IsRemote bool `json:"is_remote"`
+ IsOss bool `json:"is_oss"`
+ VulnerableCPE []string `json:"vulnerable_cpe,omitempty"`
+ Shodan *OutputShodanData `json:"shodan,omitempty"`
+ OSS *OSS `json:"oss,omitempty"`
+}
+
+type CvssMetrics struct {
+ Cvss2 *Cvss2 `json:"cvss2,omitempty"`
+ Cvss30 *Cvss30 `json:"cvss30,omitempty"`
+ Cvss31 *Cvss31 `json:"cvss31,omitempty"`
+}
+
+type Cvss2 struct {
+ Score float64 `json:"score"`
+ Vector string `json:"vector"`
+ Severity string `json:"severity"`
+}
+
+type Cvss30 struct {
+ Score float64 `json:"score"`
+ Vector string `json:"vector"`
+ Severity string `json:"severity"`
+}
+
+type Cvss31 struct {
+ Score float64 `json:"score"`
+ Vector string `json:"vector"`
+ Severity string `json:"severity"`
+}
+
+type NucleiTemplates struct {
+ TemplateIssue string `json:"template_issue,omitempty"`
+ TemplateIssueType string `json:"template_issue_type,omitempty"`
+ TemplatePath string `json:"template_path,omitempty"`
+ TemplatePR string `json:"template_pr,omitempty"`
+ TemplateURL string `json:"template_url,omitempty"`
+ CreatedAt *time.Time `json:"created_at,omitempty"`
+ UpdatedAt *time.Time `json:"updated_at,omitempty"`
+}
+
+type OSS struct {
+ AllLanguages map[string]int `json:"all_languages,omitempty"`
+ Description string `json:"description,omitempty"`
+ Forks int `json:"forks,omitempty"`
+ Language string `json:"language,omitempty"`
+ Stars int `json:"stars,omitempty"`
+ Subscribers int `json:"subscribers,omitempty"`
+ Topics []string `json:"topics,omitempty"`
+ PushedAt CustomTime `json:"pushed_at,omitempty"`
+ CreatedAt CustomTime `json:"created_at,omitempty"`
+ UpdatedAt CustomTime `json:"updated_at,omitempty"`
+ URL string `json:"url,omitempty"`
+}
+
+type CustomTime struct {
+ time.Time
+}
+
+func (ct *CustomTime) UnmarshalJSON(b []byte) error {
+ s := string(b)
+ if s == "null" {
+ return nil
+ }
+ t, err := time.Parse(`"2006-01-02 15:04:05 -0700 MST"`, s)
+ if err != nil {
+ return err
+ }
+ ct.Time = t
+ return nil
+}
+
+type OutputCpe struct {
+ Cpe *string `json:"cpe,omitempty"`
+ Vendor *string `json:"vendor,omitempty"`
+ Product *string `json:"product,omitempty"`
+ Platform *string `json:"framework,omitempty"`
+}
+
+type KevObject struct {
+ AddedDate string `json:"added_date"`
+ DueDate string `json:"due_date"`
+}
+
+type OutputShodanData struct {
+ Count int `json:"count"`
+ Query []string `json:"query"`
+}
+
+type ErrorMessage struct {
+ Message string `json:"message"`
+}
+
+type CVEIdList struct {
+ Cves []string `json:"cves"`
+}
diff --git a/runner/util.go b/runner/util.go
new file mode 100644
index 0000000..642a67c
--- /dev/null
+++ b/runner/util.go
@@ -0,0 +1,41 @@
+package runner
+
+import (
+ "os"
+ "os/exec"
+ "runtime"
+
+ fileutil "github.com/projectdiscovery/utils/file"
+)
+
+func getLatestVersionCVSSScore(cvss CvssMetrics) float64 {
+ var highestScore float64
+ if cvss.Cvss2 != nil {
+ highestScore = cvss.Cvss2.Score
+ }
+ if cvss.Cvss30 != nil {
+ highestScore = cvss.Cvss30.Score
+ }
+ if cvss.Cvss31 != nil {
+ highestScore = cvss.Cvss31.Score
+ }
+ return highestScore
+}
+
+func isDefaultRun(opts Options) bool {
+ 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 == ""
+ filters := opts.Kev == "" && opts.Hackerone == "" && opts.HasNucleiTemplate == "" && opts.HasPoc == "" && opts.RemotlyExploitable == ""
+ return options && filters && !fileutil.HasStdin()
+}
+
+// clearScreen clears the terminal screen
+func clearScreen() {
+ var cmd *exec.Cmd
+ if runtime.GOOS == "windows" {
+ cmd = exec.Command("cls")
+ } else {
+ cmd = exec.Command("clear")
+ }
+ cmd.Stdout = os.Stdout
+ _ = cmd.Run()
+}
diff --git a/static/cvemap.png b/static/cvemap.png
new file mode 100644
index 0000000000000000000000000000000000000000..edf8e929f4e3c86c5e5347d8ddd40954270019d2
GIT binary patch
literal 1471774
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
z