diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index ee3ab2fdb1e..335206d3910 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -7,6 +7,9 @@ assignees: '' --- +**Precondition** +- [ ] I checked the issues list for existing open or closed reports of the same problem. + **Describe the bug** A clear and concise description of what the bug is. diff --git a/.github/ISSUE_TEMPLATE/false-positive-report.yml b/.github/ISSUE_TEMPLATE/false-positive-report.yml index 65e34b4c9d2..080828b4c7f 100644 --- a/.github/ISSUE_TEMPLATE/false-positive-report.yml +++ b/.github/ISSUE_TEMPLATE/false-positive-report.yml @@ -6,12 +6,22 @@ body: - type: markdown attributes: value: | - False Positive identified. + **Ensure you are using the latest version of dependency-check.** + + **Automation is used to process most false positives reports**; failure to follow these guidelines will delay the process: + + - Only enter a **single (1) Package URL**. + - Only enter a **single (1) CPE or CVE**. + - If filing a CPE report you do not need to add the CVEs. Note that **most reports should be for incorrectly matched CPEs**. + + If reporting false positives for multiple PURL and/or CPE please file multiple reports. + + Thank you for filing a false positive report! - type: input id: purl attributes: label: Package URl - description: The identified package URL as identified in the HTML Report. + description: Please enter the single identified package URL as identified in the HTML Report. Only a **single PURL** can be specified, if you are reporting more then one - please open two issues using this template. placeholder: ex. pkg:maven/org.apache.logging.log4j/log4j-slf4j-impl@2.12.1 validations: required: true @@ -19,7 +29,7 @@ body: id: cpe attributes: label: CPE - description: The Common Platform enumeration (CPE) as identified in the HTML Report. Please put backtic characters around the CPE to ensure it displays correctly. + description: Please enter the single Common Platform enumeration (CPE) as identified in the HTML Report. Only a **single CPE** can be specified. **Please put backtick characters around the CPE to ensure it displays correctly**. placeholder: ex. `cpe:2.3:a:apache:log4j:2.12.1:*:*:*:*:*:*:*` validations: required: true @@ -27,7 +37,7 @@ body: id: cve attributes: label: CVE - description: The vulnerability name as identified in the HTML Report. This is optional and may not be needed as most FP reports are due to an incorrect CPE. + description: The vulnerability name as identified in the HTML Report. If specifying a CPE this is not necessary; if entered please enter only a **single CVE**; if multiple CVE should be suppressed please enter multiple FP reports. This is optional and may not be needed as most FP reports are due to an incorrect CPE. placeholder: ex. CVE-2021-44228 validations: required: false @@ -58,4 +68,4 @@ body: label: Description description: Additional information regarding the false positive report. validations: - required: false \ No newline at end of file + required: false diff --git a/.github/contributing.md b/.github/contributing.md index c70f3a911c4..646996f90e4 100644 --- a/.github/contributing.md +++ b/.github/contributing.md @@ -3,8 +3,8 @@ ## Reporting Bugs - Ensure you're running the latest version of dependency-check. -- Ensure the bug has not [already been reported](https://github.com/jeremylong/DependencyCheck/issues). -- If you're unable to find an open issue addressing the problem, please [submit a new issue](https://github.com/jeremylong/DependencyCheck/issues/new/choose). +- Ensure the bug has not [already been reported](https://github.com/dependency-check/DependencyCheck/issues). +- If you're unable to find an open issue addressing the problem, please [submit a new issue](https://github.com/dependency-check/DependencyCheck/issues/new/choose). - Please fill out the appropriate section of the bug report template provided. - Delete any sections not needed in the template. @@ -14,13 +14,13 @@ ## Asking Questions -- Your question may be answered by taking a look at the [documentation](https://jeremylong.github.io/DependencyCheck/). -- Search both the [open and closed issues issues in GitHub](https://github.com/jeremylong/DependencyCheck/issues/) -- If you still have a question ask a [new question](https://github.com/jeremylong/DependencyCheck/issues/new?assignees=&labels=question&template=ask-a-question.md&title=) +- Your question may be answered by taking a look at the [documentation](https://dependency-check.github.io/DependencyCheck/). +- Search both the [open and closed issues issues in GitHub](https://github.com/dependency-check/DependencyCheck/issues/) +- If you still have a question ask a [new question](https://github.com/dependency-check/DependencyCheck/issues/new?assignees=&labels=question&template=ask-a-question.md&title=) ## Enhancement Requests -- Suggest changes by [submitting a new issue](https://github.com/jeremylong/DependencyCheck/issues/new?assignees=&labels=enhancement&template=feature_request.md&title=) and begin coding. +- Suggest changes by [submitting a new issue](https://github.com/dependency-check/DependencyCheck/issues/new?assignees=&labels=enhancement&template=feature_request.md&title=) and begin coding. ## Contributing Code diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 65449fc67fa..95c773197c9 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -11,10 +11,4 @@ updates: - package-ecosystem: "docker" directory: "/" schedule: - interval: "daily" - ignore: - # stay .net 3.1 - - dependency-name: "mcr.microsoft.com/dotnet/runtime" - versions: - - "5.x" - - "6.x" + interval: "daily" diff --git a/.github/lock.yml b/.github/lock.yml deleted file mode 100644 index 16260112371..00000000000 --- a/.github/lock.yml +++ /dev/null @@ -1,27 +0,0 @@ -# Number of days of inactivity before a closed issue or pull request is locked -daysUntilLock: 30 - -# Issues and pull requests with these labels will not be locked. Set to `[]` to disable -exemptLabels: [] - -# Label to add before locking, such as `outdated`. Set to `false` to disable -lockLabel: false - -# Comment to post before locking. Set to `false` to disable -lockComment: false - -# Assign `resolved` as the reason for locking. Set to `false` to disable -setLockReason: false - -# Limit to only `issues` or `pulls` -# only: issues - -# Optionally, specify configuration settings just for `issues` or `pulls` -# issues: -# exemptLabels: -# - help-wanted -# lockLabel: outdated - -# pulls: -# daysUntilLock: 30 - diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index fa049cb30e2..c2b6de9bd72 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,8 +1,16 @@ -## Fixes Issue # - ## Description of Change -*Please add a description of the proposed change* + + +## Related issues + + ## Have test cases been added to cover the new functionality? diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e10b84158cc..850054c0bb5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,12 +20,12 @@ jobs: - name: Install gpg secret key id: install-gpg-key run: | - cat <(echo -e "${{ secrets.OSSRH_GPG_SECRET_KEY }}") | gpg --batch --import + cat <(echo -e "${{ secrets.GPG_PRIVATE_KEY }}") | gpg --batch --import gpg --list-secret-keys --keyid-format LONG - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 - name: Check Maven Cache id: maven-cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} @@ -33,53 +33,55 @@ jobs: ${{ runner.os }}-maven- - name: Check Local Maven Cache id: maven-it-cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: maven/target/local-repo key: mvn-it-repo - name: Check ODC Data Cache id: odc-data-cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: core/target/data key: odc-data - - uses: actions/setup-dotnet@v3.0.3 + - uses: actions/setup-dotnet@v5.0.0 with: - dotnet-version: '6.0.x' - - name: Set up JDK 1.8 - id: jdk-8 - uses: actions/setup-java@v3 + dotnet-version: '8.0.x' + - name: Set up JDK 11 + id: jdk-11 + uses: actions/setup-java@v5 with: - java-version: 8 + java-version: 11 distribution: 'zulu' - server-id: ossrh - server-username: ${{ secrets.OSSRH_USERNAME }} - server-password: ${{ secrets.OSSRH_TOKEN }} - - uses: pnpm/action-setup@v2.2.4 + server-id: central + server-username: ${{ secrets.CENTRAL_USER }} + server-password: ${{ secrets.CENTRAL_PASSWORD }} + - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 with: version: 6.0.2 - name: Build Snapshot with Maven id: build-snapshot env: - MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} - MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }} - run: mvn -s settings.xml -Prelease clean package verify source:jar javadoc:jar gpg:sign deploy -DreleaseTesting --no-transfer-progress --batch-mode -Dgpg.passphrase=${{ secrets.OSSRH_GPG_SECRET_KEY_PASSWORD }} + MAVEN_USERNAME: ${{ secrets.CENTRAL_USER }} + MAVEN_PASSWORD: ${{ secrets.CENTRAL_PASSWORD }} + MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PRIVATE_KEY_PASSWORD }} + NVD_API_KEY: ${{ secrets.NVD_API_KEY }} + run: mvn -V -s settings.xml -Prelease clean package verify source:jar javadoc:jar gpg:sign deploy -DreleaseTesting --no-transfer-progress --batch-mode - name: SARIF Multitool - uses: microsoft/sarif-actions@v0.1 + uses: microsoft/sarif-actions@v0.2 with: # Command to be sent to SARIF Multitool command: 'validate core/target/test-reports/Report.sarif' - name: Archive IT test logs id: archive-logs if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: it-test-logs retention-days: 7 path: maven/target/it/**/build.log - name: Archive code coverage results id: archive-coverage - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: code-coverage-report retention-days: 7 @@ -88,7 +90,7 @@ jobs: **/target/jacoco-results/**/*.html - name: Archive Snapshot id: archive-snapshot - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: archive-snapshot retention-days: 7 @@ -99,20 +101,20 @@ jobs: ant/target/*.zip cli/target/*.zip - publish_coverage: - name: publish code coverage reports - runs-on: ubuntu-latest - needs: build - steps: - - name: Download coverage reports - uses: actions/download-artifact@v3 - with: - name: code-coverage-report - - name: Run codacy-coverage-reporter - uses: codacy/codacy-coverage-reporter-action@master - with: - project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} - coverage-reports: utils/target/jacoco-results/jacoco.xml,core/target/jacoco-results/jacoco.xml,maven/target/jacoco-results/jacoco.xml,ant/target/jacoco-results/jacoco.xml,cli/target/jacoco-results/jacoco.xml +# publish_coverage: +# name: publish code coverage reports +# runs-on: ubuntu-latest +# needs: build +# steps: +# - name: Download coverage reports +# uses: actions/download-artifact@v5 +# with: +# name: code-coverage-report +# - name: Run codacy-coverage-reporter +# uses: codacy/codacy-coverage-reporter-action@master +# with: +# project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} +# coverage-reports: utils/target/jacoco-results/jacoco.xml,core/target/jacoco-results/jacoco.xml,maven/target/jacoco-results/jacoco.xml,ant/target/jacoco-results/jacoco.xml,cli/target/jacoco-results/jacoco.xml docker: permissions: @@ -126,22 +128,34 @@ jobs: DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }} steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v5 - name: Check Maven Cache id: maven-cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} restore-keys: | ${{ runner.os }}-maven- - name: Download release build - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v5 with: name: archive-snapshot + - name: Set up Docker + uses: docker/setup-docker-action@v4 + with: + daemon-config: | + { + "debug": true, + "features": { + "containerd-snapshotter": true + } + } + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 - name: Build Docker Image run: ./build-docker.sh - name: build scan target - run: mvn -s settings.xml package -DskipTests=true --no-transfer-progress --batch-mode + run: mvn -V -s settings.xml package -DskipTests=true --no-transfer-progress --batch-mode - name: Test Docker Image run: ./test-docker.sh diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 8a2facfec59..428f96ee81a 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -33,11 +33,11 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v5 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -61,4 +61,4 @@ jobs: mvn -s settings.xml clean package -DskipTests=true --no-transfer-progress --batch-mode - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v4 diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml deleted file mode 100644 index c5cdec4008b..00000000000 --- a/.github/workflows/coverity.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: coverity-scan -on: - schedule: - - cron: '0 0 * * SAT' - -permissions: - contents: read - -jobs: - scan: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Set up JDK 1.8 - id: jdk-8 - uses: actions/setup-java@v3 - with: - java-version: 8 - distribution: 'zulu' - - name: Get coverity cli - run: | - wget https://scan.coverity.com/download/linux64 --no-verbose --post-data "token=${{ secrets.COVERITY_TOKEN }}&project=jeremylong%2FDependencyCheck" -O coverity_tool.tgz - mkdir coverity_tool - tar xzf coverity_tool.tgz --strip 1 -C coverity_tool - - name: Perform coverity scan - run: | - export PATH=`pwd`/coverity_tool/bin:$PATH - cov-build --dir cov-int mvn -DskipTests=true package --no-transfer-progress --batch-mode - - name: Submit coverity scan - run: | - tar czvf scan.tgz cov-int - curl --form token=${{ secrets.COVERITY_TOKEN }} \ - --form email=jeremy.long@gmail.com \ - --form file=@scan.tgz \ - --form version="main" \ - --form description="Weekly Scan" \ - https://scan.coverity.com/builds?project=jeremylong%2FDependencyCheck diff --git a/.github/workflows/false-positive-approvals.yml b/.github/workflows/false-positive-approvals.yml index cec937428f5..32b978d9e96 100644 --- a/.github/workflows/false-positive-approvals.yml +++ b/.github/workflows/false-positive-approvals.yml @@ -17,19 +17,21 @@ jobs: contains(github.event.comment.body,'approved') && (github.event.comment.user.login == 'jeremylong' || github.event.comment.user.login == 'aikebah' || - github.event.comment.user.login == 'nhumblot') }} + github.event.comment.user.login == 'nhumblot' || + github.event.comment.user.login == 'marcelstoer' || + github.event.comment.user.login == 'chadlwilson') }} runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 with: ref: generatedSuppressions - - uses: actions/setup-node@v3.6.0 + - uses: actions/setup-node@v5.0.0 - run: | npm install fast-xml-parser@4.0.9 npm install fs - name: Commit Suppression Rule id: fp-ops-commit - uses: actions/github-script@v6.4.0 + uses: actions/github-script@v8.0.0 with: script: | const { execSync } = require("child_process"); @@ -150,14 +152,14 @@ jobs: } - name: Publish Updated Suppressions if: ${{ steps.fp-ops-commit.outputs.publish == 'true' }} - uses: JamesIves/github-pages-deploy-action@v4.4.1 + uses: JamesIves/github-pages-deploy-action@v4.7.3 with: branch: gh-pages folder: suppressions target-folder: suppressions - name: Message failure if: ${{ failure() || steps.fp-ops-commit.outputs.failed }} - uses: actions/github-script@v6.4.0 + uses: actions/github-script@v8.0.0 with: script: | github.rest.issues.createComment({ diff --git a/.github/workflows/false-positive-ops.yml b/.github/workflows/false-positive-ops.yml index ab8e7947ccf..81b0bb9f6db 100644 --- a/.github/workflows/false-positive-ops.yml +++ b/.github/workflows/false-positive-ops.yml @@ -15,7 +15,7 @@ jobs: steps: - name: Remove Labels if: contains(github.event.issue.labels.*.name, 'pending more information') - uses: actions/github-script@v6.4.0 + uses: actions/github-script@v8.0.0 with: script: | github.rest.issues.removeLabel({ @@ -32,7 +32,7 @@ jobs: repo: context.repo.repo }) ) - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 with: path: odc - name: Parse False Positive Issue @@ -41,7 +41,7 @@ jobs: with: issue-body: ${{ github.event.issue.body }} template-path: odc/.github/ISSUE_TEMPLATE/false-positive-report.yml - - uses: actions/setup-node@v3.6.0 + - uses: actions/setup-node@v5.0.0 with: node-version: 14 - name: Initialize npm @@ -50,7 +50,7 @@ jobs: npm install packageurl-js - name: Parse Package URL id: purl-parser - uses: actions/github-script@v6.4.0 + uses: actions/github-script@v8.0.0 env: PURL: ${{ fromJSON(steps.issue-parser.outputs.jsonString).purl }} with: @@ -83,7 +83,7 @@ jobs: ARTIFACTID: ${{ fromJSON(steps.purl-parser.outputs.result).name }} VERSION: ${{ fromJSON(steps.purl-parser.outputs.result).version }} run: | - ver=$(curl -s https://jeremylong.github.io/DependencyCheck/current.txt) + ver=$(curl -s https://dependency-check.github.io/DependencyCheck/current.txt) mkdir ./fp-project cp ${{github.workspace}}/odc/.github/workflows/files/maven-pom.start ./fp-project/pom.xml echo -n $ver >> ./fp-project/pom.xml @@ -111,9 +111,9 @@ jobs: cd .. - name: Setup dotnet if: ${{ fromJSON(steps.purl-parser.outputs.result).type == 'nuget' }} - uses: actions/setup-dotnet@v3.0.3 + uses: actions/setup-dotnet@v5.0.0 with: - dotnet-version: '6.0.x' + dotnet-version: '8.0.x' - name: Setup dotnet fp-project if: ${{ fromJSON(steps.purl-parser.outputs.result).type == 'nuget' }} env: @@ -126,7 +126,7 @@ jobs: dotnet publish cd .. - name: "Check for setup complete" - uses: andstor/file-existence-action@v2 + uses: andstor/file-existence-action@v3 id: check_files with: files: "./fp-project" @@ -140,15 +140,17 @@ jobs: args: > --failOnCVSS 11 --enableExperimental + --ossIndexUsername ${{ secrets.OSS_INDEX_USERNAME }} + --ossIndexPassword ${{ secrets.OSS_INDEX_API_TOKEN }} - name: Upload FP Report if: steps.check_files.outputs.files_exists == 'true' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: FP Report path: ${{github.workspace}}/reports - name: Comment on maven issue if: ${{ fromJSON(steps.purl-parser.outputs.result).type == 'maven' }} - uses: actions/github-script@v6.4.0 + uses: actions/github-script@v8.0.0 env: GROUPID: ${{ fromJSON(steps.purl-parser.outputs.result).namespace }} ARTIFACTID: ${{ fromJSON(steps.purl-parser.outputs.result).name }} @@ -199,7 +201,7 @@ jobs: }) - name: Comment on npm issue if: ${{ fromJSON(steps.purl-parser.outputs.result).type == 'npm' }} - uses: actions/github-script@v6.4.0 + uses: actions/github-script@v8.0.0 env: NAME: ${{ fromJSON(steps.purl-parser.outputs.result).name }} VERSION: ${{ fromJSON(steps.purl-parser.outputs.result).version }} @@ -246,7 +248,7 @@ jobs: }) - name: Comment on dotnet issue if: ${{ fromJSON(steps.purl-parser.outputs.result).type == 'nuget' }} - uses: actions/github-script@v6.4.0 + uses: actions/github-script@v8.0.0 env: NAME: ${{ fromJSON(steps.purl-parser.outputs.result).name }} VERSION: ${{ fromJSON(steps.purl-parser.outputs.result).version }} @@ -293,7 +295,7 @@ jobs: - name: Message failure if: ${{ failure() }} - uses: actions/github-script@v6.4.0 + uses: actions/github-script@v8.0.0 with: script: | github.rest.issues.createComment({ diff --git a/.github/workflows/files/maven-pom.middle b/.github/workflows/files/maven-pom.middle index 51c6559871d..9592cf9a49e 100644 --- a/.github/workflows/files/maven-pom.middle +++ b/.github/workflows/files/maven-pom.middle @@ -14,11 +14,10 @@ https://repo.itextsupport.com/releases - spring - spring - https://repo.spring.io/release/ + spring-milestones + springmilestones + https://repo.spring.io/milestone/ - mavengoogle mavengoogle @@ -54,11 +53,21 @@ gradle https://plugins.gradle.org/m2/ + + splunk-artifactory + Splunk Releases + https://splunk.jfrog.io/splunk/ext-releases-local + vaadin-addon vaadin addons https://vaadin.com/nexus/content/repositories/vaadin-addons/ + + hazelcast-release + Hazelcast Repository + https://repository.hazelcast.com/release/ + false @@ -87,4 +96,4 @@ https://oss.sonatype.org/service/local/staging/deploy/maven2/ - \ No newline at end of file + diff --git a/.github/workflows/lint-pr.yml b/.github/workflows/lint-pr.yml index ebefb0f01fb..0c4125f1bd8 100644 --- a/.github/workflows/lint-pr.yml +++ b/.github/workflows/lint-pr.yml @@ -18,6 +18,6 @@ jobs: statuses: write runs-on: ubuntu-latest steps: - - uses: amannn/action-semantic-pull-request@v5.2.0 + - uses: amannn/action-semantic-pull-request@v6.1.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml new file mode 100644 index 00000000000..9b7bd2d21ac --- /dev/null +++ b/.github/workflows/lock.yml @@ -0,0 +1,24 @@ +name: 'Lock Threads' + +on: + schedule: + - cron: '0 3 * * *' + workflow_dispatch: + +permissions: + issues: write + pull-requests: write + discussions: write + +concurrency: + group: lock-threads + +jobs: + action: + runs-on: ubuntu-latest + steps: + - uses: dessant/lock-threads@v5 + with: + issue-inactive-days: '30' + pr-inactive-days: '30' + discussion-inactive-days: '30' diff --git a/.github/workflows/publish-suppressions.yml b/.github/workflows/publish-suppressions.yml new file mode 100644 index 00000000000..75245cb59f9 --- /dev/null +++ b/.github/workflows/publish-suppressions.yml @@ -0,0 +1,40 @@ +name: Publish Suppressions + +on: + workflow_dispatch: + +permissions: {} +jobs: + update_suppression: + permissions: + contents: write # to push changes in repo (jamesives/github-pages-deploy-action) + + name: Publish Suppressions + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + with: + ref: generatedSuppressions + - uses: actions/setup-node@v5.0.0 + - run: | + npm install fs + - name: Create Generated Suppressions XML + uses: actions/github-script@v8.0.0 + with: + script: | + const fs = require('fs'); + const generatedSuppressions = fs.readFileSync('generatedSuppressions.xml', 'utf8'); + if (!fs.existsSync('./suppressions')){ + fs.mkdirSync('./suppressions'); + } + fs.appendFileSync('suppressions/publishedSuppressions.xml', '\n' + generatedSuppressions + '\n', function (err) { + if (err) throw err; + console.log('publishedSuppressions.xml created'); + }); + - name: Publish Updated Suppressions + uses: JamesIves/github-pages-deploy-action@v4.7.3 + with: + branch: gh-pages + folder: suppressions + target-folder: suppressions + diff --git a/.github/workflows/pull_requests.yml b/.github/workflows/pull_requests.yml index 5d28966f2de..fc35f684891 100644 --- a/.github/workflows/pull_requests.yml +++ b/.github/workflows/pull_requests.yml @@ -10,104 +10,190 @@ jobs: test: name: Build and Test permissions: + security-events: write contents: read runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 - name: Check Maven Cache id: maven-cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.m2/repository/ key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} restore-keys: | ${{ runner.os }}-maven- - - uses: actions/setup-dotnet@v3.0.3 + - uses: actions/setup-dotnet@v5.0.0 with: - dotnet-version: '6.0.x' - - name: Set up JDK 1.8 - id: jdk-8 - uses: actions/setup-java@v3 + dotnet-version: '8.0.x' + - name: Set up JDK 11 + id: jdk-11 + uses: actions/setup-java@v5 with: - java-version: 8 + java-version: 11 distribution: 'zulu' - - uses: pnpm/action-setup@v2.2.4 + - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 with: version: 6.0.2 - name: Test with Maven id: build run: | - mvn -s settings.xml -pl utils,core,cli,ant,archetype -am compile verify --no-transfer-progress --batch-mode + mvn -V -s settings.xml -pl utils,core,cli,ant,archetype -am compile verify --no-transfer-progress --batch-mode - name: SARIF Multitool - uses: microsoft/sarif-actions@v0.1 + uses: microsoft/sarif-actions@v0.2 with: # Command to be sent to SARIF Multitool command: 'validate core/target/test-reports/Report.sarif' - + - name: Upload SARIF file + uses: github/codeql-action/upload-sarif@v4 + with: + sarif_file: utils/target/spotbugsSarif.json + category: spotbugs-utils + - name: Upload SARIF file + uses: github/codeql-action/upload-sarif@v4 + with: + sarif_file: cli/target/spotbugsSarif.json + category: spotbugs-cli + - name: Upload SARIF file + uses: github/codeql-action/upload-sarif@v4 + with: + sarif_file: ant/target/spotbugsSarif.json + category: spotbugs-ant + - name: Upload SARIF file + uses: github/codeql-action/upload-sarif@v4 + with: + sarif_file: core/target/spotbugsSarif.json + category: spotbugs-core + - name: Archive Snapshot + id: archive-snapshot + uses: actions/upload-artifact@v4 + with: + name: archive-snapshot + retention-days: 1 + path: | + **/target/*.asc + **/target/*.jar + **/target/*.pom + ant/target/*.zip + cli/target/*.zip + maven: name: Regression Test Maven Plugin permissions: + security-events: write contents: read runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 - name: Check Maven Cache id: maven-cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.m2/repository/ key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} restore-keys: | ${{ runner.os }}-maven- - - uses: actions/setup-dotnet@v3.0.3 + - uses: actions/setup-dotnet@v5.0.0 with: - dotnet-version: '6.0.x' - - name: Set up JDK 1.8 - id: jdk-8 - uses: actions/setup-java@v3 + dotnet-version: '8.0.x' + - name: Set up JDK 11 + id: jdk-11 + uses: actions/setup-java@v5 with: - java-version: 8 + java-version: 11 distribution: 'zulu' - - uses: pnpm/action-setup@v2.2.4 + - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 with: version: 6.0.2 - name: Regression Test Maven Plugin id: build + env: + NVD_API_KEY: ${{ secrets.NVD_API_KEY }} run: | - mvn -s settings.xml -pl utils,core,maven -am compile verify -DtestMavenPlugin -DreleaseTesting --no-transfer-progress --batch-mode + mvn -V -s settings.xml -pl maven -am compile verify -DtestMavenPlugin -DreleaseTesting --no-transfer-progress --batch-mode - name: Archive IT test logs id: archive-logs if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: it-test-logs retention-days: 7 path: maven/target/it/**/build.log - audit: - runs-on: ubuntu-latest - permissions: + - name: Upload SARIF file + uses: github/codeql-action/upload-sarif@v4 + with: + sarif_file: maven/target/spotbugsSarif.json + category: spotbugs-maven + + checkstyle: + name: Checkstyle Validation + permissions: + security-events: write contents: read - pull-requests: write - name: Audit + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 - name: Check Maven Cache id: maven-cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.m2/repository/ key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} restore-keys: | ${{ runner.os }}-maven- - - name: Semgrep - id: semgrep - run: | - docker run --rm -v "${PWD}:/src" returntocorp/semgrep semgrep --config "p/ci" --sarif > semgrep.sarif - - name: Maven Site - if: always() - run: | - mvn -s settings.xml package site -DskipTests=true --no-transfer-progress --batch-mode - - name: Publish Comments - if: always() + - name: Set up JDK 11 + id: jdk-11 + uses: actions/setup-java@v5 + with: + java-version: 11 + distribution: 'zulu' + - name: Checkstyle + id: checkstyle run: | - mvn se.bjurr.violations:violation-comments-to-github-maven-plugin:violation-comments --no-transfer-progress --batch-mode -DpullRequestId=${{ github.event.pull_request.number }} -DoAuth2Token=${{ secrets.GITHUB_TOKEN }} + mvn -V -s settings.xml checkstyle:checkstyle-aggregate --no-transfer-progress --batch-mode + - name: Upload SARIF file + uses: github/codeql-action/upload-sarif@v4 + with: + sarif_file: target/checkstyle-result.sarif + category: checkstyle + + docker: + permissions: + contents: read # to fetch code (actions/checkout) + + name: Build and Test Docker + runs-on: ubuntu-latest + needs: test + steps: + - name: Checkout code + uses: actions/checkout@v5 + - name: Check Maven Cache + id: maven-cache + uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + - name: Download release build + uses: actions/download-artifact@v5 + with: + name: archive-snapshot + - name: Set up Docker + uses: docker/setup-docker-action@v4 + with: + daemon-config: | + { + "debug": true, + "features": { + "containerd-snapshotter": true + } + } + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Build Docker Image + run: ./build-docker.sh + - name: build scan target + run: mvn -V -s settings.xml package -DskipTests=true --no-transfer-progress --batch-mode + - name: Test Docker Image + run: ./test-docker.sh diff --git a/.github/workflows/purge-cache.yml b/.github/workflows/purge-cache.yml index 0c22a03c533..9820e850a90 100644 --- a/.github/workflows/purge-cache.yml +++ b/.github/workflows/purge-cache.yml @@ -10,10 +10,10 @@ jobs: name: Purge GitHub Cache runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 - name: Check Maven Cache id: maven-cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} @@ -21,13 +21,13 @@ jobs: ${{ runner.os }}-maven- - name: Check Local Maven Cache id: maven-it-cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: maven/target/local-repo key: mvn-it-repo - name: Check ODC Data Cache id: odc-data-cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: core/target/data key: odc-data diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 67d500e3706..d2cbf30c8e7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,10 +2,10 @@ name: Build and Deploy Release ## ## Automates the release process -## 1. Update the 'body:' below and the changelog.md +## 1. Run `./list-changes.sh` and update the changelog.md. ## 2. Run `./prepare-release.sh` ## 3. Create PR, merge PR -## 4. Run `git push origin main --tags` +## 4. Run `git push origin --tags` ## permissions: @@ -24,40 +24,40 @@ jobs: - name: Install gpg secret key id: install-gpg-key run: | - cat <(echo -e "${{ secrets.OSSRH_GPG_SECRET_KEY }}") | gpg --batch --import + cat <(echo -e "${{ secrets.GPG_PRIVATE_KEY }}") | gpg --batch --import gpg --list-secret-keys --keyid-format LONG - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 - name: Check Maven Cache id: maven-cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.m2/repository/ key: mvn-repo - name: Check Local Maven Cache id: maven-it-cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: maven/target/local-repo key: mvn-it-repo - name: Check ODC Data Cache id: odc-data-cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: core/target/data key: odc-data - - uses: actions/setup-dotnet@v3.0.3 + - uses: actions/setup-dotnet@v5.0.0 with: - dotnet-version: '6.0.x' - - name: Set up JDK 1.8 - id: jdk-8 - uses: actions/setup-java@v3 + dotnet-version: '8.0.x' + - name: Set up JDK 11 + id: jdk-11 + uses: actions/setup-java@v5 with: - java-version: 8 + java-version: 11 distribution: 'zulu' - server-id: ossrh - server-username: ${{ secrets.OSSRH_USERNAME }} - server-password: ${{ secrets.OSSRH_TOKEN }} - - uses: pnpm/action-setup@v2.2.4 + server-id: central + server-username: ${{ secrets.CENTRAL_USER }} + server-password: ${{ secrets.CENTRAL_PASSWORD }} + - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 with: version: 6.0.2 - name: Configure Git user @@ -72,13 +72,15 @@ jobs: id: build-release timeout-minutes: 120 env: - MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} - MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }} + MAVEN_USERNAME: ${{ secrets.CENTRAL_USER }} + MAVEN_PASSWORD: ${{ secrets.CENTRAL_PASSWORD }} + MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PRIVATE_KEY_PASSWORD }} + NVD_API_KEY: ${{ secrets.NVD_API_KEY }} run: | - mvn -s settings.xml -Prelease "-DnexusUrl=https://oss.sonatype.org/" clean package source:jar javadoc:jar gpg:sign deploy site site:stage -DreleaseTesting --no-transfer-progress --batch-mode -Dgpg.passphrase=${{ secrets.OSSRH_GPG_SECRET_KEY_PASSWORD }} + mvn -V -s settings.xml -Prelease clean package source:jar javadoc:jar gpg:sign deploy site site:stage -DreleaseTesting --no-transfer-progress --batch-mode - name: Archive code coverage results id: archive-coverage - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: code-coverage-report retention-days: 7 @@ -87,7 +89,7 @@ jobs: **/target/jacoco-results/**/*.html - name: Archive Release id: archive-release - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: archive-release retention-days: 7 @@ -100,26 +102,26 @@ jobs: target/*.buildinfo - name: Archive Site id: archive-site - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: archive-site retention-days: 7 path: target/staging/ - publish_coverage: - name: publish code coverage reports - runs-on: ubuntu-latest - needs: build - steps: - - name: Download coverage reports - uses: actions/download-artifact@v3 - with: - name: code-coverage-report - - name: Run codacy-coverage-reporter - uses: codacy/codacy-coverage-reporter-action@master - with: - project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} - coverage-reports: utils/target/jacoco-results/jacoco.xml,core/target/jacoco-results/jacoco.xml,maven/target/jacoco-results/jacoco.xml,ant/target/jacoco-results/jacoco.xml,cli/target/jacoco-results/jacoco.xml +# publish_coverage: +# name: publish code coverage reports +# runs-on: ubuntu-latest +# needs: build +# steps: +# - name: Download coverage reports +# uses: actions/download-artifact@v5 +# with: +# name: code-coverage-report +# - name: Run codacy-coverage-reporter +# uses: codacy/codacy-coverage-reporter-action@master +# with: +# project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} +# coverage-reports: utils/target/jacoco-results/jacoco.xml,core/target/jacoco-results/jacoco.xml,maven/target/jacoco-results/jacoco.xml,ant/target/jacoco-results/jacoco.xml,cli/target/jacoco-results/jacoco.xml docker: name: Publish Docker @@ -131,22 +133,34 @@ jobs: steps: - name: Check Maven Cache id: maven-cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.m2/repository/ key: mvn-repo - name: Check Docker ODC Cache id: docker-odc-cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/OWASP-Dependency-Check key: docker-repo - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v5 - name: Download release build - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v5 with: name: archive-release + - name: Set up Docker + uses: docker/setup-docker-action@v4 + with: + daemon-config: | + { + "debug": true, + "features": { + "containerd-snapshotter": true + } + } + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 - name: Build Docker Image run: ./build-docker.sh - name: build scan target @@ -164,14 +178,14 @@ jobs: needs: build steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v5 - name: Get version id: get-version run: | VERSION=$( mvn help:evaluate -Dexpression=project.version -q -DforceStdout ) echo "VERSION=$VERSION" >> $GITHUB_ENV - name: Download release build - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v5 with: name: archive-release - name: Create Release @@ -185,13 +199,7 @@ jobs: prerelease: false draft: false body: | - ### Fixed - - - NullPointerException in MSBuildAnalyzer (#5589) - - SQL Syntax for Oracle (#5590) - - Use `https://` URLs in report templates (#5582) - - See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/64?closed=1). + Refer to the [CHANGELOG.md](https://github.com/dependency-check/DependencyCheck/blob/main/CHANGELOG.md#change-log) for information about improvements and upgrade notes. - name: Upload CLI id: upload-release-cli @@ -250,9 +258,9 @@ jobs: needs: build steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v5 - name: Download Site - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v5 with: name: archive-site path: target/staging @@ -260,7 +268,7 @@ jobs: run: ls -R working-directory: target - name: Deploy gh-pages - uses: JamesIves/github-pages-deploy-action@v4.4.1 + uses: JamesIves/github-pages-deploy-action@v4.7.3 with: branch: gh-pages folder: target/staging diff --git a/.java-version b/.java-version index 6259340971b..2dbc24b32d3 100644 --- a/.java-version +++ b/.java-version @@ -1 +1 @@ -1.8 +11.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dd26b3b1e1..6686cb21509 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,482 +1,976 @@ # Change Log +## [Version 12.1.8](https://github.com/dependency-check/DependencyCheck/releases/tag/v12.1.8) (2025-10-13) + +- fix: improve VulnerableSoftware comparison ([#8031](https://github.com/dependency-check/DependencyCheck/pull/8031)) +- build: fix flaky central test ([#8039](https://github.com/dependency-check/DependencyCheck/pull/8039)) +- docs: Improve Gradle docs wrt experimental analyzers, use of Central and Proxy configuration ([#8036](https://github.com/dependency-check/DependencyCheck/pull/8036)) +- docs: add note about central analyzer for gradle ([#8038](https://github.com/dependency-check/DependencyCheck/pull/8038)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/101?closed=1) + +## [Version 12.1.7](https://github.com/dependency-check/DependencyCheck/releases/tag/v12.1.7) (2025-10-12) + +- fix: disable central analyzer after failures ([#7993](https://github.com/dependency-check/DependencyCheck/pull/7993)) +- fix: Suppress JVM warnings from Lucene within CLI ([#8003](https://github.com/dependency-check/DependencyCheck/pull/8003)) +- fix: Clean up Apache Lucene logging via SLF4j redirect ([#7979](https://github.com/dependency-check/DependencyCheck/pull/7979)) +- fix: Correct Archive Analyzer behaviour on certain tgz archives ([#7986](https://github.com/dependency-check/DependencyCheck/pull/7986)) +- fix: Update NVD CPE search URLs in generated reports to match new search interface ([#7970](https://github.com/dependency-check/DependencyCheck/pull/7970)) +- fix: improve OSS Index Error Reporting ([#7977](https://github.com/dependency-check/DependencyCheck/pull/7977)) +- fix(fp): Consolidate false positive suppression for false positives on Redis client libs ([#8017](https://github.com/dependency-check/DependencyCheck/pull/8017)) +- fix(fp): Fix more common false positives for popular PHP/composer frameworks with generic names ([#7994](https://github.com/dependency-check/DependencyCheck/pull/7994)) +- docs: improve slack notification documentation ([#8026](https://github.com/dependency-check/DependencyCheck/pull/8026)) +- docs: Documentation artifactory settings fix ([#7999](https://github.com/dependency-check/DependencyCheck/pull/7999)) +- docs: Clarify Nexus Analyzer requirements and usage ([#8000](https://github.com/dependency-check/DependencyCheck/pull/8000)) +- build: Build amd64 and arm64 multi-platform Docker image ([#7952](https://github.com/dependency-check/DependencyCheck/pull/7952)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/100?closed=1) + +## [Version 12.1.6](https://github.com/dependency-check/DependencyCheck/releases/tag/v12.1.6) (2025-09-24) + +- fix: Disable OSS Index if its credentials are missing ([#7963](https://github.com/dependency-check/DependencyCheck/pull/7963)) +- fix: Correct CVSSv4 parsing for low precision OSSIndex values ([#7935](https://github.com/dependency-check/DependencyCheck/pull/7935)) +- fix(fp): Fix false positives for Redis Server against NPM/JS client libs ([#7942](https://github.com/dependency-check/DependencyCheck/pull/7942)) +- docs: Fix legacy GitHub links within docs and CHANGELOG ([#7944](https://github.com/dependency-check/DependencyCheck/pull/7944)) +- chore: fix version typo in security policy ([#7936](https://github.com/dependency-check/DependencyCheck/pull/7936)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/99?closed=1) + +## [Version 12.1.5](https://github.com/dependency-check/DependencyCheck/releases/tag/v12.1.5) (2025-09-20) + +- **fix**: Update to support OSS Index Authentication Requirements ([#7920](https://github.com/dependency-check/DependencyCheck/pull/7920)) + - Note: OSS Index will require authentication starting 9/22/2025. Users must configure a free account to continue using the OSS Index Analyzer. See https://ossindex.sonatype.org/doc/auth-required. +- fix: add CVSSv4 to suppressed entries in JSON report ([#7900](https://github.com/dependency-check/DependencyCheck/pull/7900)) +- fix: correctly utilize CVSSv4 from ossindex ([#7899](https://github.com/dependency-check/DependencyCheck/pull/7899)) +- fix: npe when processing cve with empty configuration ([#7888](https://github.com/dependency-check/DependencyCheck/pull/7888)) +- fix: Return unsorted vulnerabilities in new HashSet, avoiding CoMod ([#7848](https://github.com/dependency-check/DependencyCheck/pull/7848)) +- fix: Return unsorted vulnerabilities in new HashSet, avoiding CoMod +- fix: class loading problem with fat jars ([#7786](https://github.com/dependency-check/DependencyCheck/pull/7786)) ([#7787](https://github.com/dependency-check/DependencyCheck/pull/7787)) +- fix: Improve Artifactory handler log message ([#7838](https://github.com/dependency-check/DependencyCheck/pull/7838)) +- fix: classloading problem with fat jars ([#7786](https://github.com/dependency-check/DependencyCheck/pull/7786)) +- fix: Add null checking when parsing the license json in AbstractNpmAnalyzer. ([#7784](https://github.com/dependency-check/DependencyCheck/pull/7784)) +- fix(fp): resolves several false positives related to CVE-2021-41033 ([#7736](https://github.com/dependency-check/DependencyCheck/pull/7736)) +- docs: Clarify format of exclude patterns ([#7879](https://github.com/dependency-check/DependencyCheck/pull/7879)) +- docs: Document poetry-based analysis behaviour in Python analyzer ([#7855](https://github.com/dependency-check/DependencyCheck/pull/7855)) +- docs: request FP reporters use the latest version of ODC. ([#7820](https://github.com/dependency-check/DependencyCheck/pull/7820)) +- docs: update development pre-reqs ([#7792](https://github.com/dependency-check/DependencyCheck/pull/7792)) +- docs: fix minor typos in false positive issue template ([#7763](https://github.com/dependency-check/DependencyCheck/pull/7763)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/98?closed=1) + +## [Version 12.1.3](https://github.com/dependency-check/DependencyCheck/releases/tag/v12.1.3) (2025-06-10) + +- fix: correct regex matches introduced in 12.1.2 ([#7726](https://github.com/dependency-check/DependencyCheck/pull/7726)) +- build(deps): bump org.semver4j:semver4j from 5.7.0 to 5.7.1 ([#7718](https://github.com/dependency-check/DependencyCheck/pull/7718)) +- build(deps): bump junit.version from 5.13.0 to 5.13.1 ([#7719](https://github.com/dependency-check/DependencyCheck/pull/7719)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/97?closed=1) + +## [Version 12.1.2](https://github.com/dependency-check/DependencyCheck/releases/tag/v12.1.2) (2025-06-07) + +- fix: Allow configuring OSS Index user/pw directly ([#7640](https://github.com/dependency-check/DependencyCheck/pull/7640)) +- fix: remove vulnerable transitive dependency - beanutils ([#7705](https://github.com/dependency-check/DependencyCheck/pull/7705)) +- fix: Simplify PHP framework suppression for Composer ([#7693](https://github.com/dependency-check/DependencyCheck/pull/7693)) +- fix: update CPE pattern to remove FP ([#7684](https://github.com/dependency-check/DependencyCheck/pull/7684)) +- fix(cli): Patch generated Windows shell script for JAVACMD installs with spaces ([#7653](https://github.com/dependency-check/DependencyCheck/pull/7653)) +- fix: Resolve various WCAG accessibility / css issues in the HTML report ([#7629](https://github.com/dependency-check/DependencyCheck/pull/7629)) +- fix: [#7510](https://github.com/dependency-check/DependencyCheck/pull/7510) Display a dedicated message when receiving an HTTP 403 ([#7575](https://github.com/dependency-check/DependencyCheck/pull/7575)) +- docs: Make `Vulnerability Sources` in `Related Work` clearer ([#7691](https://github.com/dependency-check/DependencyCheck/pull/7691)) +- docs: [#7610](https://github.com/dependency-check/DependencyCheck/pull/7610) add a reference to NVD mirroring in getting started documentation ([#7611](https://github.com/dependency-check/DependencyCheck/pull/7611)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/96?closed=1) + +## [Version 12.1.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v12.1.1) (2025-04-05) + +- fix: resolve NVD data Parse error `com.fasterxml.jackson.core.JsonParseException: Unexpected character (']' (code 93))` + - bump open-vulnerability-client from 7.3.1 to 7.3.2 ([#7577](https://github.com/dependency-check/DependencyCheck/pull/7577)) +- fix: update links for repository move from `jeremylong` to the `dependency-check` organization ([#7373](https://github.com/dependency-check/DependencyCheck/pull/7373)) +- fix: resolve NPE when processing CVE-2025-2682 ([#7558](https://github.com/dependency-check/DependencyCheck/pull/7558)) +- fix: prevent rogue base suppression files ([#7544](https://github.com/dependency-check/DependencyCheck/pull/7544)) +- fix: [#6819](https://github.com/dependency-check/DependencyCheck/pull/6819) handle invalid toml file ([#7548](https://github.com/dependency-check/DependencyCheck/pull/7548)) +- fix: Use unscored severity only in absence of any CVSS baseScore ([#7530](https://github.com/dependency-check/DependencyCheck/pull/7530)) +- fix: protect against exotic version number of yarn ([#7525](https://github.com/dependency-check/DependencyCheck/pull/7525)) +- fix: Ignore require-bundle MANIFEST.MF entry for evidence ([#7523](https://github.com/dependency-check/DependencyCheck/pull/7523)) +- fix: avoid error on yarn berry audit when no vulnerability found ([#7501](https://github.com/dependency-check/DependencyCheck/pull/7501)) +- fix: improve null checks in Downloader ([#7493](https://github.com/dependency-check/DependencyCheck/pull/7493)) +- fix: improve null checks resolves https://github.com/dependency-check/dependency-check-gradle/issues/441 +- fix: Avoid FPs when Composer product name has php ([#7486](https://github.com/dependency-check/DependencyCheck/pull/7486)) +- fix: cli not honoring window paths correctly ([#7470](https://github.com/dependency-check/DependencyCheck/pull/7470)) +- fix: Also apply muteNoisyLoggers to UpdateMojo ([#7469](https://github.com/dependency-check/DependencyCheck/pull/7469)) +- fix: Make HC5 Downloader honor the connection- and readTimeout settings that the old URLConnectionFactory based downloads observed ([#7437](https://github.com/dependency-check/DependencyCheck/pull/7437)) +- docs: sync the supported Maven version with the one stated in the system requirement section ([#7570](https://github.com/dependency-check/DependencyCheck/pull/7570)) +- docs: update proxy config documentation ([#7550](https://github.com/dependency-check/DependencyCheck/pull/7550)) +- docs: Remove copyright as requested by the Apache foundation +- docs: drop redundant text in the Internet Access Required section ([#7521](https://github.com/dependency-check/DependencyCheck/pull/7521)) +- docs: correct gradle documentation ([#7511](https://github.com/dependency-check/DependencyCheck/pull/7511)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/95?closed=1) + +## [Version 12.1.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v12.1.0) (2025-02-16) + +- build(deps): bump open-vulnerability-client to 7.2.2 ([#7407](https://github.com/dependency-check/DependencyCheck/pull/7407)) + - resolves issue with downloading data from the NVD ([#7406](https://github.com/dependency-check/DependencyCheck/pull/7406)) +- fix: Improve thread safety issue [#7338](https://github.com/dependency-check/DependencyCheck/pull/7338) alternative ([#7367](https://github.com/dependency-check/DependencyCheck/pull/7367)) +- feat: Implement Yarn Berry Analyser ([#7319](https://github.com/dependency-check/DependencyCheck/pull/7319)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/94?closed=1) + +## [Version 12.0.2](https://github.com/dependency-check/DependencyCheck/releases/tag/v12.0.2) (2025-01-29) + +- fix: correct JSON report error ([#7350](https://github.com/dependency-check/DependencyCheck/pull/7350)) +- fix: some compatability issues in the gitlab report ([#7349](https://github.com/dependency-check/DependencyCheck/pull/7349)) +- fix: ArtifactoryAnalyzer updated to use the HTTPClient5-based Downloader and skip unusable results ([#7293](https://github.com/dependency-check/DependencyCheck/pull/7293)) +- chore: allow messages via EngineVersionCheck ([#7353](https://github.com/dependency-check/DependencyCheck/pull/7353)) +- chore: switch from javax.json to jakarta.json ([#7326](https://github.com/dependency-check/DependencyCheck/pull/7326)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/93?closed=1). + +## [Version 12.0.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v12.0.1) (2025-01-19) + +- docs: Fix OSS Index Maven config documentation ([#7322](https://github.com/dependency-check/DependencyCheck/pull/7322)) +- Fix OSS Index Maven config documentation +- chore(docs): Document Gradle plugin support for failBuildOnUnusedSuppressionRule ([#7307](https://github.com/dependency-check/DependencyCheck/pull/7307)) +- chore(docs): Correct analyzers config example to use Gradle dot-syntax ([#7305](https://github.com/dependency-check/DependencyCheck/pull/7305)) +- fix: improve error message on improperly configured serverId credentials in settings.xml ([#7313](https://github.com/dependency-check/DependencyCheck/pull/7313)) +- fix: Lower Basic serverId when Bearer was expected to a warning +- fix: improve error message on improperly configured serverId credentials +- fix: Correct nonProxyHosts support when no sys properties set ([#7306](https://github.com/dependency-check/DependencyCheck/pull/7306)) +- core(docs): Group failBuildOnUnusedSuppressionRule flag next to suppression file configuration +- core(docs): Update Gradle plugin documentation for failBuildOnUnusedSuppressionRule support +- fix: Correct nonProxyHosts support when no sys properties set +- chore(docs): Correct analyzers config example to use Gradle dot-syntax + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/92?closed=1). + +## [Version 12.0.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v12.0.0) (2025-01-11) + +- BREAKING CHANGE: report on CVSS v4 ([#7204](https://github.com/dependency-check/DependencyCheck/pull/7204)) + - the schema has been updated to include CVSS v4 for JSON and XML reports +- feat: show from which dependency the CVE comes in failure report ([#7224](https://github.com/dependency-check/DependencyCheck/pull/7224)) +- feat: Use Maven settings decryption API for decrypting secrets from settings.xml ([#7284](https://github.com/dependency-check/DependencyCheck/pull/7284)) +- feat: Extend authentication to support Bearer token for many resources ([#7277](https://github.com/dependency-check/DependencyCheck/pull/7277)) +- feat: Add a flag to fail when one or more suppression rules are not used ([#7244](https://github.com/dependency-check/DependencyCheck/pull/7244)) +- fix: add product evidence as vendor to reduce FN ([#7295](https://github.com/dependency-check/DependencyCheck/pull/7295)) +- fix: Make the HTTP-Client use pre-emptive authentication ([#7255](https://github.com/dependency-check/DependencyCheck/pull/7255)) +- fix: Add the missing proxy credentials for suppressionFileUser/Password authentication scenario +- fix: increase max retry count ([#7252](https://github.com/dependency-check/DependencyCheck/pull/7252)) +- fix: Make the HTTP-Client use pre-emptive authentication for configured server credentials and extend HTTPClient usage to Nexus search +- fix: Tranform into UTC the last modified date from database ([#7222](https://github.com/dependency-check/DependencyCheck/pull/7222)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/91?closed=1). + +## [Version 11.1.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v11.1.1) (2024-12-04) + +- fix: re-enable issue locking ([#7220](https://github.com/dependency-check/DependencyCheck/pull/7220)) +- fix: add username/password properties to be able to authenticate for central.content.url and analyzer.central.url again ([#7169](https://github.com/dependency-check/DependencyCheck/pull/7169)) +- fix: rework replaceOrAddVulnerability ([#7177](https://github.com/dependency-check/DependencyCheck/pull/7177)) +- fix: do not log loading of JDBC driver ([#7155](https://github.com/dependency-check/DependencyCheck/pull/7155)) +- fix: expose flag to disable version check ([#7147](https://github.com/dependency-check/DependencyCheck/pull/7147)) +- fix: Gracefully handle CVEs with bad configuration nodes missing CPE match expressions ([#7125](https://github.com/dependency-check/DependencyCheck/pull/7125)) +- chore: cleanup base suppression ([#7138](https://github.com/dependency-check/DependencyCheck/pull/7138)) +- docs: update gradle configuration documentation ([#7176](https://github.com/dependency-check/DependencyCheck/pull/7176)) +- docs: update documentation for Gradle plugin ([#7143](https://github.com/dependency-check/DependencyCheck/pull/7143)) +- docs: improve false positive issue templat ([#7130](https://github.com/dependency-check/DependencyCheck/pull/7130)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/90?closed=1). + +## [Version 11.1.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v11.1.0) (2024-10-30) + +- feat: PHP Composer Analyzer now scans packages-dev by default ([#7114](https://github.com/dependency-check/DependencyCheck/pull/7114)) + - Users can configure if packages-dev should be skipped +- fix(regression): re-add h2 database driver name ([#7115](https://github.com/dependency-check/DependencyCheck/pull/7115)) +- fix(regression): Make the Downloader honour the proxy.nonproxyhosts ODC Setting ([#7077](https://github.com/dependency-check/DependencyCheck/pull/7077)) +- fix: do not set legacy proxy from maven or env ([#7072](https://github.com/dependency-check/DependencyCheck/pull/7072)) ([#7074](https://github.com/dependency-check/DependencyCheck/pull/7074)) +- docs: add missing documentation for the MS Build Analyzer ([#7113](https://github.com/dependency-check/DependencyCheck/pull/7113)) +- docs: Document the breaking change for Maven plugin as reporting plugin ([#7079](https://github.com/dependency-check/DependencyCheck/pull/7079)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/89?closed=1). + +## [Version 11.0.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v11.0.0) (2024-10-21) + +- **breaking change**: Switch from JMockit to Mockito & build target to Java 11 ([#6922](https://github.com/dependency-check/DependencyCheck/pull/6922)) + - dependency-check now requires a minimum of Java 11.0 to run +- **breaking change**: bump com.h2database:h2 from 2.1.214 to 2.3.232 ([#6132](https://github.com/dependency-check/DependencyCheck/pull/6132)) + - H2 databases generated with an older version of ODC will not work with ODC 11.0.0; a new H2 db must be generated +- **breaking change**: Maven plugin updated to Doxia 2.x reporting stack + - Users of the Maven plugin that configure it as a reporting plugin will need to use maven-site-plugin 3.20.0 or later ([#6959](https://github.com/dependency-check/DependencyCheck/pull/6959)) +- feat: Replace old Downloader by an Apache HTTPClient based downloader +- feat: Use Apache HTTPClient for downloads of public resources ([#6949](https://github.com/dependency-check/DependencyCheck/pull/6949)) +- feat: Also make NodeAuditSearch usr our HTTPClient based connections +- feat: Also make OSSIndexAnalyzer use our HTTPClient based connections +- feat: Migrate CentralSearch to use Apache HTTP-client via Downloader +- feat: Extend apache HTTP-client usage to EngineVersionCheck +- feat: Remove the need to specify dbDriver for external databases using JDBCv4 ServiceLoader supporting JDBC drivers ([#6938](https://github.com/dependency-check/DependencyCheck/pull/6938)) +- fix: use latest generated suppressions ([#7064](https://github.com/dependency-check/DependencyCheck/pull/7064)) +- fix: Fixup parameter sequence for Dowloader credentials ([#7033](https://github.com/dependency-check/DependencyCheck/pull/7033)) +- fix: Fixup the missing addition of NVD API Datafeed credentials (if configured) +- fix: Fixup broken proxy authentication in first attempt; extend to include KEV downloads +- fix: store timestamps locally for local resources ([#6936](https://github.com/dependency-check/DependencyCheck/pull/6936)) +- build: Remove the animal-sniffer, propagate java version to plugin-archetype ([#6950](https://github.com/dependency-check/DependencyCheck/pull/6950)) +- build: Update Checkstyle configuration and Suppression DTD references ([#6951](https://github.com/dependency-check/DependencyCheck/pull/6951)) +- chore: Update test db schema ([#7036](https://github.com/dependency-check/DependencyCheck/pull/7036)) +- chore: remove old, unneeded database upgrade script +- docs: reformat javadoc ([#7009](https://github.com/dependency-check/DependencyCheck/pull/7009)) +- docs: Fixup javadoc warnings ([#6995](https://github.com/dependency-check/DependencyCheck/pull/6995)) +- chore: Replace use of several deprecated methods/classes by their successors ([#6933](https://github.com/dependency-check/DependencyCheck/pull/6933)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/87?closed=1). + +## [Version 10.0.4](https://github.com/dependency-check/DependencyCheck/releases/tag/v10.0.4) (2024-09-01) + + - build(deps): exclude unused dependency ([#6916](https://github.com/dependency-check/DependencyCheck/pull/6916)) + - fix: improve regex ([#6917](https://github.com/dependency-check/DependencyCheck/pull/6917)) + - fix: correctly handle null values in cpeMatch ([#6915](https://github.com/dependency-check/DependencyCheck/pull/6915)) + - fix(site): Update Fluido skin to resolve broken fork-me-on-github image ([#6914](https://github.com/dependency-check/DependencyCheck/pull/6914)) + - fix: do not report over 100% download complete ([#6899](https://github.com/dependency-check/DependencyCheck/pull/6899)) + - fix: Correct spelling of occurring in NvdApiDataSource.java ([#6883](https://github.com/dependency-check/DependencyCheck/pull/6883)) + - fix: skip blank lines in requirements.txt ([#6867](https://github.com/dependency-check/DependencyCheck/pull/6867)) + - fix: correct percentage calculation ([#6868](https://github.com/dependency-check/DependencyCheck/pull/6868)) + - docs: remove old recommendation ([#6860](https://github.com/dependency-check/DependencyCheck/pull/6860)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/88?closed=1). + +## [Version 10.0.3](https://github.com/dependency-check/DependencyCheck/releases/tag/v10.0.3) (2024-07-16) + +- feat: Enable configuration of a lower resultsPerPage on NVD API ([#6843](https://github.com/dependency-check/DependencyCheck/pull/6843)) +- build(deps): bump open-vulnerability-clients from 6.1.6 to 6.1.7 ([#6848](https://github.com/dependency-check/DependencyCheck/pull/6848)) +- build(deps): bump JamesIves/github-pages-deploy-action from 4.6.1 to 4.6.3 ([#6814](https://github.com/dependency-check/DependencyCheck/pull/6814)) +- build(deps): bump org.codehaus.mojo:versions-maven-plugin from 2.16.2 to 2.17.0 ([#6762](https://github.com/dependency-check/DependencyCheck/pull/6762)) +- build(deps): bump org.apache.maven.plugins:maven-checkstyle-plugin from 3.3.1 to 3.4.0 ([#6815](https://github.com/dependency-check/DependencyCheck/pull/6815)) +- build(deps): bump golang from 1.22.4-alpine to 1.22.5-alpine ([#6805](https://github.com/dependency-check/DependencyCheck/pull/6805)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/84?closed=1). + +## [Version 10.0.2](https://github.com/dependency-check/DependencyCheck/releases/tag/v10.0.2) (2024-07-06) + +**Mandatory Upgrade** - due to older versions of dependency-check causing numerous, spurious requests that end in processing failures, this upgrade is mandatory so that the NVD can differentiate valid requests and block the old clients. + +- build(deps): bump open-vulnerability-clients ([#6810](https://github.com/dependency-check/DependencyCheck/pull/6810)) +- fix(db): [#6788](https://github.com/dependency-check/DependencyCheck/pull/6788) removing redundant db index "idxVulnerability" on "vulnerability.cve" ([#6807](https://github.com/dependency-check/DependencyCheck/pull/6807)) +- docs: Further improve formatting and docs of H2 database caching strats ([#6804](https://github.com/dependency-check/DependencyCheck/pull/6804)) +- fix: update_vulnerability in dbStatements_oracle.properties ([#6803](https://github.com/dependency-check/DependencyCheck/pull/6803)) +- fix: fix NPE ([#6778](https://github.com/dependency-check/DependencyCheck/pull/6778)) +- fix: add hint to resolve false negative ([#6802](https://github.com/dependency-check/DependencyCheck/pull/6802)) +- chore: update configure ([#6794](https://github.com/dependency-check/DependencyCheck/pull/6794)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/86?closed=1). + +## [Version 10.0.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v10.0.1) (2024-07-02) + +- build(deps): bump open-vulnerability-client ([#6772](https://github.com/dependency-check/DependencyCheck/pull/6772)) +- fix: remove debug logging ([#6770](https://github.com/dependency-check/DependencyCheck/pull/6770)) +- fix: postgresql column count error ([#6773](https://github.com/dependency-check/DependencyCheck/pull/6773)) +- fix: mssql column name and version ([#6761](https://github.com/dependency-check/DependencyCheck/pull/6761)) +- docs: update supported versions ([#6771](https://github.com/dependency-check/DependencyCheck/pull/6771)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/85?closed=1). + +## [Version 10.0.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v10.0.0) (2024-07-01) + +- **breaking change**: upgrade to dotnet 8.0 ([#6580](https://github.com/dependency-check/DependencyCheck/pull/6580)) + - Users of the AssemblyAnalyzer must upgrade/utilize dotnet 8 to analyze assemblies +- feat: fix the NVD API related errors by adding cvssV4 support ([#6756](https://github.com/dependency-check/DependencyCheck/pull/6756)) + - **breaking changes**: anyone utilizing a centralized database will need to upgrade the schema; see changes in [PR #6756](https://github.com/dependency-check/DependencyCheck/pull/6756/files#diff-ca432c4b41d39caa84d140e06694b09c7e6394c8a2db72ba27516dc77ee3bd67) +- fix: avoid escaping unnecessary chars in HTML report suppression regexes ([#6749](https://github.com/dependency-check/DependencyCheck/pull/6749)) +- fix: [#6688](https://github.com/dependency-check/DependencyCheck/pull/6688) Trim version number when parsing POM ([#6705](https://github.com/dependency-check/DependencyCheck/pull/6705)) +- fix: change request if lockfile is file v3 ([#6690](https://github.com/dependency-check/DependencyCheck/pull/6690)) +- fix: skip pyproject.toml unless it contains `tool.poetry` before ensuring lockfiles ([#6681](https://github.com/dependency-check/DependencyCheck/pull/6681)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/83?closed=1). + +## [Version 9.2.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v9.2.0) (2024-05-15) + + - docs: update logo per intellj ([#6660](https://github.com/dependency-check/DependencyCheck/pull/6660)) + - feat: Carthage analyzer ([#6614](https://github.com/dependency-check/DependencyCheck/pull/6614)) + - fix: Ensure valid JSON output for gitlab report ([#6630](https://github.com/dependency-check/DependencyCheck/pull/6630)) + - feat: Support Package.swift version 3 Specification ([#6578](https://github.com/dependency-check/DependencyCheck/pull/6578)) + - chore: Update the packaged suppressions to include new hosted suppressions ([#6567](https://github.com/dependency-check/DependencyCheck/pull/6567)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/82?closed=1). + +## [Version 9.1.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v9.1.0) (2024-03-31) + +- feat: Add v2 support for maven_install.json ([#6528](https://github.com/dependency-check/DependencyCheck/pull/6528)) +- build(deps): bump open-vulnerability-client ([#6554](https://github.com/dependency-check/DependencyCheck/pull/6554)) + - resolves update issues due to CVSS Metrics 4.0 +- build(deps): bump jackson.version from 2.16.0 to 2.16.1 ([#6353](https://github.com/dependency-check/DependencyCheck/pull/6353)) +- build(deps): bump org.jsoup:jsoup from 1.16.2 to 1.17.2 ([#6362](https://github.com/dependency-check/DependencyCheck/pull/6362)) +- build(deps): bump golang from 1.21.5-alpine to 1.22.1-alpine ([#6506](https://github.com/dependency-check/DependencyCheck/pull/6506)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/81?closed=1). + +## [Version 9.0.10](https://github.com/dependency-check/DependencyCheck/releases/tag/v9.0.10) (2024-03-15) + +- fix: [#4321](https://github.com/dependency-check/DependencyCheck/pull/4321) Suppress redis server CVEs for client libraries ([#4321](https://github.com/dependency-check/DependencyCheck/pull/4321)) ([#6489](https://github.com/dependency-check/DependencyCheck/pull/6489)) +- fix: bump commons-compress from 1.25.0 to 1.26.0 to fix CVE-2024-25710 and CVE-2024-26308 ([#6492](https://github.com/dependency-check/DependencyCheck/pull/6492)) +- feat: Allow to pass NVD API key via environment variable ([#6454](https://github.com/dependency-check/DependencyCheck/pull/6454)) +- fix: issue 5452 - ConcurrentModificationException in NodePackageAnalyzer.processDependencies - adding synchronized block ([#6501](https://github.com/dependency-check/DependencyCheck/pull/6501)) +- docs: document the default data directory ([#6484](https://github.com/dependency-check/DependencyCheck/pull/6484)) +- fix: prevent NPE in bundler audit ([#6462](https://github.com/dependency-check/DependencyCheck/pull/6462)) +- fix: [#6441](https://github.com/dependency-check/DependencyCheck/pull/6441) Improve suppression rule to not restrict to a single version ([#6442](https://github.com/dependency-check/DependencyCheck/pull/6442)) -## [Version 8.2.1](https://github.com/jeremylong/DependencyCheck/releases/tag/v8.2.1) (2023-03-23) +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/80?closed=1). + +## [Version 9.0.9](https://github.com/dependency-check/DependencyCheck/releases/tag/v9.0.9) (2024-01-17) + +- fix: for [#6374](https://github.com/dependency-check/DependencyCheck/pull/6374) to delete non-empty directories ([#6375](https://github.com/dependency-check/DependencyCheck/pull/6375)) +- fix: NoSuchMethodError closeQuietly(java.io.Closeable[]) ([#6377](https://github.com/dependency-check/DependencyCheck/pull/6377)) +- chore: close stream to prevent possible resource leak ([#6382](https://github.com/dependency-check/DependencyCheck/pull/6382)) +- docs: Document default for CLI --data ([#6359](https://github.com/dependency-check/DependencyCheck/pull/6359)) +- docs: document gradle build ([#6371](https://github.com/dependency-check/DependencyCheck/pull/6371)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/79?closed=1). + +## [Version 9.0.8](https://github.com/dependency-check/DependencyCheck/releases/tag/v9.0.8) (2024-01-06) + +- fix: favor stability over performance ([#6349](https://github.com/dependency-check/DependencyCheck/pull/6349)) +- chore: replace commons-io with core java calls ([#6343](https://github.com/dependency-check/DependencyCheck/pull/6343)) +- fix: improve error reporting for invalid H2 database ([#6339](https://github.com/dependency-check/DependencyCheck/pull/6339)) +- fix: rework fix for closing input streams on errors correctly ([#6338](https://github.com/dependency-check/DependencyCheck/pull/6338)) +- fix: reduce chance NVD API block updates due to rate limit ([#6333](https://github.com/dependency-check/DependencyCheck/pull/6333)) +- fix: ensure open handles will not leak on errors ([#6326](https://github.com/dependency-check/DependencyCheck/pull/6326)) +- fix: improve error reporting ([#6324](https://github.com/dependency-check/DependencyCheck/pull/6324)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/78?closed=1). + +## [Version 9.0.7](https://github.com/dependency-check/DependencyCheck/releases/tag/v9.0.7) (2023-12-18) + +- docs: document insecure configuration for GHSA-qqhq-8r2c-c3f5 ([#6315](https://github.com/dependency-check/DependencyCheck/pull/6315)) +- fix: improve memory usage on NVD update ([#6321](https://github.com/dependency-check/DependencyCheck/pull/6321)) +- fix: skip pyproject.toml unless it contains `tool.poetry` ([#6316](https://github.com/dependency-check/DependencyCheck/pull/6316)) +- fix: resolve build error that may cause an issue on some JDK versions ([#6312](https://github.com/dependency-check/DependencyCheck/pull/6312)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/77?closed=1). + +## [Version 9.0.6](https://github.com/dependency-check/DependencyCheck/releases/tag/v9.0.6) (2023-12-15) + +- build: bump open-vulnerability-clients@5.1.1 ([#6308](https://github.com/dependency-check/DependencyCheck/pull/6308)) +- fix: mask nvd.api.key in logs; see GHSA-qqhq-8r2c-c3f5 ([#6307](https://github.com/dependency-check/DependencyCheck/pull/6307)) +- fix: update java version check ([#6297](https://github.com/dependency-check/DependencyCheck/pull/6297)) +- fix: more efficient memory usage ([#6299](https://github.com/dependency-check/DependencyCheck/pull/6299)) +- fix: stream NVD data via Jackson to reduce memory footprint ([#6275](https://github.com/dependency-check/DependencyCheck/pull/6275)) +- docs: document github action caching ([#6301](https://github.com/dependency-check/DependencyCheck/pull/6301)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/76?closed=1). + +## [Version 9.0.5](https://github.com/dependency-check/DependencyCheck/releases/tag/v9.0.5) (2023-12-13) + +- fix: make NVD API endpoint configurable ([#6287](https://github.com/dependency-check/DependencyCheck/pull/6287)) +- fix: synch last modified timestamp for NVD API ([#6281](https://github.com/dependency-check/DependencyCheck/pull/6281)) +- fix: read NVD cache meta files if cache.properties does not exist ([#6282](https://github.com/dependency-check/DependencyCheck/pull/6282)) +- fix: correct property for nonProxyHosts ([#6285](https://github.com/dependency-check/DependencyCheck/pull/6285)) +- fix: reduce apache http logging ([#6280](https://github.com/dependency-check/DependencyCheck/pull/6280)) +- fix: store last modified timestamp for RetireJS and the Hosted Suppression File in db ([#6271](https://github.com/dependency-check/DependencyCheck/pull/6271)) +- build: bump golang in the docker image ([#6274](https://github.com/dependency-check/DependencyCheck/pull/6274)) +- fix: use temporary files to reduce memory usage during the NVD Update ([#6270](https://github.com/dependency-check/DependencyCheck/pull/6270)) +- fix: use BIT for Oracle DB instead of Boolean when calling prepared statements ([#6264](https://github.com/dependency-check/DependencyCheck/pull/6264)) +- fix: showing all reference tags in reports ([#6259](https://github.com/dependency-check/DependencyCheck/pull/6259)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/75?closed=1). + +## [Version 9.0.4](https://github.com/dependency-check/DependencyCheck/releases/tag/v9.0.4) (2023-12-08) + +- fix: utilize maven proxy if present ([#6255](https://github.com/dependency-check/DependencyCheck/pull/6255)) +- fix: allow api key in cli to be quoted ([#6253](https://github.com/dependency-check/DependencyCheck/pull/6253)) +- fix: use correct maven plugin reporting plugin ([#6244](https://github.com/dependency-check/DependencyCheck/pull/6244)) +- fix: correct trailing comma in JSON report ([#6245](https://github.com/dependency-check/DependencyCheck/pull/6245)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/74?closed=1). + +## [Version 9.0.3](https://github.com/dependency-check/DependencyCheck/releases/tag/v9.0.3) (2023-12-06) + +- fix: use Java properties for proxy configuration ([#6238](https://github.com/dependency-check/DependencyCheck/pull/6238)) +- docs: update proxy configuration documentation ([#6237](https://github.com/dependency-check/DependencyCheck/pull/6237)) +- docs: add documentation on caching ([#6204](https://github.com/dependency-check/DependencyCheck/pull/6204)) +- docs: Clarify H2 database caching strategy ([#6220](https://github.com/dependency-check/DependencyCheck/pull/6220)) +- docs: Update list of supported report formats ([#6224](https://github.com/dependency-check/DependencyCheck/pull/6224)) +- docs: example 5 with new nvdDatafeedUrl parameter ([#6215](https://github.com/dependency-check/DependencyCheck/pull/6215)) +- fix: prevent NPEs ([#6232](https://github.com/dependency-check/DependencyCheck/pull/6232) and [#6206](https://github.com/dependency-check/DependencyCheck/pull/6206)) +- fix: check valid for hours for NVD API ([#6225](https://github.com/dependency-check/DependencyCheck/pull/6225)) +- fix: correct NVD cache last checked logic ([#6218](https://github.com/dependency-check/DependencyCheck/pull/6218)) +- fix: nvd datafeed should process current year ([#6213](https://github.com/dependency-check/DependencyCheck/pull/6213)) +- fix: correct references to cvssv2 and cvssv3 fields in json and xml reports ([#6212](https://github.com/dependency-check/DependencyCheck/pull/6212)) +- fix: correct name on reference links in report ([#6205](https://github.com/dependency-check/DependencyCheck/pull/6205)) +- fix: flaws int the gitlab report ([#6193](https://github.com/dependency-check/DependencyCheck/pull/6193)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/73?closed=1). + +## [Version 9.0.2](https://github.com/dependency-check/DependencyCheck/releases/tag/v9.0.2) (2023-12-01) + +- fix: remove virtual match string on NVD API Request ([#6177](https://github.com/dependency-check/DependencyCheck/pull/6177)) +- fix: correct meta data in report after switching the NVD API ([#6154](https://github.com/dependency-check/DependencyCheck/pull/6154)) +- fix: retry HTTP connections to NVD on 502 and 504 errors ([#6151](https://github.com/dependency-check/DependencyCheck/pull/6151)) +- fix: Gitlab report format needs severity capitalized ([#6182](https://github.com/dependency-check/DependencyCheck/pull/6182)) +- fix: improve JDK update version parsing ([#6163](https://github.com/dependency-check/DependencyCheck/pull/6163)) +- fix: mute JCS logging (again) ([#6153](https://github.com/dependency-check/DependencyCheck/pull/6153)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/72?closed=1). + +## [Version 9.0.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v9.0.1) (2023-11-26) + +**breaking changes**: See the [upgrade notice](https://github.com/dependency-check/DependencyCheck#900-upgrade-notice) + +- fix: check java 8 update version; minimum JRE is 8 update 251 ([#6118](https://github.com/dependency-check/DependencyCheck/pull/6118)) +- fix: add retry for failed NVD API requests ([#6136](https://github.com/dependency-check/DependencyCheck/pull/6136)) +- docs: add default values to documentation for the NVD API Delay ([#6135](https://github.com/dependency-check/DependencyCheck/pull/6135)) +- chore: Revert "build(deps): bump com.h2database:h2 from 2.1.214 to 2.2.224" ([#6131](https://github.com/dependency-check/DependencyCheck/pull/6131)) + - this is a **breaking change** for anyone that successfully created the H2 database with 9.0.0. +- fix: mute jcs logging ([#6130](https://github.com/dependency-check/DependencyCheck/pull/6130)) +- docs: update NVD notice ([#6110](https://github.com/dependency-check/DependencyCheck/pull/6110)) +- fix: Use the correct key for NVD API-Key from Maven Settings serverId ([#6109](https://github.com/dependency-check/DependencyCheck/pull/6109)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/71?closed=1). + +## [Version 9.0.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v9.0.0) (2023-11-22) + +**breaking changes**: See the [upgrade notice](https://github.com/dependency-check/DependencyCheck#900-upgrade-notice) + +- feat: Utilize NVD API ([#5978](https://github.com/dependency-check/DependencyCheck/pull/5978)) +- feat: gitlab dependency scanner report format [#5919](https://github.com/dependency-check/DependencyCheck/pull/5919) ([#5920](https://github.com/dependency-check/DependencyCheck/pull/5920)) +- fix: Use ASCII apostrophe for console message ([#6076](https://github.com/dependency-check/DependencyCheck/pull/6076)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/68?closed=1). + +## [Version 8.4.3](https://github.com/dependency-check/DependencyCheck/releases/tag/v8.4.3) (2023-11-15) + +- fix: bump jcs3 ([#6047](https://github.com/dependency-check/DependencyCheck/pull/6047)) +- docs: Corrected docs on hostedSuppressions ([#6035](https://github.com/dependency-check/DependencyCheck/pull/6035)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/70?closed=1). + +## [Version 8.4.2](https://github.com/dependency-check/DependencyCheck/releases/tag/v8.4.2) (2023-10-22) + +- fix: correct log configuration in cli ([#6002](https://github.com/dependency-check/DependencyCheck/pull/6002)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/69?closed=1). + +## [Version 8.4.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v8.4.1) (2023-10-21) + +### Fixed + +- fix: upgrade to JCS3 ([#5114](https://github.com/dependency-check/DependencyCheck/pull/5114)) +- fix: Support ~= version specifier in requirements.txt and pipfile ([#5902](https://github.com/dependency-check/DependencyCheck/pull/5902)) +- fix: Version of dependency no longer ignored when CPE product has a 'java' suffix in a product name ([#5901](https://github.com/dependency-check/DependencyCheck/pull/5901)) +- fix: Do not filter out evidences added by hints ([#5900](https://github.com/dependency-check/DependencyCheck/pull/5900)) +- fix: fixes FP [#5925](https://github.com/dependency-check/DependencyCheck/pull/5925) ([#5927](https://github.com/dependency-check/DependencyCheck/pull/5927)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/67?closed=1). + +## [Version 8.4.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v8.4.0) (2023-08-19) + +### Added + +- feat: Add support for Nexus v3 to NexusAnalyzer ([#5849](https://github.com/dependency-check/DependencyCheck/pull/5849)) + +### Fixed + +- fix: Hint Analyzer should run before VersionFilter Analyzer ([#5818](https://github.com/dependency-check/DependencyCheck/pull/5818)) +- chore: switch to sha1-pinning as suggested by Semgrep +- fix: OSS Index Analyzer SocketTimeoutException exception handling based on warn only parameter ([#5845](https://github.com/dependency-check/DependencyCheck/pull/5845)) +- fix: use curl with -L to follow github redirect ([#5808](https://github.com/dependency-check/DependencyCheck/pull/5808)) +- fix: use curl with -L to follow github redirect +- fix: [#5671](https://github.com/dependency-check/DependencyCheck/pull/5671) out of memory error ([#5789](https://github.com/dependency-check/DependencyCheck/pull/5789)) +- fix: [#5671](https://github.com/dependency-check/DependencyCheck/pull/5671) Exit method as soon as we detect a loop to prevent an infinite loop leading to an OutOfMemoryError + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/66?closed=1). + +## [Version 8.3.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v8.3.1) (2023-06-12) + +Re-release of 8.3.0 as 8.3.1. + +## [Version 8.3.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v8.3.0) (2023-06-12) + +### Added + + - Add LibmanAnalyzer ([#5652](https://github.com/dependency-check/DependencyCheck/pull/5652)) + - Update HTML report Dependencies header based on display settings ([#5619](https://github.com/dependency-check/DependencyCheck/pull/5619)) + - Add link to suppressed vulnerabilities header in HTML report ([#5620](https://github.com/dependency-check/DependencyCheck/pull/5620)) + - Enable local proxy configuration in maven plugin configuration ([#5696](https://github.com/dependency-check/DependencyCheck/pull/5696)) + +### Fixed + + - Fix npm alias present in requires of dependencies ([#5703](https://github.com/dependency-check/DependencyCheck/pull/5703)) + - Make Central URL configurable via CLI ([#5667](https://github.com/dependency-check/DependencyCheck/pull/5667)) + - Ensure support of CVSSv3.1 ([#5602](https://github.com/dependency-check/DependencyCheck/pull/5602)) + +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/65?closed=1). + +## [Version 8.2.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v8.2.1) (2023-03-23) ### Fixed - - NullPointerException in MSBuildAnalyzer (#5589) - - SQL Syntax for Oracle (#5590) - - Use `https://` URLs in report templates (#5582) + - NullPointerException in MSBuildAnalyzer ([#5589](https://github.com/dependency-check/DependencyCheck/pull/5589)) + - SQL Syntax for Oracle ([#5590](https://github.com/dependency-check/DependencyCheck/pull/5590)) + - Use `https://` URLs in report templates ([#5582](https://github.com/dependency-check/DependencyCheck/pull/5582)) -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/64?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/64?closed=1). -## [Version 8.2.0](https://github.com/jeremylong/DependencyCheck/releases/tag/v8.2.0) (2023-03-22) +## [Version 8.2.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v8.2.0) (2023-03-22) ### Added - - Support msbuild Directory.build.props (#5475) + - Support msbuild Directory.build.props ([#5475](https://github.com/dependency-check/DependencyCheck/pull/5475)) - better display of NPM audit references - Add CVSS V3 results from NPM Audit results ### Fixed - - Fix several issues on NPM Audit reporting (#5546) - - Case issue in SQL (#5557) + - Fix several issues on NPM Audit reporting ([#5546](https://github.com/dependency-check/DependencyCheck/pull/5546)) + - Case issue in SQL ([#5557](https://github.com/dependency-check/DependencyCheck/pull/5557)) - Fix CWE(s) extraction for NPM Audit advisories - Use the stable github_advisory_id instead of the now unstable id in NPM audit results -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/63?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/63?closed=1). -## [Version 8.1.2](https://github.com/jeremylong/DependencyCheck/releases/tag/v8.1.2) (2023-02-28) +## [Version 8.1.2](https://github.com/dependency-check/DependencyCheck/releases/tag/v8.1.2) (2023-02-28) ### Fixed - - Fix `NullPointerException` in the Jar Analyzer introduced in 8.1.1 (#5512) + - Fix `NullPointerException` in the Jar Analyzer introduced in 8.1.1 ([#5512](https://github.com/dependency-check/DependencyCheck/pull/5512)) -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/62?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/62?closed=1). -## [Version 8.1.1](https://github.com/jeremylong/DependencyCheck/releases/tag/v8.1.1) (2023-02-27) +## [Version 8.1.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v8.1.1) (2023-02-27) ### Fixed - - allow hosted suppressions file to be disabled (#5509) - - Several FPs not suitable for our automation (#5504) - - Fix incorrect defaults for nexus and central-analyzer in gradle plugin documentation (#5503) - - Erroneous error-log for deprecated CLI flag usage when using properyfile based disablement of Node Audit Analyzer (#5487) - - Prefer pom.properties G/A/V over pom.xml G/A/V to resolve GAV interpolation issues (#5473) - - Node package dependencies ending up as related dependency of the wrong version of the package (#5479) - - do not throw error if pyproject.toml is in node_modules (#5470) + - allow hosted suppressions file to be disabled ([#5509](https://github.com/dependency-check/DependencyCheck/pull/5509)) + - Several FPs not suitable for our automation ([#5504](https://github.com/dependency-check/DependencyCheck/pull/5504)) + - Fix incorrect defaults for nexus and central-analyzer in gradle plugin documentation ([#5503](https://github.com/dependency-check/DependencyCheck/pull/5503)) + - Erroneous error-log for deprecated CLI flag usage when using properyfile based disablement of Node Audit Analyzer ([#5487](https://github.com/dependency-check/DependencyCheck/pull/5487)) + - Prefer pom.properties G/A/V over pom.xml G/A/V to resolve GAV interpolation issues ([#5473](https://github.com/dependency-check/DependencyCheck/pull/5473)) + - Node package dependencies ending up as related dependency of the wrong version of the package ([#5479](https://github.com/dependency-check/DependencyCheck/pull/5479)) + - do not throw error if pyproject.toml is in node_modules ([#5470](https://github.com/dependency-check/DependencyCheck/pull/5470)) -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/61?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/61?closed=1). -## [Version 8.1.0](https://github.com/jeremylong/DependencyCheck/releases/tag/v8.1.0) (2023-01-26) +## [Version 8.1.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v8.1.0) (2023-01-26) ### Added -- `Pipefile.lock` files are now supported ([#5404](https://github.com/jeremylong/DependencyCheck/pull/5404)). -- Python projects with only a `pyproject.toml` but no lock file or requirements will report an error as ODC is unable to analyze the project ([#5409](https://github.com/jeremylong/DependencyCheck/pull/5409)). +- `Pipefile.lock` files are now supported ([#5404](https://github.com/dependency-check/DependencyCheck/pull/5404)). +- Python projects with only a `pyproject.toml` but no lock file or requirements will report an error as ODC is unable to analyze the project ([#5409](https://github.com/dependency-check/DependencyCheck/pull/5409)). ### Fixed -- Some maven projects caused false positives due to bad string interpolation ([#5421](https://github.com/jeremylong/DependencyCheck/pull/5421)). -- Error message from Assembly Analyzer has been updated to emphasize dotnet 6 is required for analysis ([#5408](https://github.com/jeremylong/DependencyCheck/pull/5408)). -- Correct issue where database defrag occurs even when no updates were performed ([#5441](https://github.com/jeremylong/DependencyCheck/pull/5441)). +- Some maven projects caused false positives due to bad string interpolation ([#5421](https://github.com/dependency-check/DependencyCheck/pull/5421)). +- Error message from Assembly Analyzer has been updated to emphasize dotnet 6 is required for analysis ([#5408](https://github.com/dependency-check/DependencyCheck/pull/5408)). +- Correct issue where database defrag occurs even when no updates were performed ([#5441](https://github.com/dependency-check/DependencyCheck/pull/5441)). - Fixed several False Positives and one False Negative. - Fixed the `format` configuration more flexible in the gradle plugin ([dependency-check-gradle/#324](https://github.com/dependency-check/dependency-check-gradle/pull/324)). -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/60?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/60?closed=1). -## [Version 8.0.2](https://github.com/jeremylong/DependencyCheck/releases/tag/v8.0.2) (2023-01-26) +## [Version 8.0.2](https://github.com/dependency-check/DependencyCheck/releases/tag/v8.0.2) (2023-01-26) ### Fixed -- Resolved bug causing an issue with some Maven Extensions ([#5366](https://github.com/jeremylong/DependencyCheck/pull/5366)). -- ArchiveAnalyzer will now correctly throw an exception if it cannot open an Archive ([#5371](https://github.com/jeremylong/DependencyCheck/pull/5371)). -- Updated CSV report so that it no longer has a duplicate `description` column ([#5364](https://github.com/jeremylong/DependencyCheck/pull/5364)). -- Moved several logging statements to trace which should drastically reduce the log size ([#5350](https://github.com/jeremylong/DependencyCheck/pull/5350)). -- Fixed bug with RetireJS' `--retirejsFilterNonVulnerable` and `--retirejsFilter` when used with the CLI ([#5351](https://github.com/jeremylong/DependencyCheck/pull/5351)). -- Fixed the `sarif` report format and added validation ([#5345](https://github.com/jeremylong/DependencyCheck/pull/5345) and ([#5363](https://github.com/jeremylong/DependencyCheck/pull/5363)) +- Resolved bug causing an issue with some Maven Extensions ([#5366](https://github.com/dependency-check/DependencyCheck/pull/5366)). +- ArchiveAnalyzer will now correctly throw an exception if it cannot open an Archive ([#5371](https://github.com/dependency-check/DependencyCheck/pull/5371)). +- Updated CSV report so that it no longer has a duplicate `description` column ([#5364](https://github.com/dependency-check/DependencyCheck/pull/5364)). +- Moved several logging statements to trace which should drastically reduce the log size ([#5350](https://github.com/dependency-check/DependencyCheck/pull/5350)). +- Fixed bug with RetireJS' `--retirejsFilterNonVulnerable` and `--retirejsFilter` when used with the CLI ([#5351](https://github.com/dependency-check/DependencyCheck/pull/5351)). +- Fixed the `sarif` report format and added validation ([#5345](https://github.com/dependency-check/DependencyCheck/pull/5345) and ([#5363](https://github.com/dependency-check/DependencyCheck/pull/5363)) - Fixed `MalformedPackageException` in the gradle plugin ([dependency-check-gradle/#320](https://github.com/dependency-check/dependency-check-gradle/pull/320)). - Fixed `MissingMethodException` in the gradle plugin ([dependency-check-gradle/#316](https://github.com/dependency-check/dependency-check-gradle/pull/316)). -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/59?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/59?closed=1). -## [Version 8.0.1](https://github.com/jeremylong/DependencyCheck/releases/tag/v8.0.1) (2023-01-18) +## [Version 8.0.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v8.0.1) (2023-01-18) ### Fixed - Fixed Stack Overflow Exception in the gradle plugin ([dependency-check-gradle/#308](https://github.com/dependency-check/dependency-check-gradle/pull/308)). - Fixed No Signature of Method Exception in the gradle plugin ([dependency-check-gradle/#305](https://github.com/dependency-check/dependency-check-gradle/pull/305)). -- Updated DB initialization scripts for externally hosted DBs ([#5314](https://github.com/jeremylong/DependencyCheck/pull/5314) and [#5317](https://github.com/jeremylong/DependencyCheck/pull/5317)). +- Updated DB initialization scripts for externally hosted DBs ([#5314](https://github.com/dependency-check/DependencyCheck/pull/5314) and [#5317](https://github.com/dependency-check/DependencyCheck/pull/5317)). - Postgres users will need to use the updated init script and 8.0.1. -- Resolved NPE in the NodePackageAnalyzer ([#5339](https://github.com/jeremylong/DependencyCheck/pull/5339)). +- Resolved NPE in the NodePackageAnalyzer ([#5339](https://github.com/dependency-check/DependencyCheck/pull/5339)). -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/58?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/58?closed=1). -## [Version 8.0.0](https://github.com/jeremylong/DependencyCheck/releases/tag/v8.0.0) (2023-01-15) +## [Version 8.0.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v8.0.0) (2023-01-15) ### Added -- Utilize the hosted suppression file to allow for faster remediation of reported False Positives ([#4723](https://github.com/jeremylong/DependencyCheck/issues/4723)). -- Include the [CISA Known Exploited Vulnerability Catalog](https://www.cisa.gov/known-exploited-vulnerabilities-catalog) ([#4878](https://github.com/jeremylong/DependencyCheck/issues/4878)). -- The `gradle` and `maven` plugins now have the capability to scan the build plugins ([#4035](https://github.com/jeremylong/DependencyCheck/issues/4035)). -- The `gradle` and `maven` plugins, for transitive dependencies, will report the root dependency in the project that included the transitive dependency ([#5001](https://github.com/jeremylong/DependencyCheck/pull/5001)). -- Added `properties.security-severity` to SARIF report for better integration with GitHub Security Code scanning ([#5277](https://github.com/jeremylong/DependencyCheck/pull/5227)). -- Allow for HTTP auth settings for Retire JS respository ([#5209](https://github.com/jeremylong/DependencyCheck/pull/5209)). -- New schema for the XML report was added to support some of the above additions ([#5296](https://github.com/jeremylong/DependencyCheck/pull/5296)). +- Utilize the hosted suppression file to allow for faster remediation of reported False Positives ([#4723](https://github.com/dependency-check/DependencyCheck/issues/4723)). +- Include the [CISA Known Exploited Vulnerability Catalog](https://www.cisa.gov/known-exploited-vulnerabilities-catalog) ([#4878](https://github.com/dependency-check/DependencyCheck/issues/4878)). +- The `gradle` and `maven` plugins now have the capability to scan the build plugins ([#4035](https://github.com/dependency-check/DependencyCheck/issues/4035)). +- The `gradle` and `maven` plugins, for transitive dependencies, will report the root dependency in the project that included the transitive dependency ([#5001](https://github.com/dependency-check/DependencyCheck/pull/5001)). +- Added `properties.security-severity` to SARIF report for better integration with GitHub Security Code scanning ([#5277](https://github.com/dependency-check/DependencyCheck/pull/5227)). +- Allow for HTTP auth settings for Retire JS repository ([#5209](https://github.com/dependency-check/DependencyCheck/pull/5209)). +- New schema for the XML report was added to support some of the above additions ([#5296](https://github.com/dependency-check/DependencyCheck/pull/5296)). - Added missing gradle option to only warn on remote errors from the OSS Index Analyzer ([gradle #303](https://github.com/dependency-check/dependency-check-gradle/pull/303)). ### Changed - **Breaking:** the database schema updated - if using an external database the update scripts must be run! -- The [exit codes](https://tldp.org/LDP/abs/html/exit-status.html) from the CLI have been changed to be in the range from 0-255 ([#4511](https://github.com/jeremylong/DependencyCheck/pull/4511). -- The OSS Index Analyzer will automatically disable itself if a transport error occurs - preventing copious errors from being reported ([#5300](https://github.com/jeremylong/DependencyCheck/pull/5300])). +- The [exit codes](https://tldp.org/LDP/abs/html/exit-status.html) from the CLI have been changed to be in the range from 0-255 ([#4511](https://github.com/dependency-check/DependencyCheck/pull/4511). +- The OSS Index Analyzer will automatically disable itself if a transport error occurs - preventing copious errors from being reported ([#5300](https://github.com/dependency-check/DependencyCheck/pull/5300])). ### Fixed -- Added an additional check for rejected CVEs to reduce FP ([#5268](https://github.com/jeremylong/DependencyCheck/pull/5268). -- Corrected the analysis of `node_modules` to prevent NPEs ([#5266](https://github.com/jeremylong/DependencyCheck/pull/5266)). -- Fixed error when scanning node packages with local dependencies ([#5235](https://github.com/jeremylong/DependencyCheck/pull/5235)). -- Fixed NPE in the MSBuild Analyzer ([#5293](https://github.com/jeremylong/DependencyCheck/pull/5293)). +- Added an additional check for rejected CVEs to reduce FP ([#5268](https://github.com/dependency-check/DependencyCheck/pull/5268). +- Corrected the analysis of `node_modules` to prevent NPEs ([#5266](https://github.com/dependency-check/DependencyCheck/pull/5266)). +- Fixed error when scanning node packages with local dependencies ([#5235](https://github.com/dependency-check/DependencyCheck/pull/5235)). +- Fixed NPE in the MSBuild Analyzer ([#5293](https://github.com/dependency-check/DependencyCheck/pull/5293)). - Several False Positives have been resolved. -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/46?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/46?closed=1). -## [Version 7.4.4](https://github.com/jeremylong/DependencyCheck/releases/tag/v7.4.4) (2023-01-06) +## [Version 7.4.4](https://github.com/dependency-check/DependencyCheck/releases/tag/v7.4.4) (2023-01-06) ### Fixed -- Resolved issue processing NVD CVE data due to column width (#5229) +- Resolved issue processing NVD CVE data due to column width ([#5229](https://github.com/dependency-check/DependencyCheck/pull/5229)) -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/56?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/56?closed=1). -## [Version 7.4.3](https://github.com/jeremylong/DependencyCheck/releases/tag/v7.4.3) (2022-12-29) +## [Version 7.4.3](https://github.com/dependency-check/DependencyCheck/releases/tag/v7.4.3) (2022-12-29) ### Fixed -- Fixed NPE when analyzing version ranges in NPM (#5158 & #5190) -- Resolved several FP (#5191) +- Fixed NPE when analyzing version ranges in NPM ([#5158](https://github.com/dependency-check/DependencyCheck/pull/5158) & [#5190](https://github.com/dependency-check/DependencyCheck/pull/5190)) +- Resolved several FP ([#5191](https://github.com/dependency-check/DependencyCheck/pull/5191)) -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/55?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/55?closed=1). -## [Version 7.4.2](https://github.com/jeremylong/DependencyCheck/releases/tag/v7.4.2) (2022-12-28) +## [Version 7.4.2](https://github.com/dependency-check/DependencyCheck/releases/tag/v7.4.2) (2022-12-28) ### Fixed -- Fixes maven 3.1 compatibility issue (#5152) -- Fixed issue with invalid `node_module` paths in some scans (#5135) -- Fixed missing option to disable the Poetry Analyzer in the CLI (#5160) -- Fixed missing option to configure the OSS Index URL in the CLI (#5180) -- Fixed NPE when analyzing version ranges in NPM (#5158) +- Fixes maven 3.1 compatibility issue ([#5152](https://github.com/dependency-check/DependencyCheck/pull/5152)) +- Fixed issue with invalid `node_module` paths in some scans ([#5135](https://github.com/dependency-check/DependencyCheck/pull/5135)) +- Fixed missing option to disable the Poetry Analyzer in the CLI ([#5160](https://github.com/dependency-check/DependencyCheck/pull/5160)) +- Fixed missing option to configure the OSS Index URL in the CLI ([#5180](https://github.com/dependency-check/DependencyCheck/pull/5180)) +- Fixed NPE when analyzing version ranges in NPM ([#5158](https://github.com/dependency-check/DependencyCheck/pull/5158)) - Fixed issue with non-proxy host in the gradle plugin (https://github.com/dependency-check/dependency-check-gradle/pull/298) - Resolved several FP -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/54?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/54?closed=1). -## [Version 7.4.1](https://github.com/jeremylong/DependencyCheck/releases/tag/v7.4.1) (2022-12-09) +## [Version 7.4.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v7.4.1) (2022-12-09) ### Fixed -- Fixed bug when setting the proxy port in gradle (#5123) -- Fixed issue with invalid `node_module` paths in some scans (#5127) +- Fixed bug when setting the proxy port in gradle ([#5123](https://github.com/dependency-check/DependencyCheck/pull/5123)) +- Fixed issue with invalid `node_module` paths in some scans ([#5127](https://github.com/dependency-check/DependencyCheck/pull/5127)) - Resolved several FP -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/53?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/53?closed=1). -## [Version 7.4.0](https://github.com/jeremylong/DependencyCheck/releases/tag/v7.4.0) (2022-12-04) +## [Version 7.4.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v7.4.0) (2022-12-04) ### Added -- Add support for npm package lock v2 and v3 (#5078) -- Added experimental support for Python Poetry (#5025) -- Added a vanilla HTML report for use in Jenkins (#5053) +- Add support for npm package lock v2 and v3 ([#5078](https://github.com/dependency-check/DependencyCheck/pull/5078)) +- Added experimental support for Python Poetry ([#5025](https://github.com/dependency-check/DependencyCheck/pull/5025)) +- Added a vanilla HTML report for use in Jenkins ([#5053](https://github.com/dependency-check/DependencyCheck/pull/5053)) ### Changed - Renamed `RELEASE_NOTES.md` to `CHANGELOG.md` to be more conventional -- Optimized checksum calculation to improve performance (#5112) -- Added support for scanning .NET assemblies when only the dotnet runtime is installed (#5087) +- Optimized checksum calculation to improve performance ([#5112](https://github.com/dependency-check/DependencyCheck/pull/5112)) +- Added support for scanning .NET assemblies when only the dotnet runtime is installed ([#5087](https://github.com/dependency-check/DependencyCheck/pull/5087)) - Bumped several dependencies ### Fixed -- Fixed bug when setting the proxy port (#5076) +- Fixed bug when setting the proxy port ([#5076](https://github.com/dependency-check/DependencyCheck/pull/5076)) - Resolved several FP and FN -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/52?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/52?closed=1). -## [Version 7.3.2](https://github.com/jeremylong/DependencyCheck/releases/tag/v7.3.2) (2022-11-18) +## [Version 7.3.2](https://github.com/dependency-check/DependencyCheck/releases/tag/v7.3.2) (2022-11-18) ### Changed - Automated release of 7.3.1 failed and only published to Central; 7.3.2 is a re-release of 7.3.1. - Resolved several false positives and false negatives. -- Use Jackson Afterburner if still on Java 8 (#4966). -- Exclude `node_modules` from the Maven plugin's scan path (#4974). +- Use Jackson Afterburner if still on Java 8 ([#4966](https://github.com/dependency-check/DependencyCheck/pull/4966)). +- Exclude `node_modules` from the Maven plugin's scan path ([#4974](https://github.com/dependency-check/DependencyCheck/pull/4974)). -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/51?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/51?closed=1). -## [Version 7.3.1](https://github.com/jeremylong/DependencyCheck/releases/tag/v7.3.1) (2022-11-16) +## [Version 7.3.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v7.3.1) (2022-11-16) ### Changed - Resolved several false positives and false negatives. -- Use Jackson Afterburner if still on Java 8 (#4966). -- Exclude `node_modules` from the Maven plugin's scan path (#4974). +- Use Jackson Afterburner if still on Java 8 ([#4966](https://github.com/dependency-check/DependencyCheck/pull/4966)). +- Exclude `node_modules` from the Maven plugin's scan path ([#4974](https://github.com/dependency-check/DependencyCheck/pull/4974)). -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/51?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/51?closed=1). -## [Version 7.3.0](https://github.com/jeremylong/DependencyCheck/releases/tag/v7.3.0) (2022-10-19) +## [Version 7.3.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v7.3.0) (2022-10-19) ### Added -- Added an experimental Dart analyzer (#4869). +- Added an experimental Dart analyzer ([#4869](https://github.com/dependency-check/DependencyCheck/pull/4869)). ### Changed -- Migrated from Jackson Afterburner to Blackbird (#4905). +- Migrated from Jackson Afterburner to Blackbird ([#4905](https://github.com/dependency-check/DependencyCheck/pull/4905)). ### Fixed -- Fixed issue with the Maven plugin that caused concurrent modification exceptions (#4935). +- Fixed issue with the Maven plugin that caused concurrent modification exceptions ([#4935](https://github.com/dependency-check/DependencyCheck/pull/4935)). -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/50?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/50?closed=1). -## [Version 7.2.1](https://github.com/jeremylong/DependencyCheck/releases/tag/v7.2.1) (2022-09-20) +## [Version 7.2.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v7.2.1) (2022-09-20) ### Fixed -- Fixed logging issue (#4846). +- Fixed logging issue ([#4846](https://github.com/dependency-check/DependencyCheck/pull/4846)). -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/49?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/49?closed=1). -## [Version 7.2.0](https://github.com/jeremylong/DependencyCheck/releases/tag/v7.2.0) (2022-09-14) +## [Version 7.2.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v7.2.0) (2022-09-14) ### Changed -- Add support for Bazel's pinned `maven_install.json` (#4772). -- Fixed bug preventing the use of custom report templates (#4800). +- Add support for Bazel's pinned `maven_install.json` ([#4772](https://github.com/dependency-check/DependencyCheck/pull/4772)). +- Fixed bug preventing the use of custom report templates ([#4800](https://github.com/dependency-check/DependencyCheck/pull/4800)). - Updated several dependencies including upgrades for dependencies with CVEs. - Several bug fixes made and suppression rules were added. -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/48?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/48?closed=1). -## [Version 7.1.2](https://github.com/jeremylong/DependencyCheck/releases/tag/v7.1.2) (2022-08-20) +## [Version 7.1.2](https://github.com/dependency-check/DependencyCheck/releases/tag/v7.1.2) (2022-08-20) ### Changed -- The maven plugin now includes pnpm and yarn lock files in the scan by default (#4753). -- If a suppression rule is no longer used a log entry will be written (#4685). +- The maven plugin now includes pnpm and yarn lock files in the scan by default ([#4753](https://github.com/dependency-check/DependencyCheck/pull/4753)). +- If a suppression rule is no longer used a log entry will be written ([#4685](https://github.com/dependency-check/DependencyCheck/pull/4685)). - Several bug fixes made and suppression rules added. -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/47?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/47?closed=1). -## [Version 7.1.1](https://github.com/jeremylong/DependencyCheck/releases/tag/v7.1.1) (2022-06-12) +## [Version 7.1.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v7.1.1) (2022-06-12) ### Fixed - Minor bug fixes. - Resolved several false positives. -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/45?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/45?closed=1). -## [Version 7.1.0](https://github.com/jeremylong/DependencyCheck/releases/tag/v7.1.0) (2022-04-23) +## [Version 7.1.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v7.1.0) (2022-04-23) ### Changed -- Improved sorting in the HTML report ([see #4112](https://github.com/jeremylong/DependencyCheck/issues/4112)). -- Improved support for Swift ([see #4265](https://github.com/jeremylong/DependencyCheck/pull/4265)). +- Improved sorting in the HTML report ([see #4112](https://github.com/dependency-check/DependencyCheck/issues/4112)). +- Improved support for Swift ([see #4265](https://github.com/dependency-check/DependencyCheck/pull/4265)). - Resolved several false positives. -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/45?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/45?closed=1). -## [Version 7.0.4](https://github.com/jeremylong/DependencyCheck/releases/tag/v7.0.4) (2022-03-30) +## [Version 7.0.4](https://github.com/dependency-check/DependencyCheck/releases/tag/v7.0.4) (2022-03-30) ### Changed -- Update to `jackson-databind` (see #4285). +- Update to `jackson-databind` (see [#4285](https://github.com/dependency-check/DependencyCheck/pull/4285)). -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/43?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/43?closed=1). -## [Version 7.0.3](https://github.com/jeremylong/DependencyCheck/releases/tag/v7.0.3) (2022-03-29) +## [Version 7.0.3](https://github.com/dependency-check/DependencyCheck/releases/tag/v7.0.3) (2022-03-29) ### Changed -- Update to `jackson-databind` (see #4285). +- Update to `jackson-databind` (see [#4285](https://github.com/dependency-check/DependencyCheck/pull/4285)). -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/42?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/42?closed=1). -## [Version 7.0.2](https://github.com/jeremylong/DependencyCheck/releases/tag/v7.0.2) (2022-03-28) +## [Version 7.0.2](https://github.com/dependency-check/DependencyCheck/releases/tag/v7.0.2) (2022-03-28) ### Changed - General project maintenance, bug fixes, and false positive and false negative reductions. -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/41?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/41?closed=1). -## [Version 7.0.1](https://github.com/jeremylong/DependencyCheck/releases/tag/v7.0.1) (2022-03-23) +## [Version 7.0.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v7.0.1) (2022-03-23) ### Changed - General project maintenance, bug fixes, and false positive reductions. -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/40?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/40?closed=1). -## [Version 7.0.0](https://github.com/jeremylong/DependencyCheck/releases/tag/v7.0.0) (2022-02-28) +## [Version 7.0.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v7.0.0) (2022-02-28) ### Changed - **Breaking:** The H2 database version has been upgraded. - if you use the `dataDirectory` option you will need to run a purge after upgrading. - **Breaking:** Upgraded to dotnet core 6.0. If analyzing dotnet assemblies the system will need to have the dotnet core 6.0.x runtime available. -- The Sarif report format has been fixed and can now be imported into GitHub if desired (See #3993). +- The Sarif report format has been fixed and can now be imported into GitHub if desired (See [#3993](https://github.com/dependency-check/DependencyCheck/pull/3993)). - Introduced IssueOps for False Positive reports to assist the team in evaluating FP reports. - - [Create New FP Report Issue](https://github.com/jeremylong/DependencyCheck/issues/new?assignees=&labels=FP+Report&template=false-positive-report.yml&title=%5BFP%5D%3A+). + - [Create New FP Report Issue](https://github.com/dependency-check/DependencyCheck/issues/new?assignees=&labels=FP+Report&template=false-positive-report.yml&title=%5BFP%5D%3A+). - When analyzing Java projects ODC now includes data from the developers section. - This will likely cause false positives on things like Apache James, please report the FP and we will fix these quickly. - General project maintenance, bug fixes, and false positive reductions. -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/28?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/28?closed=1). -## [Version 6.5.3](https://github.com/jeremylong/DependencyCheck/releases/tag/v6.5.3) (2022-01-12) +## [Version 6.5.3](https://github.com/dependency-check/DependencyCheck/releases/tag/v6.5.3) (2022-01-12) ### Changed -- Performance improvements for some Maven projects (see #3923 and #3931). -- Fixed bug in npm version handling introduced in 6.5.2 (see #3956). -- Improved the node package analyzer to correctly report the origin of a dependency (see #3970). +- Performance improvements for some Maven projects (see [#3923](https://github.com/dependency-check/DependencyCheck/pull/3923) and [#3931](https://github.com/dependency-check/DependencyCheck/pull/3931)). +- Fixed bug in npm version handling introduced in 6.5.2 (see [#3956](https://github.com/dependency-check/DependencyCheck/pull/3956)). +- Improved the node package analyzer to correctly report the origin of a dependency (see [#3970](https://github.com/dependency-check/DependencyCheck/pull/3970)). - General code maintenance and false positive reductions. -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/39?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/39?closed=1). -## [Version 6.5.2](https://github.com/jeremylong/DependencyCheck/releases/tag/v6.5.2) (2022-01-03) +## [Version 6.5.2](https://github.com/dependency-check/DependencyCheck/releases/tag/v6.5.2) (2022-01-03) ### Changed -- Fixed false positives around log4j-api and Log4j-web (#3910 & #3937). -- Bug fix when processing NPM lock files (#3893). -- Added missing `pnpm` argmument to the CLI (#3916). +- Fixed false positives around log4j-api and Log4j-web ([#3910](https://github.com/dependency-check/DependencyCheck/pull/3910) & [#3937](https://github.com/dependency-check/DependencyCheck/pull/3937)). +- Bug fix when processing NPM lock files ([#3893](https://github.com/dependency-check/DependencyCheck/pull/3893)). +- Added missing `pnpm` argmument to the CLI ([#3916](https://github.com/dependency-check/DependencyCheck/pull/3916)). - General code maintenance and false positive reductions. -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/38?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/38?closed=1). -## [Version 6.5.1](https://github.com/jeremylong/DependencyCheck/releases/tag/v6.5.1) (2021-12-17) +## [Version 6.5.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v6.5.1) (2021-12-17) ### Changed -- Updated the dependency-check-maven plugin to correctly support SNAPSHOT version when a classifier is specified (#3787). -- Improved the analysis of Swift package manager (package.resolved - see #3813). +- Updated the dependency-check-maven plugin to correctly support SNAPSHOT version when a classifier is specified ([#3787](https://github.com/dependency-check/DependencyCheck/pull/3787)). +- Improved the analysis of Swift package manager (package.resolved - see [#3813](https://github.com/dependency-check/DependencyCheck/pull/3813)). - General code maintenance and false positive reductions. -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/37?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/37?closed=1). -## [Version 6.5.0](https://github.com/jeremylong/DependencyCheck/releases/tag/v6.5.0) (2021-11-08) +## [Version 6.5.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v6.5.0) (2021-11-08) ### Changed - Updated build configuration to create [reproducible builds](https://reproducible-builds.org/). - Updated automated release process to work with branch protection. - Resolved several false positives in the Java ecosystem. -- Enabled the Swift Resolved analyzer per #3735 -- Improved iOS support per #3168 and #3765 +- Enabled the Swift Resolved analyzer per [#3735](https://github.com/dependency-check/DependencyCheck/pull/3735) +- Improved iOS support per [#3168](https://github.com/dependency-check/DependencyCheck/pull/3168) and [#3765](https://github.com/dependency-check/DependencyCheck/pull/3765) - Added the a new pnpm Analyzer - Fixed issue with some npm and yarn analysis failing due to large audit output -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/36?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/36?closed=1). -## [Version 6.4.1](https://github.com/jeremylong/DependencyCheck/releases/tag/v6.4.1) (2021-10-11) +## [Version 6.4.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v6.4.1) (2021-10-11) ### Added -- Added download attempts with increasing wait time for `CVE meta` files from the NVD to prevent rate limiting issues (see [#3725](https://github.com/jeremylong/DependencyCheck/pull/3725)). +- Added download attempts with increasing wait time for `CVE meta` files from the NVD to prevent rate limiting issues (see [#3725](https://github.com/dependency-check/DependencyCheck/pull/3725)). -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/35?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/35?closed=1). -## [Version 6.4.0](https://github.com/jeremylong/DependencyCheck/releases/tag/v6.4.0) (2021-10-11) +## [Version 6.4.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v6.4.0) (2021-10-11) ### Changed -- Increased timeout between downloads from the NVD to prevent rate limiting issues (see [#3722](https://github.com/jeremylong/DependencyCheck/pull/3722)). +- Increased timeout between downloads from the NVD to prevent rate limiting issues (see [#3722](https://github.com/dependency-check/DependencyCheck/pull/3722)). - `cveStartYear` is now configurable and can be set to any year from 2002 to present. - - `cveWaitTime` is a new configuration option to define how many milliseconds to wait between NVD downloads; default is 4000 ms (see [#3690](https://github.com/jeremylong/DependencyCheck/pull/3690)). + - `cveWaitTime` is a new configuration option to define how many milliseconds to wait between NVD downloads; default is 4000 ms (see [#3690](https://github.com/dependency-check/DependencyCheck/pull/3690)). - The NVD CVE data files are now being cached for up to 4 hours in case a download fails, re-running ODC will use the cached version. -- Fixed NPE in the ODC maven plugin (see [#3702](https://github.com/jeremylong/DependencyCheck/pull/3702). +- Fixed NPE in the ODC maven plugin (see [#3702](https://github.com/dependency-check/DependencyCheck/pull/3702). -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/34?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/34?closed=1). -## [Version 6.3.2](https://github.com/jeremylong/DependencyCheck/releases/tag/v6.3.2) (2021-09-29) +## [Version 6.3.2](https://github.com/dependency-check/DependencyCheck/releases/tag/v6.3.2) (2021-09-29) ### Changed -- Reduced chance of rate limiting when download files from NVD (see [#2670](https://github.com/jeremylong/DependencyCheck/pull/3670)). -- Fixed bug causing some transitive dependencies being skipped in the odc-maven-plugin (see [#3627](https://github.com/jeremylong/DependencyCheck/pull/3627)). +- Reduced chance of rate limiting when download files from NVD (see [#2670](https://github.com/dependency-check/DependencyCheck/pull/3670)). +- Fixed bug causing some transitive dependencies being skipped in the odc-maven-plugin (see [#3627](https://github.com/dependency-check/DependencyCheck/pull/3627)). -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/33?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/33?closed=1). -## [Version 6.3.1](https://github.com/jeremylong/DependencyCheck/releases/tag/v6.3.1) (2021-09-01) +## [Version 6.3.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v6.3.1) (2021-09-01) ### Fixed -- Fixed [ConcurrentModificationException](https://github.com/jeremylong/DependencyCheck/issues/3618) +- Fixed [ConcurrentModificationException](https://github.com/dependency-check/DependencyCheck/issues/3618) -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/32?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/32?closed=1). -## [Version 6.3.0](https://github.com/jeremylong/DependencyCheck/releases/tag/v6.3.0) (2021-08-31) +## [Version 6.3.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v6.3.0) (2021-08-31) ### Changed - Many updates were made to improve performance on large scans, reduce false positives, and other bug fixes. -- Increased the width of four columns in the database; if you use a an external database you should also update the width (see [upgrade_5.1.sql](https://github.com/jeremylong/DependencyCheck/blob/main/core/src/main/resources/data/upgrade_5.1.sql)). +- Increased the width of four columns in the database; if you use a an external database you should also update the width (see [upgrade_5.1.sql](https://github.com/dependency-check/DependencyCheck/blob/main/core/src/main/resources/data/upgrade_5.1.sql)). -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/31?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/31?closed=1). -## [Version 6.2.2](https://github.com/jeremylong/DependencyCheck/releases/tag/v6.2.2) (2021-06-10) +## [Version 6.2.2](https://github.com/dependency-check/DependencyCheck/releases/tag/v6.2.2) (2021-06-10) ### Fixed -- Resolved issue with database connections introduced in 6.2.0 (see https://github.com/jeremylong/DependencyCheck/issues/3432). +- Resolved issue with database connections introduced in 6.2.0 (see https://github.com/dependency-check/DependencyCheck/issues/3432). -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/30?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/30?closed=1). -## [Version 6.2.1](https://github.com/jeremylong/DependencyCheck/releases/tag/v6.2.1) (2021-06-08) +## [Version 6.2.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v6.2.1) (2021-06-08) ### Fixed -- Resolved issue with database connections introduced in 6.2.0 (see https://github.com/jeremylong/DependencyCheck/issues/3416). +- Resolved issue with database connections introduced in 6.2.0 (see https://github.com/dependency-check/DependencyCheck/issues/3416). -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/29?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/29?closed=1). -## [Version 6.2.0](https://github.com/jeremylong/DependencyCheck/releases/tag/v6.2.0) (2021-05-29) +## [Version 6.2.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v6.2.0) (2021-05-29) ### Changed -- Added an experimental Perl CPAN analyzer [#3378](https://github.com/jeremylong/DependencyCheck/pull/3378) +- Added an experimental Perl CPAN analyzer [#3378](https://github.com/dependency-check/DependencyCheck/pull/3378) - Note that the full DSL of the CPAN is not yet supported so any required dependency is analyzed (i.e. there is no way to exclude development requirements) -- Improved database performance [#3206](https://github.com/jeremylong/DependencyCheck/pull/3206) -- The archive analyzer now extracts files from RPM archives [#3226](https://github.com/jeremylong/DependencyCheck/pull/3226) -- Ensure ordered output in reports [#3243](https://github.com/jeremylong/DependencyCheck/pull/3343) +- Improved database performance [#3206](https://github.com/dependency-check/DependencyCheck/pull/3206) +- The archive analyzer now extracts files from RPM archives [#3226](https://github.com/dependency-check/DependencyCheck/pull/3226) +- Ensure ordered output in reports [#3243](https://github.com/dependency-check/DependencyCheck/pull/3343) - Several minor bug fixes and updates to reduce false positives -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/27?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/27?closed=1). -## [Version 6.1.6](https://github.com/jeremylong/DependencyCheck/releases/tag/v6.1.6) (2021-04-29) +## [Version 6.1.6](https://github.com/dependency-check/DependencyCheck/releases/tag/v6.1.6) (2021-04-29) ### Fixed -- Resolved issue with Sarif report (#3243) -- Resolved issue with Ruby Bundle Audit (#3256) +- Resolved issue with Sarif report ([#3243](https://github.com/dependency-check/DependencyCheck/pull/3243)) +- Resolved issue with Ruby Bundle Audit ([#3256](https://github.com/dependency-check/DependencyCheck/pull/3256)) - Several minor bug fixes and updates to reduce false positives -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/26?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/26?closed=1). -## [Version 6.1.5](https://github.com/jeremylong/DependencyCheck/releases/tag/v6.1.5) (2021-03-31) +## [Version 6.1.5](https://github.com/dependency-check/DependencyCheck/releases/tag/v6.1.5) (2021-03-31) ### Fixed -- Fixed a second NPE introduced in 6.1.3 (see #3246) +- Fixed a second NPE introduced in 6.1.3 (see [#3246](https://github.com/dependency-check/DependencyCheck/pull/3246)) -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/25?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/25?closed=1). -## [Version 6.1.4](https://github.com/jeremylong/DependencyCheck/releases/tag/v6.1.4) (2021-03-30) +## [Version 6.1.4](https://github.com/dependency-check/DependencyCheck/releases/tag/v6.1.4) (2021-03-30) ### Changed -- Fixed an NPE introduced in 6.1.3 (see #3212) +- Fixed an NPE introduced in 6.1.3 (see [#3212](https://github.com/dependency-check/DependencyCheck/pull/3212)) -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/24?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/24?closed=1). -## [Version 6.1.3](https://github.com/jeremylong/DependencyCheck/releases/tag/v6.1.3) (2021-03-22) +## [Version 6.1.3](https://github.com/dependency-check/DependencyCheck/releases/tag/v6.1.3) (2021-03-22) ### Changed -- Modified the new CPE matching strategy to be more performant (#3207) -- Upgraded a vulnerable dependency (velocity-engine-core/CVE-2020-13936) (#3205) +- Modified the new CPE matching strategy to be more performant ([#3207](https://github.com/dependency-check/DependencyCheck/pull/3207)) +- Upgraded a vulnerable dependency (velocity-engine-core/CVE-2020-13936) ([#3205](https://github.com/dependency-check/DependencyCheck/pull/3205)) -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/23?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/23?closed=1). -## [Version 6.1.2](https://github.com/jeremylong/DependencyCheck/releases/tag/v6.1.2) (2021-03-08) +## [Version 6.1.2](https://github.com/dependency-check/DependencyCheck/releases/tag/v6.1.2) (2021-03-08) ### Changed @@ -486,79 +980,79 @@ See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/ - CLI and Ant task will no longer be published to bintray. - Several minor bug fixes. -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/22?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/22?closed=1). -## [Version 6.1.1](https://github.com/jeremylong/DependencyCheck/releases/tag/v6.1.1) (2021-02-13) +## [Version 6.1.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v6.1.1) (2021-02-13) ### Changed - Added missing configuration options for yarn and msbuild. - Several bug fixes. -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/21?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/21?closed=1). -## [Version 6.1.0](https://github.com/jeremylong/DependencyCheck/releases/tag/v6.1.0) (2021-01-27) +## [Version 6.1.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v6.1.0) (2021-01-27) ### Changed -- Added SARIF file format per [#3081](https://github.com/jeremylong/DependencyCheck/issues/3081). -- Added support for Yarn per [#3063](https://github.com/jeremylong/DependencyCheck/pull/3063). +- Added SARIF file format per [#3081](https://github.com/dependency-check/DependencyCheck/issues/3081). +- Added support for Yarn per [#3063](https://github.com/dependency-check/DependencyCheck/pull/3063). - False positive reduction and minor bug fixes. -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/20?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/20?closed=1). -## [Version 6.0.5](https://github.com/jeremylong/DependencyCheck/releases/tag/v6.0.5) (2021-01-07) +## [Version 6.0.5](https://github.com/dependency-check/DependencyCheck/releases/tag/v6.0.5) (2021-01-07) ### Changed -- Added missing command line arguments per #3028 and #3035. +- Added missing command line arguments per [#3028](https://github.com/dependency-check/DependencyCheck/pull/3028) and [#3035](https://github.com/dependency-check/DependencyCheck/pull/3035). - False positive reduction and minor bug fixes. -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/19?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/19?closed=1). -## [Version 6.0.4](https://github.com/jeremylong/DependencyCheck/releases/tag/v6.0.4) (2020-12-31) +## [Version 6.0.4](https://github.com/dependency-check/DependencyCheck/releases/tag/v6.0.4) (2020-12-31) ### Changed - Minor bug fixes and reduction of false positives. -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/18?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/18?closed=1). -## [Version 6.0.3](https://github.com/jeremylong/DependencyCheck/releases/tag/v6.0.3) (2020-11-03) +## [Version 6.0.3](https://github.com/dependency-check/DependencyCheck/releases/tag/v6.0.3) (2020-11-03) ### Changed -- Added a bash command completion script (see #2916); to add completion to your shell +- Added a bash command completion script (see [#2916](https://github.com/dependency-check/DependencyCheck/pull/2916)); to add completion to your shell `completion-for-dependency-check.sh` can be found in the bin directory of the CLI: ```bash $ source completion-for-dependency-check.sh ``` -- An experimental PIP File Analyzer was added (see #2877). -- Analysis of Node JS produced several false positives (see #2796); the analysis has +- An experimental PIP File Analyzer was added (see [#2877](https://github.com/dependency-check/DependencyCheck/pull/2877)). +- Analysis of Node JS produced several false positives (see [#2796](https://github.com/dependency-check/DependencyCheck/pull/2796)); the analysis has been updated to reduce the number of false positives. - If analyzing Node JS projects it is highly recommended to disable the Node JS Analyzer and solely rely on the Node Audit Analyzer. There are plans to rework Node JS analysis in a future release. -- Support for external Oracle databases has been add for the 6.x releases (see #2899) +- Support for external Oracle databases has been add for the 6.x releases (see [#2899](https://github.com/dependency-check/DependencyCheck/pull/2899)) - Resolved several reported false positives. -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/17?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/17?closed=1). -## [Version 6.0.2](https://github.com/jeremylong/DependencyCheck/releases/tag/v6.0.2) (2020-09-27) +## [Version 6.0.2](https://github.com/dependency-check/DependencyCheck/releases/tag/v6.0.2) (2020-09-27) ### Changed -- The project is migrating from hosting the release archives on Bintray and moving them to Github under the assets for each [release](https://github.com/jeremylong/DependencyCheck/releases) +- The project is migrating from hosting the release archives on Bintray and moving them to Github under the assets for each [release](https://github.com/dependency-check/DependencyCheck/releases) - **Please update any automation you have to point to the new location.** -- Npm Audit Analyzer now correctly skips dev dependencies (`--nodeAuditSkipDevDependencies`); see #2482. -- GoLang Analyzer now scans transitive dependencies; see #2680. +- Npm Audit Analyzer now correctly skips dev dependencies (`--nodeAuditSkipDevDependencies`); see [#2482](https://github.com/dependency-check/DependencyCheck/pull/2482). +- GoLang Analyzer now scans transitive dependencies; see [#2680](https://github.com/dependency-check/DependencyCheck/pull/2680). - Several bug fixes found in 6.0.1. -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/16?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/16?closed=1). -## [Version 6.0.1](https://github.com/jeremylong/DependencyCheck/releases/tag/v6.0.1) (2020-09-13) +## [Version 6.0.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v6.0.1) (2020-09-13) ### Changed @@ -567,85 +1061,85 @@ See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/ - Fixed the database path for the Ant and Gradle plugins. - Added locking around the RetireJS updates to resolve read/write conflicts in CI environments. -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/15?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/15?closed=1). -## [Version 6.0.0](https://github.com/jeremylong/DependencyCheck/releases/tag/v6.0.0) (2020-09-07) +## [Version 6.0.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v6.0.0) (2020-09-07) ### Changed - Updated database schema; this is a *breaking change* and anyone using an external database or those whom specify the data directory will need recreate the database (including users of the docker image). The schema changes were made to: - - Improve the CVSS data, when available, per #2547 + - Improve the CVSS data, when available, per [#2547](https://github.com/dependency-check/DependencyCheck/pull/2547) - Improve the way that ecosystems are determined - Improve the update performance of external databases -- Users with an **external Oracle** database will not be able to upgrade as https://github.com/jeremylong/DependencyCheck/issues/2755 +- Users with an **external Oracle** database will not be able to upgrade as https://github.com/dependency-check/DependencyCheck/issues/2755 has not been resolved - as such, version 6.0.0 does not support Oracle. - Users mirroring the NVD - ODC 6.0.0 requires the use of the version 1.1 data feeds - please ensure you are using 1.1 not the 1.0 data feed. -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/14?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/14?closed=1). -## [Version 5.3.2](https://github.com/jeremylong/DependencyCheck/releases/tag/v5.3.2) (2020-03-26) +## [Version 5.3.2](https://github.com/dependency-check/DependencyCheck/releases/tag/v5.3.2) (2020-03-26) ### Changed - Several bug fixes -- Full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/13?closed=1). +- Full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/13?closed=1). -## [Version 5.3.1](https://github.com/jeremylong/DependencyCheck/releases/tag/v5.3.1) (2020-03-10) +## [Version 5.3.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v5.3.1) (2020-03-10) ### Changed -- Added an experimental PE Analyzer that reads the PE headers of DLL and EXE files; see [#2448](https://github.com/jeremylong/DependencyCheck/pull/2448) and [#2446](https://github.com/jeremylong/DependencyCheck/pull/2446). +- Added an experimental PE Analyzer that reads the PE headers of DLL and EXE files; see [#2448](https://github.com/dependency-check/DependencyCheck/pull/2448) and [#2446](https://github.com/dependency-check/DependencyCheck/pull/2446). - Lots of bug fixes and updates to false positives and false negatives - You may see a large one time performance hit when updating the database after updating to 5.3.1 -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/12?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/12?closed=1). -## [Version 5.3.0](https://github.com/jeremylong/DependencyCheck/releases/tag/v5.3.0) (2020-01-15) +## [Version 5.3.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v5.3.0) (2020-01-15) ### Changed -- Updated the JSON report to include a new field for unscored vulnerabilities (see #2392). -- Updated the XML report to include a new attribute to flag unscored vulnerabilities (see #2392) - - see https://github.com/jeremylong/DependencyCheck/blob/main/core/src/main/resources/schema/dependency-check.2.3.xsd -- Added an experimental analyzer that will lookup Node libraries in the NVD data feeds (see #1249) +- Updated the JSON report to include a new field for unscored vulnerabilities (see [#2392](https://github.com/dependency-check/DependencyCheck/pull/2392)). +- Updated the XML report to include a new attribute to flag unscored vulnerabilities (see [#2392](https://github.com/dependency-check/DependencyCheck/pull/2392)) + - see https://github.com/dependency-check//DependencyCheck/blob/main/core/src/main/resources/schema/dependency-check.2.3.xsd +- Added an experimental analyzer that will lookup Node libraries in the NVD data feeds (see [#1249](https://github.com/dependency-check/DependencyCheck/pull/1249)) - `NpmCPEAnalyzer`, experimental analyzers must be enabled, controlled via property `analyzer.npm.cpe.enabled` which will be exposed as a configuration option in the next release. -See the full listing of [changes](https://github.com/jeremylong/DependencyCheck/milestone/11?closed=1). +See the full listing of [changes](https://github.com/dependency-check/DependencyCheck/milestone/11?closed=1). -## [Version 5.2.4](https://github.com/jeremylong/DependencyCheck/releases/tag/v5.2.4) (2019-11-12) +## [Version 5.2.4](https://github.com/dependency-check/DependencyCheck/releases/tag/v5.2.4) (2019-11-12) ### Changed - Reverted a in 5.2.3 that caused the dependency-check.sh script to fail on some systems (including the docker image). - Fixed issue with pretty printing the XML report. -See the full listing of [resolved issues](https://github.com/jeremylong/DependencyCheck/issues?utf8=%E2%9C%93&q=is%3Aissue++is%3Aclosed+milestone%3A5.2.4). +See the full listing of [resolved issues](https://github.com/dependency-check/DependencyCheck/issues?utf8=%E2%9C%93&q=is%3Aissue++is%3Aclosed+milestone%3A5.2.4). -## [Version 5.2.3](https://github.com/jeremylong/DependencyCheck/releases/tag/v5.2.3) (2019-11-11) +## [Version 5.2.3](https://github.com/dependency-check/DependencyCheck/releases/tag/v5.2.3) (2019-11-11) ### Changed -- Updated to use the NVD JSON 1.1 schema (see [#2273](https://github.com/jeremylong/DependencyCheck/issues/2273)). +- Updated to use the NVD JSON 1.1 schema (see [#2273](https://github.com/dependency-check/DependencyCheck/issues/2273)). - This update is 100% backward compatible with the 1.0 schema if you are mirroring the 1.0 JSON files. - Added `nonProxyHosts` to the CLI and gradle plugin. - False positive corrections. - General code cleanup/bug fix. -See the full listing of [resolved issues](https://github.com/jeremylong/DependencyCheck/issues?utf8=%E2%9C%93&q=is%3Aissue++is%3Aclosed+milestone%3A5.2.3) and [pull requests](https://github.com/jeremylong/DependencyCheck/pulls?utf8=%E2%9C%93&q=is%3Apr+milestone%3A5.2.3+is%3Aclosed+). +See the full listing of [resolved issues](https://github.com/dependency-check/DependencyCheck/issues?utf8=%E2%9C%93&q=is%3Aissue++is%3Aclosed+milestone%3A5.2.3) and [pull requests](https://github.com/dependency-check/DependencyCheck/pulls?utf8=%E2%9C%93&q=is%3Apr+milestone%3A5.2.3+is%3Aclosed+). -## [Version 5.2.2](https://github.com/jeremylong/DependencyCheck/releases/tag/v5.2.2) (2019-09-22) +## [Version 5.2.2](https://github.com/dependency-check/DependencyCheck/releases/tag/v5.2.2) (2019-09-22) ### Changed - False positive corrections - General code cleanup/bug fix -See the full listing of [resolved issues](https://github.com/jeremylong/DependencyCheck/issues?utf8=%E2%9C%93&q=is%3Aissue++is%3Aclosed+milestone%3A5.2.2). +See the full listing of [resolved issues](https://github.com/dependency-check/DependencyCheck/issues?utf8=%E2%9C%93&q=is%3Aissue++is%3Aclosed+milestone%3A5.2.2). -## [Version 5.2.1](https://github.com/jeremylong/DependencyCheck/releases/tag/v5.2.1) (2019-08-04) +## [Version 5.2.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v5.2.1) (2019-08-04) ### Changed @@ -654,49 +1148,49 @@ See the full listing of [resolved issues](https://github.com/jeremylong/Dependen - False positive corrections - General code cleanup/bug fix -See the full listing of [resolved issues](https://github.com/jeremylong/DependencyCheck/issues?utf8=%E2%9C%93&q=is%3Aissue++is%3Aclosed+milestone%3A5.2.1). +See the full listing of [resolved issues](https://github.com/dependency-check/DependencyCheck/issues?utf8=%E2%9C%93&q=is%3Aissue++is%3Aclosed+milestone%3A5.2.1). -## [Version 5.2.0](https://github.com/jeremylong/DependencyCheck/releases/tag/v5.2.0) (2019-07-21) +## [Version 5.2.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v5.2.0) (2019-07-21) ### Changed - Resolved formatting issues within the CSV report - False positive corrections - Renamed three properties within the `dependencycheck.properties`; there is no impact unless you are using a properties file in your build to control the CLI. -- Added support for rbenv for Bundle Audit Analysis (see https://github.com/jeremylong/DependencyCheck/issues/2060). +- Added support for rbenv for Bundle Audit Analysis (see https://github.com/dependency-check/DependencyCheck/issues/2060). -See the full listing of [resolved issues](https://github.com/jeremylong/DependencyCheck/issues?utf8=%E2%9C%93&q=is%3Aissue++is%3Aclosed+milestone%3A5.2.0). +See the full listing of [resolved issues](https://github.com/dependency-check/DependencyCheck/issues?utf8=%E2%9C%93&q=is%3Aissue++is%3Aclosed+milestone%3A5.2.0). -## [Version 5.1.1](https://github.com/jeremylong/DependencyCheck/releases/tag/v5.1.1) (2019-07-15) +## [Version 5.1.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v5.1.1) (2019-07-15) ### Changed - False positive corrections - General code cleanup -See the full listing of [resolved issues](https://github.com/jeremylong/DependencyCheck/issues?q=is%3Aissue+milestone%3A5.1.1+is%3Aclosed). +See the full listing of [resolved issues](https://github.com/dependency-check/DependencyCheck/issues?q=is%3Aissue+milestone%3A5.1.1+is%3Aclosed). -## [Version 5.1.0](https://github.com/jeremylong/DependencyCheck/releases/tag/v5.1.0) (2019-06-28) +## [Version 5.1.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v5.1.0) (2019-06-28) ### Changed - Added two experimental analyzers to support Golang. - Updated the suppression schema to support suppressing OSS Index, RetireJS, NSP vulnerabilities, etc. - The HTML report now uses the 1.3 suppression schema by default to generate suppression rules. - - See the updated examples on https://jeremylong.github.io/DependencyCheck/general/suppression.html. + - See the updated examples on https://dependency-check.github.io/DependencyCheck/general/suppression.html. - Added optional configuration to add credentials to the OSS Index analysis. - Resolved issues when Oracle or MySQL were used as a centralized database in 5.0.0. -See the full listing of [resolved issues](https://github.com/jeremylong/DependencyCheck/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+milestone%3A5.1.0) and [pull requests](https://github.com/jeremylong/DependencyCheck/pulls?utf8=%E2%9C%93&q=is%3Apr+milestone%3A5.1.0). +See the full listing of [resolved issues](https://github.com/dependency-check/DependencyCheck/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+milestone%3A5.1.0) and [pull requests](https://github.com/dependency-check/DependencyCheck/pulls?utf8=%E2%9C%93&q=is%3Apr+milestone%3A5.1.0). -## [Version 5.0.0](https://github.com/jeremylong/DependencyCheck/releases/tag/v5.0.0) (2019-06-09) +## [Version 5.0.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v5.0.0) (2019-06-09) ### Changed - Add caching of OSS-Index, Central Analyzer, and Node Audit analysis results. -- General bug fixes identified in the previous milestone releases; see [5.0.0 resolved issues](https://github.com/jeremylong/DependencyCheck/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+milestone%3A5.0.0+) and [pull requests](https://github.com/jeremylong/DependencyCheck/pulls?utf8=%E2%9C%93&q=is%3Apr+milestone%3A5.0.0). +- General bug fixes identified in the previous milestone releases; see [5.0.0 resolved issues](https://github.com/dependency-check/DependencyCheck/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+milestone%3A5.0.0+) and [pull requests](https://github.com/dependency-check/DependencyCheck/pulls?utf8=%E2%9C%93&q=is%3Apr+milestone%3A5.0.0). -## [Version 5.0.0-M3](https://github.com/jeremylong/DependencyCheck/releases/tag/v5.0.0-M3) (2019-05-06) +## [Version 5.0.0-M3](https://github.com/dependency-check/DependencyCheck/releases/tag/v5.0.0-M3) (2019-05-06) ### Changed @@ -704,7 +1198,7 @@ See the full listing of [resolved issues](https://github.com/jeremylong/Dependen ### Changed -- Several bug fixes and minor enhancements have been made; see the related [issues](https://github.com/jeremylong/DependencyCheck/issues?utf8=%E2%9C%93&q=+milestone%3A5.0.0-M3+) and [pull requests](https://github.com/jeremylong/DependencyCheck/pulls?utf8=%E2%9C%93&q=+milestone%3A5.0.0-M3+). +- Several bug fixes and minor enhancements have been made; see the related [issues](https://github.com/dependency-check/DependencyCheck/issues?utf8=%E2%9C%93&q=+milestone%3A5.0.0-M3+) and [pull requests](https://github.com/dependency-check/DependencyCheck/pulls?utf8=%E2%9C%93&q=+milestone%3A5.0.0-M3+). - Multiple report formats can be specified; if you wanted just two of the reports you no longer need to use ALL. - A new JUNIT formatted report has been added; this provides a different way to integrate with Jenkins builds; the following example creates a JUNIT report with failures for any CVE with a CVSS score greater than or equal to 7.0 the Jenkins pipeline script shows how to publish the report: @@ -747,14 +1241,14 @@ See the full listing of [resolved issues](https://github.com/jeremylong/Dependen } ``` -## [Version 5.0.0-M2](https://github.com/jeremylong/DependencyCheck/releases/tag/v5.0.0-M2) (2019-03-11) +## [Version 5.0.0-M2](https://github.com/dependency-check/DependencyCheck/releases/tag/v5.0.0-M2) (2019-03-11) ### Changed - **Breaking:** [dotnet core](https://dotnet.microsoft.com/download/dotnet-core/2.2) must be installed to analyze .NET assemblies. - **Breaking:** The retire.js analyzer is no longer considered experimental and is enabled by default. -## [Version 5.0.0-M1](https://github.com/jeremylong/DependencyCheck/releases/tag/v5.0.0-M1) (2019-02-17) +## [Version 5.0.0-M1](https://github.com/dependency-check/DependencyCheck/releases/tag/v5.0.0-M1) (2019-02-17) ### Changed @@ -771,7 +1265,7 @@ See the full listing of [resolved issues](https://github.com/jeremylong/Dependen from one technology stack do not appear on a dependency built using a completely different stack (e.g. NodeJS vulnerabilities should not show up on a .NET DLL). -## [Version 4.0.2](https://github.com/jeremylong/DependencyCheck/releases/tag/v4.0.2) (2019-01-01) +## [Version 4.0.2](https://github.com/dependency-check/DependencyCheck/releases/tag/v4.0.2) (2019-01-01) ### Added @@ -780,91 +1274,91 @@ See the full listing of [resolved issues](https://github.com/jeremylong/Dependen To enable this feature set `false`. - If using a local Nexus server (v2 or v3 pro) it is now possible to provide authentication credentials. - Previous versions only worked with anonymous/unauthenticated access. - - See [issue #977](https://github.com/jeremylong/DependencyCheck/issues/977) + - See [issue #977](https://github.com/dependency-check/DependencyCheck/issues/977) ### Fixed - Updated fix for transitive dependencies with known vulnerabilities (guava and commons-collections) so that the upgrade occurs correctly in other integrations that utilize core; see - [issue #1562](https://github.com/jeremylong/DependencyCheck/issues/1561#issuecomment-450112110). + [issue #1562](https://github.com/dependency-check/DependencyCheck/issues/1561#issuecomment-450112110). - Resolved several false positives -## [Version 4.0.1](https://github.com/jeremylong/DependencyCheck/releases/tag/v4.0.1) (2018-12-17) +## [Version 4.0.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v4.0.1) (2018-12-17) ### Fixed -- Fixed issue with false positives due to Lucene upgrade. See [#1531](https://github.com/jeremylong/DependencyCheck/issues/1580). +- Fixed issue with false positives due to Lucene upgrade. See [#1531](https://github.com/dependency-check/DependencyCheck/issues/1580). - Resolved several false positives. - Resolved typo in documentation. -## [Version 4.0.0](https://github.com/jeremylong/DependencyCheck/releases/tag/v4.0.0) (2018-11-21) +## [Version 4.0.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v4.0.0) (2018-11-21) ### Changed -- OWASP dependency-check no longer supports running in JRE/JDK 7; JRE/JDK 8 or higher is required run dependency-check. See [#1531](https://github.com/jeremylong/DependencyCheck/issues/1531). +- OWASP dependency-check no longer supports running in JRE/JDK 7; JRE/JDK 8 or higher is required run dependency-check. See [#1531](https://github.com/dependency-check/DependencyCheck/issues/1531). ### Fixed -- Upgraded dependencies to resolve published vulnerabilities (Guava and Lucene); See [#1561](https://github.com/jeremylong/DependencyCheck/issues/1561). +- Upgraded dependencies to resolve published vulnerabilities (Guava and Lucene); See [#1561](https://github.com/dependency-check/DependencyCheck/issues/1561). -## [Version 3.3.4](https://github.com/jeremylong/DependencyCheck/releases/tag/v3.3.4) (2018-10-28) +## [Version 3.3.4](https://github.com/dependency-check/DependencyCheck/releases/tag/v3.3.4) (2018-10-28) ### Fixed - Resolved bug with parsing license information during analysis of Node.js modules. -## [Version 3.3.3](https://github.com/jeremylong/DependencyCheck/releases/tag/v3.3.3) (2018-10-27) +## [Version 3.3.3](https://github.com/dependency-check/DependencyCheck/releases/tag/v3.3.3) (2018-10-27) ### Changed -- Migrated the NSP Analyzer to use the Node Audit APIs instead; see [#1366](https://github.com/jeremylong/DependencyCheck/issues/1366). +- Migrated the NSP Analyzer to use the Node Audit APIs instead; see [#1366](https://github.com/dependency-check/DependencyCheck/issues/1366). - Note that the analyzer and configuration was changed to NodeAuditAnalyzer. - Configurations for the NSP analyzer have been deprecated and will control the NodeAuditAnalyzer if used; note that the NSP configuration options will be removed in a future release. -- The [dependency-check-gradle](https://github.com/jeremylong/dependency-check-gradle) plugin was updated to include a default scan set +- The [dependency-check-gradle](https://github.com/dependency-check/Dependency-check-gradle) plugin was updated to include a default scan set of ['src/main/resources','src/main/webapp'] and any dependencies contained in these directories will be analyzed. The purpose of this enhancement is to enable the RetireJS Analyzer to scan JavaScript files that may be included. ### Fixed -- Resolved **false negative** on Bouncy Castle JAR files; see [#1500](https://github.com/jeremylong/DependencyCheck/issues/1500). -- Resolved **false negatives** that may occur when using the Maven plugin if transitive dependencies of a library in use and is also declared as a primary dependency in a scope that is not used; see [#1512](https://github.com/jeremylong/DependencyCheck/issues/1512). -- Resolved **false negatives** on libraries that contain an update version or timestamp tacked onto the end of the version number; see [#1537](https://github.com/jeremylong/DependencyCheck/issues/1537). +- Resolved **false negative** on Bouncy Castle JAR files; see [#1500](https://github.com/dependency-check/DependencyCheck/issues/1500). +- Resolved **false negatives** that may occur when using the Maven plugin if transitive dependencies of a library in use and is also declared as a primary dependency in a scope that is not used; see [#1512](https://github.com/dependency-check/DependencyCheck/issues/1512). +- Resolved **false negatives** on libraries that contain an update version or timestamp tacked onto the end of the version number; see [#1537](https://github.com/dependency-check/DependencyCheck/issues/1537). - The resolution for these false negatives may generate some false positives, please continue to report false positives and the engine can continue to be tuned. -- Fixed bug preventing multiple proxies from being defined for Maven; see [#831](https://github.com/jeremylong/DependencyCheck/issues/831). -- Updated the suppress buttons in the HTML report to generate the XML using the latest suppression schema; see [#489](https://github.com/jeremylong/DependencyCheck/issues/1489). -- Added the `--artifactoryUrl` argument to the CLI - this was missed when the Artifactory Analyzer was previously added; see [#1492](https://github.com/jeremylong/DependencyCheck/issues/1492). -- Updated test cases so that they no longer fail behind a proxy; see [#1493](https://github.com/jeremylong/DependencyCheck/issues/1493). -- Resolved several reported false positives; see [#1504](https://github.com/jeremylong/DependencyCheck/issues/1504), [#1513](https://github.com/jeremylong/DependencyCheck/issues/1513), - [#1515](https://github.com/jeremylong/DependencyCheck/issues/1515), [#1529](https://github.com/jeremylong/DependencyCheck/issues/1529), [#1535](https://github.com/jeremylong/DependencyCheck/issues/1535), - and [#1437](https://github.com/jeremylong/DependencyCheck/issues/1437). -- Fixed copy/paste error in JavaDoc; see [#1509](https://github.com/jeremylong/DependencyCheck/issues/1509). +- Fixed bug preventing multiple proxies from being defined for Maven; see [#831](https://github.com/dependency-check/DependencyCheck/issues/831). +- Updated the suppress buttons in the HTML report to generate the XML using the latest suppression schema; see [#489](https://github.com/dependency-check/DependencyCheck/issues/1489). +- Added the `--artifactoryUrl` argument to the CLI - this was missed when the Artifactory Analyzer was previously added; see [#1492](https://github.com/dependency-check/DependencyCheck/issues/1492). +- Updated test cases so that they no longer fail behind a proxy; see [#1493](https://github.com/dependency-check/DependencyCheck/issues/1493). +- Resolved several reported false positives; see [#1504](https://github.com/dependency-check/DependencyCheck/issues/1504), [#1513](https://github.com/dependency-check/DependencyCheck/issues/1513), + [#1515](https://github.com/dependency-check/DependencyCheck/issues/1515), [#1529](https://github.com/dependency-check/DependencyCheck/issues/1529), [#1535](https://github.com/dependency-check/DependencyCheck/issues/1535), + and [#1437](https://github.com/dependency-check/DependencyCheck/issues/1437). +- Fixed copy/paste error in JavaDoc; see [#1509](https://github.com/dependency-check/DependencyCheck/issues/1509). -## [Version 3.3.2](https://github.com/jeremylong/DependencyCheck/releases/tag/v3.3.2) (2018-09-14) +## [Version 3.3.2](https://github.com/dependency-check/DependencyCheck/releases/tag/v3.3.2) (2018-09-14) ### Fixed -- Gradle plugin was updated to include backward compatibility with gradle < v4.0; see [#95](https://github.com/jeremylong/dependency-check-gradle/issues/95). -- Gradle plugin improved handling of Android project; see [#94](https://github.com/jeremylong/dependency-check-gradle/issues/94) -- CLI used an incorrect key for RetireJS causing the analyzer to not be loaded in some cases; see [#1440](https://github.com/jeremylong/DependencyCheck/issues/1440). -- Resolved failure in the `CentralAnalyzer` when the pom.xml is not available in Central; see [#1439](https://github.com/jeremylong/DependencyCheck/issues/1439). -- Resolved exception when JAR files contain invalid pom.xml files outside of META-INF; see [#1438](https://github.com/jeremylong/DependencyCheck/issues/1438). +- Gradle plugin was updated to include backward compatibility with gradle < v4.0; see [#95](https://github.com/dependency-check/Dependency-check-gradle/issues/95). +- Gradle plugin improved handling of Android project; see [#94](https://github.com/dependency-check/Dependency-check-gradle/issues/94) +- CLI used an incorrect key for RetireJS causing the analyzer to not be loaded in some cases; see [#1440](https://github.com/dependency-check/DependencyCheck/issues/1440). +- Resolved failure in the `CentralAnalyzer` when the pom.xml is not available in Central; see [#1439](https://github.com/dependency-check/DependencyCheck/issues/1439). +- Resolved exception when JAR files contain invalid pom.xml files outside of META-INF; see [#1438](https://github.com/dependency-check/DependencyCheck/issues/1438). - Resolved several reported false positives. -## [Version 3.3.1](https://github.com/jeremylong/DependencyCheck/releases/tag/v3.3.1) (2018-08-06) +## [Version 3.3.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v3.3.1) (2018-08-06) ### Changed -- An Nuget Packages.config Analyzer was added; see [#1412](https://github.com/jeremylong/DependencyCheck/issues/1412). +- An Nuget Packages.config Analyzer was added; see [#1412](https://github.com/dependency-check/DependencyCheck/issues/1412). ### Fixed -- Fixed error handling with regard to invalid manifest files contained within JAR files; see [#1024](https://github.com/jeremylong/DependencyCheck/issues/1024). -- Fixed parsing of pom.xml files, in some cases a SAX Exception would be thrown; see [#1400](https://github.com/jeremylong/DependencyCheck/issues/1400). -- Fixed bug that caused dependency-check to crash if the temporary directory and data directory were on different drives; see [#1394](https://github.com/jeremylong/DependencyCheck/issues/1394). -- Fixed bug in dependency-check-maven where an aggregate analysis did not scan all files defined in the ScanSet; see [#1421](https://github.com/jeremylong/DependencyCheck/issues/1421). -- Fixed NPE in dependency-check-gradle that occurred when artifacts where included using `implementation files("./lib/some.jar")`; see [#91](https://github.com/jeremylong/dependency-check-gradle/issues/91). +- Fixed error handling with regard to invalid manifest files contained within JAR files; see [#1024](https://github.com/dependency-check/DependencyCheck/issues/1024). +- Fixed parsing of pom.xml files, in some cases a SAX Exception would be thrown; see [#1400](https://github.com/dependency-check/DependencyCheck/issues/1400). +- Fixed bug that caused dependency-check to crash if the temporary directory and data directory were on different drives; see [#1394](https://github.com/dependency-check/DependencyCheck/issues/1394). +- Fixed bug in dependency-check-maven where an aggregate analysis did not scan all files defined in the ScanSet; see [#1421](https://github.com/dependency-check/DependencyCheck/issues/1421). +- Fixed NPE in dependency-check-gradle that occurred when artifacts where included using `implementation files("./lib/some.jar")`; see [#91](https://github.com/dependency-check/Dependency-check-gradle/issues/91). -## [Version 3.3.0](https://github.com/jeremylong/DependencyCheck/releases/tag/v3.3.0) (2018-07-22) +## [Version 3.3.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v3.3.0) (2018-07-22) ### Changed @@ -873,52 +1367,52 @@ See the full listing of [resolved issues](https://github.com/jeremylong/Dependen - An experimental Retire JS analyzer has been added to analyze client side JavaScript. - This utilizes information from the RetireJS repo on github. If you have a proxy that prevents access you will either need to have access granted to https://raw.githubusercontent.com/Retirejs/retire.js/main/repository/jsrepository.json or host the file internally, update the environment variable `analyzer.retirejs.repo.js.ur`, and periodically update the file. - This analyzer is considered experimental, but the team expects this to be promoted quickly. -- NuGet dependencies contained in MSBuild files are now included in the scan. See [Issue #1131](https://github.com/jeremylong/DependencyCheck/issues/1131) for more details. -- Cocoapod's Podfile.lock is now analyzed when present. See [PR #1324](https://github.com/jeremylong/DependencyCheck/pull/1324) for more information. +- NuGet dependencies contained in MSBuild files are now included in the scan. See [Issue #1131](https://github.com/dependency-check/DependencyCheck/issues/1131) for more details. +- Cocoapod's Podfile.lock is now analyzed when present. See [PR #1324](https://github.com/dependency-check/DependencyCheck/pull/1324) for more information. ### Fixed -- The dependency-check-gradle plugin can now analyze multi-project android builds. See [PR #09](https://github.com/jeremylong/dependency-check-gradle/pull/90) for more information. -- In some cases extremely large project may cause dependency-check to fail due to the analysis time. Previously, the analysis was capped at 10 minutes; the timeout was increased to 20 minutes and made configurable if this continues to be an issue for some users. See [issue #936](https://github.com/jeremylong/DependencyCheck/issues/936) for more information. +- The dependency-check-gradle plugin can now analyze multi-project android builds. See [PR #09](https://github.com/dependency-check/Dependency-check-gradle/pull/90) for more information. +- In some cases extremely large project may cause dependency-check to fail due to the analysis time. Previously, the analysis was capped at 10 minutes; the timeout was increased to 20 minutes and made configurable if this continues to be an issue for some users. See [issue #936](https://github.com/dependency-check/DependencyCheck/issues/936) for more information. - Some pom.xml files could not be analyzed because they contained a doctype definition. The parser has been enhanced to strip the doctype definitions. - Fixed issue where, in some cases, temporary files were not correctly cleaned up in Jenkins and gradle builds. -- Fixed issue where, in some cases, files were retrieved from Maven Central using HTTP instead of HTTPS. See [issue #1325](https://github.com/jeremylong/DependencyCheck/issues/1325) for more information. +- Fixed issue where, in some cases, files were retrieved from Maven Central using HTTP instead of HTTPS. See [issue #1325](https://github.com/dependency-check/DependencyCheck/issues/1325) for more information. - Additionally, a retry count was added when attempting to download pom.xml files during analysis. -- Fixed issue where nodejs dependencies were not correctly analyzed. See [issue #1355](https://github.com/jeremylong/DependencyCheck/issues/1355) for more information. +- Fixed issue where nodejs dependencies were not correctly analyzed. See [issue #1355](https://github.com/dependency-check/DependencyCheck/issues/1355) for more information. - Fixed issue where the CWE was not written to the CSV report. - In addition, general bug fixes, code cleanup, and false positive/negatives updates were made. -## [Version 3.2.1](https://github.com/jeremylong/DependencyCheck/releases/tag/v3.2.1) (2018-05-28) +## [Version 3.2.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v3.2.1) (2018-05-28) ### Fixed -- In some cases when using the Maven or Gradle plugins the GAV coordinates were not being added as an Identifier causing suppression rules to fail; this has been resolved (#1298) -- Documentation Update (SCM links in the maven site were broken) (#1297) -- False positive reduction (#1290) -- Enhanced logging output for TLS failures to better assist with debugging (#1269) -- Resolved a Null Pointer Exception (#1296) +- In some cases when using the Maven or Gradle plugins the GAV coordinates were not being added as an Identifier causing suppression rules to fail; this has been resolved ([#1298](https://github.com/dependency-check/DependencyCheck/pull/1298)) +- Documentation Update (SCM links in the maven site were broken) ([#1297](https://github.com/dependency-check/DependencyCheck/pull/1297)) +- False positive reduction ([#1290](https://github.com/dependency-check/DependencyCheck/pull/1290)) +- Enhanced logging output for TLS failures to better assist with debugging ([#1269](https://github.com/dependency-check/DependencyCheck/pull/1269)) +- Resolved a Null Pointer Exception ([#1296](https://github.com/dependency-check/DependencyCheck/pull/1296)) -## [Version 3.2.0](https://github.com/jeremylong/DependencyCheck/releases/tag/v3.2.0) (2018-05-21) +## [Version 3.2.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v3.2.0) (2018-05-21) ### Changed - Excess white space has been removed from the XML and HTML reports; the JSON report is still pretty printed (a future release will convert this to a configurable option) - Better error reporting - Changed to use commons-text instead of commons-lang3 as a portion of commons-lang3 was moved to commonts-text -- Added more flexible suppression rules with the introduction of the `until` attribute (see [#1145](https://github.com/jeremylong/DependencyCheck/issues/1145) and [dependency-suppression.1.2.xsd](https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.2.xsd) +- Added more flexible suppression rules with the introduction of the `until` attribute (see [#1145](https://github.com/dependency-check/DependencyCheck/issues/1145) and [dependency-suppression.1.2.xsd](https://dependency-check.github.io/DependencyCheck/dependency-suppression.1.2.xsd) ### Fixed - Unsafe unzip operations ([zip slip](https://github.com/snyk/zip-slip-vulnerability)), as reported by the Snyk Security Research Team, have been corrected. CVE-2018-12036 allows attackers to write to arbitrary files via a crafted archive that holds directory traversal filenames. -- The dependency-check-maven plugin no longer uses the [Central Analyzer](https://jeremylong.github.io/DependencyCheck/analyzers/central-analyzer.html) by default -- Updated dependency-check-maven so that it will not fail when your multi-module build has dependencies that have not yet been built in the reactor (See [#740](https://github.com/jeremylong/DependencyCheck/issues/740)) +- The dependency-check-maven plugin no longer uses the [Central Analyzer](https://dependency-check.github.io/DependencyCheck/analyzers/central-analyzer.html) by default +- Updated dependency-check-maven so that it will not fail when your multi-module build has dependencies that have not yet been built in the reactor (See [#740](https://github.com/dependency-check/DependencyCheck/issues/740)) - Note if the required dependency has not yet been built in the reactor and the dependency is available in a configured repository dependency-check-maven, as expected, would pull the dependency from the repository for analysis. - Minor documentation updates - False positive reduction - Fixed the Gradle Plugin and Ant Task so that the temp directory is properly cleaned up after execution -- Removed TLSv1 from the list of protocols used by default (See [#1237](https://github.com/jeremylong/DependencyCheck/pull/1237)) +- Removed TLSv1 from the list of protocols used by default (See [#1237](https://github.com/dependency-check/DependencyCheck/pull/1237)) -## [Version 3.1.2](https://github.com/jeremylong/DependencyCheck/releases/tag/v3.1.2) (2018-04-02) +## [Version 3.1.2](https://github.com/dependency-check/DependencyCheck/releases/tag/v3.1.2) (2018-04-02) ### Fixed @@ -928,11 +1422,11 @@ See the full listing of [resolved issues](https://github.com/jeremylong/Dependen will include a reference to the project/module where they were found - The configuration option `versionCheckEnabled` was added to Maven to allow users to disable the check for new versions of dependency-check; this will be added to gradle plugin, Ant Task, and the CLI in a future release -- The XML and JSON reports were fixed so that the correct version number is displayed see [issue #1109](https://github.com/jeremylong/DependencyCheck/issues/1109) +- The XML and JSON reports were fixed so that the correct version number is displayed see [issue #1109](https://github.com/dependency-check/DependencyCheck/issues/1109) - The initial database creation time for H2 databases was improved - Changes made to decrease false positive and false negatives -## [Version 3.1.1](https://github.com/jeremylong/DependencyCheck/releases/tag/v3.1.1) (2018-01-29) +## [Version 3.1.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v3.1.1) (2018-01-29) ### Fixed @@ -941,7 +1435,7 @@ See the full listing of [resolved issues](https://github.com/jeremylong/Dependen - False positive reduction. - Minor documentation cleanup. -## [Version 3.1.0](https://github.com/jeremylong/DependencyCheck/releases/tag/v3.1.0) (2018-01-02) +## [Version 3.1.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v3.1.0) (2018-01-02) ### Changed @@ -961,19 +1455,19 @@ See the full listing of [resolved issues](https://github.com/jeremylong/Dependen the query to break. - General cleanup, false positive, and false negative reduction. -## [Version 3.0.2](https://github.com/jeremylong/DependencyCheck/releases/tag/v3.0.2) (2017-11-13) +## [Version 3.0.2](https://github.com/dependency-check/DependencyCheck/releases/tag/v3.0.2) (2017-11-13) ### Fixed - Updated the query format for the CentralAnalyzer; the old format caused the CentralAnalyzer to fail -## [Version 3.0.1](https://github.com/jeremylong/DependencyCheck/releases/tag/v3.0.1) (2017-10-20) +## [Version 3.0.1](https://github.com/dependency-check/DependencyCheck/releases/tag/v3.0.1) (2017-10-20) ### Fixed - Fixed a database connection issue that affected some usages. -## [Version 3.0.0](https://github.com/jeremylong/DependencyCheck/releases/tag/v3.0.0) (2017-10-16) +## [Version 3.0.0](https://github.com/dependency-check/DependencyCheck/releases/tag/v3.0.0) (2017-10-16) - Several bug fixes and false positive reduction - The 2.x branch introduced several new false positives – but also reduced the false negatives diff --git a/Dockerfile b/Dockerfile index dffcc4af62f..bce18e1cdf3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,14 @@ -FROM golang:1.17.1-alpine AS go +FROM golang:1.25.3-alpine AS go -FROM azul/zulu-openjdk-alpine:17 AS jlink +FROM azul/zulu-openjdk-alpine:25 AS jlink -RUN "$JAVA_HOME/bin/jlink" --compress=2 --module-path /opt/java/openjdk/jmods --add-modules java.base,java.compiler,java.datatransfer,jdk.crypto.ec,java.desktop,java.instrument,java.logging,java.management,java.naming,java.rmi,java.scripting,java.security.sasl,java.sql,java.transaction.xa,java.xml,jdk.unsupported --output /jlinked +RUN "$JAVA_HOME/bin/jlink" --compress=zip-6 --module-path /opt/java/openjdk/jmods --add-modules java.base,java.compiler,java.datatransfer,jdk.crypto.ec,java.desktop,java.instrument,java.logging,java.management,java.naming,java.rmi,java.scripting,java.security.sasl,java.sql,java.transaction.xa,java.xml,jdk.unsupported --output /jlinked -FROM mcr.microsoft.com/dotnet/runtime:6.0-alpine3.16 +FROM mcr.microsoft.com/dotnet/runtime:8.0-alpine3.22 ARG VERSION -ARG POSTGRES_DRIVER_VERSION=42.2.19 -ARG MYSQL_DRIVER_VERSION=8.0.23 +ARG POSTGRES_DRIVER_VERSION=42.7.5 +ARG MYSQL_DRIVER_VERSION=9.2.0 ARG UID=1000 ARG GID=1000 @@ -34,9 +34,9 @@ RUN apk update rm dependency-check-${VERSION}-release.zip && \ cd /usr/share/dependency-check/plugins && \ curl -Os "https://jdbc.postgresql.org/download/postgresql-${POSTGRES_DRIVER_VERSION}.jar" && \ - curl -Ls "https://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-java-${MYSQL_DRIVER_VERSION}.tar.gz" \ + curl -Ls "https://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-j-${MYSQL_DRIVER_VERSION}.tar.gz" \ | tar -xz --directory "/usr/share/dependency-check/plugins" --strip-components=1 --no-same-owner \ - "mysql-connector-java-${MYSQL_DRIVER_VERSION}/mysql-connector-java-${MYSQL_DRIVER_VERSION}.jar" && \ + "mysql-connector-j-${MYSQL_DRIVER_VERSION}/mysql-connector-j-${MYSQL_DRIVER_VERSION}.jar" && \ addgroup -S -g ${GID} ${user} && adduser -S -D -u ${UID} -G ${user} ${user} && \ mkdir /usr/share/dependency-check/data && \ chown -R ${user}:0 /usr/share/dependency-check && \ @@ -47,7 +47,7 @@ RUN apk update apk del .build-deps ### remove any suid sgid - we don't need them -RUN find / -perm +6000 -type f -exec chmod a-s {} \; +RUN find / -path /proc -prune -perm +6000 -type f -exec chmod a-s {} \; USER ${UID} VOLUME ["/src", "/report"] diff --git a/NOTICE.txt b/NOTICE.txt index 6638101b332..2a7d5099f7f 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -1,6 +1,6 @@ dependency-check -Copyright (c) 2012-2013 Jeremy Long. All Rights Reserved. +Copyright (c) 2012-2025 OWASP Dependency-Check Contributors. All Rights Reserved. The licenses for the software listed below can be found in the META-INF/licenses/[dependency name]. diff --git a/README.md b/README.md index b29246c5cbe..50a2edfec1a 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,85 @@ -[![Maven Central](https://img.shields.io/maven-central/v/org.owasp/dependency-check-maven.svg)](https://mvnrepository.com/artifact/org.owasp/dependency-check-maven) [![Build and Deploy Snapshot](https://github.com/jeremylong/DependencyCheck/actions/workflows/build.yml/badge.svg)](https://github.com/jeremylong/DependencyCheck/actions/workflows/build.yml) [![Coverity Scan Build Status](https://img.shields.io/coverity/scan/1654.svg)](https://scan.coverity.com/projects/dependencycheck) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/6b6021d481dc41a888c5da0d9ecf9494)](https://www.codacy.com/app/jeremylong/DependencyCheck?utm_source=github.com&utm_medium=referral&utm_content=jeremylong/DependencyCheck&utm_campaign=Badge_Grade) [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/843/badge)](https://bestpractices.coreinfrastructure.org/projects/843) [![Apache 2.0 License](https://img.shields.io/badge/license-Apache%202-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0.txt) +[![Maven Central](https://img.shields.io/maven-central/v/org.owasp/dependency-check-maven.svg)](https://mvnrepository.com/artifact/org.owasp/dependency-check-maven) [![Build and Deploy Snapshot](https://github.com/dependency-check/DependencyCheck/actions/workflows/build.yml/badge.svg)](https://github.com/dependency-check/DependencyCheck/actions/workflows/build.yml) [![Coverity Scan Build Status](https://img.shields.io/coverity/scan/1654.svg)](https://scan.coverity.com/projects/dependencycheck) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/6b6021d481dc41a888c5da0d9ecf9494)](https://www.codacy.com/app/jeremylong/DependencyCheck?utm_source=github.com&utm_medium=referral&utm_content=jeremylong/DependencyCheck&utm_campaign=Badge_Grade) [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/843/badge)](https://bestpractices.coreinfrastructure.org/projects/843) [![Apache 2.0 License](https://img.shields.io/badge/license-Apache%202-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0.txt) -[![Black Hat Arsenal](https://raw.githubusercontent.com/toolswatch/badges/master/arsenal/usa/2018.svg?sanitize=true)](http://www.toolswatch.org/2018/05/black-hat-arsenal-usa-2018-the-w0w-lineup/) [![Black Hat Arsenal](https://www.toolswatch.org/badges/arsenal/2015.svg)](https://www.toolswatch.org/2015/06/black-hat-arsenal-usa-2015-speakers-lineup/) [![Black Hat Arsenal](https://www.toolswatch.org/badges/arsenal/2014.svg)](https://www.toolswatch.org/2014/06/black-hat-usa-2014-arsenal-tools-speaker-list/) [![Black Hat Arsenal](https://www.toolswatch.org/badges/arsenal/2013.svg)](https://www.toolswatch.org/2013/06/announcement-blackhat-arsenal-usa-2013-selected-tools/) +[![Black Hat Arsenal](https://raw.githubusercontent.com/toolswatch/badges/master/arsenal/usa/2018.svg?sanitize=true)](https://www.blackhat.com/us-18/arsenal.html#jeremy-long) [![Black Hat Arsenal](https://raw.githubusercontent.com/toolswatch/badges/master/arsenal/usa/2015.svg?sanitize=true)](https://www.blackhat.com/us-15/arsenal.html#jeremy-long) [![Black Hat Arsenal](https://raw.githubusercontent.com/toolswatch/badges/master/arsenal/usa/2014.svg?sanitize=true)](https://www.blackhat.com/us-14/arsenal.html#Long) [![Black Hat Arsenal](https://raw.githubusercontent.com/toolswatch/badges/master/arsenal/usa/2013.svg?sanitize=true)](https://www.blackhat.com/us-13/arsenal.html#Long) # Dependency-Check Dependency-Check is a Software Composition Analysis (SCA) tool that attempts to detect publicly disclosed vulnerabilities contained within a project's dependencies. It does this by determining if there is a Common Platform Enumeration (CPE) identifier for a given dependency. If found, it will generate a report linking to the associated CVE entries. -Documentation and links to production binary releases can be found on the [github pages](http://jeremylong.github.io/DependencyCheck/). Additionally, more information about the architecture and ways to extend dependency-check can be found on the [wiki]. +Documentation and links to production binary releases can be found on the [github pages](https://dependency-check.github.io/DependencyCheck). Additionally, more information about the architecture and ways to extend dependency-check can be found on the [wiki]. -## 8.0.0 Upgrade Notice +## Notice -8.0.0 contains breaking changes which requires updates to the database. If using -an externally hosted database the schema will need to be updated. When using the -embedded H2 database the schema should be upgraded automatically. However, if -issues arise you may need to purge the database: +This product uses the NVD API but is not endorsed or certified by the NVD. -- gradle: `./gradlew dependencyCheckPurge` -- maven: `mvn org.owasp:dependency-check-maven:8.0.0:purge` -- cli: `dependency-check.sh --purge` + +## Breaking Changes in 11.0.0 + +- Java 11 is now required to run dependency-check 11.0.0 or higher +- H2 database upgrade + + 11.0.0 contains breaking changes using the local H2 database. A full download + of the NVD data will occur. Note that if you are using a shared data directory + the h2 database file is not compatible with older versions of dependency-check. + If you run into problems you may need to run a purge: + + - gradle: `./gradlew dependencyCheckPurge` + - maven: `mvn org.owasp:dependency-check-maven:9.0.0:purge` + - cli: `dependency-check.sh --purge` + +## Mandatory Upgrade Notice + +**Upgrading to 10.0.2 or later is mandatory** + +Older versions of dependency-check are causing numerous, duplicative requests that +end in processing failures are causing unnecassary load on the NVD API. Dependency-check +10.0.2 uses an updated `User-Agent` header that will allow the NVD to block calls +from the older client. + +### NVD API Key Highly Recommended + +Dependency-check has moved from using the NVD data-feed to the NVD API. +Users of dependency-check are **highly** encouraged to obtain an NVD API Key; see https://nvd.nist.gov/developers/request-an-api-key +Without an NVD API Key dependency-check's updates will be **extremely slow**. +Please see the documentation for the cli, maven, gradle, or ant integrations on +how to set the NVD API key. + +#### The NVD API Key, CI, and Rate Limiting + +The NVD API has enforced rate limits. If you are using a single API KEY and +multiple builds occur you could hit the rate limit and receive 403 errors. In +a CI environment one must use a caching strategy. + +#### Gradle build Environment + +With 9.0.0 users may encounter issues with `NoSuchMethodError` exceptions due to +dependency resolution. If you encounter this issue you will need to pin some of +the transitive dependencies of dependency-check to specific versions. For example: + +/buildSrc/build.gradle +```groovy +dependencies { + constraints { + // org.owasp.dependencycheck needs at least this version of jackson. Other plugins pull in older versions.. + add("implementation", "com.fasterxml.jackson:jackson-bom:2.16.1") + + // org.owasp.dependencycheck needs these versions. Other plugins pull in older versions.. + add("implementation", "org.apache.commons:commons-lang3:3.14.0") + add("implementation", "org.apache.commons:commons-text:1.11.0") + } +} +``` ## Requirements +### Java Version + +Minimum Java Version: Java 11 + ### Internet Access OWASP dependency-check requires access to several externally hosted resources. -For more information see [Internet Access Required](https://jeremylong.github.io/DependencyCheck/data/index.html). +For more information see [Internet Access Required](https://dependency-check.github.io/DependencyCheck/data/index.html). ### Build Tools @@ -32,8 +87,8 @@ In order to analyze some technology stacks dependency-check may require other development tools to be installed. Some of the analysis listed below may be experimental and require the experimental analyzers to be enabled. -1. To analyze .NET Assemblies the dotnet 6 run time or SDK must be installed. - - Assemblies targeting other run times can be analyzed - but 6 is required to run the analysis. +1. To analyze .NET Assemblies the dotnet 8 run time or SDK must be installed. + - Assemblies targeting other run times can be analyzed - but 8 is required to run the analysis. 2. If analyzing GoLang projects `go` must be installed. 3. The analysis of `Elixir` projects requires `mix_audit`. 4. The analysis of `npm`, `pnpm`, and `yarn` projects requires `npm`, `pnpm`, or `yarn` to be installed. @@ -49,13 +104,13 @@ For instructions on the use of the Jenkins plugin please see the [OWASP Dependen ### Command Line More detailed instructions can be found on the -[dependency-check github pages](http://jeremylong.github.io/DependencyCheck/dependency-check-cli/). -The latest CLI can be downloaded from github in the [releases section](https://github.com/jeremylong/DependencyCheck/releases). +[dependency-check github pages](https://dependency-check.github.io/DependencyCheck/dependency-check-cli/). +The latest CLI can be downloaded from github in the [releases section](https://github.com/dependency-check/DependencyCheck/releases). Downloading the latest release: ``` -$ VERSION=$(curl -s https://jeremylong.github.io/DependencyCheck/current.txt) -$ curl -s "https://github.com/jeremylong/DependencyCheck/releases/download/v$VERSION/dependency-check-$VERSION-release.zip" --output dependency-check.zip +$ VERSION=$(curl -s https://dependency-check.github.io/DependencyCheck/current.txt) +$ curl -Ls "https://github.com/dependency-check/DependencyCheck/releases/download/v$VERSION/dependency-check-$VERSION-release.zip" --output dependency-check.zip ``` On *nix @@ -78,7 +133,7 @@ $ dependency-check --out . --scan [path to jar files to be scanned] ### Maven Plugin -More detailed instructions can be found on the [dependency-check-maven github pages](http://jeremylong.github.io/DependencyCheck/dependency-check-maven). +More detailed instructions can be found on the [dependency-check-maven github pages](https://dependency-check.github.io/DependencyCheck/dependency-check-maven). By default, the plugin is tied to the `verify` phase (i.e. `mvn verify`). Alternatively, one can directly invoke the plugin via `mvn org.owasp:dependency-check-maven:check`. @@ -110,20 +165,20 @@ The dependency-check plugin can be configured using the following: ### Gradle Plugin -For instructions on the use of the Gradle Plugin, please see the [dependency-check-gradle github page](http://jeremylong.github.io/DependencyCheck/dependency-check-gradle). +For instructions on the use of the Gradle Plugin, please see the [dependency-check-gradle github page](https://dependency-check.github.io/DependencyCheck/dependency-check-gradle). ### Ant Task -For instructions on the use of the Ant Task, please see the [dependency-check-ant github page](http://jeremylong.github.io/DependencyCheck/dependency-check-ant). +For instructions on the use of the Ant Task, please see the [dependency-check-ant github page](https://dependency-check.github.io/DependencyCheck/dependency-check-ant). ## Development Prerequisites For installation to pass, you must have the following components installed: -* Java: `java -version` 1.8 -* Maven: `mvn -version` 3.5.0 and higher +* Java: `java -version` 11.0 +* Maven: `mvn -version` 3.6.3 and higher Tests cases require: -* dotnet core version 6.0 +* dotnet core version 8.0 * Go: `go version` 1.12 and higher * Ruby [bundler-audit](https://github.com/rubysec/bundler-audit#install) * [Yarn](https://classic.yarnpkg.com/en/docs/install/) @@ -138,7 +193,7 @@ The repository has some large files due to test resources. The team has tried to However, it is recommended that you perform a shallow clone to save yourself time: ```bash -git clone --depth 1 https://github.com/jeremylong/DependencyCheck.git +git clone --depth 1 https://github.com/dependency-check/DependencyCheck.git ``` On *nix @@ -263,7 +318,7 @@ docker run --rm ^ Building From Source -------------------- -To build dependency-check (using Java 8) run the command: +To build dependency-check (using Java 11) run the command: ``` mvn -s settings.xml install @@ -284,9 +339,9 @@ mvn org.owasp:dependency-check-maven:aggregate -P-test-dependencies -DskipProvid Building the documentation -------------------------- -The documentation on the [github pages](http://jeremylong.github.io/DependencyCheck/) is generated from this repository: +The documentation on the [github pages](https://dependency-check.github.io/DependencyCheck/) is generated from this repository: - mvn -s settings.xml site site:staging + mvn -s settings.xml site site:stage Once done, point your browser to `./target/staging/index.html`. @@ -302,11 +357,15 @@ mvn -s settings.xml install License ------- -Permission to modify and redistribute is granted under the terms of the Apache 2.0 license. See the [LICENSE.txt](https://raw.githubusercontent.com/jeremylong/DependencyCheck/main/LICENSE.txt) file for the full license. +Permission to modify and redistribute is granted under the terms of the Apache 2.0 license. See the [LICENSE.txt](https://raw.githubusercontent.com/dependency-check/DependencyCheck/main/LICENSE.txt) file for the full license. Dependency-Check makes use of several other open source libraries. Please see the [NOTICE.txt][notices] file for more information. -Copyright (c) 2012-2023 Jeremy Long. All Rights Reserved. +This product uses the NVD API but is not endorsed or certified by the NVD. + +Copyright (c) 2012-2025 Jeremy Long. All Rights Reserved. + + [wiki]: https://github.com/dependency-check/DependencyCheck/wiki + [notices]: https://github.com/dependency-check/DependencyCheck/blob/main/NOTICE.txt - [wiki]: https://github.com/jeremylong/DependencyCheck/wiki - [notices]: https://github.com/jeremylong/DependencyCheck/blob/main/NOTICE.txt + diff --git a/SECURITY.md b/SECURITY.md index ffc5f225656..08e36f7633f 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,15 +2,15 @@ ## Supported Versions -| Version | Supported | -| ---------|--------------------| -| 8.0.0+ | :white_check_mark: | -| <= 7.4.4 | :x: | +| Version | Supported | +|-----------|--------------------| +| 12.1.3+ | :white_check_mark: | +| <= 12.1.2 | :x: | ## Reporting a Vulnerability If a security vulnerability is identified in dependency-check please -open an [issue](https://github.com/jeremylong/DependencyCheck/issues/new/choose) +open an [issue](https://github.com/dependency-check/DependencyCheck/issues/new/choose) and/or submit a PR to resolve the identified vulnerability. The team is very responsive to reported vulnerabilities - historically having reported issues resolved in 30 days or less. diff --git a/ant/README.md b/ant/README.md index fc971dd1c69..3338cd1f12d 100644 --- a/ant/README.md +++ b/ant/README.md @@ -6,7 +6,7 @@ performed are a "best effort" and as such, there could be false positives as wel vulnerabilities in 3rd party components is a well-known problem and is currently documented in the 2021 OWASP Top 10 as [A06:2021 – Vulnerable and Outdated Components](https://owasp.org/Top10/A06_2021-Vulnerable_and_Outdated_Components/). -Documentation and links to production binary releases can be found on the [github pages](http://jeremylong.github.io/DependencyCheck/dependency-check-ant/index.html). +Documentation and links to production binary releases can be found on the [github pages](https://dependency-check.github.io/DependencyCheck/dependency-check-ant/index.html). Copyright & License @@ -14,6 +14,8 @@ Copyright & License Dependency-Check is Copyright (c) 2012-2014 Jeremy Long. All Rights Reserved. -Permission to modify and redistribute is granted under the terms of the Apache 2.0 license. See the [LICENSE.txt](https://github.com/jeremylong/DependencyCheck/blob/main/LICENSE.txt) file for the full license. +Permission to modify and redistribute is granted under the terms of the Apache 2.0 license. See the [LICENSE.txt](https://github.com/dependency-check/DependencyCheck/blob/main/LICENSE.txt) file for the full license. -Dependency-Check-Ant makes use of other open source libraries. Please see the [NOTICE.txt](https://github.com/jeremylong/DependencyCheck/blob/main/ant/NOTICE.txt) file for more information. +Dependency-Check-Ant makes use of other open source libraries. Please see the [NOTICE.txt](https://github.com/dependency-check/DependencyCheck/blob/main/ant/NOTICE.txt) file for more information. + + \ No newline at end of file diff --git a/ant/pom.xml b/ant/pom.xml index cd3d7a4ac5f..0d8ed742691 100644 --- a/ant/pom.xml +++ b/ant/pom.xml @@ -20,7 +20,7 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved. org.owasp dependency-check-parent - 8.2.2-SNAPSHOT + 12.1.9-SNAPSHOT dependency-check-ant @@ -29,9 +29,9 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved. Dependency-Check Ant Task dependency-check-ant is an Ant Task that uses dependency-check-core to detect publicly disclosed vulnerabilities associated with the project's dependencies. The task will generate a report listing the dependency, any identified Common Platform Enumeration (CPE) identifiers, and the associated Common Vulnerability and Exposure (CVE) entries. - scm:git:https://github.com/jeremylong/DependencyCheck.git - https://github.com/jeremylong/DependencyCheck/tree/main/ant - scm:git:git@github.com:jeremylong/DependencyCheck.git + scm:git:https://github.com/dependency-check/DependencyCheck.git + https://github.com/dependency-check/DependencyCheck/tree/main/ant + scm:git:git@github.com/dependency-check/DependencyCheck.git v6.4.1 @@ -89,25 +89,6 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved. - - copy-test-upgrade-script - pre-integration-test - - copy-resources - - - ${project.build.directory}/test-classes/data - - - ${basedir}/../core/src/test/resources/data - false - - upgrade_4.2.sql - - - - - copy-test-resources-1 pre-integration-test @@ -184,26 +165,6 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved. - - copy-data - pre-integration-test - - copy-resources - - - ${project.build.directory}/test-classes - - - ${basedir}/../src/test/resources - false - - db.cve.zip - index.cpe.zip - - - - - @@ -252,6 +213,19 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved. dependency-check-utils ${project.parent.version} + + + io.github.jeremylong + open-vulnerability-clients + + + org.slf4j + slf4j-api + + + io.github.jeremylong + jcs3-slf4j + org.owasp dependency-check-core diff --git a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java index 270c2b6f84f..97268391d73 100644 --- a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java +++ b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java @@ -20,6 +20,8 @@ import java.io.File; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.annotation.concurrent.NotThreadSafe; import org.apache.tools.ant.BuildException; @@ -35,14 +37,17 @@ import org.owasp.dependencycheck.data.nvdcve.DatabaseException; import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Vulnerability; +import org.owasp.dependencycheck.dependency.naming.Identifier; import org.owasp.dependencycheck.exception.ExceptionCollection; import org.owasp.dependencycheck.exception.ReportException; import org.owasp.dependencycheck.reporting.ReportGenerator.Format; +import org.owasp.dependencycheck.utils.Downloader; +import org.owasp.dependencycheck.utils.InvalidSettingException; import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.SeverityUtil; import org.slf4j.impl.StaticLoggerBinder; -//CSOFF: MethodCount +//CSOFF: MethodCount /** * An Ant task definition to execute dependency-check during an Ant build. * @@ -89,27 +94,6 @@ public class Check extends Update { * Sets whether or not the Node Audit Analyzer should use a local cache. */ private Boolean nodeAuditSkipDevDependencies; - /** - * Whether or not the RetireJS Analyzer is enabled. - */ - private Boolean retireJsAnalyzerEnabled; - /** - * The URL to the RetireJS JSON data. - */ - private String retireJsUrl; - /** - * The user to download URL to the RetireJS JSON data. - */ - private String retireJsUrlUser; - /** - * The password to download URL to the RetireJS JSON data. - */ - private String retireJsUrlPassword; - /** - * Whether or not the RetireJS Analyzer will be updated regardless of the - * `autoupdate` settings. Defaults to false. - */ - private Boolean retireJsAnalyzerForceUpdate; /** * The list of filters (regular expressions) used by the RetireJS Analyzer * to exclude files that contain matching content.. @@ -237,13 +221,13 @@ public class Check extends Update { */ private Boolean autoUpdate; /** - * The report format to be generated (HTML, XML, JUNIT, CSV, JSON, SARIF, - * JENKINS, ALL). Default is HTML. + * The report format to be generated (HTML, XML, CSV, JSON, JUNIT, SARIF, + * JENKINS, GITLAB, ALL). Default is HTML. */ private String reportFormat = "HTML"; /** - * The report format to be generated (HTML, XML, JUNIT, CSV, JSON, SARIF, - * JENKINS, ALL). Default is HTML. + * The report format to be generated (HTML, XML, CSV, JSON, JUNIT, SARIF, + * JENKINS, GITLAB, ALL). Default is HTML. */ private final List reportFormats = new ArrayList<>(); /** @@ -282,14 +266,6 @@ public class Check extends Update { * Whether or not the Archive Analyzer is enabled. */ private Boolean archiveAnalyzerEnabled; - /** - * Whether or not the Known Exploited Vulnerability Analyzer is enabled. - */ - private Boolean knownExploitedEnabled; - /** - * The URL to the known exploited vulnerabilities JSON datafeed. - */ - private String knownExploitedUrl; /** * Whether or not the .NET Nuspec Analyzer is enabled. */ @@ -298,10 +274,18 @@ public class Check extends Update { * Whether or not the .NET Nuget packages.config file Analyzer is enabled. */ private Boolean nugetconfAnalyzerEnabled; + /** + * Whether or not the Libman Analyzer is enabled. + */ + private Boolean libmanAnalyzerEnabled; /** * Whether or not the PHP Composer Analyzer is enabled. */ private Boolean composerAnalyzerEnabled; + /** + * Whether or not the PHP Composer Analyzer will skip "packages-dev". + */ + private Boolean composerAnalyzerSkipDev; /** * Whether or not the Perl CPAN File Analyzer is enabled. */ @@ -352,6 +336,10 @@ public class Check extends Update { * Whether or not the CocoaPods Analyzer is enabled. */ private Boolean cocoapodsAnalyzerEnabled; + /** + * Whether or not the Carthage Analyzer is enabled. + */ + private Boolean carthageAnalyzerEnabled; /** * Whether or not the Swift package Analyzer is enabled. @@ -416,9 +404,31 @@ public class Check extends Update { * The Artifactory bearer token. */ private String artifactoryAnalyzerBearerToken; + /** + * Whether the version check is enabled + */ + private Boolean versionCheckEnabled; + /** + * whether an unsused suppression rule should get force the build to fail + */ + private boolean failBuildOnUnusedSuppressionRule = false; + + /** + * The username to download user-authored suppression files from an HTTP Basic auth protected location. + */ + private String suppressionFileUser; + /** + * The password to download user-authored suppression files from an HTTP Basic auth protected location. + */ + private String suppressionFilePassword; + /** + * The token to download user-authored suppression files from an HTTP Bearer auth protected location. + */ + private String suppressionFileBearerToken; + + //region Code copied from org.apache.tools.ant.taskdefs.PathConvert //The following code was copied Apache Ant PathConvert - //BEGIN COPY from org.apache.tools.ant.taskdefs.PathConvert /** * Path to be converted */ @@ -441,28 +451,6 @@ public void add(ResourceCollection rc) { getPath().add(rc); } - /** - * Add a suppression file. - *

- * This is called by Ant with the configured {@link SuppressionFile}. - * - * @param suppressionFile the suppression file to add. - */ - public void addConfiguredSuppressionFile(final SuppressionFile suppressionFile) { - suppressionFiles.add(suppressionFile.getPath()); - } - - /** - * Add a report format. - *

- * This is called by Ant with the configured {@link ReportFormat}. - * - * @param reportFormat the reportFormat to add. - */ - public void addConfiguredReportFormat(final ReportFormat reportFormat) { - reportFormats.add(reportFormat.getFormat()); - } - /** * Returns the path. If the path has not been initialized yet, this class is * synchronized, and will instantiate the path object. @@ -519,7 +507,7 @@ private void dealWithReferences() throws BuildException { getPath().add((ResourceCollection) o); } } - // END COPY from org.apache.tools.ant.taskdefs + //endregion COPIED from org.apache.tools.ant.taskdefs /** * Construct a new DependencyCheckTask. @@ -531,6 +519,38 @@ public Check() { StaticLoggerBinder.getSingleton().setTask(this); } + /** + * Add a suppression file. + *

+ * This is called by Ant with the configured {@link SuppressionFile}. + * + * @param suppressionFile the suppression file to add. + */ + public void addConfiguredSuppressionFile(final SuppressionFile suppressionFile) { + suppressionFiles.add(suppressionFile.getPath()); + } + + /** + * Add a report format. + *

+ * This is called by Ant with the configured {@link ReportFormat}. + * + * @param reportFormat the reportFormat to add. + */ + public void addConfiguredReportFormat(final ReportFormat reportFormat) { + reportFormats.add(reportFormat.getFormat()); + } + + /** + * Sets whether the version check is enabled. + * + * @param versionCheckEnabled a Boolean indicating if the version check is + * enabled. + */ + public void setVersionCheckEnabled(Boolean versionCheckEnabled) { + this.versionCheckEnabled = versionCheckEnabled; + } + /** * Get the value of projectName. * @@ -552,15 +572,6 @@ public void setProjectName(String projectName) { this.projectName = projectName; } - /** - * Get the value of reportOutputDirectory. - * - * @return the value of reportOutputDirectory - */ - public String getReportOutputDirectory() { - return reportOutputDirectory; - } - /** * Set the value of reportOutputDirectory. * @@ -570,15 +581,6 @@ public void setReportOutputDirectory(String reportOutputDirectory) { this.reportOutputDirectory = reportOutputDirectory; } - /** - * Get the value of failBuildOnCVSS. - * - * @return the value of failBuildOnCVSS - */ - public float getFailBuildOnCVSS() { - return failBuildOnCVSS; - } - /** * Set the value of failBuildOnCVSS. * @@ -588,15 +590,6 @@ public void setFailBuildOnCVSS(float failBuildOnCVSS) { this.failBuildOnCVSS = failBuildOnCVSS; } - /** - * Get the value of junitFailOnCVSS. - * - * @return the value of junitFailOnCVSS - */ - public float getJunitFailOnCVSS() { - return junitFailOnCVSS; - } - /** * Set the value of junitFailOnCVSS. * @@ -606,15 +599,6 @@ public void setJunitFailOnCVSS(float junitFailOnCVSS) { this.junitFailOnCVSS = junitFailOnCVSS; } - /** - * Get the value of autoUpdate. - * - * @return the value of autoUpdate - */ - public Boolean isAutoUpdate() { - return autoUpdate; - } - /** * Set the value of autoUpdate. * @@ -624,15 +608,6 @@ public void setAutoUpdate(Boolean autoUpdate) { this.autoUpdate = autoUpdate; } - /** - * Get the value of prettyPrint. - * - * @return the value of prettyPrint - */ - public Boolean isPrettyPrint() { - return prettyPrint; - } - /** * Set the value of prettyPrint. * @@ -664,15 +639,6 @@ public List getReportFormats() { return this.reportFormats; } - /** - * Gets suppression file paths. - * - * @return the suppression files. - */ - public List getSuppressionFiles() { - return suppressionFiles; - } - /** * Set the value of suppressionFile. * @@ -683,48 +649,48 @@ public void setSuppressionFile(String suppressionFile) { } /** - * Get the value of hintsFile. + * Sets the username to download user-authored suppression files from an HTTP Basic auth protected location. * - * @return the value of hintsFile + * @param suppressionFileUser The username */ - public String getHintsFile() { - return hintsFile; + public void setSuppressionFileUser(String suppressionFileUser) { + this.suppressionFileUser = suppressionFileUser; } /** - * Set the value of hintsFile. + * Sets the password/token to download user-authored suppression files from an HTTP Basic auth protected location. * - * @param hintsFile new value of hintsFile + * @param suppressionFilePassword The password/token */ - public void setHintsFile(String hintsFile) { - this.hintsFile = hintsFile; + public void setSuppressionFilePassword(String suppressionFilePassword) { + this.suppressionFilePassword = suppressionFilePassword; } /** - * Get the value of showSummary. + * Sets the token to download user-authored suppression files from an HTTP Bearer auth protected location. * - * @return the value of showSummary + * @param suppressionFileBearerToken The token */ - public boolean isShowSummary() { - return showSummary; + public void setSuppressionFileBearerToken(String suppressionFileBearerToken) { + this.suppressionFileBearerToken = suppressionFileBearerToken; } /** - * Set the value of showSummary. + * Set the value of hintsFile. * - * @param showSummary new value of showSummary + * @param hintsFile new value of hintsFile */ - public void setShowSummary(boolean showSummary) { - this.showSummary = showSummary; + public void setHintsFile(String hintsFile) { + this.hintsFile = hintsFile; } /** - * Get the value of enableExperimental. + * Set the value of showSummary. * - * @return the value of enableExperimental + * @param showSummary new value of showSummary */ - public Boolean isEnableExperimental() { - return enableExperimental; + public void setShowSummary(boolean showSummary) { + this.showSummary = showSummary; } /** @@ -736,15 +702,6 @@ public void setEnableExperimental(Boolean enableExperimental) { this.enableExperimental = enableExperimental; } - /** - * Get the value of enableRetired. - * - * @return the value of enableRetired - */ - public Boolean isEnableRetired() { - return enableRetired; - } - /** * Set the value of enableRetired. * @@ -754,15 +711,6 @@ public void setEnableRetired(Boolean enableRetired) { this.enableRetired = enableRetired; } - /** - * Returns whether or not the analyzer is enabled. - * - * @return true if the analyzer is enabled - */ - public Boolean isJarAnalyzerEnabled() { - return jarAnalyzerEnabled; - } - /** * Sets whether or not the analyzer is enabled. * @@ -772,15 +720,6 @@ public void setJarAnalyzerEnabled(Boolean jarAnalyzerEnabled) { this.jarAnalyzerEnabled = jarAnalyzerEnabled; } - /** - * Returns whether or not the analyzer is enabled. - * - * @return true if the analyzer is enabled - */ - public Boolean isArchiveAnalyzerEnabled() { - return archiveAnalyzerEnabled; - } - /** * Sets whether the analyzer is enabled. * @@ -790,51 +729,6 @@ public void setArchiveAnalyzerEnabled(Boolean archiveAnalyzerEnabled) { this.archiveAnalyzerEnabled = archiveAnalyzerEnabled; } - /** - * Returns whether the analyzer is enabled. - * - * @return true if the analyzer is enabled - */ - public Boolean isKnownExploitedEnabled() { - return knownExploitedEnabled; - } - - /** - * Sets whether the analyzer is enabled. - * - * @param knownExploitedEnabled the value of the new setting - */ - public void setKnownExploitedEnabled(Boolean knownExploitedEnabled) { - this.knownExploitedEnabled = knownExploitedEnabled; - } - - /** - * Returns the knownExploitedUrl. - * - * @return the knownExploitedUrl - */ - public String getKnownExploitedUrl() { - return knownExploitedUrl; - } - - /** - * Sets the the knownExploitedUrl. - * - * @param knownExploitedUrl the URL - */ - public void setKnownExploitedUrl(String knownExploitedUrl) { - this.knownExploitedUrl = knownExploitedUrl; - } - - /** - * Returns whether or not the analyzer is enabled. - * - * @return true if the analyzer is enabled - */ - public Boolean isAssemblyAnalyzerEnabled() { - return assemblyAnalyzerEnabled; - } - /** * Sets whether or not the analyzer is enabled. * @@ -844,15 +738,6 @@ public void setAssemblyAnalyzerEnabled(Boolean assemblyAnalyzerEnabled) { this.assemblyAnalyzerEnabled = assemblyAnalyzerEnabled; } - /** - * Returns whether or not the analyzer is enabled. - * - * @return true if the analyzer is enabled - */ - public Boolean isMSBuildAnalyzerEnabled() { - return msbuildAnalyzerEnabled; - } - /** * Sets whether or not the analyzer is enabled. * @@ -862,24 +747,6 @@ public void setMSBuildAnalyzerEnabled(Boolean msbuildAnalyzerEnabled) { this.msbuildAnalyzerEnabled = msbuildAnalyzerEnabled; } - /** - * Returns whether or not the analyzer is enabled. - * - * @return true if the analyzer is enabled - */ - public Boolean isNuspecAnalyzerEnabled() { - return nuspecAnalyzerEnabled; - } - - /** - * Returns whether or not the analyzer is enabled. - * - * @return true if the analyzer is enabled - */ - public Boolean isNugetconfAnalyzerEnabled() { - return nugetconfAnalyzerEnabled; - } - /** * Sets whether or not the analyzer is enabled. * @@ -899,12 +766,12 @@ public void setNugetconfAnalyzerEnabled(Boolean nugetconfAnalyzerEnabled) { } /** - * Get the value of composerAnalyzerEnabled. + * Sets whether or not the analyzer is enabled. * - * @return the value of composerAnalyzerEnabled + * @param libmanAnalyzerEnabled the value of the new setting */ - public Boolean isComposerAnalyzerEnabled() { - return composerAnalyzerEnabled; + public void setLibmanAnalyzerEnabled(Boolean libmanAnalyzerEnabled) { + this.libmanAnalyzerEnabled = libmanAnalyzerEnabled; } /** @@ -917,12 +784,12 @@ public void setComposerAnalyzerEnabled(Boolean composerAnalyzerEnabled) { } /** - * Get the value of cpanfileAnalyzerEnabled. + * Set the value of composerAnalyzerSkipDev. * - * @return the value of cpanfileAnalyzerEnabled + * @param composerAnalyzerSkipDev new value of composerAnalyzerSkipDev */ - public Boolean isCpanfileAnalyzerEnabled() { - return cpanfileAnalyzerEnabled; + public void setComposerAnalyzerSkipDev(Boolean composerAnalyzerSkipDev) { + this.composerAnalyzerSkipDev = composerAnalyzerSkipDev; } /** @@ -934,15 +801,6 @@ public void setCpanfileAnalyzerEnabled(Boolean cpanfileAnalyzerEnabled) { this.cpanfileAnalyzerEnabled = cpanfileAnalyzerEnabled; } - /** - * Get the value of autoconfAnalyzerEnabled. - * - * @return the value of autoconfAnalyzerEnabled - */ - public Boolean isAutoconfAnalyzerEnabled() { - return autoconfAnalyzerEnabled; - } - /** * Set the value of autoconfAnalyzerEnabled. * @@ -952,15 +810,6 @@ public void setAutoconfAnalyzerEnabled(Boolean autoconfAnalyzerEnabled) { this.autoconfAnalyzerEnabled = autoconfAnalyzerEnabled; } - /** - * Get the value of pipAnalyzerEnabled. - * - * @return the value of pipAnalyzerEnabled - */ - public Boolean isPipAnalyzerEnabled() { - return pipAnalyzerEnabled; - } - /** * Set the value of pipAnalyzerEnabled. * @@ -970,15 +819,6 @@ public void setPipAnalyzerEnabled(Boolean pipAnalyzerEnabled) { this.pipAnalyzerEnabled = pipAnalyzerEnabled; } - /** - * Get the value of pipfileAnalyzerEnabled. - * - * @return the value of pipfileAnalyzerEnabled - */ - public Boolean isPipfileAnalyzerEnabled() { - return pipfileAnalyzerEnabled; - } - /** * Set the value of pipfileAnalyzerEnabled. * @@ -988,15 +828,6 @@ public void setPipfileAnalyzerEnabled(Boolean pipfileAnalyzerEnabled) { this.pipfileAnalyzerEnabled = pipfileAnalyzerEnabled; } - /** - * Get the value of poetryAnalyzerEnabled. - * - * @return the value of poetryAnalyzerEnabled - */ - public Boolean isPoetryAnalyzerEnabled() { - return poetryAnalyzerEnabled; - } - /** * Set the value of poetryAnalyzerEnabled. * @@ -1006,15 +837,6 @@ public void setPoetryAnalyzerEnabled(Boolean poetryAnalyzerEnabled) { this.poetryAnalyzerEnabled = poetryAnalyzerEnabled; } - /** - * Returns if the Bundle Audit Analyzer is enabled. - * - * @return if the Bundle Audit Analyzer is enabled. - */ - public Boolean isBundleAuditAnalyzerEnabled() { - return bundleAuditAnalyzerEnabled; - } - /** * Sets if the Bundle Audit Analyzer is enabled. * @@ -1025,15 +847,6 @@ public void setBundleAuditAnalyzerEnabled(Boolean bundleAuditAnalyzerEnabled) { this.bundleAuditAnalyzerEnabled = bundleAuditAnalyzerEnabled; } - /** - * Returns the path to the bundle audit executable. - * - * @return the path to the bundle audit executable - */ - public String getBundleAuditPath() { - return bundleAuditPath; - } - /** * Sets the path to the bundle audit executable. * @@ -1054,26 +867,6 @@ public void setBundleAuditWorkingDirectory(String bundleAuditWorkingDirectory) { this.bundleAuditWorkingDirectory = bundleAuditWorkingDirectory; } - /** - * Returns the path to the working directory that the bundle audit - * executable should be executed from. - * - * @return the path to the working directory that the bundle audit - * executable should be executed from. - */ - public String getBundleAuditWorkingDirectory() { - return bundleAuditWorkingDirectory; - } - - /** - * Returns if the cocoapods analyzer is enabled. - * - * @return if the cocoapods analyzer is enabled - */ - public boolean isCocoapodsAnalyzerEnabled() { - return cocoapodsAnalyzerEnabled; - } - /** * Sets whether or not the cocoapods analyzer is enabled. * @@ -1084,12 +877,12 @@ public void setCocoapodsAnalyzerEnabled(Boolean cocoapodsAnalyzerEnabled) { } /** - * Returns whether or not the Swift package Analyzer is enabled. + * Sets whether or not the Carthage analyzer is enabled. * - * @return whether or not the Swift package Analyzer is enabled + * @param carthageAnalyzerEnabled the state of the Carthage analyzer */ - public Boolean isSwiftPackageManagerAnalyzerEnabled() { - return swiftPackageManagerAnalyzerEnabled; + public void setCarthageAnalyzerEnabled(Boolean carthageAnalyzerEnabled) { + this.carthageAnalyzerEnabled = carthageAnalyzerEnabled; } /** @@ -1102,15 +895,6 @@ public void setSwiftPackageManagerAnalyzerEnabled(Boolean swiftPackageManagerAna this.swiftPackageManagerAnalyzerEnabled = swiftPackageManagerAnalyzerEnabled; } - /** - * Returns whether or not the Swift package resolved Analyzer is enabled. - * - * @return whether or not the Swift package resolved Analyzer is enabled - */ - public Boolean isSwiftPackageResolvedAnalyzerEnabled() { - return swiftPackageResolvedAnalyzerEnabled; - } - /** * Sets the enabled state of the swift package manager analyzer. * @@ -1121,15 +905,6 @@ public void setSwiftPackageResolvedAnalyzerEnabled(Boolean swiftPackageResolvedA this.swiftPackageResolvedAnalyzerEnabled = swiftPackageResolvedAnalyzerEnabled; } - /** - * Get the value of opensslAnalyzerEnabled. - * - * @return the value of opensslAnalyzerEnabled - */ - public Boolean isOpensslAnalyzerEnabled() { - return opensslAnalyzerEnabled; - } - /** * Set the value of opensslAnalyzerEnabled. * @@ -1139,15 +914,6 @@ public void setOpensslAnalyzerEnabled(Boolean opensslAnalyzerEnabled) { this.opensslAnalyzerEnabled = opensslAnalyzerEnabled; } - /** - * Get the value of nodeAnalyzerEnabled. - * - * @return the value of nodeAnalyzerEnabled - */ - public Boolean isNodeAnalyzerEnabled() { - return nodeAnalyzerEnabled; - } - /** * Set the value of nodeAnalyzerEnabled. * @@ -1157,15 +923,6 @@ public void setNodeAnalyzerEnabled(Boolean nodeAnalyzerEnabled) { this.nodeAnalyzerEnabled = nodeAnalyzerEnabled; } - /** - * Get the value of nodeAuditAnalyzerEnabled. - * - * @return the value of nodeAuditAnalyzerEnabled - */ - public Boolean isNodeAuditAnalyzerEnabled() { - return nodeAuditAnalyzerEnabled; - } - /** * Set the value of nodeAuditAnalyzerEnabled. * @@ -1175,15 +932,6 @@ public void setNodeAuditAnalyzerEnabled(Boolean nodeAuditAnalyzerEnabled) { this.nodeAuditAnalyzerEnabled = nodeAuditAnalyzerEnabled; } - /** - * Get the value of yarnAuditAnalyzerEnabled. - * - * @return the value of yarnAuditAnalyzerEnabled - */ - public Boolean isYarnAuditAnalyzerEnabled() { - return yarnAuditAnalyzerEnabled; - } - /** * Set the value of yarnAuditAnalyzerEnabled. * @@ -1193,15 +941,6 @@ public void setYarnAuditAnalyzerEnabled(Boolean yarnAuditAnalyzerEnabled) { this.yarnAuditAnalyzerEnabled = yarnAuditAnalyzerEnabled; } - /** - * Get the value of pnpmAuditAnalyzerEnabled. - * - * @return the value of pnpmAuditAnalyzerEnabled - */ - public Boolean isPnpmAuditAnalyzerEnabled() { - return pnpmAuditAnalyzerEnabled; - } - /** * Set the value of pnpmAuditAnalyzerEnabled. * @@ -1211,15 +950,6 @@ public void setPnpmAuditAnalyzerEnabled(Boolean pnpmAuditAnalyzerEnabled) { this.pnpmAuditAnalyzerEnabled = pnpmAuditAnalyzerEnabled; } - /** - * Get the value of nodeAuditAnalyzerUseCache. - * - * @return the value of nodeAuditAnalyzerUseCache - */ - public Boolean isNodeAuditAnalyzerUseCache() { - return nodeAuditAnalyzerUseCache; - } - /** * Set the value of nodeAuditAnalyzerUseCache. * @@ -1229,15 +959,6 @@ public void setNodeAuditAnalyzerUseCache(Boolean nodeAuditAnalyzerUseCache) { this.nodeAuditAnalyzerUseCache = nodeAuditAnalyzerUseCache; } - /** - * Get the value of nodePackageSkipDevDependencies. - * - * @return the value of nodePackageSkipDevDependencies - */ - public Boolean isNodePackageAnalyzerSkipDevDependencies() { - return nodePackageSkipDevDependencies; - } - /** * Set the value of nodePackageSkipDevDependencies. * @@ -1248,15 +969,6 @@ public void setNodePackageSkipDevDependencies(Boolean nodePackageSkipDevDependen this.nodePackageSkipDevDependencies = nodePackageSkipDevDependencies; } - /** - * Get the value of nodeAuditSkipDevDependencies. - * - * @return the value of nodeAuditSkipDevDependencies - */ - public Boolean isNodeAuditAnalyzerSkipDevDependencies() { - return nodeAuditSkipDevDependencies; - } - /** * Set the value of nodeAuditSkipDevDependencies. * @@ -1267,106 +979,6 @@ public void setNodeAuditSkipDevDependencies(Boolean nodeAuditSkipDevDependencies this.nodeAuditSkipDevDependencies = nodeAuditSkipDevDependencies; } - /** - * Get the value of retireJsAnalyzerEnabled. - * - * @return the value of retireJsAnalyzerEnabled - */ - public Boolean isRetireJsAnalyzerEnabled() { - return retireJsAnalyzerEnabled; - } - - /** - * Set the value of retireJsAnalyzerEnabled. - * - * @param retireJsAnalyzerEnabled new value of retireJsAnalyzerEnabled - */ - public void setRetireJsAnalyzerEnabled(Boolean retireJsAnalyzerEnabled) { - this.retireJsAnalyzerEnabled = retireJsAnalyzerEnabled; - } - - /** - * Get the value of Retire JS repository URL. - * - * @return the value of retireJsUrl - */ - public String getRetireJsUrl() { - return retireJsUrl; - } - - /** - * Set the value of the Retire JS repository URL. - * - * @param retireJsUrl new value of retireJsUrl - */ - public void setRetireJsUrl(String retireJsUrl) { - this.retireJsUrl = retireJsUrl; - } - - /** - * Get the value of User Retire JS repository URL. - * - * @return the value of retireJsUrlUser - */ - public String getRetireJsUrlUser() { - return retireJsUrlUser; - } - - /** - * Set the value of the User Retire JS repository URL. - * - * @param retireJsUrlUser new value of retireJsUrlUser - */ - public void setRetireJsUrlUser(String retireJsUrlUser) { - this.retireJsUrlUser = retireJsUrlUser; - } - - /** - * Get the value of Password Retire JS repository URL. - * - * @return the value of retireJsUrlPassword - */ - public String getRetireJsUrlPassword() { - return retireJsUrlPassword; - } - - /** - * Set the value of the Password Retire JS repository URL. - * - * @param retireJsUrlPassword new value of retireJsUrlPassword - */ - public void setRetireJsUrlPassword(String retireJsUrlPassword) { - this.retireJsUrlPassword = retireJsUrlPassword; - } - - /** - * Get the value of retireJsAnalyzerEnabled. - * - * @return the value of retireJsAnalyzerEnabled - */ - public Boolean isRetireJsAnalyzerForceUpdate() { - return retireJsAnalyzerForceUpdate; - } - - /** - * Set the value of retireJsAnalyzerForceUpdate. - * - * @param retireJsAnalyzerForceUpdate new value of - * retireJsAnalyzerForceUpdate - */ - public void setRetireJsAnalyzerForceUpdate(Boolean retireJsAnalyzerForceUpdate) { - this.retireJsAnalyzerForceUpdate = retireJsAnalyzerForceUpdate; - } - - /** - * Get the value of retirejsFilterNonVulnerable. - * - * @return the value of retirejsFilterNonVulnerable - */ - public Boolean isRetirejsFilterNonVulnerable() { - return retirejsFilterNonVulnerable; - } - /** * Set the value of retirejsFilterNonVulnerable. * @@ -1377,15 +989,6 @@ public void setRetirejsFilterNonVulnerable(Boolean retirejsFilterNonVulnerable) this.retirejsFilterNonVulnerable = retirejsFilterNonVulnerable; } - /** - * Gets retire JS Analyzers file content filters. - * - * @return retire JS Analyzers file content filters - */ - public List getRetirejsFilters() { - return retirejsFilters; - } - /** * Add a regular expression to the set of retire JS content filters. *

@@ -1398,15 +1001,6 @@ public void addConfiguredRetirejsFilter(final RetirejsFilter retirejsFilter) { retirejsFilters.add(retirejsFilter.getRegex()); } - /** - * Get the value of rubygemsAnalyzerEnabled. - * - * @return the value of rubygemsAnalyzerEnabled - */ - public Boolean isRubygemsAnalyzerEnabled() { - return rubygemsAnalyzerEnabled; - } - /** * Set the value of rubygemsAnalyzerEnabled. * @@ -1416,15 +1010,6 @@ public void setRubygemsAnalyzerEnabled(Boolean rubygemsAnalyzerEnabled) { this.rubygemsAnalyzerEnabled = rubygemsAnalyzerEnabled; } - /** - * Get the value of pyPackageAnalyzerEnabled. - * - * @return the value of pyPackageAnalyzerEnabled - */ - public Boolean isPyPackageAnalyzerEnabled() { - return pyPackageAnalyzerEnabled; - } - /** * Set the value of pyPackageAnalyzerEnabled. * @@ -1434,15 +1019,6 @@ public void setPyPackageAnalyzerEnabled(Boolean pyPackageAnalyzerEnabled) { this.pyPackageAnalyzerEnabled = pyPackageAnalyzerEnabled; } - /** - * Get the value of pyDistributionAnalyzerEnabled. - * - * @return the value of pyDistributionAnalyzerEnabled - */ - public Boolean isPyDistributionAnalyzerEnabled() { - return pyDistributionAnalyzerEnabled; - } - /** * Set the value of pyDistributionAnalyzerEnabled. * @@ -1453,15 +1029,6 @@ public void setPyDistributionAnalyzerEnabled(Boolean pyDistributionAnalyzerEnabl this.pyDistributionAnalyzerEnabled = pyDistributionAnalyzerEnabled; } - /** - * Get the value of mixAuditAnalyzerEnabled. - * - * @return the value of mixAuditAnalyzerEnabled - */ - public Boolean getMixAuditAnalyzerEnabled() { - return mixAuditAnalyzerEnabled; - } - /** * Set the value of mixAuditAnalyzerEnabled. * @@ -1472,14 +1039,13 @@ public void setMixAuditAnalyzerEnabled(Boolean mixAuditAnalyzerEnabled) { } /** - * Get the value of centralAnalyzerEnabled. + * Sets the path to the mix audit executable. * - * @return the value of centralAnalyzerEnabled + * @param mixAuditPath the path to the bundle audit executable */ - public Boolean isCentralAnalyzerEnabled() { - return centralAnalyzerEnabled; + public void setMixAuditPath(String mixAuditPath) { + this.mixAuditPath = mixAuditPath; } - /** * Set the value of centralAnalyzerEnabled. * @@ -1489,15 +1055,6 @@ public void setCentralAnalyzerEnabled(Boolean centralAnalyzerEnabled) { this.centralAnalyzerEnabled = centralAnalyzerEnabled; } - /** - * Get the value of centralAnalyzerUseCache. - * - * @return the value of centralAnalyzerUseCache - */ - public Boolean isCentralAnalyzerUseCache() { - return centralAnalyzerUseCache; - } - /** * Set the value of centralAnalyzerUseCache. * @@ -1507,15 +1064,6 @@ public void setCentralAnalyzerUseCache(Boolean centralAnalyzerUseCache) { this.centralAnalyzerUseCache = centralAnalyzerUseCache; } - /** - * Get the value of nexusAnalyzerEnabled. - * - * @return the value of nexusAnalyzerEnabled - */ - public Boolean isNexusAnalyzerEnabled() { - return nexusAnalyzerEnabled; - } - /** * Set the value of nexusAnalyzerEnabled. * @@ -1525,15 +1073,6 @@ public void setNexusAnalyzerEnabled(Boolean nexusAnalyzerEnabled) { this.nexusAnalyzerEnabled = nexusAnalyzerEnabled; } - /** - * Get the value of golangDepEnabled. - * - * @return the value of golangDepEnabled - */ - public Boolean isGolangDepEnabled() { - return golangDepEnabled; - } - /** * Set the value of golangDepEnabled. * @@ -1543,15 +1082,6 @@ public void setGolangDepEnabled(Boolean golangDepEnabled) { this.golangDepEnabled = golangDepEnabled; } - /** - * Get the value of golangModEnabled. - * - * @return the value of golangModEnabled - */ - public Boolean isGoModDepEnabled() { - return golangModEnabled; - } - /** * Set the value of golangModEnabled. * @@ -1561,15 +1091,6 @@ public void setGolangModEnabled(Boolean golangModEnabled) { this.golangModEnabled = golangModEnabled; } - /** - * Get the value of dartAnalyzerEnabled. - * - * @return the value of dartAnalyzerEnabled - */ - public Boolean isDartAnalyzerEnabled() { - return dartAnalyzerEnabled; - } - /** * Set the value of dartAnalyzerEnabled. * @@ -1579,15 +1100,6 @@ public void setDartAnalyzerEnabled(Boolean dartAnalyzerEnabled) { this.dartAnalyzerEnabled = dartAnalyzerEnabled; } - /** - * Get the value of pathToYarn. - * - * @return the value of pathToYarn - */ - public String getPathToYarn() { - return pathToYarn; - } - /** * Set the value of pathToYarn. * @@ -1597,15 +1109,6 @@ public void setPathToYarn(String pathToYarn) { this.pathToYarn = pathToYarn; } - /** - * Get the value of pathToPnpm. - * - * @return the value of pathToPnpm - */ - public String getPathToPnpm() { - return pathToPnpm; - } - /** * Set the value of pathToPnpm. * @@ -1615,15 +1118,6 @@ public void setPathToPnpm(String pathToPnpm) { this.pathToPnpm = pathToPnpm; } - /** - * Get the value of pathToCore. - * - * @return the value of pathToCore - */ - public String getPathToGo() { - return pathToGo; - } - /** * Set the value of pathToGo. * @@ -1633,15 +1127,6 @@ public void setPathToGo(String pathToGo) { this.pathToGo = pathToGo; } - /** - * Get the value of nexusUrl. - * - * @return the value of nexusUrl - */ - public String getNexusUrl() { - return nexusUrl; - } - /** * Set the value of nexusUrl. * @@ -1651,15 +1136,6 @@ public void setNexusUrl(String nexusUrl) { this.nexusUrl = nexusUrl; } - /** - * Get the value of nexusUser. - * - * @return the value of nexusUser - */ - public String getNexusUser() { - return nexusUser; - } - /** * Set the value of nexusUser. * @@ -1669,15 +1145,6 @@ public void setNexusUser(String nexusUser) { this.nexusUser = nexusUser; } - /** - * Get the value of nexusPassword. - * - * @return the value of nexusPassword - */ - public String getNexusPassword() { - return nexusPassword; - } - /** * Set the value of nexusPassword. * @@ -1687,15 +1154,6 @@ public void setNexusPassword(String nexusPassword) { this.nexusPassword = nexusPassword; } - /** - * Get the value of nexusUsesProxy. - * - * @return the value of nexusUsesProxy - */ - public Boolean isNexusUsesProxy() { - return nexusUsesProxy; - } - /** * Set the value of nexusUsesProxy. * @@ -1705,15 +1163,6 @@ public void setNexusUsesProxy(Boolean nexusUsesProxy) { this.nexusUsesProxy = nexusUsesProxy; } - /** - * Get the value of zipExtensions. - * - * @return the value of zipExtensions - */ - public String getZipExtensions() { - return zipExtensions; - } - /** * Set the value of zipExtensions. * @@ -1723,15 +1172,6 @@ public void setZipExtensions(String zipExtensions) { this.zipExtensions = zipExtensions; } - /** - * Get the value of pathToCore. - * - * @return the value of pathToCore - */ - public String getPathToDotnetCore() { - return pathToCore; - } - /** * Set the value of pathToCore. * @@ -1741,15 +1181,6 @@ public void setPathToDotnetCore(String pathToCore) { this.pathToCore = pathToCore; } - /** - * Get value of {@link #ossindexAnalyzerEnabled}. - * - * @return the value of ossindexAnalyzerEnabled - */ - public Boolean isOssindexAnalyzerEnabled() { - return ossindexAnalyzerEnabled; - } - /** * Set value of {@link #ossindexAnalyzerEnabled}. * @@ -1759,15 +1190,6 @@ public void setOssindexAnalyzerEnabled(Boolean ossindexAnalyzerEnabled) { this.ossindexAnalyzerEnabled = ossindexAnalyzerEnabled; } - /** - * Get value of {@link #ossindexAnalyzerUseCache}. - * - * @return the value of ossindexAnalyzerUseCache - */ - public Boolean isOssindexAnalyzerUseCache() { - return ossindexAnalyzerUseCache; - } - /** * Set value of {@link #ossindexAnalyzerUseCache}. * @@ -1777,15 +1199,6 @@ public void setOssindexAnalyzerUseCache(Boolean ossindexAnalyzerUseCache) { this.ossindexAnalyzerUseCache = ossindexAnalyzerUseCache; } - /** - * Get value of {@link #ossindexAnalyzerUrl}. - * - * @return the value of ossindexAnalyzerUrl - */ - public String getOssindexAnalyzerUrl() { - return ossindexAnalyzerUrl; - } - /** * Set value of {@link #ossindexAnalyzerUrl}. * @@ -1795,15 +1208,6 @@ public void setOssindexAnalyzerUrl(String ossindexAnalyzerUrl) { this.ossindexAnalyzerUrl = ossindexAnalyzerUrl; } - /** - * Get value of {@link #ossindexAnalyzerUsername}. - * - * @return the value of ossindexAnalyzerUsername - */ - public String getOssindexAnalyzerUsername() { - return ossindexAnalyzerUsername; - } - /** * Set value of {@link #ossindexAnalyzerUsername}. * @@ -1813,15 +1217,6 @@ public void setOssindexAnalyzerUsername(String ossindexAnalyzerUsername) { this.ossindexAnalyzerUsername = ossindexAnalyzerUsername; } - /** - * Get value of {@link #ossindexAnalyzerPassword}. - * - * @return the value of ossindexAnalyzerPassword - */ - public String getOssindexAnalyzerPassword() { - return ossindexAnalyzerPassword; - } - /** * Set value of {@link #ossindexAnalyzerPassword}. * @@ -1831,15 +1226,6 @@ public void setOssindexAnalyzerPassword(String ossindexAnalyzerPassword) { this.ossindexAnalyzerPassword = ossindexAnalyzerPassword; } - /** - * Get value of {@link #ossIndexAnalyzerWarnOnlyOnRemoteErrors}. - * - * @return the value of ossIndexWarnOnlyOnRemoteErrors - */ - public Boolean getOssIndexWarnOnlyOnRemoteErrors() { - return ossIndexAnalyzerWarnOnlyOnRemoteErrors; - } - /** * Set value of {@link #ossIndexAnalyzerWarnOnlyOnRemoteErrors}. * @@ -1850,15 +1236,6 @@ public void setOssIndexWarnOnlyOnRemoteErrors(Boolean ossIndexWarnOnlyOnRemoteEr this.ossIndexAnalyzerWarnOnlyOnRemoteErrors = ossIndexWarnOnlyOnRemoteErrors; } - /** - * Get the value of cmakeAnalyzerEnabled. - * - * @return the value of cmakeAnalyzerEnabled - */ - public Boolean isCmakeAnalyzerEnabled() { - return cmakeAnalyzerEnabled; - } - /** * Set the value of cmakeAnalyzerEnabled. * @@ -1868,15 +1245,6 @@ public void setCmakeAnalyzerEnabled(Boolean cmakeAnalyzerEnabled) { this.cmakeAnalyzerEnabled = cmakeAnalyzerEnabled; } - /** - * Returns the value of artifactoryAnalyzerEnabled. - * - * @return the value of artifactoryAnalyzerEnabled - */ - public Boolean getArtifactoryAnalyzerEnabled() { - return artifactoryAnalyzerEnabled; - } - /** * Set the value of artifactoryAnalyzerEnabled. * @@ -1886,15 +1254,6 @@ public void setArtifactoryAnalyzerEnabled(Boolean artifactoryAnalyzerEnabled) { this.artifactoryAnalyzerEnabled = artifactoryAnalyzerEnabled; } - /** - * Returns the value of artifactoryAnalyzerUrl. - * - * @return the value of artifactoryAnalyzerUrl - */ - public String getArtifactoryAnalyzerUrl() { - return artifactoryAnalyzerUrl; - } - /** * Set the value of artifactoryAnalyzerUrl. * @@ -1904,15 +1263,6 @@ public void setArtifactoryAnalyzerUrl(String artifactoryAnalyzerUrl) { this.artifactoryAnalyzerUrl = artifactoryAnalyzerUrl; } - /** - * Returns the value of artifactoryAnalyzerUseProxy. - * - * @return the value of artifactoryAnalyzerUseProxy - */ - public Boolean getArtifactoryAnalyzerUseProxy() { - return artifactoryAnalyzerUseProxy; - } - /** * Set the value of artifactoryAnalyzerUseProxy. * @@ -1923,15 +1273,6 @@ public void setArtifactoryAnalyzerUseProxy(Boolean artifactoryAnalyzerUseProxy) this.artifactoryAnalyzerUseProxy = artifactoryAnalyzerUseProxy; } - /** - * Returns the value of artifactoryAnalyzerParallelAnalysis. - * - * @return the value of artifactoryAnalyzerParallelAnalysis - */ - public Boolean getArtifactoryAnalyzerParallelAnalysis() { - return artifactoryAnalyzerParallelAnalysis; - } - /** * Set the value of artifactoryAnalyzerParallelAnalysis. * @@ -1942,15 +1283,6 @@ public void setArtifactoryAnalyzerParallelAnalysis(Boolean artifactoryAnalyzerPa this.artifactoryAnalyzerParallelAnalysis = artifactoryAnalyzerParallelAnalysis; } - /** - * Returns the value of artifactoryAnalyzerUsername. - * - * @return the value of artifactoryAnalyzerUsername - */ - public String getArtifactoryAnalyzerUsername() { - return artifactoryAnalyzerUsername; - } - /** * Set the value of artifactoryAnalyzerUsername. * @@ -1961,15 +1293,6 @@ public void setArtifactoryAnalyzerUsername(String artifactoryAnalyzerUsername) { this.artifactoryAnalyzerUsername = artifactoryAnalyzerUsername; } - /** - * Returns the value of artifactoryAnalyzerApiToken. - * - * @return the value of artifactoryAnalyzerApiToken - */ - public String getArtifactoryAnalyzerApiToken() { - return artifactoryAnalyzerApiToken; - } - /** * Set the value of artifactoryAnalyzerApiToken. * @@ -1980,15 +1303,6 @@ public void setArtifactoryAnalyzerApiToken(String artifactoryAnalyzerApiToken) { this.artifactoryAnalyzerApiToken = artifactoryAnalyzerApiToken; } - /** - * Returns the value of artifactoryAnalyzerBearerToken. - * - * @return the value of artifactoryAnalyzerBearerToken - */ - public String getArtifactoryAnalyzerBearerToken() { - return artifactoryAnalyzerBearerToken; - } - /** * Set the value of artifactoryAnalyzerBearerToken. * @@ -1999,6 +1313,16 @@ public void setArtifactoryAnalyzerBearerToken(String artifactoryAnalyzerBearerTo this.artifactoryAnalyzerBearerToken = artifactoryAnalyzerBearerToken; } + /** + * Set the value of failBuildOnUnusedSuppressionRule. + * + * @param failBuildOnUnusedSuppressionRule new value of + * failBuildOnUnusedSuppressionRule + */ + public void setFailBuildOnUnusedSuppressionRule(boolean failBuildOnUnusedSuppressionRule) { + this.failBuildOnUnusedSuppressionRule = failBuildOnUnusedSuppressionRule; + } + //see note on `dealWithReferences()` for information on this suppression @SuppressWarnings("squid:RedundantThrowsDeclarationCheck") @Override @@ -2006,6 +1330,11 @@ protected void executeWithContextClassloader() throws BuildException { dealWithReferences(); validateConfiguration(); populateSettings(); + try { + Downloader.getInstance().configure(getSettings()); + } catch (InvalidSettingException e) { + throw new BuildException(e); + } try (Engine engine = new Engine(Check.class.getClassLoader(), getSettings())) { for (Resource resource : getPath()) { final FileProvider provider = resource.as(FileProvider.class); @@ -2100,6 +1429,10 @@ protected void populateSettings() throws BuildException { super.populateSettings(); getSettings().setBooleanIfNotNull(Settings.KEYS.AUTO_UPDATE, autoUpdate); getSettings().setArrayIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE, suppressionFiles); + getSettings().setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE_USER, suppressionFileUser); + getSettings().setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE_PASSWORD, suppressionFilePassword); + getSettings().setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE_BEARER_TOKEN, suppressionFileBearerToken); + getSettings().setBooleanIfNotNull(Settings.KEYS.UPDATE_VERSION_CHECK_ENABLED, versionCheckEnabled); getSettings().setStringIfNotEmpty(Settings.KEYS.HINTS_FILE, hintsFile); getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_EXPERIMENTAL_ENABLED, enableExperimental); getSettings().setBooleanIfNotNull(Settings.KEYS.PRETTY_PRINT, prettyPrint); @@ -2122,6 +1455,7 @@ protected void populateSettings() throws BuildException { getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_SWIFT_PACKAGE_MANAGER_ENABLED, swiftPackageManagerAnalyzerEnabled); getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_SWIFT_PACKAGE_RESOLVED_ENABLED, swiftPackageResolvedAnalyzerEnabled); getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_COCOAPODS_ENABLED, cocoapodsAnalyzerEnabled); + getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_CARTHAGE_ENABLED, carthageAnalyzerEnabled); getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_BUNDLE_AUDIT_ENABLED, bundleAuditAnalyzerEnabled); getSettings().setStringIfNotNull(Settings.KEYS.ANALYZER_BUNDLE_AUDIT_PATH, bundleAuditPath); getSettings().setStringIfNotNull(Settings.KEYS.ANALYZER_BUNDLE_AUDIT_WORKING_DIRECTORY, bundleAuditWorkingDirectory); @@ -2131,6 +1465,7 @@ protected void populateSettings() throws BuildException { getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_PIPFILE_ENABLED, pipfileAnalyzerEnabled); getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_POETRY_ENABLED, poetryAnalyzerEnabled); getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_COMPOSER_LOCK_ENABLED, composerAnalyzerEnabled); + getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_COMPOSER_LOCK_SKIP_DEV, composerAnalyzerSkipDev); getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_CPANFILE_ENABLED, cpanfileAnalyzerEnabled); getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED, nodeAnalyzerEnabled); getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_NODE_PACKAGE_SKIPDEV, nodePackageSkipDevDependencies); @@ -2139,11 +1474,6 @@ protected void populateSettings() throws BuildException { getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_PNPM_AUDIT_ENABLED, pnpmAuditAnalyzerEnabled); getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_NODE_AUDIT_USE_CACHE, nodeAuditAnalyzerUseCache); getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_NODE_AUDIT_SKIPDEV, nodeAuditSkipDevDependencies); - getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_ENABLED, retireJsAnalyzerEnabled); - getSettings().setStringIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_URL, retireJsUrl); - getSettings().setStringIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_USER, retireJsUrlUser); - getSettings().setStringIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_PASSWORD, retireJsUrlPassword); - getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_FORCEUPDATE, retireJsAnalyzerForceUpdate); getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_FILTER_NON_VULNERABLE, retirejsFilterNonVulnerable); getSettings().setArrayIfNotEmpty(Settings.KEYS.ANALYZER_RETIREJS_FILTERS, retirejsFilters); getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_GOLANG_DEP_ENABLED, golangDepEnabled); @@ -2156,12 +1486,11 @@ protected void populateSettings() throws BuildException { getSettings().setStringIfNotNull(Settings.KEYS.ANALYZER_MIX_AUDIT_PATH, mixAuditPath); getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_NUSPEC_ENABLED, nuspecAnalyzerEnabled); getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_NUGETCONF_ENABLED, nugetconfAnalyzerEnabled); + getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_LIBMAN_ENABLED, libmanAnalyzerEnabled); getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, centralAnalyzerEnabled); getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_CENTRAL_USE_CACHE, centralAnalyzerUseCache); getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled); getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, archiveAnalyzerEnabled); - getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_KNOWN_EXPLOITED_ENABLED, knownExploitedEnabled); - getSettings().setStringIfNotEmpty(Settings.KEYS.KEV_URL, knownExploitedUrl); getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED, assemblyAnalyzerEnabled); getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_MSBUILD_PROJECT_ENABLED, msbuildAnalyzerEnabled); getSettings().setStringIfNotEmpty(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl); @@ -2177,6 +1506,7 @@ protected void populateSettings() throws BuildException { getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_OSSINDEX_USE_CACHE, ossindexAnalyzerUseCache); getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_OSSINDEX_WARN_ONLY_ON_REMOTE_ERRORS, ossIndexAnalyzerWarnOnlyOnRemoteErrors); getSettings().setFloat(Settings.KEYS.JUNIT_FAIL_ON_CVSS, junitFailOnCVSS); + getSettings().setBooleanIfNotNull(Settings.KEYS.FAIL_ON_UNUSED_SUPPRESSION_RULE, failBuildOnUnusedSuppressionRule); } /** @@ -2194,15 +1524,31 @@ private void checkForFailure(Dependency[] dependencies) throws BuildException { for (Dependency d : dependencies) { boolean addName = true; for (Vulnerability v : d.getVulnerabilities()) { - if ((v.getCvssV2() != null && v.getCvssV2().getScore() >= failBuildOnCVSS) - || (v.getCvssV3() != null && v.getCvssV3().getBaseScore() >= failBuildOnCVSS) - || (v.getUnscoredSeverity() != null && SeverityUtil.estimateCvssV2(v.getUnscoredSeverity()) >= failBuildOnCVSS) + final double cvssV2 = v.getCvssV2() != null && v.getCvssV2().getCvssData() != null + && v.getCvssV2().getCvssData().getBaseScore() != null ? v.getCvssV2().getCvssData().getBaseScore() : -1; + final double cvssV3 = v.getCvssV3() != null && v.getCvssV3().getCvssData() != null + && v.getCvssV3().getCvssData().getBaseScore() != null ? v.getCvssV3().getCvssData().getBaseScore() : -1; + final double cvssV4 = v.getCvssV4() != null && v.getCvssV4().getCvssData() != null + && v.getCvssV4().getCvssData().getBaseScore() != null ? v.getCvssV4().getCvssData().getBaseScore() : -1; + final boolean useUnscored = cvssV2 == -1 && cvssV3 == -1 && cvssV4 == -1; + final double unscoredCvss = + useUnscored && v.getUnscoredSeverity() != null ? SeverityUtil.estimateCvssV2(v.getUnscoredSeverity()) : -1; + + if (cvssV2 >= failBuildOnCVSS + || cvssV3 >= failBuildOnCVSS + || cvssV4 >= failBuildOnCVSS + || unscoredCvss >= failBuildOnCVSS //safety net to fail on any if for some reason the above misses on 0 - || (failBuildOnCVSS <= 0.0f)) { + || failBuildOnCVSS <= 0.0f + ) { if (addName) { addName = false; - ids.append(NEW_LINE).append(d.getFileName()).append(": "); - ids.append(v.getName()); + ids.append(NEW_LINE).append(d.getFileName()).append(" (") + .append(Stream.concat(d.getSoftwareIdentifiers().stream(), d.getVulnerableSoftwareIdentifiers().stream()) + .map(Identifier::getValue) + .collect(Collectors.joining(", "))) + .append("): ") + .append(v.getName()); } else { ids.append(", ").append(v.getName()); } diff --git a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Purge.java b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Purge.java index b8c902d3861..58cfddf8d44 100644 --- a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Purge.java +++ b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Purge.java @@ -17,21 +17,18 @@ */ package org.owasp.dependencycheck.taskdefs; +import io.github.jeremylong.jcs3.slf4j.Slf4jAdapter; import java.io.File; import java.io.IOException; import java.io.InputStream; -import org.apache.commons.jcs.JCS; -import org.apache.commons.jcs.access.CacheAccess; -import org.apache.commons.jcs.engine.CompositeCacheAttributes; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.owasp.dependencycheck.Engine; -import org.owasp.dependencycheck.data.cache.DataCache; +import org.owasp.dependencycheck.utils.Downloader; +import org.owasp.dependencycheck.utils.InvalidSettingException; import org.owasp.dependencycheck.utils.Settings; -import org.owasp.dependencycheck.xml.pom.Model; import org.slf4j.impl.StaticLoggerBinder; /** @@ -60,11 +57,6 @@ public class Purge extends Task { */ private boolean failOnError = true; - /** - * The URL to hosted suppressions file with base FP suppressions. - */ - private String hostedSuppressionsUrl = null; - /** * Construct a new DependencyCheckTask. */ @@ -80,15 +72,6 @@ public Settings getSettings() { return settings; } - /** - * Get the value of dataDirectory. - * - * @return the value of dataDirectory - */ - public String getDataDirectory() { - return dataDirectory; - } - /** * Set the value of dataDirectory. * @@ -117,34 +100,21 @@ public void setFailOnError(boolean failOnError) { } /** - * Get the value of hostedSuppressionsUrl. - * - * @return the value of hostedSuppressionsUrl - */ - public String getHostedSuppressionsUrl() { - return hostedSuppressionsUrl; - } - - /** - * Set the value of hostedSuppressionsUrl. + * Sets the + * {@link Thread#getContextClassLoader() Thread Context Class Loader} to the + * one for this class, and then calls + * {@link #executeWithContextClassloader()}. This is done because the JCS + * cache needs to have the Thread Context Class Loader set to something that + * can resolve it's classes. Other build tools do this by default but Ant + * does not. * - * @param hostedSuppressionsUrl new value of hostedSuppressionsUrl - */ - public void setHostedSuppressionsUrl(final String hostedSuppressionsUrl) { - this.hostedSuppressionsUrl = hostedSuppressionsUrl; - } - - /** - * Sets the {@link Thread#getContextClassLoader() Thread Context Class Loader} to the one for this class, - * and then calls {@link #executeWithContextClassloader()}. This is done because the JCS cache needs to have - * the Thread Context Class Loader set to something that can resolve it's classes. Other build tools do this - * by default but Ant does not. - * - * @throws BuildException throws if there is a problem. See {@link #executeWithContextClassloader()} for details + * @throws BuildException throws if there is a problem. See + * {@link #executeWithContextClassloader()} for details */ @Override public final void execute() throws BuildException { - ClassLoader current = Thread.currentThread().getContextClassLoader(); + muteNoisyLoggers(); + final ClassLoader current = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); @@ -154,6 +124,21 @@ public final void execute() throws BuildException { } } + /** + * Hacky method of muting the noisy logging from JCS. + */ + private void muteNoisyLoggers() { + System.setProperty("jcs.logSystem", "slf4j"); + Slf4jAdapter.muteLogging(true); + + final String[] noisyLoggers = { + "org.apache.hc" + }; + for (String loggerName : noisyLoggers) { + System.setProperty("org.slf4j.simpleLogger.log." + loggerName, "error"); + } + } + /** * Executes the dependency-check purge to delete the existing local copy of * the NVD CVE data. @@ -164,6 +149,11 @@ public final void execute() throws BuildException { @SuppressWarnings("squid:RedundantThrowsDeclarationCheck") protected void executeWithContextClassloader() throws BuildException { populateSettings(); + try { + Downloader.getInstance().configure(settings); + } catch (InvalidSettingException e) { + throw new BuildException(e); + } try (Engine engine = new Engine(Engine.Mode.EVIDENCE_PROCESSING, getSettings())) { engine.purge(); } finally { @@ -191,7 +181,6 @@ protected void populateSettings() throws BuildException { } log(msg, ex, Project.MSG_WARN); } - settings.setStringIfNotEmpty(Settings.KEYS.HOSTED_SUPPRESSIONS_URL, hostedSuppressionsUrl); if (dataDirectory != null) { settings.setString(Settings.KEYS.DATA_DIRECTORY, dataDirectory); } else { diff --git a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Update.java b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Update.java index 3cf35c381a8..1cac8153188 100644 --- a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Update.java +++ b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Update.java @@ -17,14 +17,13 @@ */ package org.owasp.dependencycheck.taskdefs; -import java.util.Optional; - import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.data.nvdcve.DatabaseException; import org.owasp.dependencycheck.data.update.exception.UpdateException; -import org.owasp.dependencycheck.utils.CveUrlParser; +import org.owasp.dependencycheck.utils.Downloader; +import org.owasp.dependencycheck.utils.InvalidSettingException; import org.owasp.dependencycheck.utils.Settings; import org.slf4j.impl.StaticLoggerBinder; @@ -40,6 +39,93 @@ @SuppressWarnings("common-java:DuplicatedBlocks") public class Update extends Purge { + /** + * The URL to (a mirror of) the RetireJS JSON data. + */ + private String retireJsUrl; + /** + * The user to download the RetireJS JSON data from an HTTP Basic auth protected location. + */ + private String retireJsUrlUser; + /** + * The password to download the RetireJS JSON data from an HTTP Basic auth protected location. + */ + private String retireJsUrlPassword; + /** + * The token to download the RetireJS JSON data from an HTTP Bearer auth protected location. + */ + private String retireJsUrlBearerToken; + /** + * Whether or not the RetireJS JSON repository will be updated regardless of the + * `autoupdate` settings. Defaults to false. + */ + private Boolean retireJsForceUpdate; + /** + * Whether or not the Known Exploited Vulnerability Analyzer is enabled. + */ + private Boolean knownExploitedEnabled; + /** + * The URL to the known exploited vulnerabilities JSON datafeed. + */ + private String knownExploitedUrl; + /** + * The number of hours before checking for updates for the known exploited vulnerabilities JSON datafeed. + */ + private Integer knownExploitedValidForHours; + /** + * The user to download the known exploited vulnerabilities JSON datafeed from an HTTP Basic auth protected location. + */ + private String knownExploitedUser; + /** + * The password to download the known exploited vulnerabilities JSON datafeed from an HTTP Basic auth protected location. + */ + private String knownExploitedPassword; + /** + * The token to download the known exploited vulnerabilities JSON datafeed from an HTTP Bearer auth protected location. + */ + private String knownExploitedBearerToken; + /** + * The NVD API endpoint. + */ + private String nvdApiEndpoint; + /** + * The NVD API Key. + */ + private String nvdApiKey; + /** + * The maximum number of retry requests for a single call to the NVD API. + */ + private Integer nvdMaxRetryCount; + /** + * The number of hours to wait before checking for new updates from the NVD. + */ + private Integer nvdValidForHours; + /** + * The NVD API Data Feed URL. + */ + private String nvdDatafeedUrl; + /** + * The username to download the NVD Data feed from an HTTP Basic auth protected location. + */ + private String nvdUser; + /** + * The password to download the NVD Data feed from an HTTP Basic auth protected location. + */ + private String nvdPassword; + /** + * The token to download the NVD Data feed from an HTTP Bearer auth protected location. + */ + private String nvdBearerToken; + /** + * The time in milliseconds to wait between downloading NVD API data. + */ + private Integer nvdApiDelay; + + /** + * The number of records per page of NVD API data. + */ + private Integer nvdApiResultsPerPage; + /** * The Proxy Server. */ @@ -89,38 +175,45 @@ public class Update extends Purge { */ private String databasePassword; /** - * The URL for the modified NVD CVE JSON file. - */ - private String cveUrlModified; - /** - * Base Data Mirror URL for CVE JSON files. + * The number of hours to wait before re-checking hosted suppressions file + * for updates. */ - private String cveUrlBase; + private Integer hostedSuppressionsValidForHours; /** - * The wait time in milliseconds between downloads from the NVD. + * The userid for the hostedSuppressions file. + *
+ * Only needs configuration if you customized the hostedSuppressionsUrl to a custom server that requires Basic Auth */ - private String cveWaitTime; + private String hostedSuppressionsUser; /** - * The number of hours to wait before re-checking for updates. + * The password for the hostedSuppressions file. + *
+ * Only needs configuration if you customized the hostedSuppressionsUrl to a custom server that requires Basic Auth */ - private Integer cveValidForHours; + private String hostedSuppressionsPassword; /** - * The number of hours to wait before re-checking hosted suppressions file for updates. + * The (Bearer authentication) API Token for the hostedSuppressions file. + *
+ * Only needs configuration if you customized the hostedSuppressionsUrl to a custom server that requires Bearer Auth */ - private Integer hostedSuppressionsValidForHours; + private String hostedSuppressionsBearerToken; /** - * Whether the hosted suppressions file will be updated regardless of the `autoupdate` settings. Defaults to false. + * Whether the hosted suppressions file will be updated regardless of the + * `autoupdate` settings. Defaults to false. */ private Boolean hostedSuppressionsForceUpdate; /** * Whether the hosted suppressions file will be used. Defaults to true. */ private Boolean hostedSuppressionsEnabled; - /** - * Specify the first year of NVD CVE data to download; default is 2002. + * The URL to hosted suppressions file with base FP suppressions. */ - private Integer cveStartYear; + private String hostedSuppressionsUrl = null; + /** + * Whether or not the RetireJS Analyzer is enabled. + */ + private Boolean retireJsAnalyzerEnabled; /** * Construct a new UpdateTask. @@ -133,174 +226,181 @@ public Update() { } /** - * Get the value of proxyServer. + * Set the value of nvdApiEndpoint. * - * @return the value of proxyServer + * @param nvdApiEndpoint new value of nvdApiEndpoint */ - public String getProxyServer() { - return proxyServer; + public void setNvdApiEndpoint(String nvdApiEndpoint) { + this.nvdApiEndpoint = nvdApiEndpoint; } /** - * Set the value of proxyServer. + * Set the value of nvdApiKey. * - * @param server new value of proxyServer + * @param nvdApiKey new value of nvdApiKey */ - public void setProxyServer(String server) { - this.proxyServer = server; + public void setNvdApiKey(String nvdApiKey) { + this.nvdApiKey = nvdApiKey; } /** - * Get the value of proxyPort. + * Set the value of nvdMaxRetryCount. * - * @return the value of proxyPort + * @param nvdMaxRetryCount new value of nvdMaxRetryCount */ - public String getProxyPort() { - return proxyPort; + public void setNvdMaxRetryCount(Integer nvdMaxRetryCount) { + if (nvdMaxRetryCount > 0) { + this.nvdMaxRetryCount = nvdMaxRetryCount; + } else { + throw new BuildException("Invalid setting: `nvdMaxRetryCount` must be greater than zero"); + } } /** - * Set the value of proxyPort. + * Set the value of nvdValidForHours. * - * @param proxyPort new value of proxyPort + * @param nvdValidForHours new value of nvdValidForHours */ - public void setProxyPort(String proxyPort) { - this.proxyPort = proxyPort; + public void setNvdValidForHours(int nvdValidForHours) { + if (nvdValidForHours >= 0) { + this.nvdValidForHours = nvdValidForHours; + } else { + throw new BuildException("Invalid setting: `nvdValidForHours` must be 0 or greater"); + } } /** - * Get the value of proxyUsername. + * Set the value of nvdDatafeedUrl. * - * @return the value of proxyUsername + * @param nvdDatafeedUrl new value of nvdDatafeedUrl */ - public String getProxyUsername() { - return proxyUsername; + public void setNvdDatafeedUrl(String nvdDatafeedUrl) { + this.nvdDatafeedUrl = nvdDatafeedUrl; } /** - * Set the value of proxyUsername. + * Set the value of nvdUser. * - * @param proxyUsername new value of proxyUsername + * @param nvdUser new value of nvdUser */ - public void setProxyUsername(String proxyUsername) { - this.proxyUsername = proxyUsername; + public void setNvdUser(String nvdUser) { + this.nvdUser = nvdUser; } /** - * Get the value of proxyPassword. + * Set the value of nvdPassword. * - * @return the value of proxyPassword + * @param nvdPassword new value of nvdPassword */ - public String getProxyPassword() { - return proxyPassword; + public void setNvdPassword(String nvdPassword) { + this.nvdPassword = nvdPassword; } /** - * Set the value of proxyPassword. - * - * @param proxyPassword new value of proxyPassword + * Sets the token to download the NVD Data feed from an HTTP Bearer auth protected location. + * @param nvdBearerToken The bearer token */ - public void setProxyPassword(String proxyPassword) { - this.proxyPassword = proxyPassword; + public void setNvdBearerToken(String nvdBearerToken) { + this.nvdBearerToken = nvdBearerToken; } /** - * Get the value of nonProxyHosts. + * Set the value of nvdApiDelay. * - * @return the value of nonProxyHosts + * @param nvdApiDelay new value of nvdApiDelay */ - public String getNonProxyHosts() { - return nonProxyHosts; + public void setNvdApiDelay(Integer nvdApiDelay) { + this.nvdApiDelay = nvdApiDelay; } /** - * Set the value of nonProxyHosts. + * Set the value of nvdApiResultsPerPage. * - * @param nonProxyHosts new value of nonProxyHosts + * @param nvdApiResultsPerPage new value of nvdApiResultsPerPage */ - public void setNonProxyHosts(String nonProxyHosts) { - this.nonProxyHosts = nonProxyHosts; + public void setNvdApiResultsPerPage(Integer nvdApiResultsPerPage) { + this.nvdApiResultsPerPage = nvdApiResultsPerPage; } /** - * Get the value of connectionTimeout. + * Set the value of proxyServer. * - * @return the value of connectionTimeout + * @param server new value of proxyServer */ - public String getConnectionTimeout() { - return connectionTimeout; + public void setProxyServer(String server) { + this.proxyServer = server; } /** - * Set the value of connectionTimeout. + * Set the value of proxyPort. * - * @param connectionTimeout new value of connectionTimeout + * @param proxyPort new value of proxyPort */ - public void setConnectionTimeout(String connectionTimeout) { - this.connectionTimeout = connectionTimeout; + public void setProxyPort(String proxyPort) { + this.proxyPort = proxyPort; } /** - * Get the value of readTimeout. + * Set the value of proxyUsername. * - * @return the value of readTimeout + * @param proxyUsername new value of proxyUsername */ - public String getReadTimeout() { - return readTimeout; + public void setProxyUsername(String proxyUsername) { + this.proxyUsername = proxyUsername; } /** - * Set the value of readTimeout. + * Set the value of proxyPassword. * - * @param readTimeout new value of readTimeout + * @param proxyPassword new value of proxyPassword */ - public void setReadTimeout(String readTimeout) { - this.readTimeout = readTimeout; + public void setProxyPassword(String proxyPassword) { + this.proxyPassword = proxyPassword; } /** - * Get the value of databaseDriverName. + * Set the value of nonProxyHosts. * - * @return the value of databaseDriverName + * @param nonProxyHosts new value of nonProxyHosts */ - public String getDatabaseDriverName() { - return databaseDriverName; + public void setNonProxyHosts(String nonProxyHosts) { + this.nonProxyHosts = nonProxyHosts; } /** - * Set the value of databaseDriverName. + * Set the value of connectionTimeout. * - * @param databaseDriverName new value of databaseDriverName + * @param connectionTimeout new value of connectionTimeout */ - public void setDatabaseDriverName(String databaseDriverName) { - this.databaseDriverName = databaseDriverName; + public void setConnectionTimeout(String connectionTimeout) { + this.connectionTimeout = connectionTimeout; } /** - * Get the value of databaseDriverPath. + * Set the value of readTimeout. * - * @return the value of databaseDriverPath + * @param readTimeout new value of readTimeout */ - public String getDatabaseDriverPath() { - return databaseDriverPath; + public void setReadTimeout(String readTimeout) { + this.readTimeout = readTimeout; } /** - * Set the value of databaseDriverPath. + * Set the value of databaseDriverName. * - * @param databaseDriverPath new value of databaseDriverPath + * @param databaseDriverName new value of databaseDriverName */ - public void setDatabaseDriverPath(String databaseDriverPath) { - this.databaseDriverPath = databaseDriverPath; + public void setDatabaseDriverName(String databaseDriverName) { + this.databaseDriverName = databaseDriverName; } /** - * Get the value of connectionString. + * Set the value of databaseDriverPath. * - * @return the value of connectionString + * @param databaseDriverPath new value of databaseDriverPath */ - public String getConnectionString() { - return connectionString; + public void setDatabaseDriverPath(String databaseDriverPath) { + this.databaseDriverPath = databaseDriverPath; } /** @@ -312,15 +412,6 @@ public void setConnectionString(String connectionString) { this.connectionString = connectionString; } - /** - * Get the value of databaseUser. - * - * @return the value of databaseUser - */ - public String getDatabaseUser() { - return databaseUser; - } - /** * Set the value of databaseUser. * @@ -330,15 +421,6 @@ public void setDatabaseUser(String databaseUser) { this.databaseUser = databaseUser; } - /** - * Get the value of databasePassword. - * - * @return the value of databasePassword - */ - public String getDatabasePassword() { - return databasePassword; - } - /** * Set the value of databasePassword. * @@ -349,151 +431,157 @@ public void setDatabasePassword(String databasePassword) { } /** - * Set the value of cveUrlModified. + * Set the value of hostedSuppressionsValidForHours. * - * @param cveUrlModified new value of cveUrlModified + * @param hostedSuppressionsValidForHours new value of + * hostedSuppressionsValidForHours */ - public void setCveUrlModified(String cveUrlModified) { - this.cveUrlModified = cveUrlModified; + public void setHostedSuppressionsValidForHours(final Integer hostedSuppressionsValidForHours) { + this.hostedSuppressionsValidForHours = hostedSuppressionsValidForHours; } - /** - * Get the value of cveUrlModified. - * - * @return the value of cveUrlModified - */ - public String getCveUrlModified() { - return cveUrlModified; + public void setHostedSuppressionsUser(String hostedSuppressionsUser) { + this.hostedSuppressionsUser = hostedSuppressionsUser; + } + + public void setHostedSuppressionsPassword(String hostedSuppressionsPassword) { + this.hostedSuppressionsPassword = hostedSuppressionsPassword; + } + + public void setHostedSuppressionsBearerToken(String hostedSuppressionsBearerToken) { + this.hostedSuppressionsBearerToken = hostedSuppressionsBearerToken; } /** - * Get the value of cveUrlBase. + * Set the value of hostedSuppressionsForceUpdate. * - * @return the value of cveUrlBase + * @param hostedSuppressionsForceUpdate new value of + * hostedSuppressionsForceUpdate */ - public String getCveUrlBase() { - return cveUrlBase; + public void setHostedSuppressionsForceUpdate(final Boolean hostedSuppressionsForceUpdate) { + this.hostedSuppressionsForceUpdate = hostedSuppressionsForceUpdate; } /** - * Set the value of cveUrlBase. + * Set the value of hostedSuppressionsEnabled. * - * @param cveUrlBase new value of cveUrlBase + * @param hostedSuppressionsEnabled new value of hostedSuppressionsEnabled */ - public void setCveUrlBase(String cveUrlBase) { - this.cveUrlBase = cveUrlBase; + public void setHostedSuppressionsEnabled(Boolean hostedSuppressionsEnabled) { + this.hostedSuppressionsEnabled = hostedSuppressionsEnabled; } /** - * Get the value of cveUrlBase. + * Set the value of hostedSuppressionsUrl. * - * @return the value of cveUrlBase + * @param hostedSuppressionsUrl new value of hostedSuppressionsUrl */ - public String getCveWaitTime() { - return cveWaitTime; + public void setHostedSuppressionsUrl(final String hostedSuppressionsUrl) { + this.hostedSuppressionsUrl = hostedSuppressionsUrl; } /** - * Set the value of cveWaitTime. + * Sets the the knownExploitedUrl. * - * @param cveWaitTime new value of cveWaitTime + * @param knownExploitedUrl the URL */ - public void setCveWaitTime(String cveWaitTime) { - this.cveWaitTime = cveWaitTime; + public void setKnownExploitedUrl(String knownExploitedUrl) { + this.knownExploitedUrl = knownExploitedUrl; + } + + public void setKnownExploitedValidForHours(Integer knownExploitedValidForHours) { + this.knownExploitedValidForHours = knownExploitedValidForHours; } /** - * Get the value of cveValidForHours. + * Sets the user for downloading the knownExploitedUrl from a HTTP Basic auth protected location. * - * @return the value of cveValidForHours + * @param knownExploitedUser the user */ - public Integer getCveValidForHours() { - return cveValidForHours; + public void setKnownExploitedUser(String knownExploitedUser) { + this.knownExploitedUser = knownExploitedUser; } /** - * Set the value of cveValidForHours. + * Sets the password for downloading the knownExploitedUrl from a HTTP Basic auth protected location.. * - * @param cveValidForHours new value of cveValidForHours + * @param knownExploitedPassword the password */ - public void setCveValidForHours(Integer cveValidForHours) { - this.cveValidForHours = cveValidForHours; + public void setKnownExploitedPassword(String knownExploitedPassword) { + this.knownExploitedPassword = knownExploitedPassword; } /** - * Get the value of cveStartYear. + * Sets the token for downloading the knownExploitedUrl from an HTTP Bearer auth protected location.. * - * @return the value of cveStartYear + * @param knownExploitedBearerToken the token */ - public Integer getCveStartYear() { - return cveStartYear; + public void setKnownExploitedBearerToken(String knownExploitedBearerToken) { + this.knownExploitedBearerToken = knownExploitedBearerToken; } /** - * Set the value of cveStartYear. + * Sets whether the analyzer is enabled. * - * @param cveStartYear new value of cveStartYear + * @param knownExploitedEnabled the value of the new setting */ - public void setCveStartYear(Integer cveStartYear) { - if (cveStartYear != null && cveStartYear < 2002) { - log("Invalid Configuration: cveStartYear must be 2002 or greater", Project.MSG_ERR); - this.cveStartYear = 2002; - } else { - this.cveStartYear = cveStartYear; - } + public void setKnownExploitedEnabled(Boolean knownExploitedEnabled) { + this.knownExploitedEnabled = knownExploitedEnabled; } /** - * Get the value of hostedSuppressionsValidForHours. + * Set the value of the Retire JS repository URL. * - * @return the value of hostedSuppressionsValidForHours + * @param retireJsUrl new value of retireJsUrl */ - public Integer getHostedSuppressionsValidForHours() { - return hostedSuppressionsValidForHours; + public void setRetireJsUrl(String retireJsUrl) { + this.retireJsUrl = retireJsUrl; } /** - * Set the value of hostedSuppressionsValidForHours. + * Sets the user to download the RetireJS JSON data from an HTTP Basic auth protected location. * - * @param hostedSuppressionsValidForHours new value of hostedSuppressionsValidForHours + * @param retireJsUrlUser new value of retireJsUrlUser */ - public void setHostedSuppressionsValidForHours(final Integer hostedSuppressionsValidForHours) { - this.hostedSuppressionsValidForHours = hostedSuppressionsValidForHours; + public void setRetireJsUrlUser(String retireJsUrlUser) { + this.retireJsUrlUser = retireJsUrlUser; } /** - * Get the value of hostedSuppressionsForceUpdate. + * Sets the password to download the RetireJS JSON data from an HTTP Basic auth protected location. * - * @return the value of hostedSuppressionsForceUpdate + * @param retireJsUrlPassword new value of retireJsUrlPassword */ - public Boolean isHostedSuppressionsForceUpdate() { - return hostedSuppressionsForceUpdate; + public void setRetireJsUrlPassword(String retireJsUrlPassword) { + this.retireJsUrlPassword = retireJsUrlPassword; } /** - * Set the value of hostedSuppressionsForceUpdate. + * Sets the token to download the RetireJS JSON data from an HTTP Bearer auth protected location. * - * @param hostedSuppressionsForceUpdate new value of hostedSuppressionsForceUpdate + * @param retireJsUrlBearerToken new value of retireJsUrlBearerToken */ - public void setHostedSuppressionsForceUpdate(final Boolean hostedSuppressionsForceUpdate) { - this.hostedSuppressionsForceUpdate = hostedSuppressionsForceUpdate; + public void setRetireJsUrlBearerToken(String retireJsUrlBearerToken) { + this.retireJsUrlBearerToken = retireJsUrlBearerToken; } /** - * Get the value of hostedSuppressionsEnabled. + * Set the value of retireJsForceUpdate. * - * @return the value of hostedSuppressionsEnabled + * @param retireJsForceUpdate new value of + * retireJsForceUpdate */ - public Boolean isHostedSuppressionsEnabled() { - return hostedSuppressionsEnabled; + public void setRetireJsForceUpdate(Boolean retireJsForceUpdate) { + this.retireJsForceUpdate = retireJsForceUpdate; } + /** - * Set the value of hostedSuppressionsEnabled. + * Set the value of retireJsAnalyzerEnabled. * - * @param hostedSuppressionsEnabled new value of hostedSuppressionsEnabled + * @param retireJsAnalyzerEnabled new value of retireJsAnalyzerEnabled */ - public void setHostedSuppressionsEnabled(Boolean hostedSuppressionsEnabled) { - this.hostedSuppressionsEnabled = hostedSuppressionsEnabled; + public void setRetireJsAnalyzerEnabled(Boolean retireJsAnalyzerEnabled) { + this.retireJsAnalyzerEnabled = retireJsAnalyzerEnabled; } /** @@ -508,6 +596,11 @@ public void setHostedSuppressionsEnabled(Boolean hostedSuppressionsEnabled) { @Override protected void executeWithContextClassloader() throws BuildException { populateSettings(); + try { + Downloader.getInstance().configure(getSettings()); + } catch (InvalidSettingException e) { + throw new BuildException(e); + } try (Engine engine = new Engine(Update.class.getClassLoader(), getSettings())) { engine.doUpdates(); } catch (UpdateException ex) { @@ -551,27 +644,37 @@ protected void populateSettings() throws BuildException { getSettings().setStringIfNotEmpty(Settings.KEYS.DB_USER, databaseUser); getSettings().setStringIfNotEmpty(Settings.KEYS.DB_PASSWORD, databasePassword); - final String cveModifiedJson = Optional.ofNullable(cveUrlModified) - .filter(url -> !url.isEmpty()) - .orElseGet(this::getDefaultCveUrlModified); - getSettings().setStringIfNotEmpty(Settings.KEYS.CVE_MODIFIED_JSON, cveModifiedJson); - getSettings().setStringIfNotEmpty(Settings.KEYS.CVE_BASE_JSON, cveUrlBase); - getSettings().setStringIfNotEmpty(Settings.KEYS.CVE_DOWNLOAD_WAIT_TIME, cveWaitTime); - getSettings().setIntIfNotNull(Settings.KEYS.CVE_START_YEAR, cveStartYear); + getSettings().setStringIfNotEmpty(Settings.KEYS.KEV_URL, knownExploitedUrl); + getSettings().setStringIfNotEmpty(Settings.KEYS.KEV_USER, knownExploitedUser); + getSettings().setStringIfNotEmpty(Settings.KEYS.KEV_PASSWORD, knownExploitedPassword); + getSettings().setStringIfNotEmpty(Settings.KEYS.KEV_BEARER_TOKEN, knownExploitedBearerToken); + getSettings().setIntIfNotNull(Settings.KEYS.KEV_CHECK_VALID_FOR_HOURS, knownExploitedValidForHours); + getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_KNOWN_EXPLOITED_ENABLED, knownExploitedEnabled); + + getSettings().setStringIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_URL, retireJsUrl); + getSettings().setStringIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_USER, retireJsUrlUser); + getSettings().setStringIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_PASSWORD, retireJsUrlPassword); + getSettings().setStringIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_BEARER_TOKEN, retireJsUrlBearerToken); + getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_FORCEUPDATE, retireJsForceUpdate); + getSettings().setBooleanIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_ENABLED, retireJsAnalyzerEnabled); + + getSettings().setStringIfNotEmpty(Settings.KEYS.HOSTED_SUPPRESSIONS_URL, hostedSuppressionsUrl); getSettings().setIntIfNotNull(Settings.KEYS.HOSTED_SUPPRESSIONS_VALID_FOR_HOURS, hostedSuppressionsValidForHours); + getSettings().setStringIfNotNull(Settings.KEYS.HOSTED_SUPPRESSIONS_USER, hostedSuppressionsUser); + getSettings().setStringIfNotNull(Settings.KEYS.HOSTED_SUPPRESSIONS_PASSWORD, hostedSuppressionsPassword); + getSettings().setStringIfNotNull(Settings.KEYS.HOSTED_SUPPRESSIONS_BEARER_TOKEN, hostedSuppressionsBearerToken); getSettings().setBooleanIfNotNull(Settings.KEYS.HOSTED_SUPPRESSIONS_FORCEUPDATE, hostedSuppressionsForceUpdate); getSettings().setBooleanIfNotNull(Settings.KEYS.HOSTED_SUPPRESSIONS_ENABLED, hostedSuppressionsEnabled); - if (cveValidForHours != null) { - if (cveValidForHours >= 0) { - getSettings().setInt(Settings.KEYS.CVE_CHECK_VALID_FOR_HOURS, cveValidForHours); - } else { - throw new BuildException("Invalid setting: `cpeValidForHours` must be 0 or greater"); - } - } - } - private String getDefaultCveUrlModified() { - return CveUrlParser.newInstance(getSettings()) - .getDefaultCveUrlModified(cveUrlBase); + getSettings().setStringIfNotEmpty(Settings.KEYS.NVD_API_KEY, nvdApiKey); + getSettings().setStringIfNotEmpty(Settings.KEYS.NVD_API_ENDPOINT, nvdApiEndpoint); + getSettings().setIntIfNotNull(Settings.KEYS.NVD_API_DELAY, nvdApiDelay); + getSettings().setIntIfNotNull(Settings.KEYS.NVD_API_RESULTS_PER_PAGE, nvdApiResultsPerPage); + getSettings().setStringIfNotEmpty(Settings.KEYS.NVD_API_DATAFEED_URL, nvdDatafeedUrl); + getSettings().setStringIfNotEmpty(Settings.KEYS.NVD_API_DATAFEED_USER, nvdUser); + getSettings().setStringIfNotEmpty(Settings.KEYS.NVD_API_DATAFEED_PASSWORD, nvdPassword); + getSettings().setStringIfNotEmpty(Settings.KEYS.NVD_API_DATAFEED_BEARER_TOKEN, nvdBearerToken); + getSettings().setIntIfNotNull(Settings.KEYS.NVD_API_MAX_RETRY_COUNT, nvdMaxRetryCount); + getSettings().setIntIfNotNull(Settings.KEYS.NVD_API_VALID_FOR_HOURS, nvdValidForHours); } } diff --git a/ant/src/main/resources/task.properties b/ant/src/main/resources/task.properties index 03c72cdc675..89625759080 100644 --- a/ant/src/main/resources/task.properties +++ b/ant/src/main/resources/task.properties @@ -1,2 +1,2 @@ # the path to the data directory -data.directory=data/7.0 +data.directory=data/11.0 diff --git a/ant/src/site/markdown/config-purge.md b/ant/src/site/markdown/config-purge.md index 5006865fe81..e048190e5bb 100644 --- a/ant/src/site/markdown/config-purge.md +++ b/ant/src/site/markdown/config-purge.md @@ -6,7 +6,7 @@ the rare circumstance that the local H2 database becomes corrupt. ```xml - + ``` @@ -14,15 +14,8 @@ Configuration: dependency-check-purge Task -------------------- The following properties can be set on the dependency-check-purge task. -Property | Description | Default Value -----------------------|------------------------------------------------------------------------|------------------ -dataDirectory | Data directory that is used to store the local copy of the NVD | data -failOnError | Whether the build should fail if there is an error executing the purge | true +| Property | Description | Default Value | +|---------------|----------------------------------------------------------------------------|--------------------------------------------------| +| dataDirectory | Data directory that is used to store the local caches and NVD CVE database | `/data/11.0` | +| failOnError | Whether the build should fail if there is an error executing the purge | true | -Advanced Configuration -==================== -The following properties can be configured in the plugin. However, they are less frequently changed. - -Property | Description | Default Value -----------------------|--------------------------------------------------------------------------------------------------|------------------ -hostedSuppressionsUrl | The URL to a mirrored copy of the hosted suppressions file for internet-constrained environments | https://jeremylong.github.io/DependencyCheck/suppressions/publishedSuppressions.xml diff --git a/ant/src/site/markdown/config-update.md b/ant/src/site/markdown/config-update.md index c3b776a0ec3..9d86a179987 100644 --- a/ant/src/site/markdown/config-update.md +++ b/ant/src/site/markdown/config-update.md @@ -4,12 +4,12 @@ The dependency-check-update task downloads and updates the local copy of the NVD There are several reasons that one may want to use this task; primarily, creating an update that will be run only once a day or once every few days (but not greater than 7 days) and then use the `autoUpdate="false"` setting on individual -dependency-check scans. See [Internet Access Required](https://jeremylong.github.io/DependencyCheck/data/index.html) +dependency-check scans. See [Internet Access Required](https://dependency-check.github.io/DependencyCheck/data/index.html) for more information on why this task would be used. ```xml - + ``` @@ -17,35 +17,54 @@ Configuration: dependency-check-update Task -------------------- The following properties can be set on the dependency-check-update task. -Property | Description | Default Value -----------------------|-------------------------------------------------------------------------|------------------ -proxyServer | The Proxy Server. |   -proxyPort | The Proxy Port. |   -proxyUsername | Defines the proxy user name. |   -proxyPassword | Defines the proxy password. |   -nonProxyHosts | Defines the hosts that will not be proxied. |   -connectionTimeout | The URL Connection Timeout (in milliseconds). | 10000 -readtimeout | The URL Read Timeout (in milliseconds). | 60000 -failOnError | Whether the build should fail if there is an error executing the update | true +| Property | Description | Default Value | +|-------------------------|------------------------------------------------------------------------------------------------|--------------------------------------------------| +| dataDirectory | Data directory that is used to store the local caches and NVD CVE database | `/data/11.0` | +| failOnError | Whether the build should fail if there is an error executing the update | true | +| proxyServer | The Proxy Server; see the [proxy configuration](../data/proxy.html) page for more information. |   | +| proxyPort | The Proxy Port. |   | +| proxyUsername | Defines the proxy user name. |   | +| proxyPassword | Defines the proxy password. |   | +| nonProxyHosts | Defines the hosts that will not be proxied. |   | +| connectionTimeout | The URL Connection Timeout (in milliseconds). | 10000 | +| readtimeout | The URL Read Timeout (in milliseconds). | 60000 | +| retireJsAnalyzerEnabled | Sets whether the RetireJS Analyzer update and analyzer are enabled. | true | Advanced Configuration ==================== -The following properties can be configured in the plugin. However, they are less frequently changed. One exception -may be the cvedUrl properties, which can be used to host a mirror of the NVD within an enterprise environment. +The following properties can be configured in the plugin. However, they are less frequently changed. -Property | Description | Default Value ----------------------|----------------------------------------------------------------------------------------------------------------------|------------------ -cveUrlModified | URL for the modified CVE JSON data feed. When mirroring the NVD you must mirror the *.json.gz and the *.meta files. Optional if your custom cveUrlBase is just a domain name change. | https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-modified.json.gz -cveUrlBase | Base URL for each year's CVE JSON data feed, the %d will be replaced with the year. | https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-%d.json.gz -cveWaitTime | The time in milliseconds to wait between downloads from the NVD. | 4000 -cveStartYear | The first year of NVD CVE data to download from the NVD. | 2002 -dataDirectory | Data directory that is used to store the local copy of the NVD. This should generally not be changed. | data -databaseDriverName | The name of the database driver. Example: org.h2.Driver. |   -databaseDriverPath | The path to the database driver JAR file; only used if the driver is not in the class path. |   -connectionString | The connection string used to connect to the database. See using a [database server](../data/database.html). |   -databaseUser | The username used when connecting to the database. |   -databasePassword | The password used when connecting to the database. |   -hostedSuppressionsEnabled | Whether the hosted suppression file will be used. | true -hostedSuppressionsUrl | The URL to a mirrored copy of the hosted suppressions file for internet-constrained environments | https://jeremylong.github.io/DependencyCheck/suppressions/publishedSuppressions.xml -hostedSuppressionsValidForHours | Sets the number of hours to wait before checking for new updates of the hosted suppressions file | 2 -hostedSuppressionsForceUpdate | Sets whether the hosted suppressions file should update regardless of the `autoupdate` and validForHours settings | false \ No newline at end of file +| Property | Description | Default Value | +|---------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------| +| nvdApiKey | The API Key to access the NVD API; obtained from https://nvd.nist.gov/developers/request-an-api-key |   | +| nvdApiEndpoint | The NVD API endpoint URL; setting this is uncommon. | https://services.nvd.nist.gov/rest/json/cves/2.0 | +| nvdMaxRetryCount | The maximum number of retry requests for a single call to the NVD API. | 10 | +| nvdApiDelay | The number of milliseconds to wait between calls to the NVD API. | 3500 with an NVD API Key or 8000 without an API Key | +| nvdApiResultsPerPage | The number records for a single page from NVD API (must be <=2000). | 2000 | +| nvdDatafeedUrl | The URL for the NVD API Data feed that can be generated using https://github.com/jeremylong/open-vulnerability-cli/blob/main/README.md#mirroring-the-nvd-cve-data - example value `https://internal.server/cache/nvdcve-{0}.json.gz` |   | +| nvdUser | Credentials used for basic authentication for the NVD API Data feed. |   | +| nvdPassword | Credentials used for basic authentication for the NVD API Data feed. |   | +| nvdValidForHours | The number of hours to wait before checking for new updates from the NVD. The default is 4 hours. | 4 | +| databaseDriverName | The database driver full classname; note, only needs to be set if the driver is not JDBC4 compliant or the JAR is outside of the class path. |   | +| databaseDriverPath | The path to the database driver JAR file; only needs to be set if the driver is not in the class path. |   | +| connectionString | The connection string used to connect to the database. See using a [database server](../data/database.html). |   | +| databaseUser | The username used when connecting to the database. |   | +| databasePassword | The password used when connecting to the database. |   | +| hostedSuppressionsEnabled | Whether the hosted suppression file will be used. | true | +| hostedSuppressionsUrl | The URL to a mirrored copy of the hosted suppressions file for internet-constrained environments | https://dependency-check.github.io/DependencyCheck/suppressions/publishedSuppressions.xml | +| hostedSuppressionsUser | The user for a Basic-auth-protected mirrored copy of the hosted suppressions file for internet-constrained environments |   | +| hostedSuppressionsPassword | The password/token for a Basic-auth-protected mirrored copy of the hosted suppressions file for internet-constrained environments |   | +| hostedSuppressionsBearerToken | The bearer token for a Bearer-auth-protected mirrored copy of the hosted suppressions file for internet-constrained environments |   | +| hostedSuppressionsValidForHours | Sets the number of hours to wait before checking for new updates of the hosted suppressions file | 2 | +| hostedSuppressionsForceUpdate | Sets whether the hosted suppressions file should update regardless of the `autoupdate` and validForHours settings | false | +| retireJsForceUpdate | Sets whether the RetireJS repository should update regardless of the `autoupdate` setting. | false | +| retireJsUrl | The URL to a mirrored copy of the RetireJS repository for internet-constrained environments | https://raw.githubusercontent.com/Retirejs/retire.js/main/repository/jsrepository.json | +| retireJsUrlUser | The user for a Basic-auth-protected mirrored copy of the RetireJS repository for internet-constrained environments |   | +| retireJsUrlPassword | The password/token for a Basic-auth-protected mirrored copy of the RetireJS repository for internet-constrained environments |   | +| retireJsUrlBearerToken | The bearer token for a Bearer-auth-protected mirrored copy of the RetireJS repository for internet-constrained environments |   | +| knownExploitedEnabled | Sets whether the Known Exploited Vulnerability update and analyzer are enabled. | true | +| knownExploitedUrl | Sets URL to the CISA Known Exploited Vulnerabilities JSON data feed. | https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json | +| knownExploitedUser | The user for a Basic-auth-protected mirrored copy of the CISA Known Exploited Vulnerabilities JSON data feed for internet-constrained environments |   | +| knownExploitedPassword | The password/token for a Basic-auth-protected mirrored copy of the CISA Known Exploited Vulnerabilities JSON data feed for internet-constrained environments |   | +| knownExploitedBearerToken | The bearer token for a Bearer-auth-protected mirrored copy of the CISA Known Exploited Vulnerabilities JSON data feed for internet-constrained environments |   | +| knownExploitedValidForHours | Sets the number of hours to wait before checking for new updates of the CISA Known Exploited Vulnerabilities JSON data feed | 24 | diff --git a/ant/src/site/markdown/configuration.md b/ant/src/site/markdown/configuration.md index 155cfe1518c..2eeb1a5b566 100644 --- a/ant/src/site/markdown/configuration.md +++ b/ant/src/site/markdown/configuration.md @@ -3,22 +3,26 @@ Configuration Once dependency-check-ant has been [installed](index.html) the defined tasks can be used. * dependency-check - the primary task used to check the project dependencies. Configuration options are below. -* dependency-check-purge - deletes the local copy of the NVD; this should rarely be used (if ever). See the [purge configuration](config-purge.html) for more information. -* dependency-check-update - downloads and updates the local copy of the NVD. See the [update configuration](config-update.html) for more information. +* dependency-check-purge - deletes the local copy of the NVD; this should rarely be used (if ever). See + the [purge configuration](config-purge.html) for more information. +* dependency-check-update - downloads and updates the local copy of the NVD. See + the [update configuration](config-update.html) for more information. To configure the dependency-check task you can add it to a target and include a file based [resource collection](http://ant.apache.org/manual/Types/resources.html#collection) -such as a [FileSet](http://ant.apache.org/manual/Types/fileset.html), [DirSet](http://ant.apache.org/manual/Types/dirset.html), +such as +a [FileSet](http://ant.apache.org/manual/Types/fileset.html), [DirSet](http://ant.apache.org/manual/Types/dirset.html), or [FileList](http://ant.apache.org/manual/Types/filelist.html) that includes the project's dependencies. ```xml + - - + + @@ -30,36 +34,37 @@ Configuration: dependency-check Task -------------------- The following properties can be set on the dependency-check task. -Property | Description | Default Value -----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------- -autoUpdate | Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. | true -cveValidForHours | Sets the number of hours to wait before checking for new updates from the NVD | 4 -failOnError | Whether the build should fail if there is an error executing the dependency-check analysis | true -failBuildOnCVSS | Specifies if the build should be failed if a CVSS score equal to or above a specified level is identified. The default is 11 which means since the CVSS scores are 0-10, by default the build will never fail. More information on CVSS scores can be found at the [NVD](https://nvd.nist.gov/vuln-metrics/cvss)| 11 -junitFailOnCVSS | If using the JUNIT report format the junitFailOnCVSS sets the CVSS score threshold that is considered a failure. | 0 -prettyPrint | Whether the XML and JSON formatted reports should be pretty printed. | false -projectName | The name of the project being scanned. | Dependency-Check -reportFormat | The report format to be generated (HTML, XML, CSV, JSON, JUNIT, SARIF, ALL). | HTML -reportOutputDirectory | The location to write the report(s). Note, this is not used if generating the report as part of a `mvn site` build | 'target' -hintsFile | The file path to the XML hints file \- used to resolve [false negatives](../general/hints.html) |   -proxyServer | The Proxy Server; see the [proxy configuration](../data/proxy.html) page for more information. |   -proxyPort | The Proxy Port. |   -proxyUsername | Defines the proxy user name. |   -proxyPassword | Defines the proxy password. |   -nonProxyHosts | Defines the hosts that will not be proxied. |   -connectionTimeout | The URL Connection Timeout. |   -enableExperimental | Enable the [experimental analyzers](../analyzers/index.html). If not enabled the experimental analyzers (see below) will not be loaded or used. | false -enableRetired | Enable the [retired analyzers](../analyzers/index.html). If not enabled the retired analyzers (see below) will not be loaded or used. | false -suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../general/suppression.html). The parameter value can be a local file path, a URL to a suppression file, or even a reference to a file on the class path (see https://github.com/jeremylong/DependencyCheck/issues/1878#issuecomment-487533799) |   -junitFailOnCVSS | If using the JUNIT report format the junitFailOnCVSS sets the CVSS score threshold that is considered a failure. | 0 +| Property | Description | Default Value | +|----------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------| +| autoUpdate | Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not recommended that this be turned to false. | true | +| failBuildOnCVSS | Specifies if the build should be failed if a CVSS score equal to or above a specified level is identified. The default is 11 which means since the CVSS scores are 0-10, by default the build will never fail. More information on CVSS scores can be found at the [NVD](https://nvd.nist.gov/vuln-metrics/cvss) | 11 | +| junitFailOnCVSS | If using the JUNIT report format the junitFailOnCVSS sets the CVSS score threshold that is considered a failure. | 0 | +| prettyPrint | Whether the XML and JSON formatted reports should be pretty printed. | false | +| projectName | The name of the project being scanned. | Dependency-Check | +| reportFormat | The report format to be generated (HTML, XML, CSV, JSON, JUNIT, SARIF, JENKINS, GITLAB, ALL). | HTML | +| reportOutputDirectory | The location to write the report(s). Note, this is not used if generating the report as part of a `mvn site` build | 'target' | +| hintsFile | The file path to the XML hints file \- used to resolve [false negatives](../general/hints.html) |   | +| dataDirectory | Data directory that is used to store the local caches and NVD CVE database | `/data/11.0` | +| failOnError | Whether the build should fail if there is an error executing the dependency-check analysis | true | +| proxyServer | The Proxy Server; see the [proxy configuration](../data/proxy.html) page for more information. |   | +| proxyPort | The Proxy Port. |   | +| proxyUsername | Defines the proxy user name. |   | +| proxyPassword | Defines the proxy password. |   | +| nonProxyHosts | Defines the hosts that will not be proxied. |   | +| connectionTimeout | The URL Connection Timeout (in milliseconds). | 10000 | +| readtimeout | The URL Read Timeout (in milliseconds). | 60000 | +| enableExperimental | Enable the [experimental analyzers](../analyzers/index.html). If not enabled the experimental analyzers (see below) will not be loaded or used. | false | +| enableRetired | Enable the [retired analyzers](../analyzers/index.html). If not enabled the retired analyzers (see below) will not be loaded or used. | false | +| suppressionFile | The file path to the XML suppression file \- used to suppress [false positives](../general/suppression.html). The parameter value can be a local file path, a URL to a suppression file, or even a reference to a file on the class path (see https://github.com/dependency-check/DependencyCheck/issues/1878#issuecomment-487533799) |   | +| failBuildOnUnusedSuppressionRule | Specifies that if any unused suppression rule is found, the build will fail. | false | +| junitFailOnCVSS | If using the JUNIT report format the junitFailOnCVSS sets the CVSS score threshold that is considered a failure. | 0 | The following nested elements can be set on the dependency-check task. -Element | Property | Description | Default Value -------------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------- -suppressionFile | path | The file path to the XML suppression file \- used to suppress [false positives](../general/suppression.html). Element can be specified multiple times. The parameter value can be a local file path, a URL to a suppression file, or even a reference to a file on the class path (see https://github.com/jeremylong/DependencyCheck/issues/1878#issuecomment-487533799) |  |   -reportFormat | format | The report format to be generated (HTML, XML, CSV, JSON, JUNIT, SARIF, ALL). Element can be specified multiple times. |   - +| Element | Property | Description | Default Value | +|-----------------|----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------| +| suppressionFile | path | The file path to the XML suppression file \- used to suppress [false positives](../general/suppression.html). Element can be specified multiple times. The parameter value can be a local file path, a URL to a suppression file, or even a reference to a file on the class path (see https://github.com/dependency-check/DependencyCheck/issues/1878#issuecomment-487533799) |   |   +| reportFormat | format | The report format to be generated (HTML, XML, CSV, JSON, JUNIT, SARIF, JENKINS, GITLAB, ALL). Element can be specified multiple times. |   | Analyzer Configuration ==================== @@ -69,92 +74,115 @@ Note, that specific analyzers will automatically disable themselves if no file types that they support are detected - so specifically disabling them may not be needed. -Property | Description | Default Value -------------------------------------|------------------------------------------------------------------------------------------------------------|------------------ -archiveAnalyzerEnabled | Sets whether the Archive Analyzer will be used. | true -zipExtensions | A comma-separated list of additional file extensions to be treated like a ZIP file, the contents will be extracted and analyzed. |   -jarAnalyzer | Sets whether the Jar Analyzer will be used. | true -centralAnalyzerEnabled | Sets whether the Central Analyzer will be used. **Disabling this analyzer for Ant builds is not recommended as it could lead to false negatives (e.g. libraries that have vulnerabilities may not be reported correctly).** If this analyzer is being disabled there is a good chance you also want to disable the Nexus Analyzer (see below). | true -centralAnalyzerUseCache | Sets whether the Central Analyer will cache results. Cached results expire after 30 days. | true -dartAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Dart Analyzer will be used. | true -knownExploitedEnabled | Sets whether the Known Exploited Vulnerability update and analyzer are enabled. | true -knownExploitedUrl | Sets URL to the CISA Known Exploited Vulnerabilities JSON data feed. | https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json -ossIndexAnalyzerEnabled | Sets whether the [OSS Index Analyzer](../analyzers/oss-index-analyzer.html) will be enabled. This analyzer requires an internet connection. | true -ossindexAnalyzerUseCache | Sets whether the OSS Index Analyzer will cache results. Cached results expire after 24 hours. | true -ossindexAnalyzerUsername | Sets the username for OSS Index - note an account with OSS Index is not required. |   -ossindexAnalyzerPassword | Sets the password for OSS Index. |   -ossIndexAnalyzerWarnOnlyOnRemoteErrors | Whether we should only warn about Sonatype OSS Index remote errors instead of failing completely. |   -nexusAnalyzerEnabled | Sets whether Nexus Analyzer will be used (requires Nexus Pro). This analyzer is superceded by the Central Analyzer; however, you can configure this to run against a Nexus Pro installation. | true -nexusUrl | Defines the Nexus web service endpoint (example http://domain.enterprise/nexus/service/local/). If not set the Nexus Analyzer will be disabled. |   -nexusUser | The username to authenticate to the Nexus Server's web service end point. If not set the Nexus Analyzer will use an unauthenticated connection. |   -nexusPassword | The password to authenticate to the Nexus Server's web service end point. If not set the Nexus Analyzer will use an unauthenticated connection. |   -nexusUsesProxy | Whether the defined proxy should be used when connecting to Nexus. | true -artifactoryAnalyzerEnabled | Sets whether Artifactory analyzer will be used | false -artifactoryAnalyzerUrl | The Artifactory server URL. |   -artifactoryAnalyzerUseProxy | Whether Artifactory should be accessed through a proxy or not. | false -artifactoryAnalyzerParallelAnalysis | Whether the Artifactory analyzer should be run in parallel or not | true -artifactoryAnalyzerUsername | The user name (only used with API token) to connect to Artifactory instance |   -artifactoryAnalyzerApiToken | The API token to connect to Artifactory instance, only used if the username or the API key are not defined by artifactoryAnalyzerServerId,artifactoryAnalyzerUsername or artifactoryAnalyzerApiToken |   -artifactoryAnalyzerBearerToken | The bearer token to connect to Artifactory instance |   -pyDistributionAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Python Distribution Analyzer will be used. `enableExperimental` must be set to true. | true -pyPackageAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Python Package Analyzer will be used. `enableExperimental` must be set to true. | true -rubygemsAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Ruby Gemspec Analyzer will be used. `enableExperimental` must be set to true. | true -opensslAnalyzerEnabled | Sets whether the openssl Analyzer should be used. | true -cmakeAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) CMake Analyzer should be used. `enableExperimental` must be set to true. | true -autoconfAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) autoconf Analyzer should be used. `enableExperimental` must be set to true. | true -pipAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) pip Analyzer should be used. `enableExperimental` must be set to true. | true -pipfileAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Pipfile Analyzer should be used. `enableExperimental` must be set to true. | true -poetryAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Poetry Analyzer should be used. `enableExperimental` must be set to true. | true -composerAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) PHP Composer Lock File Analyzer should be used. `enableExperimental` must be set to true. | true -cpanfileAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Perl CPAN File Analyzer should be used. `enableExperimental` must be set to true. | true -nodeAnalyzerEnabled | Sets whether the [retired](../analyzers/index.html) Node.js Analyzer should be used. | true -nodeAuditAnalyzerEnabled | Sets whether the Node Audit Analyzer should be used. This analyzer requires an internet connection. | true -nodeAuditAnalyzerUseCache | Sets whether the Node Audit Analyzer will cache results. Cached results expire after 24 hours. | true -nodeAuditSkipDevDependencies | Sets whether the Node Audit Analyzer will skip devDependencies. | false -nodePackageSkipDevDependencies | Sets whether the Node Package Analyzer will skip devDependencies. | false -yarnAuditAnalyzerEnabled | Sets whether the Yarn Audit Analyzer should be used. This analyzer requires yarn and an internet connection. Use `nodeAuditSkipDevDependencies` to skip dev dependencies. | true -pnpmAuditAnalyzerEnabled | Sets whether the Pnpm Audit Analyzer should be used. This analyzer requires pnpm and an internet connection. Use `nodeAuditSkipDevDependencies` to skip dev dependencies. | true -pathToYarn | The path to `yarn`. |   -pathToPnpm | The path to `pnpm`. |   -retireJsAnalyzerEnabled | Sets whether the RetireJS Analyzer should be used. | true -retireJsForceUpdate | Sets whether the RetireJS Analyzer should update regardless of the `autoupdate` setting. | false -retirejsFilterNonVulnerable | Configures the RetireJS Analyzer to remove non-vulnerable JS dependencies from the report. | false -retirejsFilter | A nested configuration that can be specified multple times; The regex defined is used to filter JS files based on content. |   -retireJsUrl | The URL to the Retire JS repository. | https://raw.githubusercontent.com/Retirejs/retire.js/main/repository/jsrepository.json -nuspecAnalyzerEnabled | Sets whether the .NET Nuget Nuspec Analyzer will be used. | true -nugetconfAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) .NET Nuget packages.config Analyzer will be used. `enableExperimental` must be set to true. | true -cocoapodsAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Cocoapods Analyzer should be used. `enableExperimental` must be set to true. | true -mixAuditAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Mix Audit Analyzer should be used. `enableExperimental` must be set to true. | true -mixAuditPath | Sets the path to the mix_audit executable; only used if mix audit analyzer is enabled and experimental analyzers are enabled. |   -bundleAuditAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Bundle Audit Analyzer should be used. `enableExperimental` must be set to true. | true -bundleAuditPath | Sets the path to the bundle audit executable; only used if bundle audit analyzer is enabled and experimental analyzers are enabled. |   -swiftPackageManagerAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Swift Package Analyzer should be used. `enableExperimental` must be set to true. | true -swiftPackageResolvedAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Swift Package Resolved should be used. `enableExperimental` must be set to true. | true -assemblyAnalyzerEnabled | Sets whether the .NET Assembly Analyzer should be used. | true -msbuildAnalyzerEnabled | Sets whether the MSBuild Analyzer should be used. | true -pathToCore | The path to dotnet core .NET assembly analysis on non-windows systems. |   -golangDepEnabled | Sets whether the [experimental](../analyzers/index.html) Golang Dependency Analyzer should be used. `enableExperimental` must be set to true. | true -golangModEnabled | Sets whether the [experimental](../analyzers/index.html) Goland Module Analyzer should be used; requires `go` to be installed. `enableExperimental` must be set to true. | true -pathToGo | The path to `go`. |   +| Property | Description | Default Value | +|----------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------| +| archiveAnalyzerEnabled | Sets whether the Archive Analyzer will be used. | true | +| zipExtensions | A comma-separated list of additional file extensions to be treated like a ZIP file, the contents will be extracted and analyzed. |   | +| jarAnalyzer | Sets whether the Jar Analyzer will be used. | true | +| centralAnalyzerEnabled | Sets whether the Central Analyzer will be used. **Disabling this analyzer for Ant builds is not recommended as it could lead to false negatives (e.g. libraries that have vulnerabilities may not be reported correctly).** If this analyzer is being disabled there is a good chance you also want to disable the Nexus Analyzer (see below). | true | +| centralAnalyzerUseCache | Sets whether the Central Analyer will cache results. Cached results expire after 30 days. | true | +| dartAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Dart Analyzer will be used. | true | +| knownExploitedEnabled | Sets whether the Known Exploited Vulnerability update and analyzer are enabled. | true | +| knownExploitedUrl | Sets URL to the CISA Known Exploited Vulnerabilities JSON data feed. | https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json | +| ossIndexAnalyzerEnabled | Sets whether the [OSS Index Analyzer](../analyzers/oss-index-analyzer.html) will be enabled. This analyzer requires an internet connection. | true | +| ossindexAnalyzerUseCache | Sets whether the OSS Index Analyzer will cache results. Cached results expire after 24 hours. | true | +| ossindexAnalyzerUsername | Sets the username for OSS Index - note an account with OSS Index is not required. |   | +| ossindexAnalyzerPassword | Sets the password for OSS Index. |   | +| ossIndexAnalyzerWarnOnlyOnRemoteErrors | Whether we should only warn about Sonatype OSS Index remote errors instead of failing completely. |   | +| nexusAnalyzerEnabled | Sets whether Nexus Analyzer will be used. This analyzer is an alternative to the Central or Artifactory Analyzers, allowing retrieval from Sonatype Nexus installations. | true | +| nexusUrl | Defines the Nexus web service endpoint (example http://domain.enterprise/nexus/service/local/). If not set the Nexus Analyzer will be disabled. |   | +| nexusUser | The username to authenticate to the Nexus Server's web service end point. If not set the Nexus Analyzer will use an unauthenticated connection. |   | +| nexusPassword | The password to authenticate to the Nexus Server's web service end point. If not set the Nexus Analyzer will use an unauthenticated connection. |   | +| nexusUsesProxy | Whether the defined proxy should be used when connecting to Nexus. | true | +| artifactoryAnalyzerEnabled | Sets whether Artifactory analyzer will be used | false | +| artifactoryAnalyzerUrl | The Artifactory server URL. |   | +| artifactoryAnalyzerUseProxy | Whether Artifactory should be accessed through a proxy or not. | false | +| artifactoryAnalyzerParallelAnalysis | Whether the Artifactory analyzer should be run in parallel or not | true | +| artifactoryAnalyzerUsername | The user name (only used with API token) to connect to Artifactory instance |   | +| artifactoryAnalyzerApiToken | The API token to connect to Artifactory instance, only used if the username or the API key are not defined by artifactoryAnalyzerServerId,artifactoryAnalyzerUsername or artifactoryAnalyzerApiToken |   | +| artifactoryAnalyzerBearerToken | The bearer token to connect to Artifactory instance |   | +| pyDistributionAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Python Distribution Analyzer will be used. `enableExperimental` must be set to true. | true | +| pyPackageAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Python Package Analyzer will be used. `enableExperimental` must be set to true. | true | +| rubygemsAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Ruby Gemspec Analyzer will be used. `enableExperimental` must be set to true. | true | +| opensslAnalyzerEnabled | Sets whether the openssl Analyzer should be used. | true | +| cmakeAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) CMake Analyzer should be used. `enableExperimental` must be set to true. | true | +| autoconfAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) autoconf Analyzer should be used. `enableExperimental` must be set to true. | true | +| pipAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) pip Analyzer should be used. `enableExperimental` must be set to true. | true | +| pipfileAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Pipfile Analyzer should be used. `enableExperimental` must be set to true. | true | +| poetryAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Poetry Analyzer should be used. `enableExperimental` must be set to true. | true | +| composerAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) PHP Composer Lock File Analyzer should be used. `enableExperimental` must be set to true. | true | +| composerAnalyzerSkipDev | Sets whether the [experimental](../analyzers/index.html) PHP Composer Lock File Analyzer should skip "packages-dev" | false | +| cpanfileAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Perl CPAN File Analyzer should be used. `enableExperimental` must be set to true. | true | +| nodeAnalyzerEnabled | Sets whether the [retired](../analyzers/index.html) Node.js Analyzer should be used. | true | +| nodeAuditAnalyzerEnabled | Sets whether the Node Audit Analyzer should be used. This analyzer requires an internet connection. | true | +| nodeAuditAnalyzerUseCache | Sets whether the Node Audit Analyzer will cache results. Cached results expire after 24 hours. | true | +| nodeAuditSkipDevDependencies | Sets whether the Node Audit Analyzer will skip devDependencies. | false | +| nodePackageSkipDevDependencies | Sets whether the Node Package Analyzer will skip devDependencies. | false | +| yarnAuditAnalyzerEnabled | Sets whether the Yarn Audit Analyzer should be used. This analyzer requires yarn and an internet connection. Use `nodeAuditSkipDevDependencies` to skip dev dependencies. | true | +| pnpmAuditAnalyzerEnabled | Sets whether the Pnpm Audit Analyzer should be used. This analyzer requires pnpm and an internet connection. Use `nodeAuditSkipDevDependencies` to skip dev dependencies. | true | +| pathToYarn | The path to `yarn`. |   | +| pathToPnpm | The path to `pnpm`. |   | +| retireJsAnalyzerEnabled | Sets whether the RetireJS Analyzer update and analyzer are enabled. | true | +| retirejsFilterNonVulnerable | Configures the RetireJS Analyzer to remove non-vulnerable JS dependencies from the report. | false | +| retirejsFilter | A nested configuration that can be specified multple times; The regex defined is used to filter JS files based on content. |   | +| nuspecAnalyzerEnabled | Sets whether the .NET Nuget Nuspec Analyzer will be used. | true | +| nugetconfAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) .NET Nuget packages.config Analyzer will be used. `enableExperimental` must be set to true. | true | +| libmanAnalyzerEnabled | Sets whether the Libman Analyzer will be used. | true | +| cocoapodsAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Cocoapods Analyzer should be used. `enableExperimental` must be set to true. | true | +| carthageAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Carthage Analyzer should be used. `enableExperimental` must be set to true. | true | +| mixAuditAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Mix Audit Analyzer should be used. `enableExperimental` must be set to true. | true | +| mixAuditPath | Sets the path to the mix_audit executable; only used if mix audit analyzer is enabled and experimental analyzers are enabled. |   | +| bundleAuditAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Bundle Audit Analyzer should be used. `enableExperimental` must be set to true. | true | +| bundleAuditPath | Sets the path to the bundle audit executable; only used if bundle audit analyzer is enabled and experimental analyzers are enabled. |   | +| swiftPackageManagerAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Swift Package Analyzer should be used. `enableExperimental` must be set to true. | true | +| swiftPackageResolvedAnalyzerEnabled | Sets whether the [experimental](../analyzers/index.html) Swift Package Resolved should be used. `enableExperimental` must be set to true. | true | +| assemblyAnalyzerEnabled | Sets whether the .NET Assembly Analyzer should be used. | true | +| msbuildAnalyzerEnabled | Sets whether the MSBuild Analyzer should be used. | true | +| pathToCore | The path to dotnet core .NET assembly analysis on non-windows systems. |   | +| golangDepEnabled | Sets whether the [experimental](../analyzers/index.html) Golang Dependency Analyzer should be used. `enableExperimental` must be set to true. | true | +| golangModEnabled | Sets whether the [experimental](../analyzers/index.html) Goland Module Analyzer should be used; requires `go` to be installed. `enableExperimental` must be set to true. | true | +| pathToGo | The path to `go`. |   | +| versionCheckEnabled | Whether dependency-check should check if a new version of dependency-check-maven exists. | true | Advanced Configuration ==================== -The following properties can be configured in the plugin. However, they are less frequently changed. One exception -may be the cvedUrl properties, which can be used to host a mirror of the NVD within an enterprise environment. +The following properties can be configured in the plugin. However, they are less frequently changed. -Property | Description | Default Value ----------------------|--------------------------------------------------------------------------|------------------ -cveUrlModified | URL for the modified CVE JSON data feed. When mirroring the NVD you must mirror the *.json.gz and the *.meta files. Optional if your custom cveUrlBase is just a domain name change. | https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-modified.json.gz -cveUrlBase | Base URL for each year's CVE JSON data feed, the %d will be replaced with the year. | https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-%d.json.gz -cveWaitTime | The time in milliseconds to wait between downloads from the NVD. | 4000 -cveStartYear | The first year of NVD CVE data to download from the NVD. | 2002 -dataDirectory | Data directory that is used to store the local copy of the NVD. This should generally not be changed. | data -databaseDriverName | The name of the database driver. Example: org.h2.Driver. |   -databaseDriverPath | The path to the database driver JAR file; only used if the driver is not in the class path. |   -connectionString | The connection string used to connect to the database. See using a [database server](../data/database.html). |   -databaseUser | The username used when connecting to the database. |   -databasePassword | The password used when connecting to the database. |   -hostedSuppressionsEnabled | Whether the hosted suppression file will be used. | true -hostedSuppressionsUrl | The URL to a mirrored copy of the hosted suppressions file for internet-constrained environments | https://jeremylong.github.io/DependencyCheck/suppressions/publishedSuppressions.xml -hostedSuppressionsValidForHours | Sets the number of hours to wait before checking for new updates of the hosted suppressions file | 2 -hostedSuppressionsForceUpdate | Sets whether the hosted suppressions file should update regardless of the `autoupdate` and validForHours settings | false \ No newline at end of file +| Property | Description | Default Value | +|---------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------| +| nvdApiKey | The API Key to access the NVD API; obtained from https://nvd.nist.gov/developers/request-an-api-key |   | +| nvdApiEndpoint | The NVD API endpoint URL; setting this is uncommon. | https://services.nvd.nist.gov/rest/json/cves/2.0 | +| nvdMaxRetryCount | The maximum number of retry requests for a single call to the NVD API. | 10 | +| nvdApiDelay | The number of milliseconds to wait between calls to the NVD API. | 3500 with an NVD API Key or 8000 without an API Key | +| nvdApiResultsPerPage | The number records for a single page from NVD API (must be <=2000). | 2000 | +| nvdDatafeedUrl | The URL for the NVD API Data feed that can be generated using https://github.com/jeremylong/open-vulnerability-cli/blob/main/README.md#mirroring-the-nvd-cve-data - example value `https://internal.server/cache/nvdcve-{0}.json.gz` |   | +| nvdUser | Credentials used for basic authentication for the NVD API Data feed. |   | +| nvdPassword | Credentials used for basic authentication for the NVD API Data feed. |   | +| nvdValidForHours | The number of hours to wait before checking for new updates from the NVD. The default is 4 hours. | 4 | +| databaseDriverName | The database driver full classname; note, only needs to be set if the driver is not JDBC4 compliant or the JAR is outside of the class path. |   | +| databaseDriverPath | The path to the database driver JAR file; only needs to be set if the driver is not in the class path. |   | +| connectionString | The connection string used to connect to the database. See using a [database server](../data/database.html). |   | +| databaseUser | The username used when connecting to the database. |   | +| databasePassword | The password used when connecting to the database. |   | +| hostedSuppressionsEnabled | Whether the hosted suppression file will be used. | true | +| hostedSuppressionsUrl | The URL to a mirrored copy of the hosted suppressions file for internet-constrained environments | https://dependency-check.github.io/DependencyCheck/suppressions/publishedSuppressions.xml | +| hostedSuppressionsUser | The user for a Basic-auth-protected mirrored copy of the hosted suppressions file for internet-constrained environments |   | +| hostedSuppressionsPassword | The password/token for a Basic-auth-protected mirrored copy of the hosted suppressions file for internet-constrained environments |   | +| hostedSuppressionsBearerToken | The bearer token for a Bearer-auth-protected mirrored copy of the hosted suppressions file for internet-constrained environments |   | +| hostedSuppressionsValidForHours | Sets the number of hours to wait before checking for new updates of the hosted suppressions file | 2 | +| hostedSuppressionsForceUpdate | Sets whether the hosted suppressions file should update regardless of the `autoupdate` and validForHours settings | false | +| retireJsForceUpdate | Sets whether the RetireJS repository should update regardless of the `autoupdate` setting. | false | +| retireJsUrl | The URL to a mirrored copy of the RetireJS repository for internet-constrained environments | https://raw.githubusercontent.com/Retirejs/retire.js/main/repository/jsrepository.json | +| retireJsUrlUser | The user for a Basic-auth-protected mirrored copy of the RetireJS repository for internet-constrained environments |   | +| retireJsUrlPassword | The password/token for a Basic-auth-protected mirrored copy of the RetireJS repository for internet-constrained environments |   | +| retireJsUrlBearerToken | The bearer token for a Bearer-auth-protected mirrored copy of the RetireJS repository for internet-constrained environments |   | +| suppressionFileUser | The user for Basic-auth-protected suppression files hosted on a webserver |   | +| suppressionFilePassword | The password/token for Basic-auth-protected suppression files hosted on a webserver |   | +| suppressionFileBearerToken | The bearer token for Bearer-auth-protected suppression files hosted on a webserver |   | +| knownExploitedEnabled | Sets whether the Known Exploited Vulnerability update and analyzer are enabled. | true | +| knownExploitedUrl | Sets URL to the CISA Known Exploited Vulnerabilities JSON data feed. | https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json | +| knownExploitedUser | The user for a Basic-auth-protected mirrored copy of the CISA Known Exploited Vulnerabilities JSON data feed for internet-constrained environments |   | +| knownExploitedPassword | The password/token for a Basic-auth-protected mirrored copy of the CISA Known Exploited Vulnerabilities JSON data feed for internet-constrained environments |   | +| knownExploitedBearerToken | The bearer token for a Bearer-auth-protected mirrored copy of the CISA Known Exploited Vulnerabilities JSON data feed for internet-constrained environments |   | +| knownExploitedValidForHours | Sets the number of hours to wait before checking for new updates of the CISA Known Exploited Vulnerabilities JSON data feed | 24 | + \ No newline at end of file diff --git a/ant/src/site/markdown/index.md.vm b/ant/src/site/markdown/index.md.vm index a0b18eb03ce..77f85c1bd90 100644 --- a/ant/src/site/markdown/index.md.vm +++ b/ant/src/site/markdown/index.md.vm @@ -7,12 +7,12 @@ identifiers, and the associated Common Vulnerability and Exposure (CVE) entries. Installation ==================== -1. Import the GPG key used to sign all Dependency Check releases: `gpg --keyserver hkp://keys.gnupg.net --recv-keys 259A55407DD6C00299E6607EFFDE55BE73A2D1ED`. -2. Download dependency-check-ant from [github here](https://github.com/jeremylong/DependencyCheck/releases/download/v${project.version}/dependency-check-ant-${project.version}-release.zip) and the associated GPG signature file from the [GitHub release](https://github.com/jeremylong/DependencyCheck/releases/download/v${project.version}/dependency-check-ant-${project.version}-release.zip.asc). +1. Import the GPG key used to sign all Dependency Check releases: `gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 259A55407DD6C00299E6607EFFDE55BE73A2D1ED`. +2. Download dependency-check-ant from [github here](https://github.com/dependency-check/DependencyCheck/releases/download/v${project.version}/dependency-check-ant-${project.version}-release.zip) and the associated GPG signature file from the [GitHub release](https://github.com/dependency-check/DependencyCheck/releases/download/v${project.version}/dependency-check-ant-${project.version}-release.zip.asc). 3. Verify the cryptographic integrity of your download: `gpg --verify dependency-check-ant-${project.version}-release.zip.asc`. 4. Unzip the archive 5. Add the taskdef to your build.xml: - +#[[ ```xml @@ -26,6 +26,7 @@ Installation ``` +]]# 6. Use the defined taskdefs: * [dependency-check](configuration.html) - the primary task used to check the project dependencies. * [dependency-check-purge](config-purge.html) - deletes the local copy of the NVD; this should rarely be used (if ever). @@ -34,7 +35,10 @@ Installation It is important to understand that the first time this task is executed it may take 10 minutes or more as it downloads and processes the data from the National -Vulnerability Database (NVD) hosted by NIST: https://nvd.nist.gov +Vulnerability Database (NVD) hosted by NIST: https://nvd.nist.gov. After the first batch download, as long as the task is executed at least once every seven days the update will only take a few seconds. + +The Dependency-Check team strongly recommends to [mirror the NVD database](../data/mirrornvd.html) for any operational +integration. If not done, any service disruption of the NVD database will make the usage of Dependency-Check difficult. diff --git a/ant/src/site/site.xml b/ant/src/site/site.xml index 3712590ed84..797f326f273 100644 --- a/ant/src/site/site.xml +++ b/ant/src/site/site.xml @@ -16,11 +16,11 @@ limitations under the License. Copyright (c) 2013 Jeremy Long. All Rights Reserved. --> - + - OWASP dependency-check-ant - OWASP dependency-check-ant - ./images/dc-ant.svg + OWASP dependency-check-ant @@ -31,5 +31,6 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved.

+ - \ No newline at end of file + \ No newline at end of file diff --git a/ant/src/test/java/org/owasp/dependencycheck/taskdefs/DependencyCheckTaskIT.java b/ant/src/test/java/org/owasp/dependencycheck/taskdefs/DependencyCheckTaskIT.java index a020d72092e..67b23f4819f 100644 --- a/ant/src/test/java/org/owasp/dependencycheck/taskdefs/DependencyCheckTaskIT.java +++ b/ant/src/test/java/org/owasp/dependencycheck/taskdefs/DependencyCheckTaskIT.java @@ -17,29 +17,28 @@ */ package org.owasp.dependencycheck.taskdefs; -import java.io.File; - import org.apache.tools.ant.BuildException; import org.apache.tools.ant.BuildFileRule; import org.apache.tools.ant.types.LogLevel; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.owasp.dependencycheck.BaseDBTestCase; -import static org.junit.Assert.assertTrue; +import java.io.File; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * * @author Jeremy Long */ -public class DependencyCheckTaskIT extends BaseDBTestCase { +class DependencyCheckTaskIT extends BaseDBTestCase { - @Rule - public final BuildFileRule buildFileRule = new BuildFileRule(); + private final BuildFileRule buildFileRule = new BuildFileRule(); - @Before + @BeforeEach @Override public void setUp() throws Exception { super.setUp(); @@ -47,17 +46,28 @@ public void setUp() throws Exception { buildFileRule.configureProject(buildFile, LogLevel.VERBOSE.getLevel()); } + @AfterEach + @Override + public void tearDown() throws Exception { + if (buildFileRule.getProject() != null) { + if (this.buildFileRule.getProject().getTargets().containsKey("tearDown")) { + this.buildFileRule.getProject().executeTarget("tearDown"); + } + } + super.tearDown(); + } + /** * Test of addFileSet method, of class DependencyCheckTask. */ @Test - public void testAddFileSet() throws Exception { + void testAddFileSet() throws Exception { File report = new File("target/dependency-check-report.html"); if (report.exists() && !report.delete()) { throw new Exception("Unable to delete 'target/dependency-check-report.html' prior to test."); } buildFileRule.executeTarget("test.fileset"); - assertTrue("DependencyCheck report was not generated", report.exists()); + assertTrue(report.exists(), "DependencyCheck report was not generated"); } /** @@ -66,7 +76,7 @@ public void testAddFileSet() throws Exception { * @throws Exception */ @Test - public void testAddFileList() throws Exception { + void testAddFileList() throws Exception { File report = new File("target/dependency-check-report.xml"); if (report.exists()) { if (!report.delete()) { @@ -75,7 +85,7 @@ public void testAddFileList() throws Exception { } buildFileRule.executeTarget("test.filelist"); - assertTrue("DependencyCheck report was not generated", report.exists()); + assertTrue(report.exists(), "DependencyCheck report was not generated"); } /** @@ -84,7 +94,7 @@ public void testAddFileList() throws Exception { * @throws Exception */ @Test - public void testAddDirSet() throws Exception { + void testAddDirSet() throws Exception { File report = new File("target/dependency-check-report.csv"); if (report.exists()) { if (!report.delete()) { @@ -92,11 +102,11 @@ public void testAddDirSet() throws Exception { } } buildFileRule.executeTarget("test.dirset"); - assertTrue("DependencyCheck report was not generated", report.exists()); + assertTrue(report.exists(), "DependencyCheck report was not generated"); } @Test - public void testNestedReportFormat() throws Exception { + void testNestedReportFormat() throws Exception { File reportHTML = new File("target/dependency-check-report.html"); File reportCSV = new File("target/dependency-check-report.csv"); if (reportCSV.exists()) { @@ -110,38 +120,37 @@ public void testNestedReportFormat() throws Exception { } } buildFileRule.executeTarget("test.formatNested"); - assertTrue("DependencyCheck CSV report was not generated", reportCSV.exists()); - assertTrue("DependencyCheck HTML report was not generated", reportHTML.exists()); + assertTrue(reportCSV.exists(), "DependencyCheck CSV report was not generated"); + assertTrue(reportHTML.exists(), "DependencyCheck HTML report was not generated"); } @Test - public void testNestedBADReportFormat() throws Exception { - try { - buildFileRule.executeTarget("test.formatBADNested"); - Assert.fail("Should have had a buildExceotion for a bad format attribute"); - } catch (BuildException e) { - assertTrue("Message did not have BAD, unexpected exception: " + e.getMessage(), e.getMessage().contains("BAD is not a legal value for this attribute")); - } + void testNestedBADReportFormat() { + BuildException e = assertThrows(BuildException.class, + () -> buildFileRule.executeTarget("test.formatBADNested"), + "Should have had a buildException for a bad format attribute"); + assertTrue(e.getMessage().contains("BAD is not a legal value for this attribute"), + "Message did not have BAD, unexpected exception: " + e.getMessage()); } /** * Test of getFailBuildOnCVSS method, of class DependencyCheckTask. */ @Test - public void testGetFailBuildOnCVSS() { - Exception exception = Assert.assertThrows(BuildException.class, () -> buildFileRule.executeTarget("failCVSS")); + void testGetFailBuildOnCVSS() { + Exception exception = assertThrows(BuildException.class, () -> buildFileRule.executeTarget("failCVSS")); String expectedMessage = String.format("One or more dependencies were identified with vulnerabilities that " + "have a CVSS score greater than or equal to '%.1f':", 3.0f); - Assert.assertTrue(exception.getMessage().contains(expectedMessage)); + assertTrue(exception.getMessage().contains(expectedMessage)); } /** * Test the DependencyCheckTask where a CVE is suppressed. */ @Test - public void testSuppressingCVE() { + void testSuppressingCVE() { // GIVEN an ant task with a vulnerability final String antTaskName = "suppression"; @@ -157,7 +166,7 @@ public void testSuppressingCVE() { // THEN the ant task executed without error final File report = new File("target/suppression-report.html"); - assertTrue("Expected the DependencyCheck report to be generated", report.exists()); + assertTrue(report.exists(), "Expected the DependencyCheck report to be generated"); } /** @@ -165,7 +174,7 @@ public void testSuppressingCVE() { * exception with a warning. */ @Test - public void testSuppressingSingle() { + void testSuppressingSingle() { // GIVEN an ant task with a vulnerability using the legacy property final String antTaskName = "suppression-single"; // WHEN executing the ant task @@ -173,7 +182,7 @@ public void testSuppressingSingle() { // THEN the ant task executed without error final File report = new File("target/suppression-single-report.html"); - assertTrue("Expected the DependencyCheck report to be generated", report.exists()); + assertTrue(report.exists(), "Expected the DependencyCheck report to be generated"); } /** @@ -181,7 +190,7 @@ public void testSuppressingSingle() { * exception with a warning. */ @Test - public void testSuppressingMultiple() { + void testSuppressingMultiple() { // GIVEN an ant task with a vulnerability using multiple was to configure the suppression file final String antTaskName = "suppression-multiple"; // WHEN executing the ant task @@ -189,14 +198,14 @@ public void testSuppressingMultiple() { // THEN the ant task executed without error final File report = new File("target/suppression-multiple-report.html"); - assertTrue("Expected the DependencyCheck report to be generated", report.exists()); + assertTrue(report.exists(), "Expected the DependencyCheck report to be generated"); } /** * Test the DependencyCheckTask retireJS configuration. */ @Test - public void testRetireJsConfiguration() { + void testRetireJsConfiguration() { // GIVEN an ant task with a vulnerability using multiple was to configure the suppression file final String antTaskName = "retireJS"; @@ -205,6 +214,6 @@ public void testRetireJsConfiguration() { // THEN the ant task executed without error final File report = new File("target/retirejs-report.html"); - assertTrue("Expected the DependencyCheck report to be generated", report.exists()); + assertTrue(report.exists(), "Expected the DependencyCheck report to be generated"); } } diff --git a/ant/src/test/java/org/owasp/dependencycheck/taskdefs/UpdateTest.java b/ant/src/test/java/org/owasp/dependencycheck/taskdefs/UpdateTest.java deleted file mode 100644 index 27b77fc031c..00000000000 --- a/ant/src/test/java/org/owasp/dependencycheck/taskdefs/UpdateTest.java +++ /dev/null @@ -1,90 +0,0 @@ -package org.owasp.dependencycheck.taskdefs; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.core.Is.is; - -import org.junit.Test; -import org.owasp.dependencycheck.BaseTest; -import org.owasp.dependencycheck.utils.Settings; - -public class UpdateTest extends BaseTest { - - @Test - public void testPopulateSettingsShouldSetDefaultValueToCveUrlModified() throws Exception { - // Given - System.clearProperty(Settings.KEYS.CVE_MODIFIED_JSON); - System.clearProperty(Settings.KEYS.CVE_BASE_JSON); - - final Update update = new Update(); - update.setCveUrlModified(null); - update.setCveUrlBase("https://my-custom-mirror-of-nvd/feeds/json/cve/1.1/nvdcve-1.1-%d.json.gz"); - - // When - update.populateSettings(); - - // Then - String output = update.getSettings().getString(Settings.KEYS.CVE_MODIFIED_JSON); - String expectedOutput = "https://my-custom-mirror-of-nvd/feeds/json/cve/1.1/nvdcve-1.1-modified.json.gz"; - assertThat("cveUrlModified must be set to a default of the same model", output, is(expectedOutput)); - } - - @Test - public void testPopulateSettingsShouldSetDefaultValueToCveUrlModifiedWhenCveUrlModifiedIsEmpty() throws Exception { - // Given - System.clearProperty(Settings.KEYS.CVE_MODIFIED_JSON); - System.clearProperty(Settings.KEYS.CVE_BASE_JSON); - - final Update update = new Update(); - update.setCveUrlModified(""); - update.setCveUrlBase("https://my-custom-mirror-of-nvd/feeds/json/cve/1.1/nvdcve-1.1-%d.json.gz"); - - // When - update.populateSettings(); - - // Then - String output = update.getSettings().getString(Settings.KEYS.CVE_MODIFIED_JSON); - String expectedOutput = "https://my-custom-mirror-of-nvd/feeds/json/cve/1.1/nvdcve-1.1-modified.json.gz"; - assertThat("cveUrlModified must be set to a default of the same model when arg is empty", output, - is(expectedOutput)); - } - - @Test - public void testPopulateSettingsShouldNotSetDefaultValueToCveUrlModifiedWhenValueIsExplicitelySet() throws Exception { - // Given - System.clearProperty(Settings.KEYS.CVE_MODIFIED_JSON); - System.clearProperty(Settings.KEYS.CVE_BASE_JSON); - - final Update update = new Update(); - update.setCveUrlModified("https://another-custom-mirror-of-nvd/feeds/json/cve/1.1/nvdcve-1.1-modified.json.gz"); - update.setCveUrlBase("https://my-custom-mirror-of-nvd/feeds/json/cve/1.1/some-unusual-file-name-%d.json.gz"); - - // When - update.populateSettings(); - - // Then - String output = update.getSettings().getString(Settings.KEYS.CVE_MODIFIED_JSON); - String expectedOutput = "https://another-custom-mirror-of-nvd/feeds/json/cve/1.1/nvdcve-1.1-modified.json.gz"; - assertThat("cveUrlModified must be set to the specified value", output, is(expectedOutput)); - } - - @Test - public void testPopulateSettingsShouldNotSetDefaultValueToCveUrlModifiedWhenUnknownValueIsSet() throws Exception { - // Given - System.clearProperty(Settings.KEYS.CVE_MODIFIED_JSON); - System.clearProperty(Settings.KEYS.CVE_BASE_JSON); - - final Update update = new Update(); - update.setCveUrlModified(null); - update.setCveUrlBase("https://my-custom-mirror-of-nvd/feeds/json/cve/1.1/some-unusual-file-name-%d.json.gz"); - - // When - update.populateSettings(); - - // Then - String output = update.getSettings().getString(Settings.KEYS.CVE_MODIFIED_JSON); - String expectedOutput = "https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-modified.json.gz"; - assertThat("cveUrlModified must not be set when name is not the same as from the nvd datasource", output, - is(expectedOutput)); - } - -} diff --git a/archetype/pom.xml b/archetype/pom.xml index 6d2a53031bc..75c34eea3f7 100644 --- a/archetype/pom.xml +++ b/archetype/pom.xml @@ -20,30 +20,23 @@ Copyright (c) 2017 Jeremy Long. All Rights Reserved. org.owasp dependency-check-parent - 8.2.2-SNAPSHOT + 12.1.9-SNAPSHOT dependency-check-plugin Dependency-Check Plugin Archetype jar - 2023-03-23T10:32:22Z + 2025-10-13T14:24:18Z - scm:git:https://github.com/jeremylong/DependencyCheck.git - https://github.com/jeremylong/DependencyCheck/tree/main/archetype - scm:git:git@github.com:jeremylong/DependencyCheck.git + scm:git:https://github.com/dependency-check/DependencyCheck.git + https://github.com/dependency-check/DependencyCheck/tree/main/archetype + scm:git:git@github.com/dependency-check/DependencyCheck.git HEAD - - org.codehaus.mojo - animal-sniffer-maven-plugin - - true - - org.apache.maven.plugins maven-resources-plugin diff --git a/archetype/src/main/resources/archetype-resources/pom.xml b/archetype/src/main/resources/archetype-resources/pom.xml index 712babfeabf..44343deafab 100644 --- a/archetype/src/main/resources/archetype-resources/pom.xml +++ b/archetype/src/main/resources/archetype-resources/pom.xml @@ -4,17 +4,20 @@ \${groupId} \${artifactId} \${version} - + \${artifactId} jar - + The Apache Software License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt - + + + ${maven.compiler.release} + org.owasp @@ -34,10 +37,22 @@ ${slf4j.version} provided + + org.junit.jupiter + junit-jupiter-api + 5.12.2 + test + org.junit.jupiter junit-jupiter-engine - 5.8.2 + 5.12.2 + test + + + org.junit.jupiter + junit-jupiter-params + 5.12.2 test diff --git a/archetype/src/main/resources/archetype-resources/src/test/java/__analyzerName__Test.java b/archetype/src/main/resources/archetype-resources/src/test/java/__analyzerName__Test.java index 89942160280..69ecf2c8b16 100644 --- a/archetype/src/main/resources/archetype-resources/src/test/java/__analyzerName__Test.java +++ b/archetype/src/main/resources/archetype-resources/src/test/java/__analyzerName__Test.java @@ -13,43 +13,45 @@ */ package ${package}; -import java.io.File; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.AfterAll; -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.AnalysisPhase; import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.utils.Settings; +import java.io.File; + +import static org.junit.jupiter.api.Assertions.*; + /** * Test cases for ${analyzerName} */ -public class ${analyzerName}Test { - +class ${analyzerName}Test { + Settings settings = null; - - public ${analyzerName}Test() { + + ${analyzerName}Test() { } - + @BeforeAll - public static void setUpClass() { + static void setUpClass() { } - + @AfterAll - public static void tearDownClass() { + static void tearDownClass() { } - + @BeforeEach - public void setUp() { + void setUp() { settings = new Settings(); } @AfterEach - public void tearDown() { + void tearDown() { settings.cleanup(); } @@ -57,7 +59,7 @@ public void tearDown() { * Test of accept method, of class ${analyzerName}. */ @Test - public void testAccept() { + void testAccept() { File pathname = new File("test.file"); ${analyzerName} instance = new ${analyzerName}(); boolean expResult = true; @@ -69,13 +71,13 @@ public void testAccept() { * Test of analyze method, of class ${analyzerName}. */ @Test - public void testAnalyze() throws Exception { + void testAnalyze() throws Exception { //The engine is generally null for most analyzer test cases but can be instantiated if needed. Engine engine = null; ${analyzerName} instance = new ${analyzerName}(); instance.initialize(settings); instance.prepare(engine); - + File file = new File(${analyzerName}.class.getClassLoader().getResource("test.file").toURI().getPath()); Dependency dependency = new Dependency(file); @@ -87,7 +89,7 @@ public void testAnalyze() throws Exception { * Test of getName method, of class ${analyzerName}. */ @Test - public void testGetName() { + void testGetName() { ${analyzerName} instance = new ${analyzerName}(); String expResult = "${analyzerName}"; String result = instance.getName(); @@ -98,7 +100,7 @@ public void testGetName() { * Test of getAnalysisPhase method, of class ${analyzerName}. */ @Test - public void testGetAnalysisPhase() { + void testGetAnalysisPhase() { ${analyzerName} instance = new ${analyzerName}(); AnalysisPhase expResult = AnalysisPhase.INFORMATION_COLLECTION; AnalysisPhase result = instance.getAnalysisPhase(); @@ -109,7 +111,7 @@ public void testGetAnalysisPhase() { * Test of initialize method, of class ${analyzerName}. */ @Test - public void testInitialize() throws Exception { + void testInitialize() throws Exception { ${analyzerName} instance = new ${analyzerName}(); instance.initialize(settings); } @@ -118,7 +120,7 @@ public void testInitialize() throws Exception { * Test of close method, of class ${analyzerName}. */ @Test - public void testClose() throws Exception { + void testClose() throws Exception { ${analyzerName} instance = new ${analyzerName}(); instance.close(); } @@ -127,7 +129,7 @@ public void testClose() throws Exception { * Test of supportsParallelProcessing method, of class ${analyzerName}. */ @Test - public void testSupportsParallelProcessing() { + void testSupportsParallelProcessing() { ${analyzerName} instance = new ${analyzerName}(); boolean expResult = true; boolean result = instance.supportsParallelProcessing(); @@ -138,7 +140,7 @@ public void testSupportsParallelProcessing() { * Test of isEnabled method, of class ${analyzerName}. */ @Test - public void testIsEnabled() { + void testIsEnabled() { ${analyzerName} instance = new ${analyzerName}(); boolean expResult = true; boolean result = instance.isEnabled(); diff --git a/archetype/src/site/site.xml b/archetype/src/site/site.xml index dac56d5b9a6..17e1defd4b7 100644 --- a/archetype/src/site/site.xml +++ b/archetype/src/site/site.xml @@ -16,11 +16,11 @@ limitations under the License. Copyright (c) 2017 Jeremy Long. All Rights Reserved. --> - - - OWASP dependency-check-plugin - OWASP dependency-check-plugin - /images/dc.svg + + + OWASP dependency-check-plugin @@ -29,6 +29,7 @@ Copyright (c) 2017 Jeremy Long. All Rights Reserved. - + + - \ No newline at end of file + \ No newline at end of file diff --git a/build-docker.sh b/build-docker.sh index 355a6ab0da4..297ecc4cbd7 100755 --- a/build-docker.sh +++ b/build-docker.sh @@ -1,18 +1,27 @@ -#!/bin/bash -e +#!/bin/bash +set -euo pipefail VERSION=$(mvn -q \ -Dexec.executable="echo" \ -Dexec.args='${project.version}' \ --non-recursive \ - org.codehaus.mojo:exec-maven-plugin:1.3.1:exec) + org.codehaus.mojo:exec-maven-plugin:3.5.1:exec) FILE=./cli/target/dependency-check-$VERSION-release.zip -if [ -f "$FILE" ]; then - docker build . --build-arg VERSION=$VERSION -t owasp/dependency-check:$VERSION - if [[ ! $VERSION = *"SNAPSHOT"* ]]; then - docker tag owasp/dependency-check:$VERSION owasp/dependency-check:latest - fi -else +if [ ! -f "$FILE" ]; then echo "$FILE does not exist - run 'mvn package' first" exit 1 fi + +if ! docker info -f '{{ .DriverStatus }}' | grep "driver-type io.containerd.snapshotter" >/dev/null; then + echo "Docker Engine is not running with the containerd snapshotter - this is currently needed to build and test ODC multi-platform images using docker buildx." + echo "If using Docker Desktop, enable \"Use containerd for pulling and storing images\" per https://docs.docker.com/desktop/settings-and-maintenance/settings/#general" + echo "For more technical information on Docker Engine, see https://docs.docker.com/engine/storage/containerd/" + exit 1 +fi + +extra_tag_args="$([[ ! $VERSION = *"SNAPSHOT"* ]] && echo "--tag owasp/dependency-check:latest" || echo "")" + +docker buildx build --pull --load --platform linux/amd64,linux/arm64 . \ + --build-arg VERSION=$VERSION \ + --tag owasp/dependency-check:$VERSION ${extra_tag_args} diff --git a/cli/README.md b/cli/README.md index cead8821808..7ab25b589d9 100644 --- a/cli/README.md +++ b/cli/README.md @@ -5,7 +5,7 @@ performed are a "best effort" and as such, there could be false positives as wel vulnerabilities in 3rd party components is a well-known problem and is currently documented in the 2021 OWASP Top 10 as [A06:2021 – Vulnerable and Outdated Components](https://owasp.org/Top10/A06_2021-Vulnerable_and_Outdated_Components/). -Documentation and links to production binary releases can be found on the [github pages](http://jeremylong.github.io/DependencyCheck/dependency-check-cli/index.html). +Documentation and links to production binary releases can be found on the [github pages](https://dependency-check.github.io/DependencyCheck/dependency-check-cli/index.html). Copyright & License @@ -13,6 +13,8 @@ Copyright & License Dependency-Check is Copyright (c) 2012-2014 Jeremy Long. All Rights Reserved. -Permission to modify and redistribute is granted under the terms of the Apache 2.0 license. See the [LICENSE.txt](https://github.com/jeremylong/DependencyCheck/blob/main/cli/LICENSE.txt) file for the full license. +Permission to modify and redistribute is granted under the terms of the Apache 2.0 license. See the [LICENSE.txt](https://github.com/dependency-check/DependencyCheck/blob/main/cli/LICENSE.txt) file for the full license. -Dependency-Check Command Line makes use of other open source libraries. Please see the [NOTICE.txt](https://github.com/jeremylong/DependencyCheck/blob/main/cli/NOTICE.txt) file for more information. +Dependency-Check Command Line makes use of other open source libraries. Please see the [NOTICE.txt](https://github.com/dependency-check/DependencyCheck/blob/main/cli/NOTICE.txt) file for more information. + + \ No newline at end of file diff --git a/cli/pom.xml b/cli/pom.xml index e422f6799ad..d6979f56739 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -20,7 +20,7 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved. org.owasp dependency-check-parent - 8.2.2-SNAPSHOT + 12.1.9-SNAPSHOT dependency-check-cli @@ -29,9 +29,9 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved. Dependency-Check Command Line dependency-check-cli is an command line tool that uses dependency-check-core to detect publicly disclosed vulnerabilities associated with the scanned project dependencies. The tool will generate a report listing the dependency, any identified Common Platform Enumeration (CPE) identifiers, and the associated Common Vulnerability and Exposure (CVE) entries. - scm:git:https://github.com/jeremylong/DependencyCheck.git - https://github.com/jeremylong/DependencyCheck/tree/main/cli - scm:git:git@github.com:jeremylong/DependencyCheck.git + scm:git:https://github.com/dependency-check/DependencyCheck.git + https://github.com/dependency-check/DependencyCheck/tree/main/cli + scm:git:git@github.com/dependency-check/DependencyCheck.git v6.4.1 @@ -92,16 +92,43 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved. plugins/* true ${project.basedir}/src/main/conf/unixBinTemplate + + --enable-native-access=ALL-UNNAMED -XX:+IgnoreUnrecognizedVMOptions assemble + package assemble + + org.apache.maven.plugins + maven-antrun-plugin + + + fix-windows-shell-script + package + + run + + + + + + + + + + org.apache.maven.plugins maven-assembly-plugin @@ -152,6 +179,15 @@ Copyright (c) 2012 - Jeremy Long. All Rights Reserved. org.slf4j slf4j-api + + io.github.jeremylong + jcs3-slf4j + + + + io.github.jeremylong + open-vulnerability-clients + org.apache.ant ant diff --git a/cli/src/main/java/org/owasp/dependencycheck/App.java b/cli/src/main/java/org/owasp/dependencycheck/App.java index c1a702bf8c3..57a0355bf45 100644 --- a/cli/src/main/java/org/owasp/dependencycheck/App.java +++ b/cli/src/main/java/org/owasp/dependencycheck/App.java @@ -22,9 +22,10 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.commons.cli.ParseException; import org.apache.tools.ant.DirectoryScanner; import org.owasp.dependencycheck.data.nvdcve.DatabaseException; @@ -32,9 +33,10 @@ import org.owasp.dependencycheck.dependency.Vulnerability; import org.apache.tools.ant.types.LogLevel; import org.owasp.dependencycheck.data.update.exception.UpdateException; +import org.owasp.dependencycheck.dependency.naming.Identifier; import org.owasp.dependencycheck.exception.ExceptionCollection; import org.owasp.dependencycheck.exception.ReportException; -import org.owasp.dependencycheck.utils.CveUrlParser; +import org.owasp.dependencycheck.utils.Downloader; import org.owasp.dependencycheck.utils.InvalidSettingException; import org.owasp.dependencycheck.utils.Settings; import org.slf4j.Logger; @@ -46,6 +48,7 @@ import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.LoggerContext; +import io.github.jeremylong.jcs3.slf4j.Slf4jAdapter; import java.util.TreeSet; import org.owasp.dependencycheck.utils.SeverityUtil; @@ -81,6 +84,10 @@ public class App { */ @SuppressWarnings("squid:S4823") public static void main(String[] args) { + System.setProperty("jcs.logSystem", "slf4j"); + if (!LOGGER.isDebugEnabled()) { + Slf4jAdapter.muteLogging(true); + } final int exitCode; final App app = new App(); exitCode = app.run(args); @@ -138,6 +145,7 @@ public int run(String[] args) { } else { try { populateSettings(cli); + Downloader.getInstance().configure(settings); } catch (InvalidSettingException ex) { LOGGER.error(ex.getMessage()); LOGGER.debug(ERROR_LOADING_PROPERTIES_FILE, ex); @@ -159,6 +167,7 @@ public int run(String[] args) { try { populateSettings(cli); settings.setBoolean(Settings.KEYS.AUTO_UPDATE, true); + Downloader.getInstance().configure(settings); } catch (InvalidSettingException ex) { LOGGER.error(ex.getMessage()); LOGGER.debug(ERROR_LOADING_PROPERTIES_FILE, ex); @@ -179,6 +188,7 @@ public int run(String[] args) { } else if (cli.isRunScan()) { try { populateSettings(cli); + Downloader.getInstance().configure(settings); } catch (InvalidSettingException ex) { LOGGER.error(ex.getMessage(), ex); LOGGER.debug(ERROR_LOADING_PROPERTIES_FILE, ex); @@ -303,26 +313,38 @@ private int determineReturnCode(Engine engine, float cvssFailScore) { for (Dependency d : engine.getDependencies()) { boolean addName = true; for (Vulnerability v : d.getVulnerabilities()) { - final float cvssV2 = v.getCvssV2() != null ? v.getCvssV2().getScore() : -1; - final float cvssV3 = v.getCvssV3() != null ? v.getCvssV3().getBaseScore() : -1; - final float unscoredCvss = v.getUnscoredSeverity() != null ? SeverityUtil.estimateCvssV2(v.getUnscoredSeverity()) : -1; + final double cvssV2 = v.getCvssV2() != null && v.getCvssV2().getCvssData() != null + && v.getCvssV2().getCvssData().getBaseScore() != null ? v.getCvssV2().getCvssData().getBaseScore() : -1; + final double cvssV3 = v.getCvssV3() != null && v.getCvssV3().getCvssData() != null + && v.getCvssV3().getCvssData().getBaseScore() != null ? v.getCvssV3().getCvssData().getBaseScore() : -1; + final double cvssV4 = v.getCvssV4() != null && v.getCvssV4().getCvssData() != null + && v.getCvssV4().getCvssData().getBaseScore() != null ? v.getCvssV4().getCvssData().getBaseScore() : -1; + final boolean useUnscored = cvssV2 == -1 && cvssV3 == -1 && cvssV4 == -1; + final double unscoredCvss = (useUnscored && v.getUnscoredSeverity() != null) ? SeverityUtil.estimateCvssV2(v.getUnscoredSeverity()) : -1; if (cvssV2 >= cvssFailScore || cvssV3 >= cvssFailScore + || cvssV4 >= cvssFailScore || unscoredCvss >= cvssFailScore //safety net to fail on any if for some reason the above misses on 0 || (cvssFailScore <= 0.0f)) { - float score = 0.0f; - if (cvssV3 >= 0.0f) { + double score = 0.0; + if (cvssV4 >= 0.0) { + score = cvssV4; + } else if (cvssV3 >= 0.0) { score = cvssV3; - } else if (cvssV2 >= 0.0f) { + } else if (cvssV2 >= 0.0) { score = cvssV2; - } else if (unscoredCvss >= 0.0f) { + } else if (unscoredCvss >= 0.0) { score = unscoredCvss; } if (addName) { addName = false; - ids.append(NEW_LINE).append(d.getFileName()).append(": "); + ids.append(NEW_LINE).append(d.getFileName()).append(" (") + .append(Stream.concat(d.getSoftwareIdentifiers().stream(), d.getVulnerableSoftwareIdentifiers().stream()) + .map(Identifier::getValue) + .collect(Collectors.joining(", "))) + .append("): "); ids.append(v.getName()).append('(').append(score).append(')'); } else { ids.append(", ").append(v.getName()).append('(').append(score).append(')'); @@ -358,7 +380,11 @@ private Set scanAntStylePaths(List antStylePaths, int symLinkDepth String include = file.replace('\\', '/'); final File baseDir; final int pos = getLastFileSeparator(include); - final String tmpBase = include.substring(0, pos); + String tmpBase = include.substring(0, pos); + //fix for windows style paths scanning c:/temp. + if (tmpBase.endsWith(":")) { + tmpBase += "/"; + } final String tmpInclude = include.substring(pos + 1); if (tmpInclude.indexOf('*') >= 0 || tmpInclude.indexOf('?') >= 0 || new File(include).isFile()) { @@ -475,12 +501,14 @@ protected void populateSettings(CliParser cli) throws InvalidSettingException { cli.getStringArgument(CliParser.ARGUMENT.CONNECTION_READ_TIMEOUT)); settings.setStringIfNotEmpty(Settings.KEYS.HINTS_FILE, cli.getStringArgument(CliParser.ARGUMENT.HINTS_FILE)); - settings.setIntIfNotNull(Settings.KEYS.CVE_CHECK_VALID_FOR_HOURS, - cli.getIntegerValue(CliParser.ARGUMENT.CVE_VALID_FOR_HOURS)); - settings.setIntIfNotNull(Settings.KEYS.CVE_START_YEAR, - cli.getIntegerValue(CliParser.ARGUMENT.CVE_START_YEAR)); settings.setArrayIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE, cli.getStringArguments(CliParser.ARGUMENT.SUPPRESSION_FILES)); + settings.setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE_USER, + cli.getStringArgument(CliParser.ARGUMENT.SUPPRESSION_FILE_USER)); + settings.setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE_PASSWORD, + cli.getStringArgument(CliParser.ARGUMENT.SUPPRESSION_FILE_PASSWORD)); + settings.setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE_BEARER_TOKEN, + cli.getStringArgument(CliParser.ARGUMENT.SUPPRESSION_FILE_BEARER_TOKEN)); //File Type Analyzer Settings settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_EXPERIMENTAL_ENABLED, cli.hasOption(CliParser.ARGUMENT.EXPERIMENTAL)); @@ -500,6 +528,8 @@ protected void populateSettings(CliParser cli) throws InvalidSettingException { cli.getStringArgument(CliParser.ARGUMENT.RETIREJS_URL_USER)); settings.setStringIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_PASSWORD, cli.getStringArgument(CliParser.ARGUMENT.RETIREJS_URL_PASSWORD)); + settings.setStringIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_BEARER_TOKEN, + cli.getStringArgument(CliParser.ARGUMENT.RETIREJS_URL_BEARER_TOKEN)); settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_FORCEUPDATE, cli.hasOption(CliParser.ARGUMENT.RETIRE_JS_FORCEUPDATE)); settings.setStringIfNotNull(Settings.KEYS.ANALYZER_RETIREJS_FILTERS, @@ -508,6 +538,8 @@ protected void populateSettings(CliParser cli) throws InvalidSettingException { cli.hasOption(CliParser.ARGUMENT.RETIREJS_FILTER_NON_VULNERABLE)); settings.setBoolean(Settings.KEYS.ANALYZER_JAR_ENABLED, !cli.isDisabled(CliParser.ARGUMENT.DISABLE_JAR, Settings.KEYS.ANALYZER_JAR_ENABLED)); + settings.setBoolean(Settings.KEYS.UPDATE_VERSION_CHECK_ENABLED, + !cli.isDisabled(CliParser.ARGUMENT.DISABLE_VERSION_CHECK, Settings.KEYS.UPDATE_VERSION_CHECK_ENABLED)); settings.setBoolean(Settings.KEYS.ANALYZER_MSBUILD_PROJECT_ENABLED, !cli.isDisabled(CliParser.ARGUMENT.DISABLE_MSBUILD, Settings.KEYS.ANALYZER_MSBUILD_PROJECT_ENABLED)); settings.setBoolean(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, @@ -516,6 +548,12 @@ protected void populateSettings(CliParser cli) throws InvalidSettingException { !cli.isDisabled(CliParser.ARGUMENT.DISABLE_KEV, Settings.KEYS.ANALYZER_KNOWN_EXPLOITED_ENABLED)); settings.setStringIfNotNull(Settings.KEYS.KEV_URL, cli.getStringArgument(CliParser.ARGUMENT.KEV_URL)); + settings.setStringIfNotNull(Settings.KEYS.KEV_USER, + cli.getStringArgument(CliParser.ARGUMENT.KEV_USER)); + settings.setStringIfNotNull(Settings.KEYS.KEV_PASSWORD, + cli.getStringArgument(CliParser.ARGUMENT.KEV_PASSWORD)); + settings.setStringIfNotNull(Settings.KEYS.KEV_BEARER_TOKEN, + cli.getStringArgument(CliParser.ARGUMENT.KEV_BEARER_TOKEN)); settings.setBoolean(Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED, !cli.isDisabled(CliParser.ARGUMENT.DISABLE_PY_DIST, Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED)); settings.setBoolean(Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED, @@ -548,6 +586,8 @@ protected void populateSettings(CliParser cli) throws InvalidSettingException { !cli.isDisabled(CliParser.ARGUMENT.DISABLE_OPENSSL, Settings.KEYS.ANALYZER_OPENSSL_ENABLED)); settings.setBoolean(Settings.KEYS.ANALYZER_COMPOSER_LOCK_ENABLED, !cli.isDisabled(CliParser.ARGUMENT.DISABLE_COMPOSER, Settings.KEYS.ANALYZER_COMPOSER_LOCK_ENABLED)); + settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_COMPOSER_LOCK_SKIP_DEV, + cli.hasOption(CliParser.ARGUMENT.COMPOSER_LOCK_SKIP_DEV)); settings.setBoolean(Settings.KEYS.ANALYZER_CPANFILE_ENABLED, !cli.isDisabled(CliParser.ARGUMENT.DISABLE_CPAN, Settings.KEYS.ANALYZER_CPANFILE_ENABLED)); settings.setBoolean(Settings.KEYS.ANALYZER_GOLANG_DEP_ENABLED, @@ -574,6 +614,8 @@ protected void populateSettings(CliParser cli) throws InvalidSettingException { !cli.isDisabled(CliParser.ARGUMENT.DISABLE_SWIFT_RESOLVED, Settings.KEYS.ANALYZER_SWIFT_PACKAGE_RESOLVED_ENABLED)); settings.setBoolean(Settings.KEYS.ANALYZER_COCOAPODS_ENABLED, !cli.isDisabled(CliParser.ARGUMENT.DISABLE_COCOAPODS, Settings.KEYS.ANALYZER_COCOAPODS_ENABLED)); + settings.setBoolean(Settings.KEYS.ANALYZER_CARTHAGE_ENABLED, + !cli.isDisabled(CliParser.ARGUMENT.DISABLE_CARTHAGE, Settings.KEYS.ANALYZER_CARTHAGE_ENABLED)); settings.setBoolean(Settings.KEYS.ANALYZER_RUBY_GEMSPEC_ENABLED, !cli.isDisabled(CliParser.ARGUMENT.DISABLE_RUBYGEMS, Settings.KEYS.ANALYZER_RUBY_GEMSPEC_ENABLED)); settings.setBoolean(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, @@ -591,6 +633,14 @@ protected void populateSettings(CliParser cli) throws InvalidSettingException { cli.hasOption(CliParser.ARGUMENT.DISABLE_NODE_AUDIT_SKIPDEV)); settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_NEXUS_ENABLED, cli.hasOption(CliParser.ARGUMENT.ENABLE_NEXUS)); + settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_CENTRAL_URL, + cli.getStringArgument(CliParser.ARGUMENT.CENTRAL_URL)); + settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_CENTRAL_USER, + cli.getStringArgument(CliParser.ARGUMENT.CENTRAL_USERNAME)); + settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_CENTRAL_PASSWORD, + cli.getStringArgument(CliParser.ARGUMENT.CENTRAL_PASSWORD)); + settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_CENTRAL_BEARER_TOKEN, + cli.getStringArgument(CliParser.ARGUMENT.CENTRAL_BEARER_TOKEN)); settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_OSSINDEX_URL, cli.getStringArgument(CliParser.ARGUMENT.OSSINDEX_URL)); settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_OSSINDEX_USER, @@ -645,24 +695,33 @@ protected void populateSettings(CliParser cli) throws InvalidSettingException { cli.getStringArgument(CliParser.ARGUMENT.ADDITIONAL_ZIP_EXTENSIONS)); settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_ASSEMBLY_DOTNET_PATH, cli.getStringArgument(CliParser.ARGUMENT.PATH_TO_CORE)); - settings.setStringIfNotEmpty(Settings.KEYS.CVE_BASE_JSON, - cli.getStringArgument(CliParser.ARGUMENT.CVE_BASE_URL)); - settings.setStringIfNotEmpty(Settings.KEYS.CVE_DOWNLOAD_WAIT_TIME, - cli.getStringArgument(CliParser.ARGUMENT.CVE_DOWNLOAD_WAIT_TIME)); - final String cveModifiedJson = Optional.ofNullable(cli.getStringArgument(CliParser.ARGUMENT.CVE_MODIFIED_URL)) - .filter(arg -> !arg.isEmpty()) - .orElseGet(() -> getDefaultCveUrlModified(cli)); - settings.setStringIfNotEmpty(Settings.KEYS.CVE_MODIFIED_JSON, - cveModifiedJson); - - settings.setStringIfNotEmpty(Settings.KEYS.CVE_USER, - cli.getStringArgument(CliParser.ARGUMENT.CVE_USER)); - settings.setStringIfNotEmpty(Settings.KEYS.CVE_PASSWORD, - cli.getStringArgument(CliParser.ARGUMENT.CVE_PASSWORD, Settings.KEYS.CVE_PASSWORD)); + String key = cli.getStringArgument(CliParser.ARGUMENT.NVD_API_KEY); + if (key != null) { + if ((key.startsWith("\"") && key.endsWith("\"") || (key.startsWith("'") && key.endsWith("'")))) { + key = key.substring(1, key.length() - 1); + } + settings.setStringIfNotEmpty(Settings.KEYS.NVD_API_KEY, key); + } + settings.setStringIfNotEmpty(Settings.KEYS.NVD_API_ENDPOINT, + cli.getStringArgument(CliParser.ARGUMENT.NVD_API_ENDPOINT)); + settings.setIntIfNotNull(Settings.KEYS.NVD_API_DELAY, cli.getIntegerValue(CliParser.ARGUMENT.NVD_API_DELAY)); + settings.setIntIfNotNull(Settings.KEYS.NVD_API_RESULTS_PER_PAGE, cli.getIntegerValue(CliParser.ARGUMENT.NVD_API_RESULTS_PER_PAGE)); + settings.setStringIfNotEmpty(Settings.KEYS.NVD_API_DATAFEED_URL, cli.getStringArgument(CliParser.ARGUMENT.NVD_API_DATAFEED_URL)); + settings.setStringIfNotEmpty(Settings.KEYS.NVD_API_DATAFEED_USER, cli.getStringArgument(CliParser.ARGUMENT.NVD_API_DATAFEED_USER)); + settings.setStringIfNotEmpty(Settings.KEYS.NVD_API_DATAFEED_PASSWORD, cli.getStringArgument(CliParser.ARGUMENT.NVD_API_DATAFEED_PASSWORD)); + settings.setStringIfNotEmpty(Settings.KEYS.NVD_API_DATAFEED_BEARER_TOKEN, cli.getStringArgument(CliParser.ARGUMENT.NVD_API_DATAFEED_BEARER_TOKEN)); + settings.setIntIfNotNull(Settings.KEYS.NVD_API_MAX_RETRY_COUNT, cli.getIntegerValue(CliParser.ARGUMENT.NVD_API_MAX_RETRY_COUNT)); + settings.setIntIfNotNull(Settings.KEYS.NVD_API_VALID_FOR_HOURS, cli.getIntegerValue(CliParser.ARGUMENT.NVD_API_VALID_FOR_HOURS)); settings.setStringIfNotNull(Settings.KEYS.HOSTED_SUPPRESSIONS_URL, cli.getStringArgument(CliParser.ARGUMENT.HOSTED_SUPPRESSIONS_URL)); + settings.setStringIfNotNull(Settings.KEYS.HOSTED_SUPPRESSIONS_USER, + cli.getStringArgument(CliParser.ARGUMENT.HOSTED_SUPPRESSIONS_USER)); + settings.setStringIfNotNull(Settings.KEYS.HOSTED_SUPPRESSIONS_PASSWORD, + cli.getStringArgument(CliParser.ARGUMENT.HOSTED_SUPPRESSIONS_PASSWORD)); + settings.setStringIfNotNull(Settings.KEYS.HOSTED_SUPPRESSIONS_BEARER_TOKEN, + cli.getStringArgument(CliParser.ARGUMENT.HOSTED_SUPPRESSIONS_BEARER_TOKEN)); settings.setBoolean(Settings.KEYS.HOSTED_SUPPRESSIONS_ENABLED, !cli.isDisabled(CliParser.ARGUMENT.DISABLE_HOSTED_SUPPRESSIONS, Settings.KEYS.HOSTED_SUPPRESSIONS_ENABLED)); settings.setBooleanIfNotNull(Settings.KEYS.HOSTED_SUPPRESSIONS_FORCEUPDATE, @@ -671,11 +730,6 @@ protected void populateSettings(CliParser cli) throws InvalidSettingException { cli.getIntegerValue(CliParser.ARGUMENT.HOSTED_SUPPRESSIONS_VALID_FOR_HOURS)); } - private String getDefaultCveUrlModified(CliParser cli) { - return CveUrlParser.newInstance(settings) - .getDefaultCveUrlModified(cli.getStringArgument(CliParser.ARGUMENT.CVE_BASE_URL)); - } - //CSON: MethodLength /** * Creates a file appender and adds it to logback. diff --git a/cli/src/main/java/org/owasp/dependencycheck/CliParser.java b/cli/src/main/java/org/owasp/dependencycheck/CliParser.java index c34e734f8cd..eb833f8c6b5 100644 --- a/cli/src/main/java/org/owasp/dependencycheck/CliParser.java +++ b/cli/src/main/java/org/owasp/dependencycheck/CliParser.java @@ -64,7 +64,7 @@ public final class CliParser { /** * The supported reported formats. */ - private static final String SUPPORTED_FORMATS = "HTML, XML, CSV, JSON, JUNIT, SARIF, JENKINS, or ALL"; + private static final String SUPPORTED_FORMATS = "HTML, XML, CSV, JSON, JUNIT, SARIF, JENKINS, GITLAB or ALL"; /** * Constructs a new CLI Parser object with the configured settings. @@ -114,26 +114,49 @@ private CommandLine parseArgs(String[] args) throws ParseException { */ private void validateArgs() throws FileNotFoundException, ParseException { if (isUpdateOnly() || isRunScan()) { - String value = line.getOptionValue(ARGUMENT.CVE_VALID_FOR_HOURS); + + String value = line.getOptionValue(ARGUMENT.NVD_API_VALID_FOR_HOURS); if (value != null) { try { final int i = Integer.parseInt(value); if (i < 0) { - throw new ParseException("Invalid Setting: cveValidForHours must be a number greater than or equal to 0."); + throw new ParseException("Invalid Setting: nvdValidForHours must be a number greater than or equal to 0."); } } catch (NumberFormatException ex) { - throw new ParseException("Invalid Setting: cveValidForHours must be a number greater than or equal to 0."); + throw new ParseException("Invalid Setting: nvdValidForHours must be a number greater than or equal to 0."); } } - value = line.getOptionValue(ARGUMENT.CVE_START_YEAR); + value = line.getOptionValue(ARGUMENT.NVD_API_MAX_RETRY_COUNT); if (value != null) { try { final int i = Integer.parseInt(value); - if (i < 2002) { - throw new ParseException("Invalid Setting: cveStartYear must be a number greater than or equal to 2002."); + if (i <= 0) { + throw new ParseException("Invalid Setting: nvdMaxRetryCount must be a number greater than 0."); } } catch (NumberFormatException ex) { - throw new ParseException("Invalid Setting: cveStartYear must be a number greater than or equal to 2002."); + throw new ParseException("Invalid Setting: nvdMaxRetryCount must be a number greater than 0."); + } + } + value = line.getOptionValue(ARGUMENT.NVD_API_DELAY); + if (value != null) { + try { + final int i = Integer.parseInt(value); + if (i < 0) { + throw new ParseException("Invalid Setting: nvdApiDelay must be a number greater than or equal to 0."); + } + } catch (NumberFormatException ex) { + throw new ParseException("Invalid Setting: nvdApiDelay must be a number greater than or equal to 0."); + } + } + value = line.getOptionValue(ARGUMENT.NVD_API_RESULTS_PER_PAGE); + if (value != null) { + try { + final int i = Integer.parseInt(value); + if (i <= 0 || i > 2000) { + throw new ParseException("Invalid Setting: nvdApiResultsPerPage must be a number in the range [1, 2000]."); + } + } catch (NumberFormatException ex) { + throw new ParseException("Invalid Setting: nvdApiResultsPerPage must be a number in the range [1, 2000]."); } } } @@ -149,18 +172,12 @@ private void validateArgs() throws FileNotFoundException, ParseException { if (!isValidFormat(validating) && !isValidFilePath(validating, "format")) { final String msg = String.format("An invalid 'format' of '%s' was specified. " - + "Supported output formats are %s, and custom template files.", + + "Supported output formats are %s, and custom template files.", validating, SUPPORTED_FORMATS); throw new ParseException(msg); } } } - final String base = getStringArgument(ARGUMENT.CVE_BASE_URL); - final String modified = getStringArgument(ARGUMENT.CVE_MODIFIED_URL); - if ((base != null && modified == null) || (base == null && modified != null)) { - final String msg = "If one of the CVE URLs is specified they must all be specified; please add the missing CVE URL."; - throw new ParseException(msg); - } if (line.hasOption(ARGUMENT.SYM_LINK_DEPTH)) { try { final int i = Integer.parseInt(line.getOptionValue(ARGUMENT.SYM_LINK_DEPTH)); @@ -304,14 +321,14 @@ private void addStandardOptions(final Options options) { //This is an option group because it can be specified more then once. options.addOptionGroup(newOptionGroup(newOptionWithArg(ARGUMENT.SCAN_SHORT, ARGUMENT.SCAN, "path", - "The path to scan - this option can be specified multiple times. Ant style paths are supported (e.g. 'path/**/*.jar'); " - + "if using Ant style paths it is highly recommended to quote the argument value."))) + "The path to scan - this option can be specified multiple times. Ant style paths are supported (e.g. 'path/**/*.jar'); " + + "if using Ant style paths it is highly recommended to quote the argument value."))) .addOptionGroup(newOptionGroup(newOptionWithArg(ARGUMENT.EXCLUDE, "pattern", "Specify an exclusion pattern. This option " + "can be specified multiple times and it accepts Ant style exclusions."))) .addOption(newOptionWithArg(ARGUMENT.PROJECT, "name", "The name of the project being scanned.")) .addOption(newOptionWithArg(ARGUMENT.OUT_SHORT, ARGUMENT.OUT, "path", "The folder to write reports to. This defaults to the current directory. It is possible to set this to a specific " - + "file name if the format argument is not set to ALL.")) + + "file name if the format argument is not set to ALL.")) .addOption(newOptionWithArg(ARGUMENT.OUTPUT_FORMAT_SHORT, ARGUMENT.OUTPUT_FORMAT, "format", "The report format (" + SUPPORTED_FORMATS + "). The default is HTML. Multiple format parameters can be specified.")) .addOption(newOption(ARGUMENT.PRETTY_PRINT, "When specified the JSON and XML report formats will be pretty printed.")) @@ -324,10 +341,12 @@ private void addStandardOptions(final Options options) { "The file path to write verbose logging information.")) .addOptionGroup(newOptionGroup(newOptionWithArg(ARGUMENT.SUPPRESSION_FILES, "file", "The file path to the suppression XML file. This can be specified more then once to utilize multiple suppression files"))) + .addOption(newOption(ARGUMENT.DISABLE_VERSION_CHECK, "Disables the dependency-check version check")) .addOption(newOption(ARGUMENT.EXPERIMENTAL, "Enables the experimental analyzers.")) + .addOption(newOptionWithArg(ARGUMENT.NVD_API_KEY, "apiKey", "The API Key to access the NVD API.")) .addOption(newOptionWithArg(ARGUMENT.FAIL_ON_CVSS, "score", "Specifies if the build should be failed if a CVSS score above a specified level is identified. The default is 11; " - + "since the CVSS scores are 0-10, by default the build will never fail.")) + + "since the CVSS scores are 0-10, by default the build will never fail.")) .addOption(newOptionWithArg(ARGUMENT.FAIL_JUNIT_ON_CVSS, "score", "Specifies the CVSS score that is considered a failure when generating the junit report. The default is 0.")); } @@ -344,16 +363,30 @@ private void addAdvancedOptions(final Options options) { options .addOption(newOption(ARGUMENT.UPDATE_ONLY, "Only update the local NVD data cache; no scan will be executed.")) - .addOption(newOptionWithArg(ARGUMENT.CVE_BASE_URL, "url", - "Base URL for each year’s CVE files (json.gz), the %d will be replaced with the year.")) - .addOption(newOptionWithArg(ARGUMENT.CVE_MODIFIED_URL, "url", - "URL for the modified CVE (json.gz).")) - .addOption(newOptionWithArg(ARGUMENT.CVE_DOWNLOAD_WAIT_TIME, "milliseconds", + .addOption(newOptionWithArg(ARGUMENT.NVD_API_DELAY, "milliseconds", "Time in milliseconds to wait between downloading from the NVD.")) - .addOption(newOptionWithArg(ARGUMENT.CVE_USER, "user", - "Credentials for basic authentication to the CVE data.")) - .addOption(newOptionWithArg(ARGUMENT.CVE_PASSWORD, "password", - "Credentials for basic authentication to the CVE data.")) + .addOption(newOptionWithArg(ARGUMENT.NVD_API_RESULTS_PER_PAGE, "count", + "The number records for a single page from NVD API (must be <=2000).")) + .addOption(newOptionWithArg(ARGUMENT.NVD_API_ENDPOINT, "endpoint", + "The NVD API Endpoint - setting this is rare.")) + .addOption(newOptionWithArg(ARGUMENT.NVD_API_DATAFEED_URL, "url", + "The URL to the NVD API Datafeed.")) + .addOption(newOptionWithArg(ARGUMENT.NVD_API_DATAFEED_USER, "user", + "Credentials for basic authentication to the NVD API Datafeed.")) + .addOption(newOptionWithArg(ARGUMENT.NVD_API_DATAFEED_PASSWORD, "password", + "Credentials for basic authentication to the NVD API Datafeed.")) + .addOption(newOptionWithArg(ARGUMENT.NVD_API_DATAFEED_BEARER_TOKEN, "token", + "Credentials for bearer authentication to the NVD API Datafeed.")) + .addOption(newOptionWithArg(ARGUMENT.SUPPRESSION_FILE_USER, "user", + "Credentials for basic authentication to web-hosted suppression files.")) + .addOption(newOptionWithArg(ARGUMENT.SUPPRESSION_FILE_PASSWORD, "password", + "Credentials for basic authentication to web-hosted suppression files.")) + .addOption(newOptionWithArg(ARGUMENT.SUPPRESSION_FILE_BEARER_TOKEN, "token", + "Credentials for bearer authentication to web-hosted suppression files.")) + .addOption(newOptionWithArg(ARGUMENT.NVD_API_MAX_RETRY_COUNT, "count", + "The maximum number of retry requests for a single call to the NVD API.")) + .addOption(newOptionWithArg(ARGUMENT.NVD_API_VALID_FOR_HOURS, "hours", + "The number of hours to wait before checking for new updates from the NVD.")) .addOption(newOptionWithArg(ARGUMENT.PROXY_PORT, "port", "The proxy port to use when downloading resources.")) .addOption(newOptionWithArg(ARGUMENT.PROXY_SERVER, "server", @@ -364,7 +397,7 @@ private void addAdvancedOptions(final Options options) { "The proxy password to use when downloading resources.")) .addOption(newOptionWithArg(ARGUMENT.NON_PROXY_HOSTS, "list", "The proxy exclusion list: hostnames (or patterns) for which proxy should not be used. " - + "Use pipe, comma or colon as list separator.")) + + "Use pipe, comma or colon as list separator.")) .addOption(newOptionWithArg(ARGUMENT.CONNECTION_TIMEOUT_SHORT, ARGUMENT.CONNECTION_TIMEOUT, "timeout", "The connection timeout (in milliseconds) to use when downloading resources.")) .addOption(newOptionWithArg(ARGUMENT.CONNECTION_READ_TIMEOUT, "timeout", @@ -381,19 +414,27 @@ private void addAdvancedOptions(final Options options) { "The database driver name.")) .addOption(newOptionWithArg(ARGUMENT.DB_DRIVER_PATH, "path", "The path to the database driver; note, this does not need to be set unless the JAR is " - + "outside of the classpath.")) + + "outside of the classpath.")) .addOption(newOptionWithArg(ARGUMENT.SYM_LINK_DEPTH, "depth", "Sets how deep nested symbolic links will be followed; 0 indicates symbolic links will not be followed.")) .addOption(newOptionWithArg(ARGUMENT.PATH_TO_BUNDLE_AUDIT, "path", "The path to bundle-audit for Gem bundle analysis.")) .addOption(newOptionWithArg(ARGUMENT.PATH_TO_BUNDLE_AUDIT_WORKING_DIRECTORY, "path", "The path to working directory that the bundle-audit command should be executed from when " - + "doing Gem bundle analysis.")) + + "doing Gem bundle analysis.")) + .addOption(newOptionWithArg(ARGUMENT.CENTRAL_URL, "url", + "Alternative URL for Maven Central Search. If not set the public Sonatype Maven Central will be used.")) + .addOption(newOptionWithArg(ARGUMENT.CENTRAL_USERNAME, "username", + "Credentials for basic auth towards the --centralUrl.")) + .addOption(newOptionWithArg(ARGUMENT.CENTRAL_PASSWORD, "password", + "Credentials for basic auth towards the --centralUrl")) + .addOption(newOptionWithArg(ARGUMENT.CENTRAL_BEARER_TOKEN, "token", + "Token for bearer auth towards the --centralUrl")) .addOption(newOptionWithArg(ARGUMENT.OSSINDEX_URL, "url", "Alternative URL for the OSS Index. If not set the public Sonatype OSS Index will be used.")) .addOption(newOptionWithArg(ARGUMENT.OSSINDEX_USERNAME, "username", "The username to authenticate to Sonatype's OSS Index. If not set the Sonatype OSS Index " - + "Analyzer will use an unauthenticated connection.")) + + "Analyzer will use an unauthenticated connection.")) .addOption(newOptionWithArg(ARGUMENT.OSSINDEX_PASSWORD, "password", "" + "The password to authenticate to Sonatype's OSS Index. If not set the Sonatype OSS " + "Index Analyzer will use an unauthenticated connection.")) @@ -402,11 +443,13 @@ private void addAdvancedOptions(final Options options) { .addOption(newOption(ARGUMENT.RETIRE_JS_FORCEUPDATE, "Force the RetireJS Analyzer to update " + "even if autoupdate is disabled")) .addOption(newOptionWithArg(ARGUMENT.RETIREJS_URL, "url", - "The Retire JS Respository URL")) + "The Retire JS Repository URL")) .addOption(newOptionWithArg(ARGUMENT.RETIREJS_URL_USER, "username", - "The password to authenticate to Retire JS Respository URL")) + "The password to authenticate to Retire JS Repository URL")) .addOption(newOptionWithArg(ARGUMENT.RETIREJS_URL_PASSWORD, "password", - "The password to authenticate to Retire JS Respository URL")) + "The password to authenticate to Retire JS Repository URL")) + .addOption(newOptionWithArg(ARGUMENT.RETIREJS_URL_BEARER_TOKEN, "token", + "The password to authenticate to Retire JS Repository URL")) .addOption(newOption(ARGUMENT.RETIREJS_FILTER_NON_VULNERABLE, "Specifies that the Retire JS " + "Analyzer should filter out non-vulnerable JS files from the report.")) .addOption(newOptionWithArg(ARGUMENT.ARTIFACTORY_PARALLEL_ANALYSIS, "true/false", @@ -427,29 +470,25 @@ private void addAdvancedOptions(final Options options) { "The path to the `yarn` executable.")) .addOption(newOptionWithArg(ARGUMENT.PATH_TO_PNPM, "path", "The path to the `pnpm` executable.")) - .addOption(newOptionWithArg(ARGUMENT.CVE_VALID_FOR_HOURS, "hours", - "The number of hours to wait before checking for new updates from the NVD.")) - .addOption(newOptionWithArg(ARGUMENT.CVE_START_YEAR, "year", - "The first year to retrieve NVD CVE data for; default is 2002.")) .addOption(newOptionWithArg(ARGUMENT.RETIREJS_FILTERS, "pattern", "Specify Retire JS content filter used to exclude files from analysis based on their content; " - + "most commonly used to exclude based on your applications own copyright line. This " - + "option can be specified multiple times.")) + + "most commonly used to exclude based on your applications own copyright line. This " + + "option can be specified multiple times.")) .addOption(newOptionWithArg(ARGUMENT.NEXUS_URL, "url", "The url to the Nexus Server's REST API Endpoint (http://domain/nexus/service/local). If not " - + "set the Nexus Analyzer will be disabled.")) + + "set the Nexus Analyzer will be disabled.")) .addOption(newOptionWithArg(ARGUMENT.NEXUS_USERNAME, "username", "The username to authenticate to the Nexus Server's REST API Endpoint. If not set the Nexus " - + "Analyzer will use an unauthenticated connection.")) + + "Analyzer will use an unauthenticated connection.")) .addOption(newOptionWithArg(ARGUMENT.NEXUS_PASSWORD, "password", "The password to authenticate to the Nexus Server's REST API Endpoint. If not set the Nexus " - + "Analyzer will use an unauthenticated connection.")) + + "Analyzer will use an unauthenticated connection.")) //TODO remove as this should be covered by non-proxy hosts .addOption(newOptionWithArg(ARGUMENT.NEXUS_USES_PROXY, "true/false", "Whether or not the configured proxy should be used when connecting to Nexus.")) .addOption(newOptionWithArg(ARGUMENT.ADDITIONAL_ZIP_EXTENSIONS, "extensions", "A comma separated list of additional extensions to be scanned as ZIP files (ZIP, EAR, WAR " - + "are already treated as zip files)")) + + "are already treated as zip files)")) .addOption(newOptionWithArg(ARGUMENT.PROP_SHORT, ARGUMENT.PROP, "file", "A property file to load.")) .addOption(newOptionWithArg(ARGUMENT.PATH_TO_CORE, "path", "The path to dotnet core.")) .addOption(newOptionWithArg(ARGUMENT.HINTS_FILE, "file", "The file path to the hints XML file.")) @@ -459,6 +498,12 @@ private void addAdvancedOptions(final Options options) { .addOption(newOption(ARGUMENT.DISABLE_ARCHIVE, "Disable the Archive Analyzer.")) .addOption(newOption(ARGUMENT.DISABLE_KEV, "Disable the Known Exploited Vulnerability Analyzer.")) .addOption(newOptionWithArg(ARGUMENT.KEV_URL, "url", "The url to the CISA Known Exploited Vulnerabilities JSON data feed")) + .addOption(newOptionWithArg(ARGUMENT.KEV_USER, "user", "The user for basic authentication towards the CISA Known Exploited " + + "Vulnerabilities JSON data feed")) + .addOption(newOptionWithArg(ARGUMENT.KEV_PASSWORD, "password", "The password for basic authentication towards the CISA Known " + + "Exploited Vulnerabilities JSON data feed")) + .addOption(newOptionWithArg(ARGUMENT.KEV_BEARER_TOKEN, "token", "The token for bearer authentication towards the CISA Known " + + "Exploited Vulnerabilities JSON data feed")) .addOption(newOption(ARGUMENT.DISABLE_ASSEMBLY, "Disable the .NET Assembly Analyzer.")) .addOption(newOption(ARGUMENT.DISABLE_PY_DIST, "Disable the Python Distribution Analyzer.")) .addOption(newOption(ARGUMENT.DISABLE_CMAKE, "Disable the Cmake Analyzer.")) @@ -472,6 +517,7 @@ private void addAdvancedOptions(final Options options) { .addOption(newOption(ARGUMENT.DISABLE_PIP, "Disable the pip Analyzer.")) .addOption(newOption(ARGUMENT.DISABLE_PIPFILE, "Disable the Pipfile Analyzer.")) .addOption(newOption(ARGUMENT.DISABLE_COMPOSER, "Disable the PHP Composer Analyzer.")) + .addOption(newOption(ARGUMENT.COMPOSER_LOCK_SKIP_DEV, "Configures the PHP Composer Analyzer to skip packages-dev")) .addOption(newOption(ARGUMENT.DISABLE_CPAN, "Disable the Perl CPAN file Analyzer.")) .addOption(newOption(ARGUMENT.DISABLE_POETRY, "Disable the Poetry Analyzer.")) .addOption(newOption(ARGUMENT.DISABLE_GOLANG_MOD, "Disable the Golang Mod Analyzer.")) @@ -485,6 +531,7 @@ private void addAdvancedOptions(final Options options) { .addOption(newOption(ARGUMENT.DISABLE_OSSINDEX, "Disable the Sonatype OSS Index Analyzer.")) .addOption(newOption(ARGUMENT.DISABLE_OSSINDEX_CACHE, "Disallow the OSS Index Analyzer from caching results")) .addOption(newOption(ARGUMENT.DISABLE_COCOAPODS, "Disable the CocoaPods Analyzer.")) + .addOption(newOption(ARGUMENT.DISABLE_CARTHAGE, "Disable the Carthage Analyzer.")) .addOption(newOption(ARGUMENT.DISABLE_SWIFT, "Disable the swift package Analyzer.")) .addOption(newOption(ARGUMENT.DISABLE_SWIFT_RESOLVED, "Disable the swift package resolved Analyzer.")) .addOption(newOption(ARGUMENT.DISABLE_GO_DEP, "Disable the Golang Package Analyzer.")) @@ -501,11 +548,17 @@ private void addAdvancedOptions(final Options options) { .addOption(newOption(ARGUMENT.PURGE_NVD, "Purges the local NVD data cache")) .addOption(newOption(ARGUMENT.DISABLE_HOSTED_SUPPRESSIONS, "Disable the usage of the hosted suppressions file")) .addOption(newOption(ARGUMENT.HOSTED_SUPPRESSIONS_FORCEUPDATE, "Force the hosted suppressions file to update even" - + " if autoupdate is disabled")) + + " if autoupdate is disabled")) .addOption(newOptionWithArg(ARGUMENT.HOSTED_SUPPRESSIONS_VALID_FOR_HOURS, "hours", - "The number of hours to wait before checking for new updates of the the hosted suppressions file.")) + "The number of hours to wait before checking for new updates of the the hosted suppressions file.")) .addOption(newOptionWithArg(ARGUMENT.HOSTED_SUPPRESSIONS_URL, "url", - "The URL for a mirrored hosted suppressions file")); + "The URL for a mirrored hosted suppressions file")) + .addOption(newOptionWithArg(ARGUMENT.HOSTED_SUPPRESSIONS_USER, "user", + "The user for basic auth to a mirrored hosted suppressions file")) + .addOption(newOptionWithArg(ARGUMENT.HOSTED_SUPPRESSIONS_PASSWORD, "password", + "The password for basic auth to a mirrored hosted suppressions file")) + .addOption(newOptionWithArg(ARGUMENT.HOSTED_SUPPRESSIONS_BEARER_TOKEN, "token", + "The token for bearer auth to a mirrored hosted suppressions file")); } @@ -733,8 +786,8 @@ public void printHelp() { addAdvancedOptions(options); } final String helpMsg = String.format("%n%s" - + " can be used to identify if there are any known CVE vulnerabilities in libraries utilized by an application. " - + "%s will automatically update required data from the Internet, such as the CVE and CPE data files from nvd.nist.gov.%n%n", + + " can be used to identify if there are any known CVE vulnerabilities in libraries utilized by an application. " + + "%s will automatically update required data from the Internet, such as the CVE and CPE data files from nvd.nist.gov.%n%n", settings.getString(Settings.KEYS.APPLICATION_NAME, "DependencyCheck"), settings.getString(Settings.KEYS.APPLICATION_NAME, "DependencyCheck")); @@ -1014,6 +1067,11 @@ public static class ARGUMENT { * should not be automatically updated. */ public static final String DISABLE_AUTO_UPDATE = "noupdate"; + /** + * The long CLI argument name specifying that the version check should + * not be performed. + */ + public static final String DISABLE_VERSION_CHECK = "disableVersionCheck"; /** * The short CLI argument name specifying that the CPE/CVE/etc. data * should not be automatically updated. @@ -1121,17 +1179,59 @@ public static class ARGUMENT { */ public static final String DATA_DIRECTORY = "data"; /** - * The CLI argument name for setting the URL for the CVE Data Files. + * The CLI argument name for setting the URL for the NVD API Endpoint. */ - public static final String CVE_MODIFIED_URL = "cveUrlModified"; + public static final String NVD_API_ENDPOINT = "nvdApiEndpoint"; /** - * The CLI argument name for setting the URL for the CVE Data Files. + * The CLI argument name for setting the URL for the NVD API Key. */ - public static final String CVE_BASE_URL = "cveUrlBase"; + public static final String NVD_API_KEY = "nvdApiKey"; /** - * The time in milliseconds to wait between downloading NVD CVE data. + * The CLI argument name for setting the maximum number of retry + * requests for a single call to the NVD API. */ - public static final String CVE_DOWNLOAD_WAIT_TIME = "cveDownloadWait"; + public static final String NVD_API_MAX_RETRY_COUNT = "nvdMaxRetryCount"; + /** + * The CLI argument name for setting the number of hours to wait before + * checking for new updates from the NVD. + */ + public static final String NVD_API_VALID_FOR_HOURS = "nvdValidForHours"; + /** + * The CLI argument name for the NVD API Data Feed URL. + */ + public static final String NVD_API_DATAFEED_URL = "nvdDatafeed"; + /** + * The username for basic auth to the CVE data. + */ + public static final String NVD_API_DATAFEED_USER = "nvdUser"; + /** + * The password for basic auth to the CVE data. + */ + public static final String NVD_API_DATAFEED_PASSWORD = "nvdPassword"; + /** + * The token for bearer auth to the CVE data. + */ + public static final String NVD_API_DATAFEED_BEARER_TOKEN = "nvdBearerToken"; + /** + * The username for basic auth to web-hosted suppression files. + */ + public static final String SUPPRESSION_FILE_USER = "suppressionUser"; + /** + * The passwored for basic auth to web-hosted suppression files. + */ + public static final String SUPPRESSION_FILE_PASSWORD = "suppressionPassword"; + /** + * The toke for bearer auth to web-hosted suppression files. + */ + public static final String SUPPRESSION_FILE_BEARER_TOKEN = "suppressionBearerToken"; + /** + * The time in milliseconds to wait between downloading NVD API data. + */ + public static final String NVD_API_DELAY = "nvdApiDelay"; + /** + * The number records for a single page from NVD API. + */ + public static final String NVD_API_RESULTS_PER_PAGE = "nvdApiResultsPerPage"; /** * The short CLI argument name for setting the location of the data * directory. @@ -1160,24 +1260,6 @@ public static class ARGUMENT { * The CLI argument name for setting the location of the hint file. */ public static final String HINTS_FILE = "hints"; - /** - * The CLI argument name for setting the number of hours to wait before - * checking for new updates from the NVD. - */ - public static final String CVE_VALID_FOR_HOURS = "cveValidForHours"; - /** - * The CLI argument name for setting the first year to retrieve NVD - * data. - */ - public static final String CVE_START_YEAR = "cveStartYear"; - /** - * The username for basic auth to the CVE data. - */ - public static final String CVE_USER = "cveUser"; - /** - * The password for basic auth to the CVE data. - */ - public static final String CVE_PASSWORD = "cvePassword"; /** * Disables the Jar Analyzer. */ @@ -1198,6 +1280,18 @@ public static class ARGUMENT { * The URL to the CISA Known Exploited Vulnerability JSON datafeed. */ public static final String KEV_URL = "kevURL"; + /** + * The user for basic auth towards a CISA Known Exploited Vulnerability JSON datafeed mirror. + */ + public static final String KEV_USER = "kevUser"; + /** + * The password for basic auth towards a CISA Known Exploited Vulnerability JSON datafeed mirror. + */ + public static final String KEV_PASSWORD = "kevPassword"; + /** + * The token for bearer auth towards a CISA Known Exploited Vulnerability JSON datafeed mirror. + */ + public static final String KEV_BEARER_TOKEN = "kevBearerToken"; /** * Disables the Python Distribution Analyzer. */ @@ -1218,6 +1312,10 @@ public static class ARGUMENT { * Disables the PHP Composer Analyzer. */ public static final String DISABLE_COMPOSER = "disableComposer"; + /** + * Whether the PHP Composer Analyzer skips dev packages. + */ + public static final String COMPOSER_LOCK_SKIP_DEV = "composerSkipDev"; /** * Disables the Perl CPAN File Analyzer. */ @@ -1274,6 +1372,10 @@ public static class ARGUMENT { * Disables the cocoapods analyzer. */ public static final String DISABLE_COCOAPODS = "disableCocoapodsAnalyzer"; + /** + * Disables the Carthage analyzer. + */ + public static final String DISABLE_CARTHAGE = "disableCarthageAnalyzer"; /** * Disables the swift package manager analyzer. */ @@ -1310,6 +1412,22 @@ public static class ARGUMENT { * Disables the Central Analyzer's ability to cache results locally. */ public static final String DISABLE_CENTRAL_CACHE = "disableCentralCache"; + /** + * The alternative URL for Maven Central Search. + */ + public static final String CENTRAL_URL = "centralUrl"; + /** + * The username for basic authentication to the alternative Maven Central Search. + */ + public static final String CENTRAL_USERNAME = "centralUsername"; + /** + * The password for basic authentication to the alternative Maven Central Search. + */ + public static final String CENTRAL_PASSWORD = "centralPassword"; + /** + * The token for bearer authentication to the alternative Maven Central Search. + */ + public static final String CENTRAL_BEARER_TOKEN = "centralBearerToken"; /** * Disables the Nexus Analyzer. */ @@ -1385,13 +1503,17 @@ public static class ARGUMENT { */ public static final String RETIREJS_URL = "retireJsUrl"; /** - * The username to the retire JS repository. + * The username for basic auth to the retire JS repository. */ public static final String RETIREJS_URL_USER = "retireJsUrlUser"; /** - * The password to the retire JS repository. + * The password for basic auth to the retire JS repository. */ public static final String RETIREJS_URL_PASSWORD = "retireJsUrlPass"; + /** + * The token for bearer auth to the retire JS repository. + */ + public static final String RETIREJS_URL_BEARER_TOKEN = "retireJsUrlBearerToken"; /** * The URL of the nexus server. */ @@ -1523,21 +1645,36 @@ public static class ARGUMENT { */ public static final String FAIL_JUNIT_ON_CVSS = "junitFailOnCVSS"; /** - * The CLI argument to set the number of hours to wait before re-checking hosted suppressions file for updates. + * The CLI argument to set the number of hours to wait before + * re-checking hosted suppressions file for updates. */ public static final String DISABLE_HOSTED_SUPPRESSIONS = "disableHostedSuppressions"; /** - * The CLI argument to set the number of hours to wait before re-checking hosted suppressions file for updates. + * The CLI argument to set the number of hours to wait before + * re-checking hosted suppressions file for updates. */ public static final String HOSTED_SUPPRESSIONS_VALID_FOR_HOURS = "hostedSuppressionsValidForHours"; /** - * The CLI argument to set Whether the hosted suppressions file will update regardless of the `noupdate` argument. + * The CLI argument to set Whether the hosted suppressions file will + * update regardless of the `noupdate` argument. */ public static final String HOSTED_SUPPRESSIONS_FORCEUPDATE = "hostedSuppressionsForceUpdate"; /** - * The CLI argument to set the location of a mirrored hosted suppressions - * file . + * The CLI argument to set the location of a mirrored hosted + * suppressions file . */ public static final String HOSTED_SUPPRESSIONS_URL = "hostedSuppressionsUrl"; + /** + * The username for basic auth to a mirrored hosted suppressions file. + */ + public static final String HOSTED_SUPPRESSIONS_USER = "hostedSuppressionsUser"; + /** + * The passwored for basic auth to a mirrored hosted suppressions file. + */ + public static final String HOSTED_SUPPRESSIONS_PASSWORD = "hostedSuppressionsPassword"; + /** + * The toke for bearer auth to a mirrored hosted suppressions file. + */ + public static final String HOSTED_SUPPRESSIONS_BEARER_TOKEN = "hostedSuppressionsBearerToken"; } } diff --git a/cli/src/main/resources/completion-for-dependency-check.sh b/cli/src/main/resources/completion-for-dependency-check.sh index 76af9d41d9a..09ffff27370 100755 --- a/cli/src/main/resources/completion-for-dependency-check.sh +++ b/cli/src/main/resources/completion-for-dependency-check.sh @@ -19,13 +19,6 @@ _odc_completions() --bundleAuditWorkingDirectory -c --connectiontimeout --connectionString - --cveUrlBase - --cveUrlModified - --cveValidForHours - --cveStartYear - --cveUser - --cvePassword - --cveDownloadWait -d --data --dbDriverName --dbDriverPath @@ -39,6 +32,7 @@ _odc_completions() --disableCentralCache --disableCmake --disableCocoapodsAnalyzer + --disableCarthageAnalyzer --disableComposer --disableDart --disableFileName @@ -94,6 +88,12 @@ _odc_completions() --nodeAuditSkipDevDependencies --nodePackageSkipDevDependencies --nonProxyHosts + --nvdApiKey + --nvdDatafeed + --nvdUser + --nvdPassword + --nvdApiDelay + --nvdValidForHours -o --out --ossIndexPassword --ossIndexUsername diff --git a/cli/src/main/resources/logback.xml b/cli/src/main/resources/logback.xml index c7adf1499db..da49803591a 100644 --- a/cli/src/main/resources/logback.xml +++ b/cli/src/main/resources/logback.xml @@ -9,9 +9,12 @@ [%level] %msg%n - + + + + - \ No newline at end of file + diff --git a/cli/src/site/markdown/arguments.md b/cli/src/site/markdown/arguments.md index 0cb8d1baf3c..28f99c21090 100644 --- a/cli/src/site/markdown/arguments.md +++ b/cli/src/site/markdown/arguments.md @@ -3,122 +3,142 @@ Command Line Arguments The following table lists the command line arguments: -| Short | Argument Name | Parameter | Description | Requirement | -|-------|------------------------|-----------------|----------------------------------------|-------------| -| | \-\-project | \ | The name of the project being scanned. | Optional | -| \-s | \-\-scan | \ | The path to scan \- this option can be specified multiple times. It is also possible to specify Ant style paths (e.g. 'directory/**/*.jar'); if using an Ant style path it is highly recommended that you use single quotes around the path so that the shell itself does not automatically perform replacements (see [issue #1812](https://github.com/jeremylong/DependencyCheck/issues/1812). | Required | -| | \-\-exclude | \ | The path patterns to exclude from the scan \- this option can be specified multiple times. This accepts Ant style path patterns (e.g. **/exclude/**). | Optional | -| | \-\-symLink | \ | The depth that symbolic links will be followed; the default is 0 meaning symbolic links will not be followed. | Optional | -| \-o | \-\-out | \ | The folder to write reports to. This defaults to the current directory. If the format is not set to ALL one could specify a specific file name. | Optional | -| \-f | \-\-format | \ | The output format to write to (XML, HTML, CSV, JSON, JUNIT, SARIF, ALL). Multiple formats can be specified by specifying the parameter multiple times. The default is HTML. | Required | -| | \-\-junitFailOnCVSS | \ | If using the JUNIT report format the junitFailOnCVSS sets the CVSS score threshold that is considered a failure. The default is 0. | Optional | -| | \-\-prettyPrint | | When specified the JSON and XML report formats will be pretty printed. | Optional | -| | \-\-failOnCVSS | \ | If the score set between 0 and 10 the exit code from dependency-check will indicate if a vulnerability with a CVSS score equal to or higher was identified. | Optional | -| \-l | \-\-log | \ | The file path to write verbose logging information. | Optional | -| \-n | \-\-noupdate | | Disables the automatic updating of the NVD-CVE, hosted-suppressions and RetireJS data. | Optional | -| | \-\-suppression | \ | The file paths to the suppression XML files; used to suppress [false positives](../general/suppression.html). This can be specified more than once to utilize multiple suppression files. The argument can be a local file path, a URL to a suppression file, or even a reference to a file on the class path (see https://github.com/jeremylong/DependencyCheck/issues/1878#issuecomment-487533799) | Optional | -| \-h | \-\-help | | Print the help message. | Optional | -| | \-\-advancedHelp | | Print the advanced help message. | Optional | -| \-v | \-\-version | | Print the version information. | Optional | -| | \-\-cveValidForHours | \ | The number of hours to wait before checking for new updates from the NVD. The default is 4 hours. | Optional | -| | \-\-enableExperimental | | Enable the [experimental analyzers](../analyzers/index.html). If not set the analyzers marked as experimental below will not be loaded or used. | Optional | -| | \-\-enableRetired | | Enable the [retired analyzers](../analyzers/index.html). If not set the analyzers marked as retired below will not be loaded or used. | Optional | +| Short | Argument Name | Parameter | Description | Requirement | +|-------|------------------------|-------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------| +| | \-\-project | \ | The name of the project being scanned. | Optional | +| \-s | \-\-scan | \ | The path to scan \- this option can be specified multiple times. It is also possible to specify Ant style paths (e.g. 'directory/**/*.jar'); if using an Ant style path it is highly recommended that you use single quotes around the path so that the shell itself does not automatically perform replacements (see [issue #1812](https://github.com/dependency-check/DependencyCheck/issues/1812). | Required | +| | \-\-exclude | \ | The path patterns to exclude from the scan \- this option can be specified multiple times. This accepts Ant style path patterns (e.g. **/exclude/**). | Optional | +| | \-\-symLink | \ | The depth that symbolic links will be followed; the default is 0 meaning symbolic links will not be followed. | Optional | +| \-o | \-\-out | \ | The folder to write reports to. This defaults to the current directory. If the format is not set to ALL one could specify a specific file name. | Optional | +| \-f | \-\-format | \ | The output format to write to (HTML, XML, CSV, JSON, JUNIT, SARIF, JENKINS, GITLAB, ALL). Multiple formats can be specified by specifying the parameter multiple times. The default is HTML. | Required | +| | \-\-junitFailOnCVSS | \ | If using the JUNIT report format the junitFailOnCVSS sets the CVSS score threshold that is considered a failure. The default is 0. | Optional | +| | \-\-prettyPrint | | When specified the JSON and XML report formats will be pretty printed. | Optional | +| | \-\-failOnCVSS | \ | If the score set between 0 and 10 the exit code from dependency-check will indicate if a vulnerability with a CVSS score equal to or higher was identified. | Optional | +| \-l | \-\-log | \ | The file path to write verbose logging information. | Optional | +| \-n | \-\-noupdate | | Disables the automatic updating of the NVD-CVE, hosted-suppressions and RetireJS data. | Optional | +| | \-\-suppression | \ | The file paths to the suppression XML files; used to suppress [false positives](../general/suppression.html). This can be specified more than once to utilize multiple suppression files. The argument can be a local file path, a URL to a suppression file, or even a reference to a file on the class path (see https://github.com/dependency-check/DependencyCheck/issues/1878#issuecomment-487533799) | Optional | +| \-h | \-\-help | | Print the help message. | Optional | +| | \-\-advancedHelp | | Print the advanced help message. | Optional | +| \-v | \-\-version | | Print the version information. | Optional | +| | \-\-enableExperimental | | Enable the [experimental analyzers](../analyzers/index.html). If not set the analyzers marked as experimental below will not be loaded or used. | Optional | +| | \-\-enableRetired | | Enable the [retired analyzers](../analyzers/index.html). If not set the analyzers marked as retired below will not be loaded or used. | Optional | Advanced Options ================ -| Short | Argument Name | Parameter | Description | Default Value | -|-------|---------------------------------------|-----------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------| -| | \-\-cveUrlModified | \ | URL for the modified CVE JSON data feed. When mirroring the NVD you must mirror the *.json.gz and the *.meta files. Optional if your custom cveUrlBase is just a domain name change. | https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-modified.json.gz | -| | \-\-cveUrlBase | \ | Base URL for each year's CVE JSON data feed, the %d will be replaced with the year. | https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-%d.json.gz | -| | \-\-cveUser | \ | Credentials used for basic authentication for the CVE data. |   | -| | \-\-cvePassword | \ | Credentials used for basic authentication for the CVE data. |   | -| | \-\-cveStartYear | \ | The first year of NVD CVE data to retrieve. | 2002 | -| | \-\-cveDownloadWait | \| The number of milliseconds to wait between NVD CVE download. | 4000 | -| | \-\-hints | \ | The file path to the XML hints file \- used to resolve [false negatives](../general/hints.html) |   | -| \-P | \-\-propertyfile | \ | Specifies a file that contains properties to use instead of application defaults. The key values used in the properties file are not the same as the arguments listed on this page; use the keys here: https://github.com/jeremylong/DependencyCheck/blob/main/core/src/main/resources/dependencycheck.properties |   | -| | \-\-updateonly | | If set only the update phase of dependency-check will be executed; no scan will be executed and no report will be generated. |   | -| | \-\-disableKnownExploited | | Sets whether the Known Exploited Vulnerability update and analyzer are enabled. |   | -| | \-\-kevURL | \ | URL to the CISA Known Exploited Vulnerabilities JSON data feed. | https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json | -| | \-\-disableFileName | | Disables the File Name Analyzer; in generally, this should not be disabled. |   | -| | \-\-disablePyDist | | Sets whether the [experimental](../analyzers/index.html) Python Distribution Analyzer will be used. |   | -| | \-\-disablePyPkg | | Sets whether the [experimental](../analyzers/index.html) Python Package Analyzer will be used. |   | -| | \-\-disableMSBuild | | Sets whether the MS Build Project Analyzer will be used. |   | -| | \-\-disableNodeJS | | Sets whether the Node.js Package Analyzer will be used. |   | -| | \-\-disableYarnAudit | | Sets whether the yarn Audit Analyzer will be used. This analyzer requires an internet connection and that yarn is installed. Use `--nodeAuditSkipDevDependencies` to skip dev dependencies. |   | -| | \-\-yarn | \ | The path to `yarn`. |   | -| | \-\-disablePnpmAudit | | Sets whether the pnpm Audit Analyzer will be used. This analyzer requires an internet connection and that pnpm is installed. Use `--nodeAuditSkipDevDependencies` to skip dev dependencies. |   | -| | \-\-pnpm | \ | The path to `pnpm`. |   | -| | \-\-disableNodeAudit | | Sets whether the Node Audit Analyzer will be used. This analyzer requires an internet connection. |   | -| | \-\-disableNodeAuditCache | | When the argument is present the Node Audit Analyzer will not cache results. By default the results are cached for 24 hours. |   | -| | \-\-nodeAuditSkipDevDependencies | | Configures the Node Audit Analyzer to skip devDependencies. |   | -| | \-\-nodePackageSkipDevDependencies | | Configures the Node Package Analyzer to skip devDependencies. |   | -| | \-\-disableRetireJS | | Sets whether the RetireJS Analyzer will be used. |   | -| | \-\-retireJsForceUpdate | | Sets whether the RetireJS Analyzer will update regardless of the `noupdate` argument. | false | -| | \-\-retireJsUrl | \ | The URL to the Retire JS repository. | https://raw.githubusercontent.com/Retirejs/retire.js/master/repository/jsrepository.json | -| | \-\-retirejsFilter | \ | The RetireJS Analyzers content filter used to exclude JS files when the content contains the given regular expression; this option can be specified multiple times. |   | -| | \-\-retirejsFilterNonVulnerable | | Specifies that the Retire JS Analyzer should filter out non-vulnerable JS files from the report. |   | -| | \-\-retirejsUser | \ | Credentials used for basic authentication for the RetireJS data. |   | -| | \-\-retirejsPassword | \ | Credentials used for basic authentication for the RetireJS data. |   | -| | \-\-disableRubygems | | Sets whether the [experimental](../analyzers/index.html) Ruby Gemspec Analyzer will be used. |   | -| | \-\-disableBundleAudit | | Sets whether the [experimental](../analyzers/index.html) Ruby Bundler Audit Analyzer will be used. |   | -| | \-\-disableCocoapodsAnalyzer | | Sets whether the [experimental](../analyzers/index.html) Cocoapods Analyzer will be used. |   | -| | \-\-disableSwiftPackageManagerAnalyzer | | Sets whether the [experimental](../analyzers/index.html) Swift Package Manager Analyzer will be used. |   | -| | \-\-disableSwiftPackageResolvedAnalyzer| | Sets whether the [experimental](../analyzers/index.html) Swift Package Resolved Analyzer will be used. |   | -| | \-\-disableAutoconf | | Sets whether the [experimental](../analyzers/index.html) Autoconf Analyzer will be used. |   | -| | \-\-disableOpenSSL | | Sets whether the OpenSSL Analyzer will be used. |   | -| | \-\-disableCmake | | Sets whether the [experimental](../analyzers/index.html) Cmake Analyzer will be disabled. |   | -| | \-\-disableArchive | | Sets whether the Archive Analyzer will be disabled. |   | -| | \-\-zipExtensions | \ | A comma-separated list of additional file extensions to be treated like a ZIP file, the contents will be extracted and analyzed. |   | -| | \-\-disableJar | | Sets whether the Jar Analyzer will be disabled. |   | -| | \-\-disableComposer | | Sets whether the [experimental](../analyzers/index.html) PHP Composer Lock File Analyzer will be disabled. |   | -| | \-\-disableCpan | | Sets whether the [experimental](../analyzers/index.html) Perl CPAN File Analyzer will be disabled. |   | -| | \-\-disableDart | | Sets whether the [experimental](../analyzers/index.html) Dart Analyzer will be disabled. |   | -| | \-\-disableOssIndex | | Sets whether the [OSS Index Analyzer](../analyzers/oss-index-analyzer.html) will be disabled. This analyzer requires an internet connection. |   | -| | \-\-disableOssIndexCache | | When the argument is present the OSS Index Analyzer will not cache results. By default results are cached for 24 hours. |   | -| | \-\-ossIndexUsername | \ | The optional username to connect to Sonatype's OSS Index. |   | -| | \-\-ossIndexPassword | \ | The optional password to connect to Sonatype's OSS Index. |   | -| | \-\-ossIndexRemoteErrorWarnOnly | \ | Whether we should only warn about Sonatype OSS Index remote errors instead of failing completely. |   | -| | \-\-ossIndexUrl | \ | Alternative URL for the OSS Index. If not set the public Sonatype OSS Index will be used. | https://ossindex.sonatype.org | -| | \-\-disableCentral | | Sets whether the Central Analyzer will be used. **Disabling this analyzer is not recommended as it could lead to false negatives (e.g. libraries that have vulnerabilities may not be reported correctly).** If this analyzer is being disabled there is a good chance you also want to disable the Artifactory or Nexus Analyzer. |   | -| | \-\-disableCentralCache | | When the argument is present the Central Analyzer will not cache results locally. By default results are cached locally for 30 days. |   | -| | \-\-enableNexus | | Sets whether the Nexus Analyzer will be used (requires Nexus v2 or Pro v3). You can configure the Nexus URL to utilize an internally hosted Nexus server. |   | -| | \-\-enableArtifactory | | Sets whether Artifactory analyzer will be used |   | -| | \-\-artifactoryUrl | \ | The Artifactory server URL. |   | -| | \-\-artifactoryUseProxy | \ | Whether Artifactory should be accessed through a proxy or not. | false | -| | \-\-artifactoryParallelAnalysis | \ | Whether the Artifactory analyzer should be run in parallel or not | true | -| | \-\-artifactoryUsername | \ | The user name (only used with API token) to connect to Artifactory instance |   | -| | \-\-artifactoryApiToken | \ | The API token to connect to Artifactory instance, only used if the username or the API key are not defined by artifactoryAnalyzerServerId, artifactoryAnalyzerUsername or artifactoryAnalyzerApiToken. |   | -| | \-\-artifactoryBearerToken | \ | The bearer token to connect to Artifactory instance |   | -| | \-\-nexus | \ | The url to the Nexus Server's web service end point (example: http://domain.enterprise/nexus/service/local/). If not set the Nexus Analyzer will be disabled. |   | -| | \-\-nexusUser | \ | The username to authenticate to the Nexus Server's REST API Endpoint. If not set the Nexus Analyzer will use an unauthenticated connection. |   | -| | \-\-nexusPass | \ | The password to authenticate to the Nexus Server's REST API Endpoint. If not set the Nexus Analyzer will use an unauthenticated connection. |   | -| | \-\-nexusUsesProxy | \ | Whether or not the defined proxy should be used when connecting to Nexus. | true | -| | \-\-disableNuspec | | Sets whether the .NET Nuget Nuspec Analyzer will be used. |   | -| | \-\-disableNugetconf | | Sets whether the [experimental](../analyzers/index.html) .NET Nuget packages.config Analyzer will be used. |   | -| | \-\-disableAssembly | | Sets whether the .NET Assembly Analyzer should be used. |   | -| | \-\-dotnet | \ | The path to dotnet core for .NET Assembly analysis on non-windows systems. |   | -| | \-\-disableGolangDep | | Sets whether the [experimental](../analyzers/index.html) Go Dependency Analyzer should be used. |   | -| | \-\-disableGolangMod | | Sets whether the [experimental](../analyzers/index.html) Go Mod Analyzer should be used. |   | -| | \-\-disableMixAudit | | Sets whether the [experimental](../analyzers/index.html) Elixir mix audit Analyze should be used. |   | -| | \-\-disablePoetry | | Sets whether the [experimental](../analyzers/index.html) Poetry Analyzer should be used. |   | -| | \-\-go | \ | The path to `go` executable for the Go Mode Analyzer; only necassary if `go` is not on the path. |   | -| | \-\-bundleAudit | | The path to the bundle-audit executable. |   | -| | \-\-bundleAuditWorkingDirectory | \ | The path to working directory that the bundle-audit command should be executed from when doing Gem bundle analysis. |   | -| | \-\-proxyserver | \ | The proxy server to use when downloading resources; see the [proxy configuration](../data/proxy.html) page for more information. |   | -| | \-\-proxyport | \ | The proxy port to use when downloading resources. |   | -| | \-\-nonProxyHosts | \ | The proxy exclusion list: hostnames (or patterns) for which proxy should not be used. Use pipe, comma or colon as list separator. Example: `something.com|*.something.com|www.somethingelse.*` |   | -| \-c | \-\-connectiontimeout | \ | The connection timeout (in milliseconds) to use when downloading resources. | 10000 | -| | \-\-readtimeout | \ | The read timeout (in milliseconds) to use when downloading resources. | 60000 | -| | \-\-proxypass | \ | The proxy password to use when downloading resources. |   | -| | \-\-proxyuser | \ | The proxy username to use when downloading resources. |   | -| | \-\-connectionString | \ | The connection string to the database. See using a [database server](../data/database.html). |   | -| | \-\-dbDriverName | \ | The database driver name. |   | -| | \-\-dbDriverPath | \ | The path to the database driver; note, this does not need to be set unless the JAR is outside of the class path. |   | -| | \-\-dbPassword | \ | The password for connecting to the database. |   | -| | \-\-dbUser | \ | The username used to connect to the database. |   | -| \-d | \-\-data | \ | The location of the data directory used to store persistent data. This option should generally not be set. |   | -| | \-\-purge | | Delete the local copy of the NVD. This is used to force a refresh of the data. |   | -| | \-\-disableHostedSuppressions | | Whether the usage of the hosted suppressions file will be disabled. | false | -| | \-\-hostedSuppressionsForceUpdate | | Whether the hosted suppressions file will update regardless of the `noupdate` argument. | false | -| | \-\-hostedSuppressionsValidForHours | \ | The number of hours to wait before checking for new updates of the hosted suppressions file | 2 | -| | \-\-hostedSuppressionsUrl | \ | The URL to a mirrored copy of the hosted suppressions file for internet-constrained environments | https://jeremylong.github.io/DependencyCheck/suppressions/publishedSuppressions.xml | +| Short | Argument Name | Parameter | Description | Default Value | +|-------|-----------------------------------------|------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| | \-\-nvdApiKey | \ | The API Key to access the NVD API; obtained from https://nvd.nist.gov/developers/request-an-api-key |   | +| | \-\-nvdApiEndpoint | \ | The NVD API endpoint URL; setting this is uncommon. | https://services.nvd.nist.gov/rest/json/cves/2.0 | +| | \-\-nvdMaxRetryCount | \ | The maximum number of retry requests for a single call to the NVD API. | 10 | +| | \-\-nvdApiDelay | \ | The number of milliseconds to wait between calls to the NVD API. | 3500 with an NVD API Key or 8000 without an API Key | +| | \-\-nvdApiResultsPerPage | \ | The number records for a single page from NVD API (must be <=2000). | 2000 | +| | \-\-nvdDatafeed | \ | The URL for the NVD API Data feed that can be generated using https://github.com/jeremylong/open-vulnerability-cli/blob/main/README.md#mirroring-the-nvd-cve-data - example value `https://internal.server/cache/nvdcve-{0}.json.gz` |   | +| | \-\-nvdUser | \ | Credentials used for basic authentication for the NVD API Data feed. |   | +| | \-\-nvdPassword | \ | Credentials used for basic authentication for the NVD API Data feed. |   | +| | \-\-nvdBearerToken | \ | Credentials used for bearer authentication for the NVD API Data feed. |   | +| | \-\-nvdValidForHours | \ | The number of hours to wait before checking for new updates from the NVD. The default is 4 hours. | 4 | +| | \-\-hints | \ | The file path to the XML hints file \- used to resolve [false negatives](../general/hints.html) |   | +| \-P | \-\-propertyfile | \ | Specifies a file that contains properties to use instead of application defaults. The key values used in the properties file are not the same as the arguments listed on this page; use the keys here: https://github.com/dependency-check/DependencyCheck/blob/main/core/src/main/resources/dependencycheck.properties |   | +| | \-\-updateonly | | If set only the update phase of dependency-check will be executed; no scan will be executed and no report will be generated. |   | +| | \-\-disableKnownExploited | | Sets whether the Known Exploited Vulnerability update and analyzer are enabled. |   | +| | \-\-kevURL | \ | URL to the CISA Known Exploited Vulnerabilities JSON data feed. | https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json | +| | \-\-kevUser | \ | Credentials used for basic authentication for the CISA Known Exploited Vulnerabilities JSON data feed. |   | +| | \-\-kevPassword | \ | Credentials used for basic authentication for URL to the CISA Known Exploited Vulnerabilities JSON data feed. |   | +| | \-\-kevBearerToken | \ | Credentials used for bearer authentication for URL to the CISA Known Exploited Vulnerabilities JSON data feed. |   | +| | \-\-disableFileName | | Disables the File Name Analyzer; in generally, this should not be disabled. |   | +| | \-\-disablePyDist | | Sets whether the [experimental](../analyzers/index.html) Python Distribution Analyzer will be used. |   | +| | \-\-disablePyPkg | | Sets whether the [experimental](../analyzers/index.html) Python Package Analyzer will be used. |   | +| | \-\-disableMSBuild | | Sets whether the MS Build Project Analyzer will be used. |   | +| | \-\-disableNodeJS | | Sets whether the Node.js Package Analyzer will be used. |   | +| | \-\-disableYarnAudit | | Sets whether the yarn Audit Analyzer will be used. This analyzer requires an internet connection and that yarn is installed. Use `--nodeAuditSkipDevDependencies` to skip dev dependencies. |   | +| | \-\-yarn | \ | The path to `yarn`. |   | +| | \-\-disablePnpmAudit | | Sets whether the pnpm Audit Analyzer will be used. This analyzer requires an internet connection and that pnpm is installed. Use `--nodeAuditSkipDevDependencies` to skip dev dependencies. |   | +| | \-\-pnpm | \ | The path to `pnpm`. |   | +| | \-\-disableNodeAudit | | Sets whether the Node Audit Analyzer will be used. This analyzer requires an internet connection. |   | +| | \-\-disableNodeAuditCache | | When the argument is present the Node Audit Analyzer will not cache results. By default the results are cached for 24 hours. |   | +| | \-\-nodeAuditSkipDevDependencies | | Configures the Node Audit Analyzer to skip devDependencies. |   | +| | \-\-nodePackageSkipDevDependencies | | Configures the Node Package Analyzer to skip devDependencies. |   | +| | \-\-disableRetireJS | | Sets whether the RetireJS Analyzer will be used. |   | +| | \-\-retireJsForceUpdate | | Sets whether the RetireJS Analyzer will update regardless of the `noupdate` argument. | false | +| | \-\-retireJsUrl | \ | The URL to the Retire JS repository. | https://raw.githubusercontent.com/Retirejs/retire.js/master/repository/jsrepository.json | +| | \-\-retirejsFilter | \ | The RetireJS Analyzers content filter used to exclude JS files when the content contains the given regular expression; this option can be specified multiple times. |   | +| | \-\-retirejsFilterNonVulnerable | | Specifies that the Retire JS Analyzer should filter out non-vulnerable JS files from the report. |   | +| | \-\-retireJsUrlUser | \ | Credentials used for basic authentication for the RetireJS data. |   | +| | \-\-retirejsUrlPassword | \ | Credentials used for basic authentication for the RetireJS data. |   | +| | \-\-retirejsUrlBearerToken | \ | Credentials used for bearer authentication for the RetireJS data. |   | +| | \-\-disableRubygems | | Sets whether the [experimental](../analyzers/index.html) Ruby Gemspec Analyzer will be used. |   | +| | \-\-disableBundleAudit | | Sets whether the [experimental](../analyzers/index.html) Ruby Bundler Audit Analyzer will be used. |   | +| | \-\-disableCocoapodsAnalyzer | | Sets whether the [experimental](../analyzers/index.html) Cocoapods Analyzer will be used. |   | +| | \-\-disableCarthageAnalyzer | | Sets whether the [experimental](../analyzers/index.html) Carthage Analyzer will be used. |   | +| | \-\-disableSwiftPackageManagerAnalyzer | | Sets whether the [experimental](../analyzers/index.html) Swift Package Manager Analyzer will be used. |   | +| | \-\-disableSwiftPackageResolvedAnalyzer | | Sets whether the [experimental](../analyzers/index.html) Swift Package Resolved Analyzer will be used. |   | +| | \-\-disableAutoconf | | Sets whether the [experimental](../analyzers/index.html) Autoconf Analyzer will be used. |   | +| | \-\-disableOpenSSL | | Sets whether the OpenSSL Analyzer will be used. |   | +| | \-\-disableCmake | | Sets whether the [experimental](../analyzers/index.html) Cmake Analyzer will be disabled. |   | +| | \-\-disableArchive | | Sets whether the Archive Analyzer will be disabled. |   | +| | \-\-zipExtensions | \ | A comma-separated list of additional file extensions to be treated like a ZIP file, the contents will be extracted and analyzed. |   | +| | \-\-disableJar | | Sets whether the Jar Analyzer will be disabled. |   | +| | \-\-disableComposer | | Sets whether the [experimental](../analyzers/index.html) PHP Composer Lock File Analyzer will be disabled. |   | +| | \-\-composerSkipDev | | Sets whether the [experimental](../analyzers/index.html) PHP Composer Lock File Analyzer should skip "packages-dev". |   | +| | \-\-disableCpan | | Sets whether the [experimental](../analyzers/index.html) Perl CPAN File Analyzer will be disabled. |   | +| | \-\-disableDart | | Sets whether the [experimental](../analyzers/index.html) Dart Analyzer will be disabled. |   | +| | \-\-disableOssIndex | | Sets whether the [OSS Index Analyzer](../analyzers/oss-index-analyzer.html) will be disabled. This analyzer requires an internet connection. |   | +| | \-\-disableOssIndexCache | | When the argument is present the OSS Index Analyzer will not cache results. By default results are cached for 24 hours. |   | +| | \-\-ossIndexUsername | \ | To authenticate Sonatype OSS Index requests and profit from higher rate limits, provide the OSS account email address as username. Provide both a username _and_ a password (see below) or none. |   | +| | \-\-ossIndexPassword | \ | Password or API token to connect to Sonatype's OSS Index. Provide both a username (see above) _and_ a password or none. |   | +| | \-\-ossIndexRemoteErrorWarnOnly | \ | Whether we should only warn about Sonatype OSS Index remote errors instead of failing completely. |   | +| | \-\-ossIndexUrl | \ | Alternative URL for the OSS Index. If not set the public Sonatype OSS Index will be used. | https://ossindex.sonatype.org | +| | \-\-disableCentral | | Sets whether the Central Analyzer will be used to enrich Java dependencies. **Disabling this analyzer is not recommended as it could lead to false negatives (e.g. libraries that have vulnerabilities may not be reported correctly).** If this analyzer is being disabled, you can use the Artifactory Analyzer or Nexus Analyzer as a replacement. |   | +| | \-\-disableCentralCache | | When the argument is present the Central Analyzer will not cache results locally. By default results are cached locally for 30 days. |   | +| | \-\-centralUrl | | Alternative URL for Maven Central Search. If not set the public Sonatype Maven Central will be used. | https://search.maven.org/solrsearch/select | +| | \-\-centralUsername | \ | The username to authenticate with bearer auth to the alternative Maven Central url set by the 'centralUrl' argument. If neither basic nor bearer auth config is set it will use an unauthenticated connection. |   | +| | \-\-centralPassword | \ | The password to authenticate with bearer auth to the alternative Maven Central url set by the 'centralUrl' argument. If neither basic nor bearer auth config is set it will use an unauthenticated connection. |   | +| | \-\-centralBearerToken | \ | The token to authenticate with bearer auth to the alternative Maven Central url set by the 'centralUrl' argument. If neither basic nor bearer auth config is set it will use an unauthenticated connection. |   | +| | \-\-enableNexus | | Sets whether Nexus Analyzer will be used. This analyzer is an alternative to the Central or Artifactory Analyzers, allowing retrieval from Sonatype Nexus installations. |   | +| | \-\-enableArtifactory | | Sets whether Artifactory analyzer will be used to enrich Java dependencies. **To use Artifactory, you will need to disable the central analyzer by adding the --disableCentral parameter.** |   | +| | \-\-artifactoryUrl | \ | The Artifactory server URL. |   | +| | \-\-artifactoryUseProxy | \ | Whether Artifactory should be accessed through a proxy or not. | false | +| | \-\-artifactoryParallelAnalysis | \ | Whether the Artifactory analyzer should be run in parallel or not | true | +| | \-\-artifactoryUsername | \ | The user name (only used with API token) to connect to Artifactory instance |   | +| | \-\-artifactoryApiToken | \ | The API token to connect to Artifactory instance, only used if the username or the API key are not defined by artifactoryAnalyzerServerId, artifactoryAnalyzerUsername or artifactoryAnalyzerApiToken. |   | +| | \-\-artifactoryBearerToken | \ | The bearer token to connect to Artifactory instance |   | +| | \-\-nexus | \ | The url to the Nexus Server's web service end point (example: http://domain.enterprise/nexus/service/local/). If not set the Nexus Analyzer will be disabled. |   | +| | \-\-nexusUser | \ | The username to authenticate to the Nexus Server's REST API Endpoint. If not set the Nexus Analyzer will use an unauthenticated connection. |   | +| | \-\-nexusPass | \ | The password to authenticate to the Nexus Server's REST API Endpoint. If not set the Nexus Analyzer will use an unauthenticated connection. |   | +| | \-\-nexusUsesProxy | \ | Whether or not the defined proxy should be used when connecting to Nexus. | true | +| | \-\-disableNuspec | | Sets whether the .NET Nuget Nuspec Analyzer will be used. |   | +| | \-\-disableNugetconf | | Sets whether the [experimental](../analyzers/index.html) .NET Nuget packages.config Analyzer will be used. |   | +| | \-\-disableAssembly | | Sets whether the .NET Assembly Analyzer should be used. |   | +| | \-\-dotnet | \ | The path to dotnet core for .NET Assembly analysis on non-windows systems. |   | +| | \-\-disableGolangDep | | Sets whether the [experimental](../analyzers/index.html) Go Dependency Analyzer should be used. |   | +| | \-\-disableGolangMod | | Sets whether the [experimental](../analyzers/index.html) Go Mod Analyzer should be used. |   | +| | \-\-disableMixAudit | | Sets whether the [experimental](../analyzers/index.html) Elixir mix audit Analyze should be used. |   | +| | \-\-disablePoetry | | Sets whether the [experimental](../analyzers/index.html) Poetry Analyzer should be used. |   | +| | \-\-disableVersionCheck | | Sets whether dependency-check should check if a new version is available. |   | +| | \-\-go | \ | The path to `go` executable for the Go Mode Analyzer; only necessary if `go` is not on the path. |   | +| | \-\-bundleAudit | | The path to the bundle-audit executable. |   | +| | \-\-bundleAuditWorkingDirectory | \ | The path to working directory that the bundle-audit command should be executed from when doing Gem bundle analysis. |   | +| | \-\-proxyserver | \ | The proxy server to use when downloading resources; see the [proxy configuration](../data/proxy.html) page for more information. |   | +| | \-\-proxyport | \ | The proxy port to use when downloading resources. |   | +| | \-\-nonProxyHosts | \ | The proxy exclusion list: hostnames (or patterns) for which proxy should not be used. Use pipe, comma or colon as list separator. Example: `something.com\|*.something.com\|www.somethingelse.*` |   | +| \-c | \-\-connectiontimeout | \ | The connection timeout (in milliseconds) to use when downloading resources. | 10000 | +| | \-\-readtimeout | \ | The read timeout (in milliseconds) to use when downloading resources. | 60000 | +| | \-\-proxypass | \ | The proxy password to use when downloading resources. |   | +| | \-\-proxyuser | \ | The proxy username to use when downloading resources. |   | +| | \-\-connectionString | \ | The connection string to the database. See using a [database server](../data/database.html). |   | +| | \-\-dbDriverName | \ | The database driver full classname; note, only needs to be set if the driver is not JDBC4 compliant or the JAR is outside of the class path. |   | +| | \-\-dbDriverPath | \ | The path to the database driver; note, this does not need to be set unless the JAR is outside of the class path. |   | +| | \-\-dbPassword | \ | The password for connecting to the database. |   | +| | \-\-dbUser | \ | The username used to connect to the database. |   | +| \-d | \-\-data | \ | The location of the data directory used to store persistent data. | /usr/local/var/dependencycheck if installed through brew (→ [formula](https://github.com/Homebrew/homebrew-core/blob/master/Formula/d/dependency-check.rb#L29)). Otherwise, the data directory is created inside the install directory i.e. as a sibling to the `/bin`, `/lib` directories. | +| | \-\-purge | | Delete the local copy of the NVD. This is used to force a refresh of the data. |   | +| | \-\-disableHostedSuppressions | | Whether the usage of the hosted suppressions file will be disabled. | false | +| | \-\-hostedSuppressionsForceUpdate | | Whether the hosted suppressions file will update regardless of the `noupdate` argument. | false | +| | \-\-hostedSuppressionsValidForHours | \ | The number of hours to wait before checking for new updates of the hosted suppressions file | 2 | +| | \-\-hostedSuppressionsUrl | \ | The URL to a mirrored copy of the hosted suppressions file for internet-constrained environments | https://dependency-check.github.io/DependencyCheck/suppressions/publishedSuppressions.xml | +| | \-\-hostedSuppressionsUser | \ | The user for basic authentication to a mirrored copy of the hosted suppressions file |   | +| | \-\-hostedSuppressionsPassword | \ | The password for basic authentication to a mirrored copy of the hosted suppressions file |   | +| | \-\-hostedSuppressionsBearerToken | \ | The token for bearer authentication to a mirrored copy of the hosted suppressions file |   | +| | \-\-suppressionUser | \ | The user for basic authentication to web-hosted suppression XML files (as configured with `--suppression`) |   | +| | \-\-suppressionPassword | \ | The password for basic authentication to web-hosted suppression XML files (as configured with `--suppression`) |   | +| | \-\-suppressionBearerToken | \ | The token for bearer authentication to web-hosted suppression XML files (as configured with `--suppression`) |   | diff --git a/cli/src/site/markdown/index.md.vm b/cli/src/site/markdown/index.md.vm index cc8a23b0aa1..fdb675ad605 100644 --- a/cli/src/site/markdown/index.md.vm +++ b/cli/src/site/markdown/index.md.vm @@ -7,8 +7,8 @@ identifiers, and the associated Common Vulnerability and Exposure (CVE) entries. Installation & Usage ==================== -Import the GPG key used to sign all Dependency Check releases: `gpg --keyserver hkp://keys.gnupg.net --recv-keys 259A55407DD6C00299E6607EFFDE55BE73A2D1ED`. -Download the dependency-check command line tool the [GitHub Release](https://github.com/jeremylong/DependencyCheck/releases/download/v${project.version}/dependency-check-${project.version}-release.zip) and the associated GPG signature file from the [GitHub Release](https://github.com/jeremylong/DependencyCheck/releases/download/v${project.version}/dependency-check-${project.version}-release.zip.asc). +Import the GPG key used to sign all Dependency Check releases: `gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 259A55407DD6C00299E6607EFFDE55BE73A2D1ED`. +Download the dependency-check command line tool the [GitHub Release](https://github.com/dependency-check/DependencyCheck/releases/download/v${project.version}/dependency-check-${project.version}-release.zip) and the associated GPG signature file from the [GitHub Release](https://github.com/dependency-check/DependencyCheck/releases/download/v${project.version}/dependency-check-${project.version}-release.zip.asc). Verify the cryptographic integrity of your download: `gpg --verify dependency-check-${project.version}-release.zip.asc`. Extract the zip file to a location on your computer and put the 'bin' directory into the path environment variable. @@ -51,4 +51,4 @@ the JAR files the directory. - repos - data - plugins -``` \ No newline at end of file +``` diff --git a/cli/src/site/site.xml b/cli/src/site/site.xml index 30cd83a0937..87e2776f51f 100644 --- a/cli/src/site/site.xml +++ b/cli/src/site/site.xml @@ -16,11 +16,11 @@ limitations under the License. Copyright (c) 2013 Jeremy Long. All Rights Reserved. --> - + - OWASP dependency-check-cli - OWASP dependency-check-cli - ./images/dc-cli.svg + OWASP dependency-check-cli @@ -31,5 +31,6 @@ Copyright (c) 2013 Jeremy Long. All Rights Reserved. + - \ No newline at end of file + \ No newline at end of file diff --git a/cli/src/test/java/org/owasp/dependencycheck/AppTest.java b/cli/src/test/java/org/owasp/dependencycheck/AppTest.java index 4e8ca751be4..45f10d8c2cb 100644 --- a/cli/src/test/java/org/owasp/dependencycheck/AppTest.java +++ b/cli/src/test/java/org/owasp/dependencycheck/AppTest.java @@ -17,35 +17,34 @@ */ package org.owasp.dependencycheck; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import org.apache.commons.cli.ParseException; +import org.apache.commons.cli.UnrecognizedOptionException; +import org.junit.jupiter.api.Test; +import org.owasp.dependencycheck.utils.InvalidSettingException; +import org.owasp.dependencycheck.utils.Settings; +import org.owasp.dependencycheck.utils.Settings.KEYS; import java.io.File; import java.io.FileNotFoundException; -import java.net.URISyntaxException; import java.util.HashMap; import java.util.Map; -import org.apache.commons.cli.ParseException; -import org.apache.commons.cli.UnrecognizedOptionException; import static org.hamcrest.MatcherAssert.assertThat; -import org.junit.Assert; -import org.junit.Test; -import org.owasp.dependencycheck.utils.InvalidSettingException; -import org.owasp.dependencycheck.utils.Settings; -import org.owasp.dependencycheck.utils.Settings.KEYS; +import static org.hamcrest.core.Is.is; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * Tests for the {@link AppTest} class. */ -public class AppTest extends BaseTest { +class AppTest extends BaseTest { /** * Test of ensureCanonicalPath method, of class App. */ @Test - public void testEnsureCanonicalPath() { + void testEnsureCanonicalPath() { String file = "../*.jar"; App instance = new App(getSettings()); String result = instance.ensureCanonicalPath(file); @@ -55,7 +54,7 @@ public void testEnsureCanonicalPath() { file = "../some/skip/../path/file.txt"; String expResult = "/some/path/file.txt"; result = instance.ensureCanonicalPath(file); - assertTrue("result=" + result, result.endsWith(expResult)); + assertTrue(result.endsWith(expResult), "result=" + result); } /** @@ -65,7 +64,7 @@ public void testEnsureCanonicalPath() { * @throws Exception the unexpected {@link Exception}. */ @Test - public void testPopulateSettings() throws Exception { + void testPopulateSettings() throws Exception { File prop = new File(this.getClass().getClassLoader().getResource("sample.properties").toURI().getPath()); String[] args = {"-P", prop.getAbsolutePath()}; Map expected = new HashMap<>(); @@ -115,13 +114,12 @@ public void testPopulateSettings() throws Exception { * Assert that an {@link UnrecognizedOptionException} is thrown when a * property that is not supported is specified on the CLI. * - * @throws Exception the unexpected {@link Exception}. */ @Test - public void testPopulateSettingsException() throws Exception { + void testPopulateSettingsException() { String[] args = {"-invalidPROPERTY"}; - Exception exception = Assert.assertThrows(UnrecognizedOptionException.class, () -> testBooleanProperties(args, null)); - Assert.assertTrue(exception.getMessage().contains("Unrecognized option: -invalidPROPERTY")); + UnrecognizedOptionException exception = assertThrows(UnrecognizedOptionException.class, () -> testBooleanProperties(args, null)); + assertTrue(exception.getMessage().contains("Unrecognized option: -invalidPROPERTY")); } /** @@ -130,7 +128,7 @@ public void testPopulateSettingsException() throws Exception { * @throws Exception the unexpected {@link Exception}. */ @Test - public void testPopulatingSuppressionSettingsWithASingleFile() throws Exception { + void testPopulatingSuppressionSettingsWithASingleFile() throws Exception { // GIVEN CLI properties with the mandatory arguments File prop = new File(this.getClass().getClassLoader().getResource("sample.properties").toURI().getPath()); @@ -154,7 +152,7 @@ public void testPopulatingSuppressionSettingsWithASingleFile() throws Exception * @throws Exception the unexpected {@link Exception}. */ @Test - public void testPopulatingSuppressionSettingsWithMultipleFiles() throws Exception { + void testPopulatingSuppressionSettingsWithMultipleFiles() throws Exception { // GIVEN CLI properties with the mandatory arguments File prop = new File(this.getClass().getClassLoader().getResource("sample.properties").toURI().getPath()); @@ -171,95 +169,8 @@ public void testPopulatingSuppressionSettingsWithMultipleFiles() throws Exceptio assertThat("Expected the suppression files to be set in the Settings with a separator", getSettings().getString(KEYS.SUPPRESSION_FILE), is("[\"first-file.xml\",\"another-file.xml\"]")); } - @Test - public void testPopulateSettingsShouldSetDefaultValueToCveUrlModified() throws Exception { - // Given - System.clearProperty(Settings.KEYS.CVE_MODIFIED_JSON); - System.clearProperty(Settings.KEYS.CVE_BASE_JSON); - - final Settings settings = getSettings(); - final App app = new App(settings); - - String[] args = {"--cveUrlBase", "https://my-custom-mirror-of-nvd/feeds/json/cve/1.1/nvdcve-1.1-%d.json.gz"}; - final CliParser parser = new CliParser(settings); - parser.parse(args); - - // When - app.populateSettings(parser); - - // Then - String output = settings.getString(Settings.KEYS.CVE_MODIFIED_JSON); - String expectedOutput = "https://my-custom-mirror-of-nvd/feeds/json/cve/1.1/nvdcve-1.1-modified.json.gz"; - assertThat("cveUrlModified must be set to a default of the same model", output, is(expectedOutput)); - } - - @Test - public void testPopulateSettingsShouldSetDefaultValueToCveUrlModifiedWhenCveUrlModifiedIsEmpty() throws Exception { - // Given - System.clearProperty(Settings.KEYS.CVE_MODIFIED_JSON); - System.clearProperty(Settings.KEYS.CVE_BASE_JSON); - - final Settings settings = getSettings(); - final App app = new App(settings); - - String[] args = {"--cveUrlBase", "https://my-custom-mirror-of-nvd/feeds/json/cve/1.1/nvdcve-1.1-%d.json.gz", "--cveUrlModified", ""}; - final CliParser parser = new CliParser(settings); - parser.parse(args); - - // When - app.populateSettings(parser); - - // Then - String output = settings.getString(Settings.KEYS.CVE_MODIFIED_JSON); - String expectedOutput = "https://my-custom-mirror-of-nvd/feeds/json/cve/1.1/nvdcve-1.1-modified.json.gz"; - assertThat("cveUrlModified must be set to a default of the same model when arg is empty", output, is(expectedOutput)); - } - - @Test - public void testPopulateSettingsShouldNotSetDefaultValueToCveUrlModifiedWhenValueIsExplicitelySet() throws Exception { - // Given - System.clearProperty(Settings.KEYS.CVE_MODIFIED_JSON); - System.clearProperty(Settings.KEYS.CVE_BASE_JSON); - - final Settings settings = getSettings(); - final App app = new App(settings); - - String[] args = {"--cveUrlBase", "https://my-custom-mirror-of-nvd/feeds/json/cve/1.1/some-unusual-file-name-%d.json.gz", "--cveUrlModified", "https://another-custom-mirror-of-nvd/feeds/json/cve/1.1/nvdcve-1.1-modified.json.gz"}; - final CliParser parser = new CliParser(settings); - parser.parse(args); - - // When - app.populateSettings(parser); - - // Then - String output = settings.getString(Settings.KEYS.CVE_MODIFIED_JSON); - String expectedOutput = "https://another-custom-mirror-of-nvd/feeds/json/cve/1.1/nvdcve-1.1-modified.json.gz"; - assertThat("cveUrlModified must be set to the specified value", output, is(expectedOutput)); - } - - @Test - public void testPopulateSettingsShouldNotSetDefaultValueToCveUrlModifiedWhenUnknownValueIsSet() throws Exception { - // Given - System.clearProperty(Settings.KEYS.CVE_MODIFIED_JSON); - System.clearProperty(Settings.KEYS.CVE_BASE_JSON); - - final Settings settings = getSettings(); - final App app = new App(settings); - - String[] args = {"--cveUrlBase", "https://my-custom-mirror-of-nvd/feeds/json/cve/1.1/some-unusual-file-name-%d.json.gz"}; - final CliParser parser = new CliParser(settings); - parser.parse(args); - - // When - app.populateSettings(parser); - - // Then - String output = settings.getString(Settings.KEYS.CVE_MODIFIED_JSON); - String expectedOutput = "https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-modified.json.gz"; - assertThat("cveUrlModified must not be set when name is not the same as from the nvd datasource", output, is(expectedOutput)); - } - private boolean testBooleanProperties(String[] args, Map expected) throws URISyntaxException, FileNotFoundException, ParseException, InvalidSettingException { + private boolean testBooleanProperties(String[] args, Map expected) throws FileNotFoundException, ParseException, InvalidSettingException { this.reloadSettings(); final CliParser cli = new CliParser(getSettings()); cli.parse(args); diff --git a/cli/src/test/java/org/owasp/dependencycheck/BaseTest.java b/cli/src/test/java/org/owasp/dependencycheck/BaseTest.java index b486fa6a089..072baf8593b 100644 --- a/cli/src/test/java/org/owasp/dependencycheck/BaseTest.java +++ b/cli/src/test/java/org/owasp/dependencycheck/BaseTest.java @@ -15,8 +15,8 @@ */ package org.owasp.dependencycheck; -import org.junit.After; -import org.junit.Before; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.owasp.dependencycheck.utils.Settings; /** @@ -33,7 +33,7 @@ public abstract class BaseTest { /** * Initialize the {@link Settings}. */ - @Before + @BeforeEach public void setUp() { settings = new Settings(); } @@ -41,7 +41,7 @@ public void setUp() { /** * Clean the {@link Settings}. */ - @After + @AfterEach public void tearDown() { settings.cleanup(true); } diff --git a/cli/src/test/java/org/owasp/dependencycheck/CliParserTest.java b/cli/src/test/java/org/owasp/dependencycheck/CliParserTest.java index 6800f4c4489..f92288c6ade 100644 --- a/cli/src/test/java/org/owasp/dependencycheck/CliParserTest.java +++ b/cli/src/test/java/org/owasp/dependencycheck/CliParserTest.java @@ -17,21 +17,28 @@ */ package org.owasp.dependencycheck; +import org.apache.commons.cli.ParseException; +import org.junit.jupiter.api.Test; + import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintStream; + import static java.nio.charset.StandardCharsets.UTF_8; -import org.apache.commons.cli.ParseException; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; /** * * @author Jeremy Long */ -public class CliParserTest extends BaseTest { +class CliParserTest extends BaseTest { /** * Test of parse method, of class CliParser. @@ -39,7 +46,7 @@ public class CliParserTest extends BaseTest { * @throws Exception thrown when an exception occurs. */ @Test - public void testParse() throws Exception { + void testParse() throws Exception { String[] args = {}; @@ -49,9 +56,9 @@ public void testParse() throws Exception { CliParser instance = new CliParser(getSettings()); instance.parse(args); - Assert.assertFalse(instance.isGetVersion()); - Assert.assertFalse(instance.isGetHelp()); - Assert.assertFalse(instance.isRunScan()); + assertFalse(instance.isGetVersion()); + assertFalse(instance.isGetHelp()); + assertFalse(instance.isRunScan()); } /** @@ -60,16 +67,16 @@ public void testParse() throws Exception { * @throws Exception thrown when an exception occurs. */ @Test - public void testParse_help() throws Exception { + void testParse_help() throws Exception { String[] args = {"-help"}; CliParser instance = new CliParser(getSettings()); instance.parse(args); - Assert.assertFalse(instance.isGetVersion()); - Assert.assertTrue(instance.isGetHelp()); - Assert.assertFalse(instance.isRunScan()); + assertFalse(instance.isGetVersion()); + assertTrue(instance.isGetHelp()); + assertFalse(instance.isRunScan()); } /** @@ -78,38 +85,35 @@ public void testParse_help() throws Exception { * @throws Exception thrown when an exception occurs. */ @Test - public void testParse_version() throws Exception { + void testParse_version() throws Exception { String[] args = {"-version"}; CliParser instance = new CliParser(getSettings()); instance.parse(args); - Assert.assertTrue(instance.isGetVersion()); - Assert.assertFalse(instance.isGetHelp()); - Assert.assertFalse(instance.isRunScan()); + assertTrue(instance.isGetVersion()); + assertFalse(instance.isGetHelp()); + assertFalse(instance.isRunScan()); } /** * Test of parse method with failOnCVSS without an argument * - * @throws Exception thrown when an exception occurs. */ @Test - public void testParse_failOnCVSSNoArg() throws Exception { + void testParse_failOnCVSSNoArg() { String[] args = {"--failOnCVSS"}; CliParser instance = new CliParser(getSettings()); - try { - instance.parse(args); - Assert.fail("an argument for failOnCVSS was missing and an exception was not thrown"); - } catch (ParseException ex) { - Assert.assertTrue(ex.getMessage().contains("Missing argument")); - } - Assert.assertFalse(instance.isGetVersion()); - Assert.assertFalse(instance.isGetHelp()); - Assert.assertFalse(instance.isRunScan()); + ParseException ex = assertThrows(ParseException.class, () -> instance.parse(args), + "an argument for failOnCVSS was missing and an exception was not thrown"); + assertTrue(ex.getMessage().contains("Missing argument")); + + assertFalse(instance.isGetVersion()); + assertFalse(instance.isGetHelp()); + assertFalse(instance.isRunScan()); } /** @@ -119,16 +123,16 @@ public void testParse_failOnCVSSNoArg() throws Exception { * @throws Exception thrown when an exception occurs. */ @Test - public void testParse_failOnCVSSInvalidArgument() throws Exception { + void testParse_failOnCVSSInvalidArgument() throws Exception { String[] args = {"--failOnCVSS", "bad"}; CliParser instance = new CliParser(getSettings()); instance.parse(args); - Assert.assertEquals("Default should be 11", 11.0, instance.getFailOnCVSS(), 0); - Assert.assertFalse(instance.isGetVersion()); - Assert.assertFalse(instance.isGetHelp()); - Assert.assertFalse(instance.isRunScan()); + assertEquals(11.0, instance.getFailOnCVSS(), 0, "Default should be 11"); + assertFalse(instance.isGetVersion()); + assertFalse(instance.isGetHelp()); + assertFalse(instance.isRunScan()); } /** @@ -138,25 +142,24 @@ public void testParse_failOnCVSSInvalidArgument() throws Exception { * @throws Exception thrown when an exception occurs. */ @Test - public void testParse_failOnCVSSValidArgument() throws Exception { + void testParse_failOnCVSSValidArgument() throws Exception { String[] args = {"--failOnCVSS", "6"}; CliParser instance = new CliParser(getSettings()); instance.parse(args); - Assert.assertEquals(6.0, instance.getFailOnCVSS(), 0); - Assert.assertFalse(instance.isGetVersion()); - Assert.assertFalse(instance.isGetHelp()); - Assert.assertFalse(instance.isRunScan()); + assertEquals(6.0, instance.getFailOnCVSS(), 0); + assertFalse(instance.isGetVersion()); + assertFalse(instance.isGetHelp()); + assertFalse(instance.isRunScan()); } /** * Test of parse method with jar and cpe args, of class CliParser. * - * @throws Exception thrown when an exception occurs. */ @Test - public void testParse_unknown() throws Exception { + void testParse_unknown() { String[] args = {"-unknown"}; @@ -167,62 +170,53 @@ public void testParse_unknown() throws Exception { CliParser instance = new CliParser(getSettings()); - try { - instance.parse(args); - Assert.fail("Unrecognized option should have caused an exception"); - } catch (ParseException ex) { - Assert.assertTrue(ex.getMessage().contains("Unrecognized option")); - } - Assert.assertFalse(instance.isGetVersion()); - Assert.assertFalse(instance.isGetHelp()); - Assert.assertFalse(instance.isRunScan()); + ParseException ex = assertThrows(ParseException.class, () -> instance.parse(args) , + "Unrecognized option should have caused an exception"); + assertTrue(ex.getMessage().contains("Unrecognized option")); + + assertFalse(instance.isGetVersion()); + assertFalse(instance.isGetHelp()); + assertFalse(instance.isRunScan()); } /** * Test of parse method with scan arg, of class CliParser. * - * @throws Exception thrown when an exception occurs. */ @Test - public void testParse_scan() throws Exception { + void testParse_scan() { String[] args = {"-scan"}; CliParser instance = new CliParser(getSettings()); - try { - instance.parse(args); - Assert.fail("Missing argument should have caused an exception"); - } catch (ParseException ex) { - Assert.assertTrue(ex.getMessage().contains("Missing argument")); - } + ParseException ex = assertThrows(ParseException.class, () -> instance.parse(args), + "Missing argument should have caused an exception"); + assertTrue(ex.getMessage().contains("Missing argument")); - Assert.assertFalse(instance.isGetVersion()); - Assert.assertFalse(instance.isGetHelp()); - Assert.assertFalse(instance.isRunScan()); + assertFalse(instance.isGetVersion()); + assertFalse(instance.isGetHelp()); + assertFalse(instance.isRunScan()); } /** * Test of parse method with jar arg, of class CliParser. * - * @throws Exception thrown when an exception occurs. */ @Test - public void testParse_scan_unknownFile() throws Exception { + void testParse_scan_unknownFile() { String[] args = {"-scan", "jar.that.does.not.exist", "--project", "test"}; CliParser instance = new CliParser(getSettings()); - try { - instance.parse(args); - Assert.fail("An exception should have been thrown"); - } catch (FileNotFoundException ex) { - Assert.assertTrue(ex.getMessage().contains("Invalid 'scan' argument")); - } - Assert.assertFalse(instance.isGetVersion()); - Assert.assertFalse(instance.isGetHelp()); - Assert.assertFalse(instance.isRunScan()); + FileNotFoundException ex = assertThrows(FileNotFoundException.class, () -> instance.parse(args), + "An exception should have been thrown"); + assertTrue(ex.getMessage().contains("Invalid 'scan' argument")); + + assertFalse(instance.isGetVersion()); + assertFalse(instance.isGetHelp()); + assertFalse(instance.isRunScan()); } /** @@ -231,28 +225,27 @@ public void testParse_scan_unknownFile() throws Exception { * @throws Exception thrown when an exception occurs. */ @Test - public void testParse_scan_withFileExists() throws Exception { + void testParse_scan_withFileExists() throws Exception { File path = new File(this.getClass().getClassLoader().getResource("checkSumTest.file").toURI().getPath()); String[] args = {"--scan", path.getCanonicalPath(), "--out", "./", "--project", "test"}; CliParser instance = new CliParser(getSettings()); instance.parse(args); - Assert.assertEquals(path.getCanonicalPath(), instance.getScanFiles()[0]); + assertEquals(path.getCanonicalPath(), instance.getScanFiles()[0]); - Assert.assertFalse(instance.isGetVersion()); - Assert.assertFalse(instance.isGetHelp()); - Assert.assertTrue(instance.isRunScan()); + assertFalse(instance.isGetVersion()); + assertFalse(instance.isGetHelp()); + assertTrue(instance.isRunScan()); } /** * Test of printVersionInfo, of class CliParser. * - * @throws Exception thrown when an exception occurs. */ @Test @SuppressWarnings("StringSplitter") - public void testParse_printVersionInfo() throws Exception { + void testParse_printVersionInfo() { PrintStream out = System.out; ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -262,14 +255,14 @@ public void testParse_printVersionInfo() throws Exception { instance.printVersionInfo(); try { baos.flush(); - String text = new String(baos.toByteArray(), UTF_8).toLowerCase(); - String[] lines = text.split(System.getProperty("line.separator")); - Assert.assertTrue(lines.length >= 1); - Assert.assertTrue(text.contains("version")); - Assert.assertFalse(text.contains("unknown")); + String text = baos.toString(UTF_8).toLowerCase(); + String[] lines = text.split(System.lineSeparator()); + assertTrue(lines.length >= 1); + assertTrue(text.contains("version")); + assertFalse(text.contains("unknown")); } catch (IOException ex) { System.setOut(out); - Assert.fail("CliParser.printVersionInfo did not write anything to system.out."); + fail("CliParser.printVersionInfo did not write anything to system.out.", ex); } finally { System.setOut(out); } @@ -282,7 +275,7 @@ public void testParse_printVersionInfo() throws Exception { */ @Test @SuppressWarnings("StringSplitter") - public void testParse_printHelp() throws Exception { + void testParse_printHelp() throws Exception { PrintStream out = System.out; ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -297,13 +290,13 @@ public void testParse_printHelp() throws Exception { instance.printHelp(); try { baos.flush(); - String text = (new String(baos.toByteArray(), UTF_8)); - String[] lines = text.split(System.getProperty("line.separator")); - Assert.assertTrue(lines[0].startsWith("usage: ")); - Assert.assertTrue((lines.length > 2)); + String text = (baos.toString(UTF_8)); + String[] lines = text.split(System.lineSeparator()); + assertTrue(lines[0].startsWith("usage: ")); + assertTrue((lines.length > 2)); } catch (IOException ex) { System.setOut(out); - Assert.fail("CliParser.printVersionInfo did not write anything to system.out."); + fail("CliParser.printVersionInfo did not write anything to system.out."); } finally { System.setOut(out); } @@ -313,70 +306,66 @@ public void testParse_printHelp() throws Exception { * Test of getBooleanArgument method, of class CliParser. */ @Test - public void testGetBooleanArgument() throws ParseException { + void testGetBooleanArgument() { String[] args = {"--scan", "missing.file", "--artifactoryUseProxy", "false", "--artifactoryParallelAnalysis", "true", "--project", "test"}; CliParser instance = new CliParser(getSettings()); - try { - instance.parse(args); - Assert.fail("invalid scan should have caused an error"); - } catch (FileNotFoundException ex) { - Assert.assertTrue(ex.getMessage().contains("Invalid 'scan' argument")); - } + + FileNotFoundException ex = assertThrows(FileNotFoundException.class, () -> instance.parse(args), + "invalid scan should have caused an error"); + assertTrue(ex.getMessage().contains("Invalid 'scan' argument")); + boolean expResult; Boolean result = instance.getBooleanArgument("missingArgument"); - Assert.assertNull(result); + assertNull(result); expResult = false; result = instance.getBooleanArgument(CliParser.ARGUMENT.ARTIFACTORY_USES_PROXY); - Assert.assertEquals(expResult, result); + assertEquals(expResult, result); expResult = true; result = instance.getBooleanArgument(CliParser.ARGUMENT.ARTIFACTORY_PARALLEL_ANALYSIS); - Assert.assertEquals(expResult, result); + assertEquals(expResult, result); } /** * Test of getStringArgument method, of class CliParser. */ @Test - public void testGetStringArgument() throws ParseException { + void testGetStringArgument() { String[] args = {"--scan", "missing.file", "--artifactoryUsername", "blue42", "--project", "test"}; CliParser instance = new CliParser(getSettings()); - try { - instance.parse(args); - Assert.fail("invalid scan argument should have caused an exception"); - } catch (FileNotFoundException ex) { - Assert.assertTrue(ex.getMessage().contains("Invalid 'scan' argument")); - } + + FileNotFoundException ex = assertThrows(FileNotFoundException.class, () -> instance.parse(args), + "invalid scan argument should have caused an exception"); + assertTrue(ex.getMessage().contains("Invalid 'scan' argument")); + String expResult; String result = instance.getStringArgument("missingArgument"); - Assert.assertNull(result); + assertNull(result); expResult = "blue42"; result = instance.getStringArgument(CliParser.ARGUMENT.ARTIFACTORY_USERNAME); - Assert.assertEquals(expResult, result); + assertEquals(expResult, result); } @Test - public void testHasOption() throws ParseException { + void testHasOption() { String[] args = {"--scan", "missing.file", "--artifactoryUsername", "blue42", "--project", "test"}; CliParser instance = new CliParser(getSettings()); - try { - instance.parse(args); - Assert.fail("invalid scan argument should have caused an exception"); - } catch (FileNotFoundException ex) { - Assert.assertTrue(ex.getMessage().contains("Invalid 'scan' argument")); - } + + FileNotFoundException ex = assertThrows(FileNotFoundException.class, () -> instance.parse(args), + "invalid scan argument should have caused an exception"); + assertTrue(ex.getMessage().contains("Invalid 'scan' argument")); Boolean result = instance.hasOption("missingOption"); - Assert.assertNull(result); + assertNull(result); Boolean expResult = true; result = instance.hasOption(CliParser.ARGUMENT.PROJECT); - Assert.assertEquals(expResult, result); + assertEquals(expResult, result); } } diff --git a/cli/src/test/resources/sample.properties b/cli/src/test/resources/sample.properties index a8595dee200..ca09248d7dd 100644 --- a/cli/src/test/resources/sample.properties +++ b/cli/src/test/resources/sample.properties @@ -21,6 +21,7 @@ analyzer.openssl.enabled=true analyzer.central.enabled=true analyzer.nexus.enabled=false analyzer.cocoapods.enabled=true +analyzer.carthage.enabled=true analyzer.swift.package.manager.enabled=true #whether the nexus analyzer uses the proxy analyzer.nexus.proxy=true diff --git a/cli/src/test/resources/sample2.properties b/cli/src/test/resources/sample2.properties index e94af3186bd..859ede41042 100644 --- a/cli/src/test/resources/sample2.properties +++ b/cli/src/test/resources/sample2.properties @@ -21,6 +21,7 @@ analyzer.openssl.enabled=false analyzer.central.enabled=false analyzer.nexus.enabled=true analyzer.cocoapods.enabled=false +analyzer.carthage.enabled=false analyzer.swift.package.manager.enabled=false #whether the nexus analyzer uses the proxy analyzer.nexus.proxy=false diff --git a/core/README.md b/core/README.md index b05b6e327e2..1b6c759cb08 100644 --- a/core/README.md +++ b/core/README.md @@ -8,10 +8,12 @@ Copyright & License Dependency-Check is Copyright (c) 2012-2014 Jeremy Long. All Rights Reserved. -Permission to modify and redistribute is granted under the terms of the Apache 2.0 license. See the [LICENSE.txt](https://raw.githubusercontent.com/jeremylong/DependencyCheck/main/LICENSE.txt) file for the full license. +Permission to modify and redistribute is granted under the terms of the Apache 2.0 license. See the [LICENSE.txt](https://raw.githubusercontent.com/dependency-check/DependencyCheck/main/LICENSE.txt) file for the full license. Dependency-Check makes use of several other open source libraries. Please see the [NOTICE.txt][notices] file for more information. - [wiki]: https://github.com/jeremylong/DependencyCheck/wiki - [notices]: https://github.com/jeremylong/DependencyCheck/blob/main/NOTICE.txt + [wiki]: https://github.com/dependency-check/DependencyCheck/wiki + [notices]: https://github.com/dependency-check/DependencyCheck/blob/main/NOTICE.txt + + \ No newline at end of file diff --git a/core/pom.xml b/core/pom.xml index cd0d820b391..05407c13ead 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -20,7 +20,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved. org.owasp dependency-check-parent - 8.2.2-SNAPSHOT + 12.1.9-SNAPSHOT dependency-check-core @@ -29,9 +29,9 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved. Dependency-Check Core dependency-check-core is the engine and reporting tool used to identify and report if there are any known, publicly disclosed vulnerabilities in the scanned project's dependencies. The engine extracts meta-data from the dependencies and uses this to do fuzzy key-word matching against the Common Platfrom Enumeration (CPE), if any CPE identifiers are found the associated Common Vulnerability and Exposure (CVE) entries are added to the generated report. - scm:git:https://github.com/jeremylong/DependencyCheck.git - https://github.com/jeremylong/DependencyCheck/tree/main/core - scm:git:git@github.com:jeremylong/DependencyCheck.git + scm:git:https://github.com/dependency-check/DependencyCheck.git + https://github.com/dependency-check/DependencyCheck/tree/main/core + scm:git:git@github.com/dependency-check/DependencyCheck.git v6.4.1 @@ -105,7 +105,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved. jsonschema2pojo-maven-plugin - + generate-knownexploited generate-sources @@ -126,6 +126,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved. generate + false ${basedir}/src/main/resources/schema/external/cisa ${project.build.directory}/generated-sources/java true @@ -184,6 +185,10 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved. + + io.github.jeremylong + open-vulnerability-clients + org.anarres.jdiagnostics jdiagnostics @@ -194,7 +199,12 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved. org.apache.commons - commons-jcs-core + commons-jcs3-core + + + io.github.jeremylong + jcs3-slf4j + runtime com.github.package-url @@ -218,6 +228,11 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved. logback-classic test + + ch.qos.logback + logback-core + test + org.owasp dependency-check-utils @@ -258,12 +273,17 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved. org.apache.lucene - lucene-analyzers-common + lucene-analysis-common org.apache.lucene lucene-queryparser + + + org.slf4j + jul-to-slf4j + org.apache.velocity velocity-engine-core @@ -275,7 +295,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved. org.glassfish - javax.json + jakarta.json org.jsoup @@ -286,8 +306,8 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved. jackson-databind - com.fasterxml.jackson.module - jackson-module-afterburner + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 com.fasterxml.jackson.module @@ -320,21 +340,64 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved. org.mockito - mockito-core + mockito-junit-jupiter test commons-validator commons-validator - - commons-beanutils - commons-beanutils - org.eclipse.packager packager-rpm + + org.apache.httpcomponents.core5 + httpcore5 + + + org.apache.httpcomponents.client5 + httpclient5 + + + com.fasterxml.jackson.core + jackson-core + + + com.fasterxml.jackson.core + jackson-annotations + + + org.sonatype.goodies + package-url-java + 1.2.0 + + + joda-time + joda-time + 2.14.0 + + + org.sonatype.ossindex + ossindex-service-api + 1.8.2 + + + com.esotericsoftware + minlog + 1.3.1 + + + com.vaadin.external.google + android-json + 0.0.20131108.vaadin1 + + + xml-apis + xml-apis + 1.4.01 + test + @@ -376,20 +439,11 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-failsafe-plugin - - - data.driver_path - ${driver_path} - - - data.driver_name - ${driver_name} - - - data.connection_string - ${connection_string} - - + + ${driver_path} + ${driver_name} + ${connection_string} + **/*MySqlIT.java @@ -417,7 +471,7 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved. org.postgresql postgresql - 42.6.0 + 42.7.8 @@ -426,20 +480,11 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved. org.apache.maven.plugins maven-failsafe-plugin - - - data.driver_path - ${driver_path} - - - data.driver_name - ${driver_name} - - - data.connection_string - ${connection_string} - - + + ${driver_path} + ${driver_name} + ${connection_string} + **/*MySqlIT.java @@ -462,6 +507,45 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved. true + + + + + org.apache.maven.plugins + maven-dependency-plugin + ${maven-dependency-plugin.version} + + + + org.springframework:spring-webmvc + org.mortbay.jetty:jetty + net.sf.ehcache:ehcache-core + com.google.inject:guice + org.apache.struts:struts2-core + xalan:xalan + com.hazelcast:hazelcast + commons-fileupload:commons-fileupload + org.jslipc:jslipc + com.thoughtworks.xstream:xstream + org.dojotoolkit:dojo-war + org.apache.openjpa:openjpa + uk.ltd.getahead:dwr + org.glassfish.main.admingui:war + org.springframework.retry:spring-retry + io.github.faob-dev:aar + org.apache.maven.scm:maven-scm-provider-cvsexe + org.apache.axis2:axis2-spring + org.apache.geronimo.daytrader:daytrader-ear + org.springframework.security:spring-security-web + org.apache.axis2:axis2-adb + + + + + + diff --git a/core/src/main/java/org/owasp/dependencycheck/AnalysisTask.java b/core/src/main/java/org/owasp/dependencycheck/AnalysisTask.java index 97cf62b93db..06b63fafec7 100644 --- a/core/src/main/java/org/owasp/dependencycheck/AnalysisTask.java +++ b/core/src/main/java/org/owasp/dependencycheck/AnalysisTask.java @@ -87,7 +87,7 @@ public Void call() { try { analyzer.analyze(dependency, engine); } catch (AnalysisException ex) { - LOGGER.warn("An error occurred while analyzing '{}' ({}).", dependency.getActualFilePath(), analyzer.getName()); + LOGGER.warn("An error occurred while analyzing '{}' ({}): {}", dependency.getActualFilePath(), analyzer.getName(), ex.getMessage()); LOGGER.debug("", ex); exceptions.add(ex); } catch (Throwable ex) { diff --git a/core/src/main/java/org/owasp/dependencycheck/Engine.java b/core/src/main/java/org/owasp/dependencycheck/Engine.java index 5b6d41e5929..625da29a419 100644 --- a/core/src/main/java/org/owasp/dependencycheck/Engine.java +++ b/core/src/main/java/org/owasp/dependencycheck/Engine.java @@ -18,8 +18,7 @@ package org.owasp.dependencycheck; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import org.apache.commons.io.FileUtils; -import org.apache.commons.jcs.JCS; +import org.apache.commons.jcs3.JCS; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.owasp.dependencycheck.analyzer.AnalysisPhase; @@ -40,6 +39,7 @@ import org.owasp.dependencycheck.exception.ReportException; import org.owasp.dependencycheck.exception.WriteLockException; import org.owasp.dependencycheck.reporting.ReportGenerator; +import org.owasp.dependencycheck.utils.FileUtils; import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.WriteLock; import org.slf4j.Logger; @@ -78,7 +78,9 @@ import static org.owasp.dependencycheck.analyzer.AnalysisPhase.INITIAL; import static org.owasp.dependencycheck.analyzer.AnalysisPhase.POST_FINDING_ANALYSIS; import static org.owasp.dependencycheck.analyzer.AnalysisPhase.POST_IDENTIFIER_ANALYSIS; -import static org.owasp.dependencycheck.analyzer.AnalysisPhase.POST_INFORMATION_COLLECTION; +import static org.owasp.dependencycheck.analyzer.AnalysisPhase.POST_INFORMATION_COLLECTION1; +import static org.owasp.dependencycheck.analyzer.AnalysisPhase.POST_INFORMATION_COLLECTION2; +import static org.owasp.dependencycheck.analyzer.AnalysisPhase.POST_INFORMATION_COLLECTION3; import static org.owasp.dependencycheck.analyzer.AnalysisPhase.PRE_FINDING_ANALYSIS; import static org.owasp.dependencycheck.analyzer.AnalysisPhase.PRE_IDENTIFIER_ANALYSIS; import static org.owasp.dependencycheck.analyzer.AnalysisPhase.PRE_INFORMATION_COLLECTION; @@ -187,6 +189,7 @@ public Engine(@NotNull final ClassLoader serviceClassLoader, @NotNull final Mode this.serviceClassLoader = serviceClassLoader; this.mode = mode; this.accessExternalSchema = System.getProperty("javax.xml.accessExternalSchema"); + initializeEngine(); } @@ -252,8 +255,8 @@ public List getAnalyzers(AnalysisPhase phase) { /** * Adds a dependency. In some cases, when adding a virtual dependency, the - * method will identify if the virtual dependency was previously added and update - * the existing dependency rather then adding a duplicate. + * method will identify if the virtual dependency was previously added and + * update the existing dependency rather then adding a duplicate. * * @param dependency the dependency to add */ @@ -639,13 +642,12 @@ public void analyzeDependencies() throws ExceptionCollection { LOGGER.info("\n\nDependency-Check is an open source tool performing a best effort analysis of 3rd party dependencies; false positives and " + "false negatives may exist in the analysis performed by the tool. Use of the tool and the reporting provided constitutes " + "acceptance for use in an AS IS condition, and there are NO warranties, implied or otherwise, with regard to the analysis " - + "or its use. Any use of the tool and the reporting provided is at the user’s risk. In no event shall the copyright holder " + + "or its use. Any use of the tool and the reporting provided is at the user's risk. In no event shall the copyright holder " + "or OWASP be held liable for any damages whatsoever arising out of or in connection with the use of this tool, the analysis " + "performed, or the resulting report.\n\n\n" - + " About ODC: https://jeremylong.github.io/DependencyCheck/general/internals.html\n" - + " False Positives: https://jeremylong.github.io/DependencyCheck/general/suppression.html\n" - + "\n" - + "💖 Sponsor: https://github.com/sponsors/jeremylong\n\n"); + + " About ODC: https://dependency-check.github.io/DependencyCheck/general/internals.html\n" + + " False Positives: https://dependency-check.github.io/DependencyCheck/general/suppression.html\n" + + "\n"); LOGGER.debug("\n----------------------------------------------------\nBEGIN ANALYSIS\n----------------------------------------------------"); LOGGER.info("Analysis Started"); final long analysisStart = System.currentTimeMillis(); @@ -943,7 +945,7 @@ public boolean purge() { try { final File cache = new File(settings.getDataDirectory(), "cache"); if (cache.exists()) { - if (FileUtils.deleteQuietly(cache)) { + if (FileUtils.delete(cache)) { LOGGER.info("Cache directory purged"); } } @@ -953,7 +955,7 @@ public boolean purge() { try { final File cache = new File(settings.getDataDirectory(), "oss_cache"); if (cache.exists()) { - if (FileUtils.deleteQuietly(cache)) { + if (FileUtils.delete(cache)) { LOGGER.info("OSS Cache directory purged"); } } @@ -1181,7 +1183,7 @@ private void throwFatalExceptionCollection(String message, @NotNull final Throwa * @param applicationName the name of the application/project * @param outputDir the path to the output directory (can include the full * file name if the format is not ALL) - * @param format the report format (ALL, HTML, CSV, JSON, etc.) + * @param format the report format (see {@link ReportGenerator.Format}) * @throws ReportException thrown if there is an error generating the report * @deprecated use * {@link #writeReports(java.lang.String, java.io.File, java.lang.String, org.owasp.dependencycheck.exception.ExceptionCollection)} @@ -1198,7 +1200,7 @@ public void writeReports(String applicationName, File outputDir, String format) * @param applicationName the name of the application/project * @param outputDir the path to the output directory (can include the full * file name if the format is not ALL) - * @param format the report format (ALL, HTML, CSV, JSON, etc.) + * @param format the report format (see {@link ReportGenerator.Format}) * @param exceptions a collection of exceptions that may have occurred * during the analysis * @throws ReportException thrown if there is an error generating the report @@ -1217,7 +1219,7 @@ public void writeReports(String applicationName, File outputDir, String format, * @param version the Maven version * @param outputDir the path to the output directory (can include the full * file name if the format is not ALL) - * @param format the report format (ALL, HTML, CSV, JSON, etc.) + * @param format the report format (see {@link ReportGenerator.Format}) * @throws ReportException thrown if there is an error generating the report * @deprecated use * {@link #writeReports(String, String, String, String, File, String, ExceptionCollection)} @@ -1239,7 +1241,7 @@ public synchronized void writeReports(String applicationName, @Nullable final St * @param version the Maven version * @param outputDir the path to the output directory (can include the full * file name if the format is not ALL) - * @param format the report format (ALL, HTML, CSV, JSON, etc.) + * @param format the report format (see {@link ReportGenerator.Format}) * @param exceptions a collection of exceptions that may have occurred * during the analysis * @throws ReportException thrown if there is an error generating the report @@ -1294,7 +1296,9 @@ public enum Mode { PRE_INFORMATION_COLLECTION, INFORMATION_COLLECTION, INFORMATION_COLLECTION2, - POST_INFORMATION_COLLECTION + POST_INFORMATION_COLLECTION1, + POST_INFORMATION_COLLECTION2, + POST_INFORMATION_COLLECTION3 ), /** * In evidence processing mode the {@link Engine} processes the evidence diff --git a/core/src/main/java/org/owasp/dependencycheck/agent/DependencyCheckScanAgent.java b/core/src/main/java/org/owasp/dependencycheck/agent/DependencyCheckScanAgent.java index b7f893fb85d..598c342f343 100644 --- a/core/src/main/java/org/owasp/dependencycheck/agent/DependencyCheckScanAgent.java +++ b/core/src/main/java/org/owasp/dependencycheck/agent/DependencyCheckScanAgent.java @@ -101,12 +101,17 @@ public class DependencyCheckScanAgent { * to 11. The valid range for the fail build on CVSS is 0 to 11, where * anything above 10 will not cause the build to fail. */ - private float failBuildOnCVSS = 11; + private Double failBuildOnCVSS = 11.0; /** * Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not * recommended that this be turned to false. Default is true. */ private boolean autoUpdate = true; + /** + * The NVD API key. + */ + private String nvdApiKey; + /** * Sets whether the data directory should be updated without performing a * scan. Default is false. @@ -117,9 +122,10 @@ public class DependencyCheckScanAgent { */ private boolean generateReport = true; /** - * The report format to be generated (HTML, XML, CSV, JSON, JUNIT, ALL). - * This configuration option has no affect if using this within the Site - * plugin unless the externalReport is set to true. Default is HTML. + * The report format to be generated (HTML, XML, CSV, JSON, JUNIT, SARIF, + * JENKINS, GITLAB, ALL). This configuration option has no affect if using + * this within the Site plugin unless the externalReport is set to true. + * Default is HTML. */ private ReportGenerator.Format reportFormat = ReportGenerator.Format.HTML; /** @@ -171,6 +177,10 @@ public class DependencyCheckScanAgent { * Whether the Maven Central analyzer is enabled. */ private boolean centralAnalyzerEnabled = true; + /** + * Whether the build should fail if there are unused suppression rules. + */ + private boolean failOnUnusedSuppressionRule = false; /** * The URL of Maven Central. */ @@ -208,14 +218,6 @@ public class DependencyCheckScanAgent { * comma-separated list of file extensions to treat like ZIP files. */ private String zipExtensions; - /** - * The URL for the modified NVD CVE JSON. - */ - private String cveUrlModified; - /** - * The base URL for the NVD CVE JSON data feeds. - */ - private String cveUrlBase; /** * The path to dotnet core for .NET assembly analysis. */ @@ -251,6 +253,24 @@ public void setApplicationName(String applicationName) { this.applicationName = applicationName; } + /** + * Get the value of nvdApiKey. + * + * @return the value of nvdApiKey + */ + public String getNvdApiKey() { + return nvdApiKey; + } + + /** + * Set the value of nvdApiKey. + * + * @param nvdApiKey new value of nvdApiKey + */ + public void setNvdApiKey(String nvdApiKey) { + this.nvdApiKey = nvdApiKey; + } + /** * Returns a list of pre-determined dependencies. * @@ -310,7 +330,7 @@ public void setReportOutputDirectory(String reportOutputDirectory) { * * @return the value of failBuildOnCVSS */ - public float getFailBuildOnCVSS() { + public Double getFailBuildOnCVSS() { return failBuildOnCVSS; } @@ -319,7 +339,7 @@ public float getFailBuildOnCVSS() { * * @param failBuildOnCVSS new value of failBuildOnCVSS */ - public void setFailBuildOnCVSS(float failBuildOnCVSS) { + public void setFailBuildOnCVSS(Double failBuildOnCVSS) { this.failBuildOnCVSS = failBuildOnCVSS; } @@ -603,6 +623,24 @@ public String getCpeStartsWithFilter() { return cpeStartsWithFilter; } + /** + * Get the value of failOnUnusedSuppressionRule. + * + * @return the value of failOnUnusedSuppressionRule + */ + public boolean isFailOnUnusedSuppressionRule() { + return failOnUnusedSuppressionRule; + } + + /** + * Set the value of failOnUnusedSuppressionRule. + * + * @param failOnUnusedSuppressionRule new value of failOnUnusedSuppressionRule + */ + public void setFailOnUnusedSuppressionRule(boolean failOnUnusedSuppressionRule) { + this.failOnUnusedSuppressionRule = failOnUnusedSuppressionRule; + } + /** * Get the value of centralAnalyzerEnabled. * @@ -801,42 +839,6 @@ public void setZipExtensions(String zipExtensions) { this.zipExtensions = zipExtensions; } - /** - * Get the value of cveUrlModified. - * - * @return the value of cveUrlModified - */ - public String getCveUrlModified() { - return cveUrlModified; - } - - /** - * Set the value of cveUrlModified. - * - * @param cveUrlModified new value of cveUrlModified - */ - public void setCveUrlModified(String cveUrlModified) { - this.cveUrlModified = cveUrlModified; - } - - /** - * Get the value of cveUrlBase. - * - * @return the value of cveUrlBase - */ - public String getCveUrlBase() { - return cveUrlBase; - } - - /** - * Set the value of cveUrlBase. - * - * @param cveUrlBase new value of cveUrlBase - */ - public void setCveUrlBase(String cveUrlBase) { - this.cveUrlBase = cveUrlBase; - } - /** * Get the value of pathToCore. * @@ -970,9 +972,9 @@ private void populateSettings() { settings.setStringIfNotEmpty(Settings.KEYS.DB_USER, databaseUser); settings.setStringIfNotEmpty(Settings.KEYS.DB_PASSWORD, databasePassword); settings.setStringIfNotEmpty(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, zipExtensions); - settings.setStringIfNotEmpty(Settings.KEYS.CVE_MODIFIED_JSON, cveUrlModified); - settings.setStringIfNotEmpty(Settings.KEYS.CVE_BASE_JSON, cveUrlBase); + settings.setStringIfNotEmpty(Settings.KEYS.NVD_API_KEY, nvdApiKey); settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_ASSEMBLY_DOTNET_PATH, pathToCore); + settings.setBoolean(Settings.KEYS.FAIL_ON_UNUSED_SUPPRESSION_RULE, failOnUnusedSuppressionRule); } /** @@ -993,7 +995,7 @@ public Engine execute() throws ScanAgentException { if (this.showSummary) { showSummary(engine.getDependencies()); } - if (this.failBuildOnCVSS <= 10) { + if (this.failBuildOnCVSS <= 10.0) { checkForFailure(engine.getDependencies()); } } @@ -1025,15 +1027,29 @@ private void checkForFailure(Dependency[] dependencies) throws ScanAgentExceptio for (Dependency d : dependencies) { boolean addName = true; for (Vulnerability v : d.getVulnerabilities()) { - if ((v.getCvssV2() != null && v.getCvssV2().getScore() >= failBuildOnCVSS) - || (v.getCvssV3() != null && v.getCvssV3().getBaseScore() >= failBuildOnCVSS) - || (v.getUnscoredSeverity() != null && SeverityUtil.estimateCvssV2(v.getUnscoredSeverity()) >= failBuildOnCVSS) + final double cvssV2 = v.getCvssV2() != null && v.getCvssV2().getCvssData() != null + && v.getCvssV2().getCvssData().getBaseScore() != null ? v.getCvssV2().getCvssData().getBaseScore() : -1; + final double cvssV3 = v.getCvssV3() != null && v.getCvssV3().getCvssData() != null + && v.getCvssV3().getCvssData().getBaseScore() != null ? v.getCvssV3().getCvssData().getBaseScore() : -1; + final double cvssV4 = v.getCvssV4() != null && v.getCvssV4().getCvssData() != null + && v.getCvssV4().getCvssData().getBaseScore() != null ? v.getCvssV4().getCvssData().getBaseScore() : -1; + final boolean useUnscored = cvssV2 == -1 && cvssV3 == -1 && cvssV4 == -1; + final double unscoredCvss = (useUnscored && v.getUnscoredSeverity() != null) ? SeverityUtil.estimateCvssV2(v.getUnscoredSeverity()) : -1; + if (cvssV2 >= failBuildOnCVSS + || cvssV3 >= failBuildOnCVSS + || cvssV4 >= failBuildOnCVSS + || unscoredCvss >= failBuildOnCVSS //safety net to fail on any if for some reason the above misses on 0 - || (failBuildOnCVSS <= 0.0f)) { + || failBuildOnCVSS <= 0.0f + ) { if (addName) { addName = false; - ids.append(NEW_LINE).append(d.getFileName()).append(": "); - ids.append(v.getName()); + ids.append(NEW_LINE).append(d.getFileName()).append(" (") + .append(Stream.concat(d.getSoftwareIdentifiers().stream(), d.getVulnerableSoftwareIdentifiers().stream()) + .map(Identifier::getValue) + .collect(Collectors.joining(", "))) + .append("): ") + .append(v.getName()); } else { ids.append(", ").append(v.getName()); } diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractNpmAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractNpmAnalyzer.java index 573c50e3372..a02e3d40d74 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractNpmAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractNpmAnalyzer.java @@ -28,7 +28,6 @@ import org.owasp.dependencycheck.data.nodeaudit.NodeAuditSearch; import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Dependency; -import org.owasp.dependencycheck.dependency.Reference; import org.owasp.dependencycheck.dependency.Vulnerability; import org.owasp.dependencycheck.dependency.VulnerableSoftware; import org.owasp.dependencycheck.dependency.VulnerableSoftwareBuilder; @@ -45,13 +44,13 @@ import java.util.List; import java.util.Map; import javax.annotation.concurrent.ThreadSafe; -import javax.json.Json; -import javax.json.JsonArray; -import javax.json.JsonObject; -import javax.json.JsonObjectBuilder; -import javax.json.JsonString; -import javax.json.JsonValue; -import javax.json.JsonValue.ValueType; +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.json.JsonObjectBuilder; +import jakarta.json.JsonString; +import jakarta.json.JsonValue; +import jakarta.json.JsonValue.ValueType; import org.apache.commons.collections4.MultiValuedMap; import org.apache.commons.lang3.StringUtils; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; @@ -394,8 +393,11 @@ public void gatherEvidence(final JsonObject json, Dependency dependency) { } } dependency.setLicense(sb.toString()); - } else { - dependency.setLicense(json.getJsonObject("license").getString("type")); + } else if (value instanceof JsonObject) { + final JsonObject object = (JsonObject) value; + if (object.containsKey("type") && !object.isNull("type")) { + dependency.setLicense(object.getString("type")); + } } } } @@ -505,16 +507,13 @@ protected void processResults(final List advisories, Engine engine, * @param vuln the vulnerability to add */ protected void replaceOrAddVulnerability(Dependency dependency, Vulnerability vuln) { - boolean found = false; - for (Vulnerability existing : dependency.getVulnerabilities()) { - for (Reference ref : existing.getReferences()) { - if (ref.getName() != null - && vuln.getSource().toString().equals("NPM") - && ref.getName().equals("https://nodesecurity.io/advisories/" + vuln.getName())) { - found = true; - } - } - } + final boolean found = vuln.getSource() == Vulnerability.Source.NPM + && dependency.getVulnerabilities().stream().anyMatch(existing -> { + return existing.getReferences().stream().anyMatch(ref -> { + return ref.getName() != null + && ref.getName().equals("https://nodesecurity.io/advisories/" + vuln.getName()); + }); + }); if (!found) { dependency.addVulnerability(vuln); } diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractSuppressionAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractSuppressionAnalyzer.java index 7b741bdf87c..f03d2f6157f 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractSuppressionAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/AbstractSuppressionAnalyzer.java @@ -188,23 +188,37 @@ private void loadSuppressionBaseData(final Engine engine) throws SuppressionPars } /** - * Loads all the base suppression rules packaged with the application. + * Loads the base suppression rules packaged with the application. * * @param parser The suppression parser to use * @param engine a reference the dependency-check engine * @throws SuppressionParseException thrown if the XML cannot be parsed. */ private void loadPackagedSuppressionBaseData(final SuppressionParser parser, final Engine engine) throws SuppressionParseException { - final List ruleList; - try (InputStream in = FileUtils.getResourceAsStream(BASE_SUPPRESSION_FILE)) { - if (in == null) { - throw new SuppressionParseException("Suppression rules `" + BASE_SUPPRESSION_FILE + "` could not be found"); - } + List ruleList = null; + final URL jarLocation = AbstractSuppressionAnalyzer.class.getProtectionDomain().getCodeSource().getLocation(); + String suppressionFileLocation = jarLocation.getFile(); + if (suppressionFileLocation.endsWith(".jar")) { + suppressionFileLocation = "jar:file:" + suppressionFileLocation + "!/" + BASE_SUPPRESSION_FILE; + } else if (suppressionFileLocation.startsWith("nested:") && suppressionFileLocation.endsWith(".jar!/")) { + // suppressionFileLocation -> nested:/app/app.jar/!BOOT-INF/lib/dependency-check-core-.jar!/ + // goal-> jar:nested:/app/app.jar/!BOOT-INF/lib/dependency-check-core-.jar!/dependencycheck-base-suppression.xml + suppressionFileLocation = "jar:" + suppressionFileLocation + BASE_SUPPRESSION_FILE; + } else { + suppressionFileLocation = "file:" + suppressionFileLocation + BASE_SUPPRESSION_FILE; + } + URL baseSuppresssionURL = null; + try { + baseSuppresssionURL = new URL(suppressionFileLocation); + } catch (MalformedURLException e) { + throw new SuppressionParseException("Unable to load the base suppression data file", e); + } + try (InputStream in = baseSuppresssionURL.openStream()) { ruleList = parser.parseSuppressionRules(in); } catch (SAXException | IOException ex) { throw new SuppressionParseException("Unable to parse the base suppression data file", ex); } - if (!ruleList.isEmpty()) { + if (ruleList != null && !ruleList.isEmpty()) { if (engine.hasObject(SUPPRESSION_OBJECT_KEY)) { @SuppressWarnings("unchecked") final List rules = (List) engine.getObject(SUPPRESSION_OBJECT_KEY); @@ -345,14 +359,15 @@ private List loadSuppressionFile(final SuppressionParser parser deleteTempFile = true; file = getSettings().getTempFile("suppression", "xml"); final URL url = new URL(suppressionFilePath); - final Downloader downloader = new Downloader(getSettings()); try { - downloader.fetchFile(url, file, false, Settings.KEYS.SUPPRESSION_FILE_USER, Settings.KEYS.SUPPRESSION_FILE_PASSWORD); + Downloader.getInstance().fetchFile(url, file, false, Settings.KEYS.SUPPRESSION_FILE_USER, + Settings.KEYS.SUPPRESSION_FILE_PASSWORD, Settings.KEYS.SUPPRESSION_FILE_BEARER_TOKEN); } catch (DownloadFailedException ex) { LOGGER.trace("Failed download suppression file - first attempt", ex); try { Thread.sleep(500); - downloader.fetchFile(url, file, true, Settings.KEYS.SUPPRESSION_FILE_USER, Settings.KEYS.SUPPRESSION_FILE_PASSWORD); + Downloader.getInstance().fetchFile(url, file, true, Settings.KEYS.SUPPRESSION_FILE_USER, + Settings.KEYS.SUPPRESSION_FILE_PASSWORD, Settings.KEYS.SUPPRESSION_FILE_BEARER_TOKEN); } catch (TooManyRequestsException ex1) { throw new SuppressionParseException("Unable to download supression file `" + file + "`; received 429 - too many requests", ex1); @@ -377,7 +392,7 @@ private List loadSuppressionFile(final SuppressionParser parser deleteTempFile = true; file = getSettings().getTempFile("suppression", "xml"); try { - org.apache.commons.io.FileUtils.copyInputStreamToFile(suppressionFromClasspath, file); + Files.copy(suppressionFromClasspath, file.toPath()); } catch (IOException ex) { throwSuppressionParseException("Unable to locate suppression file in classpath", ex, suppressionFilePath); } diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/AnalysisPhase.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/AnalysisPhase.java index 818ba2186c8..1dcaa3bafe9 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/AnalysisPhase.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/AnalysisPhase.java @@ -26,54 +26,127 @@ public enum AnalysisPhase { /** * Initialization phase. + * @implNote Bound analyzers are {@link ArchiveAnalyzer} */ INITIAL, /** * Pre information collection phase. + * @implNote Bound analyzers are {@link ElixirMixAuditAnalyzer},{@link RubyBundleAuditAnalyzer} */ PRE_INFORMATION_COLLECTION, /** * Information collection phase. + * @implNote Bound analyzers are + * {@link ArtifactoryAnalyzer} + * {@link AssemblyAnalyzer} + * {@link AutoconfAnalyzer} + * {@link CMakeAnalyzer} + * {@link CentralAnalyzer} + * {@link CarthageAnalyzer} + * {@link CocoaPodsAnalyzer} + * {@link ComposerLockAnalyzer} + * {@link DartAnalyzer} + * {@link FileNameAnalyzer} + * {@link GolangDepAnalyzer} + * {@link GolangModAnalyzer} + * {@link JarAnalyzer} + * {@link LibmanAnalyzer} + * {@link MSBuildProjectAnalyzer} + * {@link NexusAnalyzer} + * {@link NodeAuditAnalyzer} + * {@link NugetconfAnalyzer} + * {@link NuspecAnalyzer} + * {@link OpenSSLAnalyzer} + * {@link PinnedMavenInstallAnalyzer} + * {@link PipAnalyzer} + * {@link PipfileAnalyzer} + * {@link PipfilelockAnalyzer} + * {@link PoetryAnalyzer} + * {@link PythonDistributionAnalyzer} + * {@link PythonPackageAnalyzer} + * {@link RubyGemspecAnalyzer} + * {@link RubyBundlerAnalyzer} + * {@link SwiftPackageManagerAnalyzer} + * {@link SwiftPackageResolvedAnalyzer} */ INFORMATION_COLLECTION, /** * Information collection phase 2. + * @implNote Bound analyzers are + * {@link PEAnalyzer} */ INFORMATION_COLLECTION2, /** - * Post information collection phase. + * Post information collection phase 1. + * @implNote Bound analyzers are + * {@link DependencyMergingAnalyzer} */ - POST_INFORMATION_COLLECTION, + POST_INFORMATION_COLLECTION1, + /** + * Post information collection phase 2. + * @implNote Bound analyzers are + * {@link HintAnalyzer} (must run before {@link VersionFilterAnalyzer}, should run after {@link DependencyMergingAnalyzer}) + */ + POST_INFORMATION_COLLECTION2, + /** + * Post information collection phase 3. + * @implNote Bound analyzers are + * {@link VersionFilterAnalyzer} + */ + POST_INFORMATION_COLLECTION3, /** * Pre identifier analysis phase. + * @implNote Bound analyzers are + * {@link NpmCPEAnalyzer} (must run in a separate phase from {@link CPEAnalyzer} due to singleton re-use) */ PRE_IDENTIFIER_ANALYSIS, /** * Identifier analysis phase. + * @implNote Bound analyzers are + * {@link CPEAnalyzer} */ IDENTIFIER_ANALYSIS, /** * Post identifier analysis phase. + * @implNote Bound analyzers are + * {@link CpeSuppressionAnalyzer} + * {@link FalsePositiveAnalyzer} */ POST_IDENTIFIER_ANALYSIS, /** * Pre finding analysis phase. + * @implNote No analyzers bound to this phase */ PRE_FINDING_ANALYSIS, /** * Finding analysis phase. + * @implNote Bound analyzers are + * {@link NodeAuditAnalyzer} + * {@link NvdCveAnalyzer} + * {@link PnpmAuditAnalyzer} + * {@link RetireJsAnalyzer} + * {@link YarnAuditAnalyzer} + * */ FINDING_ANALYSIS, /** * Finding analysis phase 2. + * @implNote Bound analyzers are + * {@link OssIndexAnalyzer} */ FINDING_ANALYSIS_PHASE2, /** * Post analysis phase. + * @implNote Bound analyzers are + * {@link KnownExploitedVulnerabilityAnalyzer} + * {@link VulnerabilitySuppressionAnalyzer} */ POST_FINDING_ANALYSIS, /** * The final analysis phase. + * @implNote Bound analyzers are + * {@link DependencyBundlingAnalyzer} + * {@link UnusedSuppressionRuleAnalyzer} */ FINAL } diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzer.java index 593b6d42500..7e7a113b6b0 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/ArchiveAnalyzer.java @@ -17,41 +17,21 @@ */ package org.owasp.dependencycheck.analyzer; -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileFilter; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.file.Path; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; -import javax.annotation.concurrent.ThreadSafe; - import org.apache.commons.compress.archivers.ArchiveEntry; import org.apache.commons.compress.archivers.ArchiveInputStream; import org.apache.commons.compress.archivers.cpio.CpioArchiveInputStream; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; -import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream; import org.apache.commons.compress.archivers.zip.ZipFile; import org.apache.commons.compress.compressors.CompressorInputStream; import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream; import org.apache.commons.compress.compressors.bzip2.BZip2Utils; import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; import org.apache.commons.compress.compressors.gzip.GzipUtils; -import org.apache.commons.compress.utils.IOUtils; +import org.apache.commons.io.IOUtils; import org.eclipse.packager.rpm.RpmTag; import org.eclipse.packager.rpm.parse.RpmInputStream; import org.owasp.dependencycheck.Engine; -import static org.owasp.dependencycheck.analyzer.AbstractNpmAnalyzer.shouldProcess; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.analyzer.exception.ArchiveExtractionException; import org.owasp.dependencycheck.analyzer.exception.UnexpectedAnalysisException; @@ -60,10 +40,30 @@ import org.owasp.dependencycheck.utils.FileFilterBuilder; import org.owasp.dependencycheck.utils.FileUtils; import org.owasp.dependencycheck.utils.Settings; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.concurrent.ThreadSafe; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import static org.owasp.dependencycheck.analyzer.AbstractNpmAnalyzer.shouldProcess; + /** *

* An analyzer that extracts files from archives and ensures any supported files @@ -360,7 +360,7 @@ private void addDisguisedJarsToDependencies(Dependency dependency, Engine engine dependency.setMd5sum(""); dependency.setSha1sum(""); dependency.setSha256sum(""); - org.apache.commons.io.FileUtils.copyFile(dependency.getActualFile(), tmpLoc); + Files.copy(dependency.getActualFile().toPath(), tmpLoc.toPath()); final List dependencySet = findMoreDependencies(engine, tmpLoc); if (dependencySet != null && !dependencySet.isEmpty()) { dependencySet.forEach((d) -> { @@ -460,7 +460,7 @@ private void extractFiles(File archive, File destination, Engine engine) throws tin = new TarArchiveInputStream(in); extractArchive(tin, destination, engine); } else if ("gz".equals(archiveExt) || "tgz".equals(archiveExt)) { - final String uncompressedName = GzipUtils.getUncompressedFilename(archive.getName()); + final String uncompressedName = GzipUtils.getUncompressedFileName(archive.getName()); final File f = new File(destination, uncompressedName); if (engine.accept(f)) { final String destPath = destination.getCanonicalPath(); @@ -475,7 +475,7 @@ private void extractFiles(File archive, File destination, Engine engine) throws decompressFile(gin, f); } } else if ("bz2".equals(archiveExt) || "tbz2".equals(archiveExt)) { - final String uncompressedName = BZip2Utils.getUncompressedFilename(archive.getName()); + final String uncompressedName = BZip2Utils.getUncompressedFileName(archive.getName()); final File f = new File(destination, uncompressedName); if (engine.accept(f)) { final String destPath = destination.getCanonicalPath(); @@ -524,12 +524,11 @@ private void extractFiles(File archive, File destination, Engine engine) throws * executable JAR is identified the input stream will be advanced to the * start of the actual JAR file ( skipping the script). * - * @see - * Installing - * Spring Boot Applications * @param archiveExt the file extension * @param in the input stream * @throws IOException thrown if there is an error reading the stream + * @see Installing + * Spring Boot Applications */ private void ensureReadableJar(final String archiveExt, BufferedInputStream in) throws IOException { if (("war".equals(archiveExt) || "jar".equals(archiveExt)) && in.markSupported()) { @@ -729,7 +728,7 @@ private boolean isZipFileActuallyJarFile(Dependency dependency) { boolean isJar = false; ZipFile zip = null; try { - zip = new ZipFile(dependency.getActualFilePath()); + zip = ZipFile.builder().setFile(dependency.getActualFilePath()).get(); if (zip.getEntry("META-INF/MANIFEST.MF") != null || zip.getEntry("META-INF/maven") != null) { final Enumeration entries = zip.getEntries(); diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/ArtifactoryAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/ArtifactoryAnalyzer.java index 0aaf21e7ac5..332323a0063 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/ArtifactoryAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/ArtifactoryAnalyzer.java @@ -17,7 +17,6 @@ */ package org.owasp.dependencycheck.analyzer; -import org.apache.commons.io.FileUtils; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.data.artifactory.ArtifactorySearch; @@ -30,8 +29,11 @@ import org.owasp.dependencycheck.utils.DownloadFailedException; import org.owasp.dependencycheck.utils.Downloader; import org.owasp.dependencycheck.utils.FileFilterBuilder; +import org.owasp.dependencycheck.utils.FileUtils; import org.owasp.dependencycheck.utils.InvalidSettingException; +import org.owasp.dependencycheck.utils.ResourceNotFoundException; import org.owasp.dependencycheck.utils.Settings; +import org.owasp.dependencycheck.utils.TooManyRequestsException; import org.owasp.dependencycheck.xml.pom.PomUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -44,8 +46,6 @@ import java.net.URL; import java.nio.file.Files; import java.util.List; -import org.owasp.dependencycheck.utils.ResourceNotFoundException; -import org.owasp.dependencycheck.utils.TooManyRequestsException; /** * Analyzer which will attempt to locate a dependency, and the GAV information, @@ -234,10 +234,10 @@ private void processPom(Dependency dependency, MavenArtifact ma) throws IOExcept Files.delete(pomFile.toPath()); LOGGER.debug("Downloading {}", ma.getPomUrl()); //TODO add caching - final Downloader downloader = new Downloader(getSettings()); - downloader.fetchFile(new URL(ma.getPomUrl()), pomFile, + Downloader.getInstance().fetchFile(new URL(ma.getPomUrl()), pomFile, true, Settings.KEYS.ANALYZER_ARTIFACTORY_API_USERNAME, - Settings.KEYS.ANALYZER_ARTIFACTORY_API_TOKEN); + Settings.KEYS.ANALYZER_ARTIFACTORY_API_TOKEN, + Settings.KEYS.ANALYZER_ARTIFACTORY_BEARER_TOKEN); PomUtils.analyzePOM(dependency, pomFile); } catch (DownloadFailedException ex) { @@ -251,7 +251,7 @@ private void processPom(Dependency dependency, MavenArtifact ma) throws IOExcept LOGGER.warn("pom.xml not found for {} from Artifactory; " + "this could result in undetected CPE/CVEs.", dependency.getFileName()); } finally { - if (pomFile != null && pomFile.exists() && !FileUtils.deleteQuietly(pomFile)) { + if (pomFile != null && pomFile.exists() && !FileUtils.delete(pomFile)) { LOGGER.debug("Failed to delete temporary pom file {}", pomFile); pomFile.deleteOnExit(); } diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/AssemblyAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/AssemblyAnalyzer.java index f3b2ec4c167..d9cd109f3ba 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/AssemblyAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/AssemblyAnalyzer.java @@ -284,20 +284,24 @@ private void updateDependency(final AssemblyData data, Dependency dependency) { if (!StringUtils.isBlank(data.getCompanyName())) { dependency.addEvidence(EvidenceType.VENDOR, "grokassembly", "CompanyName", data.getCompanyName(), Confidence.HIGHEST); + dependency.addEvidence(EvidenceType.PRODUCT, "grokassembly", "CompanyName", data.getCompanyName(), Confidence.LOW); addMatchingValues(data.getNamespaces(), data.getCompanyName(), dependency, EvidenceType.VENDOR); } if (!StringUtils.isBlank(data.getProductName())) { dependency.addEvidence(EvidenceType.PRODUCT, "grokassembly", "ProductName", data.getProductName(), Confidence.HIGHEST); + dependency.addEvidence(EvidenceType.VENDOR, "grokassembly", "ProductName", data.getProductName(), Confidence.MEDIUM); addMatchingValues(data.getNamespaces(), data.getProductName(), dependency, EvidenceType.PRODUCT); } if (!StringUtils.isBlank(data.getFileDescription())) { dependency.addEvidence(EvidenceType.PRODUCT, "grokassembly", "FileDescription", data.getFileDescription(), Confidence.HIGH); + dependency.addEvidence(EvidenceType.VENDOR, "grokassembly", "FileDescription", data.getFileDescription(), Confidence.LOW); addMatchingValues(data.getNamespaces(), data.getFileDescription(), dependency, EvidenceType.PRODUCT); } final String internalName = data.getInternalName(); if (!StringUtils.isBlank(internalName)) { dependency.addEvidence(EvidenceType.PRODUCT, "grokassembly", "InternalName", internalName, Confidence.MEDIUM); + dependency.addEvidence(EvidenceType.VENDOR, "grokassembly", "InternalName", internalName, Confidence.LOW); addMatchingValues(data.getNamespaces(), internalName, dependency, EvidenceType.PRODUCT); addMatchingValues(data.getNamespaces(), internalName, dependency, EvidenceType.VENDOR); if (dependency.getName() == null && StringUtils.containsIgnoreCase(dependency.getActualFile().getName(), internalName)) { @@ -313,6 +317,7 @@ private void updateDependency(final AssemblyData data, Dependency dependency) { final String originalFilename = data.getOriginalFilename(); if (!StringUtils.isBlank(originalFilename)) { dependency.addEvidence(EvidenceType.PRODUCT, "grokassembly", "OriginalFilename", originalFilename, Confidence.MEDIUM); + dependency.addEvidence(EvidenceType.VENDOR, "grokassembly", "OriginalFilename", originalFilename, Confidence.LOW); addMatchingValues(data.getNamespaces(), originalFilename, dependency, EvidenceType.PRODUCT); if (dependency.getName() == null && StringUtils.containsIgnoreCase(dependency.getActualFile().getName(), originalFilename)) { final String ext = FileUtils.getFileExtension(originalFilename); @@ -355,7 +360,7 @@ public void prepareFileTypeAnalyzer(Engine engine) throws InitializationExceptio + "'exe' or 'dll' was scanned. The 'dotnet' executable could not be found on " + "the path; either disable the Assembly Analyzer or add the path to dotnet " + "core in the configuration."); - LOGGER.error("The dotnet 6.0 core runtime or SDK is required to analyze assemblies"); + LOGGER.error("The dotnet 8.0 core runtime or SDK is required to analyze assemblies"); LOGGER.error("----------------------------------------------------"); return; } @@ -367,28 +372,28 @@ public void prepareFileTypeAnalyzer(Engine engine) throws InitializationExceptio final String error = processReader.getError(); if (p.exitValue() != 1 || !StringUtils.isBlank(error)) { LOGGER.warn("An error occurred with the .NET AssemblyAnalyzer, please see the log for more details.\n" - + "dependency-check requires dotnet 6.0 core runtime or sdk to be installed to analyze assemblies."); + + "dependency-check requires dotnet 8.0 core runtime or sdk to be installed to analyze assemblies."); LOGGER.debug("GrokAssembly.dll is not working properly"); grokAssembly = null; setEnabled(false); - throw new InitializationException("Could not execute .NET AssemblyAnalyzer, is the dotnet 6.0 runtime or sdk installed?"); + throw new InitializationException("Could not execute .NET AssemblyAnalyzer, is the dotnet 8.0 runtime or sdk installed?"); } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); LOGGER.warn("An error occurred with the .NET AssemblyAnalyzer;\n" - + "dependency-check requires dotnet 6.0 core runtime or sdk to be installed to analyze assemblies;\n" + + "dependency-check requires dotnet 8.0 core runtime or sdk to be installed to analyze assemblies;\n" + "this can be ignored unless you are scanning .NET DLLs. Please see the log for more details."); LOGGER.debug("Could not execute GrokAssembly {}", e.getMessage()); setEnabled(false); throw new InitializationException("An error occurred with the .NET AssemblyAnalyzer", e); } catch (IOException e) { LOGGER.warn("An error occurred with the .NET AssemblyAnalyzer;\n" - + "dependency-check requires dotnet 6.0 core to be installed to analyze assemblies;\n" + + "dependency-check requires dotnet 8.0 core to be installed to analyze assemblies;\n" + "this can be ignored unless you are scanning .NET DLLs. Please see the log for more details."); LOGGER.debug("Could not execute GrokAssembly {}", e.getMessage()); setEnabled(false); - throw new InitializationException("An error occurred with the .NET AssemblyAnalyzer, is the dotnet 6.0 runtime or sdk installed?", e); + throw new InitializationException("An error occurred with the .NET AssemblyAnalyzer, is the dotnet 8.0 runtime or sdk installed?", e); } } @@ -422,7 +427,9 @@ private File extractGrokAssembly() throws InitializationException { */ @Override public void closeAnalyzer() throws Exception { - FileUtils.delete(grokAssembly.getParentFile()); + if (grokAssembly != null) { + FileUtils.delete(grokAssembly.getParentFile()); + } } @Override diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/AutoconfAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/AutoconfAnalyzer.java index 303d775e58b..08c059b8a70 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/AutoconfAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/AutoconfAnalyzer.java @@ -17,11 +17,12 @@ */ package org.owasp.dependencycheck.analyzer; -import org.apache.commons.io.FileUtils; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Dependency; +import org.owasp.dependencycheck.dependency.EvidenceType; +import org.owasp.dependencycheck.exception.InitializationException; import org.owasp.dependencycheck.utils.FileFilterBuilder; import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.UrlStringUtils; @@ -29,11 +30,10 @@ import java.io.File; import java.io.FileFilter; import java.io.IOException; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.owasp.dependencycheck.dependency.EvidenceType; -import org.owasp.dependencycheck.exception.InitializationException; /** * Used to analyze Autoconf input files named configure.ac or configure.in. @@ -187,7 +187,7 @@ protected void analyzeDependency(Dependency dependency, Engine engine) * @param contents the contents to analyze for evidence */ private void extractConfigureScriptEvidence(Dependency dependency, - final String name, final String contents) { + final String name, final String contents) { final Matcher matcher = PACKAGE_VAR.matcher(contents); while (matcher.find()) { final String variable = matcher.group(1); @@ -195,12 +195,15 @@ private void extractConfigureScriptEvidence(Dependency dependency, if (!value.isEmpty()) { if (variable.endsWith("NAME")) { dependency.addEvidence(EvidenceType.PRODUCT, name, variable, value, Confidence.HIGHEST); + dependency.addEvidence(EvidenceType.VENDOR, name, variable, value, Confidence.MEDIUM); } else if ("VERSION".equals(variable)) { dependency.addEvidence(EvidenceType.VERSION, name, variable, value, Confidence.HIGHEST); } else if ("BUGREPORT".equals(variable)) { dependency.addEvidence(EvidenceType.VENDOR, name, variable, value, Confidence.HIGH); + dependency.addEvidence(EvidenceType.PRODUCT, name, variable, value, Confidence.MEDIUM); } else if ("URL".equals(variable)) { dependency.addEvidence(EvidenceType.VENDOR, name, variable, value, Confidence.HIGH); + dependency.addEvidence(EvidenceType.PRODUCT, name, variable, value, Confidence.MEDIUM); } } } @@ -216,7 +219,7 @@ private void extractConfigureScriptEvidence(Dependency dependency, private String getFileContents(final File actualFile) throws AnalysisException { try { - return FileUtils.readFileToString(actualFile, Charset.defaultCharset()).trim(); + return new String(Files.readAllBytes(actualFile.toPath()), StandardCharsets.UTF_8).trim(); } catch (IOException e) { throw new AnalysisException( "Problem occurred while reading dependency file.", e); @@ -231,7 +234,7 @@ private String getFileContents(final File actualFile) * @param contents the evidence to analyze */ private void gatherEvidence(Dependency dependency, final String name, - String contents) { + String contents) { final Matcher matcher = AC_INIT_PATTERN.matcher(contents); if (matcher.find()) { dependency.addEvidence(EvidenceType.PRODUCT, name, "Package", matcher.group(1), Confidence.HIGHEST); diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/CMakeAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/CMakeAnalyzer.java index 4b422c3d756..fdd36476954 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/CMakeAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/CMakeAnalyzer.java @@ -17,10 +17,10 @@ */ package org.owasp.dependencycheck.analyzer; -import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; +import org.owasp.dependencycheck.data.nvd.ecosystem.Ecosystem; import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.EvidenceType; @@ -30,14 +30,14 @@ import org.owasp.dependencycheck.utils.DependencyVersionUtil; import org.owasp.dependencycheck.utils.FileFilterBuilder; import org.owasp.dependencycheck.utils.Settings; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.FileFilter; import java.io.IOException; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -45,7 +45,6 @@ import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.owasp.dependencycheck.data.nvd.ecosystem.Ecosystem; /** *

@@ -101,9 +100,8 @@ public class CMakeAnalyzer extends AbstractFileTypeAnalyzer { /** * Regex to extract product and version information. * - * Group 1: Product - * - * Group 2: Version + *

Group 1: Product

+ *

Group 2: Version

*/ private static final Pattern SET_VERSION = Pattern .compile("^\\s*set\\s*\\(\\s*(\\w+)_version\\s+\"?([^\")]*)\\s*\"?\\)", REGEX_OPTIONS); @@ -171,7 +169,7 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An final String name = file.getName(); final String contents; try { - contents = FileUtils.readFileToString(file, Charset.defaultCharset()).trim(); + contents = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8).trim(); } catch (IOException e) { throw new AnalysisException( "Problem occurred while reading dependency file.", e); @@ -349,8 +347,8 @@ protected String getAnalyzerEnabledSettingKey() { * initialized by other variables and end up forming an unresolvable * chain. * - * This method takes the resolved variables map as an input and will return - * a new map, without the keys generate an infinite resolution chain. + *

This method takes the resolved variables map as an input and will return + * a new map, without the keys generating an infinite resolution chain.

* * @param vars variables initialization detected in the CMake build file * @@ -379,6 +377,9 @@ private boolean isVariableSelfReferencing(Map vars, String key) break; } nextKey = matcher.group(2); + if (Objects.nonNull(nextKey) && resolutionChain.contains(nextKey)) { + return true; + } resolutionChain.add(nextKey); } while (Objects.nonNull(nextKey) && vars.containsKey(nextKey) && !key.equals(nextKey)); diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/CPEAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/CPEAnalyzer.java index e1c89c41c74..d2fe65a1460 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/CPEAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/CPEAnalyzer.java @@ -20,8 +20,6 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; @@ -49,6 +47,7 @@ import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.TopDocs; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.data.cpe.CpeMemoryIndex; @@ -110,24 +109,7 @@ public class CPEAnalyzer extends AbstractAnalyzer { * alpha characters. */ private static final String CLEANSE_NONALPHA_RX = "[^A-Za-z]*"; - /** - * UTF-8 character set name. - */ - private static final String UTF8 = StandardCharsets.UTF_8.name(); - /** - * The URL to search the NVD CVE data at NIST. This is used by calling: - *
String.format(NVD_SEARCH_URL, vendor, product, version);
- */ - public static final String NVD_SEARCH_URL = "https://nvd.nist.gov/vuln/search/results?form_type=Advanced&" - + "results_type=overview&search_type=all&cpe_vendor=cpe%%3A%%2F%%3A%1$s&cpe_product=cpe%%3A%%2F%%3A%1$s%%3A%2$s&" - + "cpe_version=cpe%%3A%%2F%%3A%1$s%%3A%2$s%%3A%3$s"; - /** - * The URL to search the NVD CVE data at NIST. This is used by calling: - *
String.format(NVD_SEARCH_URL, vendor, product);
- */ - public static final String NVD_SEARCH_BROAD_URL = "https://nvd.nist.gov/vuln/search/results?form_type=Advanced&" - + "results_type=overview&search_type=all&cpe_vendor=cpe%%3A%%2F%%3A%1$s&cpe_product=cpe%%3A%%2F%%3A%1$s%%3A%2$s"; /** * The CPE in memory index. */ @@ -805,12 +787,11 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An * analysis * @return true if an identifier was added to the dependency; * otherwise false - * @throws UnsupportedEncodingException is thrown if UTF-8 is not supported * @throws AnalysisException thrown if the suppression rules failed */ @SuppressWarnings("StringSplitter") protected boolean determineIdentifiers(Dependency dependency, String vendor, String product, - Confidence currentConfidence) throws UnsupportedEncodingException, AnalysisException { + Confidence currentConfidence) throws AnalysisException { final CpeBuilder cpeBuilder = new CpeBuilder(); @@ -831,7 +812,7 @@ protected boolean determineIdentifiers(Dependency dependency, String vendor, Str String bestGuessURL = null; final Set collected = new HashSet<>(); - considerDependencyVersion(dependency, vendor, product, currentConfidence, collected, bestGuess); + considerDependencyVersion(dependency, vendor, product, currentConfidence, collected); //TODO the following algorithm incorrectly identifies things as a lower version // if there lower confidence evidence when the current (highest) version number @@ -863,8 +844,7 @@ protected boolean determineIdentifiers(Dependency dependency, String vendor, Str dbVerUpdate = DependencyVersionUtil.parseVersion(vs.getVersion() + '.' + vs.getUpdate(), true); } if (dbVer == null) { //special case, no version specified - everything is vulnerable - final String url = String.format(NVD_SEARCH_BROAD_URL, URLEncoder.encode(vs.getVendor(), UTF8), - URLEncoder.encode(vs.getProduct(), UTF8)); + final String url = CpeIdentifier.nvdProductSearchUrlFor(vs); final IdentifierMatch match = new IdentifierMatch(vs, url, IdentifierConfidence.BROAD_MATCH, conf); collected.add(match); } else if (evVer.equals(dbVer)) { @@ -874,8 +854,7 @@ protected boolean determineIdentifiers(Dependency dependency, String vendor, Str bestGuessConf = conf; bestGuess = dbVer; bestGuessUpdate = evBaseVerUpdate; - bestGuessURL = String.format(NVD_SEARCH_URL, URLEncoder.encode(vs.getVendor(), UTF8), - URLEncoder.encode(vs.getProduct(), UTF8), URLEncoder.encode(vs.getVersion(), UTF8)); + bestGuessURL = CpeIdentifier.nvdSearchUrlFor(vs); } else if (dbVerUpdate != null && evVer.getVersionParts().size() <= dbVerUpdate.getVersionParts().size() && evVer.matchesAtLeastThreeLevels(dbVerUpdate)) { if (bestGuessConf == null || bestGuessConf.compareTo(conf) > 0) { @@ -982,14 +961,12 @@ protected boolean determineIdentifiers(Dependency dependency, String vendor, Str * @param updateVersion the update version * @param conf the current confidence * @param collected a reference to the collected identifiers - * @throws UnsupportedEncodingException thrown if UTF-8 is not supported */ private void addExactMatch(Cpe vs, String updateVersion, Confidence conf, - final Set collected) throws UnsupportedEncodingException { + final Set collected) { final CpeBuilder cpeBuilder = new CpeBuilder(); - final String url = String.format(NVD_SEARCH_URL, URLEncoder.encode(vs.getVendor(), UTF8), - URLEncoder.encode(vs.getProduct(), UTF8), URLEncoder.encode(vs.getVersion(), UTF8)); + final String url = CpeIdentifier.nvdSearchUrlFor(vs); Cpe useCpe; if (updateVersion != null && "*".equals(vs.getUpdate())) { try { @@ -1019,16 +996,13 @@ private void addExactMatch(Cpe vs, String updateVersion, Confidence conf, * @param vendor the vendor name * @param confidence the current confidence level * @param collected a reference to the identifiers matched - * @param bestGuess the current best guess as to the dependency version * @throws AnalysisException thrown if aliens attacked and valid input could * not be used to construct a CPE - * @throws UnsupportedEncodingException thrown if run on a system that - * doesn't support UTF-8 */ private void considerDependencyVersion(Dependency dependency, String vendor, String product, Confidence confidence, - final Set collected, DependencyVersion bestGuess) - throws AnalysisException, UnsupportedEncodingException { + final Set collected) + throws AnalysisException { if (dependency.getVersion() != null && !dependency.getVersion().isEmpty()) { final CpeBuilder cpeBuilder = new CpeBuilder(); @@ -1037,7 +1011,8 @@ private void considerDependencyVersion(Dependency dependency, if (dependency.getName() != null && !dependency.getName().isEmpty()) { final String name = dependency.getName(); for (String word : product.split("[^a-zA-Z0-9]")) { - useDependencyVersion &= name.contains(word) || stopWords.contains(word); + useDependencyVersion &= name.contains(word) || stopWords.contains(word) + || wordMatchesEcosystem(dependency.getEcosystem(), word); } } @@ -1050,18 +1025,37 @@ private void considerDependencyVersion(Dependency dependency, addVersionAndUpdate(depVersion, cpeBuilder); try { final Cpe depCpe = cpeBuilder.build(); - final String url = String.format(NVD_SEARCH_URL, URLEncoder.encode(vendor, UTF8), - URLEncoder.encode(product, UTF8), URLEncoder.encode(depCpe.getVersion(), UTF8)); + final String url = CpeIdentifier.nvdSearchUrlFor(vendor, product, depCpe.getVersion()); final IdentifierMatch match = new IdentifierMatch(depCpe, url, IdentifierConfidence.EXACT_MATCH, confidence); collected.add(match); } catch (CpeValidationException ex) { - throw new AnalysisException(String.format("Unable to create a CPE for %s:%s:%s", vendor, product, bestGuess.toString())); + throw new AnalysisException(String.format("Unable to create a CPE for %s:%s:%s", vendor, product, depVersion)); } } } } } + /** + * If a CPE product word represents the ecosystem of a dependency it is not required + * to appear in the dependencyName to still consider the CPE product a match. + * + * @param ecosystem The ecosystem of the dependency + * @param word The word from the CPE product to check + * @return {@code true} when the CPE product word is known to match the ecosystem of the dependency + * @implNote This method is not intended to cover every possible case where the ecosystem is represented by the word. It is a + * best-effort attempt to prevent {@link #considerDependencyVersion(Dependency, String, String, Confidence, Set)} + * from not taking an exact-match versioned CPE into account because the ecosystem-related word does not appear in + * the dependencyName. It helps prevent false-positive cases like https://github.com/dependency-check/DependencyCheck/issues/5545 + * @see #considerDependencyVersion(Dependency, String, String, Confidence, Set) + */ + private boolean wordMatchesEcosystem(@Nullable String ecosystem, String word) { + if (Ecosystem.JAVA.equalsIgnoreCase(word)) { + return Ecosystem.JAVA.equals(ecosystem); + } + return false; + } + /** *

* Returns the setting key to determine if the analyzer is enabled.

diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/CarthageAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/CarthageAnalyzer.java new file mode 100644 index 00000000000..05d711a49d3 --- /dev/null +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/CarthageAnalyzer.java @@ -0,0 +1,297 @@ +/* + * This file is part of dependency-check-core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2023 The OWASP Foundation. All Rights Reserved. + */ +package org.owasp.dependencycheck.analyzer; + +import com.github.packageurl.MalformedPackageURLException; +import com.github.packageurl.PackageURL; +import com.github.packageurl.PackageURLBuilder; +import org.owasp.dependencycheck.Engine; +import org.owasp.dependencycheck.analyzer.exception.AnalysisException; +import org.owasp.dependencycheck.data.nvd.ecosystem.Ecosystem; +import org.owasp.dependencycheck.dependency.Confidence; +import org.owasp.dependencycheck.dependency.Dependency; +import org.owasp.dependencycheck.dependency.EvidenceType; +import org.owasp.dependencycheck.dependency.naming.GenericIdentifier; +import org.owasp.dependencycheck.dependency.naming.PurlIdentifier; +import org.owasp.dependencycheck.utils.Checksum; +import org.owasp.dependencycheck.utils.FileFilterBuilder; +import org.owasp.dependencycheck.utils.Settings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.concurrent.ThreadSafe; +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * This analyzer is used to analyze SWIFT and Objective-C packages by collecting + * information from Cartfile files. Carthage dependency manager see + * https://github.com/Carthage/Carthage. + * + * Based on CocoaPodsAnalyzer by Bianca Jiang. + * + * @author Alin Radut (https://github.com/alinradut) + */ +@Experimental +@ThreadSafe +public class CarthageAnalyzer extends AbstractFileTypeAnalyzer { + + /** + * A descriptor for the type of dependencies processed or added by this + * analyzer. + */ + public static final String DEPENDENCY_ECOSYSTEM = Ecosystem.IOS; + + /** + * The logger. + */ + private static final Logger LOGGER = LoggerFactory.getLogger(CarthageAnalyzer.class); + /** + * The name of the analyzer. + */ + private static final String ANALYZER_NAME = "Carthage Package Analyzer"; + + /** + * The phase that this analyzer is intended to run in. + */ + private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION; + + /** + * The file name to scan. + */ + public static final String CARTFILE_RESOLVED = "Cartfile.resolved"; + /** + * Filter that detects files named "Cartfile.resolved". + */ + private static final FileFilter CARTHAGE_FILTER = FileFilterBuilder.newInstance().addFilenames(CARTFILE_RESOLVED).build(); + + /** + * The capture group #1 is the dependency type, #2 is the name, #3 is + * dependency version. The version can be a commit ref, so we can't assume + * it's a number + * + * Example values: + *
    + *
  • binary "https://dl.google.com/geosdk/GoogleMaps.json" "7.2.0"
  • + *
  • git "https://gitlab.matrix.org/matrix-org/olm.git" "3.2.16"
  • + *
  • github "alinradut/SwiftEntryKit" + * "95f4a08f41ddcf2c02e2b22789038774c8c94df5"
  • + *
  • github "CocoaLumberjack/CocoaLumberjack" "3.8.5"
  • + *
  • github "realm/realm-swift" "v10.44.0"
  • + *
+ */ + private static final Pattern CARTFILE_RESOLVED_DEPENDENCY_PATTERN = Pattern.compile("(github|git|binary) \"([^\"]+)\" \"([^\"]+)\""); + + /** + * The capture group #1 is the actual numerical version. + */ + private static final Pattern CARTFILE_VERSION_PATTERN = Pattern.compile("^v?(\\d+(\\.\\d+){0,4})$"); + + /** + * Capture group #1 is the dependency name. + * + * Example values: + *
    + *
  • robbiehanson/XMPPFramework
  • + *
  • CocoaLumberjack/CocoaLumberjack
  • + *
+ */ + private static final Pattern CARTFILE_RESOLVED_GITHUB_DEPENDENCY = Pattern.compile("[a-zA-Z0-9-_]+/([a-zA-Z0-9\\-_\\.]+)"); + + /** + * Capture group #1 is the dependency name. + */ + private static final Pattern CARTFILE_RESOLVED_GIT_DEPENDENCY = Pattern.compile(".*?/([a-zA-Z0-9\\-_\\.]+).git"); + + /** + * Capture group #1 is the dependency name. + * + * Example values: + *
    + *
  • https://my.domain.com/release/MyFramework.json
  • + *
  • file:///some/Path/MyFramework.json - + * relative/path/MyFramework.json
  • + *
  • /absolute/path/MyFramework.json
  • + *
+ */ + private static final Pattern CARTFILE_RESOLVED_BINARY_DEPENDENCY = Pattern.compile("([a-zA-Z0-9\\-_\\.]+).json"); + + /** + * Returns the FileFilter + * + * @return the FileFilter + */ + @Override + protected FileFilter getFileFilter() { + return CARTHAGE_FILTER; + } + + @Override + protected void prepareFileTypeAnalyzer(Engine engine) { + // NO-OP + } + + /** + * Returns the name of the analyzer. + * + * @return the name of the analyzer. + */ + @Override + public String getName() { + return ANALYZER_NAME; + } + + /** + * Returns the phase that the analyzer is intended to run in. + * + * @return the phase that the analyzer is intended to run in. + */ + @Override + public AnalysisPhase getAnalysisPhase() { + return ANALYSIS_PHASE; + } + + /** + * Returns the key used in the properties file to reference the analyzer's + * enabled property. + * + * @return the analyzer's enabled property setting key + */ + @Override + protected String getAnalyzerEnabledSettingKey() { + return Settings.KEYS.ANALYZER_CARTHAGE_ENABLED; + } + + @Override + protected void analyzeDependency(Dependency dependency, Engine engine) + throws AnalysisException { + if (CARTFILE_RESOLVED.equals(dependency.getFileName())) { + analyzeCartfileResolvedDependency(dependency, engine); + } + } + + /** + * Analyzes the Cartfile.resolved and adds the evidence to the dependency. + * + * @param cartfileResolved the dependency + * @param engine a reference to the dependency-check engine + * @throws AnalysisException thrown if there is an error analyzing the + * Cartfile + */ + private void analyzeCartfileResolvedDependency(Dependency cartfileResolved, Engine engine) + throws AnalysisException { + engine.removeDependency(cartfileResolved); + + final String contents; + try { + contents = new String(Files.readAllBytes(cartfileResolved.getActualFile().toPath()), StandardCharsets.UTF_8); + } catch (IOException e) { + throw new AnalysisException( + "Problem occurred while reading dependency file.", e); + } + + final Matcher matcher = CARTFILE_RESOLVED_DEPENDENCY_PATTERN.matcher(contents); + while (matcher.find()) { + final String type = matcher.group(1); + String name = matcher.group(2); + String version = matcher.group(3); + + final Matcher versionMatcher = CARTFILE_VERSION_PATTERN.matcher(version); + if (versionMatcher.find()) { + version = versionMatcher.group(1); + } else { + // this is probably a git commit reference, so we'll default to 0.0.0. + // this will probably bubble up a ton of CVEs, but serves you right for + // not using semantic versioning. + version = "0.0.0"; + } + + if (type.contentEquals("git")) { + final Matcher nameMatcher = CARTFILE_RESOLVED_GIT_DEPENDENCY.matcher(name); + if (!nameMatcher.find()) { + continue; + } + name = nameMatcher.group(1); + } else if (type.contentEquals("github")) { + final Matcher nameMatcher = CARTFILE_RESOLVED_GITHUB_DEPENDENCY.matcher(name); + if (!nameMatcher.find()) { + continue; + } + name = nameMatcher.group(1); + } else if (type.contentEquals("binary")) { + final Matcher nameMatcher = CARTFILE_RESOLVED_BINARY_DEPENDENCY.matcher(name); + if (!nameMatcher.find()) { + continue; + } + name = nameMatcher.group(1); + } + + final Dependency dependency = new Dependency(cartfileResolved.getActualFile(), true); + dependency.setEcosystem(DEPENDENCY_ECOSYSTEM); + dependency.setName(name); + dependency.setVersion(version); + + try { + final PackageURLBuilder builder = PackageURLBuilder.aPackageURL().withType("carthage").withName(dependency.getName()); + if (dependency.getVersion() != null) { + builder.withVersion(dependency.getVersion()); + } + final PackageURL purl = builder.build(); + dependency.addSoftwareIdentifier(new PurlIdentifier(purl, Confidence.HIGHEST)); + } catch (MalformedPackageURLException ex) { + LOGGER.debug("Unable to build package url for carthage", ex); + final GenericIdentifier id; + if (dependency.getVersion() != null) { + id = new GenericIdentifier("carthage:" + dependency.getName() + "@" + dependency.getVersion(), Confidence.HIGHEST); + } else { + id = new GenericIdentifier("carthage:" + dependency.getName(), Confidence.HIGHEST); + } + dependency.addSoftwareIdentifier(id); + } + + final String packagePath = String.format("%s:%s", name, version); + dependency.setPackagePath(packagePath); + dependency.setDisplayFileName(packagePath); + dependency.setSha1sum(Checksum.getSHA1Checksum(packagePath)); + dependency.setSha256sum(Checksum.getSHA256Checksum(packagePath)); + dependency.setMd5sum(Checksum.getMD5Checksum(packagePath)); + dependency.addEvidence(EvidenceType.VENDOR, CARTFILE_RESOLVED, "name", name, Confidence.HIGHEST); + dependency.addEvidence(EvidenceType.PRODUCT, CARTFILE_RESOLVED, "name", name, Confidence.HIGHEST); + dependency.addEvidence(EvidenceType.VERSION, CARTFILE_RESOLVED, "version", version, Confidence.HIGHEST); + engine.addDependency(dependency); + } + } + + /** + * Sets the package path on the given dependency. + * + * @param dep the dependency to update + */ + private void setPackagePath(Dependency dep) { + final File file = new File(dep.getFilePath()); + final String parent = file.getParent(); + if (parent != null) { + dep.setPackagePath(parent); + } + } +} diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/CentralAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/CentralAnalyzer.java index 1495bcb6b70..be270c96e8e 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/CentralAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/CentralAnalyzer.java @@ -17,20 +17,34 @@ */ package org.owasp.dependencycheck.analyzer; -import org.apache.commons.io.FileUtils; +import org.apache.commons.jcs3.access.exception.CacheException; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.analyzer.exception.UnexpectedAnalysisException; +import org.owasp.dependencycheck.data.cache.DataCache; +import org.owasp.dependencycheck.data.cache.DataCacheFactory; import org.owasp.dependencycheck.data.central.CentralSearch; -import org.owasp.dependencycheck.utils.TooManyRequestsException; import org.owasp.dependencycheck.data.nexus.MavenArtifact; import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Evidence; +import org.owasp.dependencycheck.dependency.EvidenceType; +import org.owasp.dependencycheck.exception.InitializationException; +import org.owasp.dependencycheck.utils.DownloadFailedException; +import org.owasp.dependencycheck.utils.Downloader; +import org.owasp.dependencycheck.utils.FileFilterBuilder; +import org.owasp.dependencycheck.utils.FileUtils; +import org.owasp.dependencycheck.utils.ForbiddenException; +import org.owasp.dependencycheck.utils.InvalidSettingException; +import org.owasp.dependencycheck.utils.ResourceNotFoundException; +import org.owasp.dependencycheck.utils.Settings; +import org.owasp.dependencycheck.utils.TooManyRequestsException; +import org.owasp.dependencycheck.xml.pom.Model; import org.owasp.dependencycheck.xml.pom.PomUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.concurrent.ThreadSafe; import java.io.File; import java.io.FileFilter; import java.io.FileNotFoundException; @@ -39,20 +53,6 @@ import java.net.URL; import java.text.MessageFormat; import java.util.List; -import javax.annotation.concurrent.ThreadSafe; -import org.apache.commons.jcs.access.exception.CacheException; -import org.owasp.dependencycheck.data.cache.DataCache; -import org.owasp.dependencycheck.data.cache.DataCacheFactory; - -import org.owasp.dependencycheck.dependency.EvidenceType; -import org.owasp.dependencycheck.exception.InitializationException; -import org.owasp.dependencycheck.utils.DownloadFailedException; -import org.owasp.dependencycheck.utils.Downloader; -import org.owasp.dependencycheck.utils.FileFilterBuilder; -import org.owasp.dependencycheck.utils.InvalidSettingException; -import org.owasp.dependencycheck.utils.ResourceNotFoundException; -import org.owasp.dependencycheck.utils.Settings; -import org.owasp.dependencycheck.xml.pom.Model; /** * Analyzer which will attempt to locate a dependency, and the GAV information, @@ -242,12 +242,12 @@ public void analyzeDependency(Dependency dependency, Engine engine) throws Analy + "this could result in undetected CPE/CVEs.", dependency.getFileName()); LOGGER.debug("Unable to delete temp file"); } - final Downloader downloader = new Downloader(getSettings()); final int maxAttempts = this.getSettings().getInt(Settings.KEYS.ANALYZER_CENTRAL_RETRY_COUNT, 3); int retryCount = 0; long sleepingTimeBetweenRetriesInMillis = BASE_RETRY_WAIT; boolean success = false; Model model = null; + DownloadFailedException lastException = null; if (cache != null) { model = cache.get(ma.getPomUrl()); } @@ -259,9 +259,10 @@ public void analyzeDependency(Dependency dependency, Engine engine) throws Analy do { //CSOFF: NestedTryDepth try { - downloader.fetchFile(new URL(ma.getPomUrl()), pomFile); + Downloader.getInstance().fetchFile(new URL(ma.getPomUrl()), pomFile); success = true; } catch (DownloadFailedException ex) { + lastException = ex; try { Thread.sleep(sleepingTimeBetweenRetriesInMillis); } catch (InterruptedException ex1) { @@ -288,6 +289,10 @@ public void analyzeDependency(Dependency dependency, Engine engine) throws Analy } else { LOGGER.warn("Unable to download pom.xml for {} from Central; " + "this could result in undetected CPE/CVEs.", dependency.getFileName()); + setEnabled(false); + LOGGER.warn("Disabling the Central Analyzer due to repeated download failures; Central Search " + + "may be down see https://status.maven.org/\n Note that this could result in both false " + + "positives and false negatives", lastException); } } catch (AnalysisException ex) { @@ -295,7 +300,7 @@ public void analyzeDependency(Dependency dependency, Engine engine) throws Analy + "this could result in undetected CPE/CVEs.", dependency.getFileName()), ex); } finally { - if (pomFile != null && pomFile.exists() && !FileUtils.deleteQuietly(pomFile)) { + if (pomFile != null && pomFile.exists() && !FileUtils.delete(pomFile)) { LOGGER.debug("Failed to delete temporary pom file {}", pomFile); pomFile.deleteOnExit(); } @@ -304,15 +309,25 @@ public void analyzeDependency(Dependency dependency, Engine engine) throws Analy } } catch (TooManyRequestsException tre) { this.setEnabled(false); - final String message = "Connections to Central search refused. Analysis failed."; + final String message = "Connections to Central search refused. Analysis failed. Disabling Central analyzer - this " + + "could lead to both false positives and false negatives."; LOGGER.error(message, tre); throw new AnalysisException(message, tre); } catch (IllegalArgumentException iae) { LOGGER.info("invalid sha1-hash on {}", dependency.getFileName()); } catch (FileNotFoundException fnfe) { LOGGER.debug("Artifact not found in repository: '{}", dependency.getFileName()); + } catch (ForbiddenException e) { + this.setEnabled(false); + final String message = "Connection to Central search refused. This is most likely not a problem with " + + "Dependency-Check itself and is related to network connectivity. Please check " + + "https://central.sonatype.org/faq/403-error-central/."; + LOGGER.error(message); + throw new AnalysisException(message, e); } catch (IOException ioe) { - final String message = "Could not connect to Central search. Analysis failed."; + this.setEnabled(false); + final String message = "Could not connect to Central search. Analysis failed; disabling Central analyzer - this " + + "could lead to both false positives and false negatives."; LOGGER.error(message, ioe); throw new AnalysisException(message, ioe); } @@ -332,7 +347,8 @@ public void analyzeDependency(Dependency dependency, Engine engine) throws Analy * @throws TooManyRequestsException if Central has received too many * requests. */ - protected List fetchMavenArtifacts(Dependency dependency) throws IOException, TooManyRequestsException { + protected List fetchMavenArtifacts(Dependency dependency) throws IOException, + TooManyRequestsException { IOException lastException = null; long sleepingTimeBetweenRetriesInMillis = BASE_RETRY_WAIT; int triesLeft = numberOfRetries; diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/CocoaPodsAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/CocoaPodsAnalyzer.java index 21be018850b..4b347bd3061 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/CocoaPodsAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/CocoaPodsAnalyzer.java @@ -20,15 +20,6 @@ import com.github.packageurl.MalformedPackageURLException; import com.github.packageurl.PackageURL; import com.github.packageurl.PackageURLBuilder; -import java.io.File; -import java.io.FileFilter; -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.annotation.concurrent.ThreadSafe; - -import org.apache.commons.io.FileUtils; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.data.nvd.ecosystem.Ecosystem; @@ -37,12 +28,21 @@ import org.owasp.dependencycheck.dependency.EvidenceType; import org.owasp.dependencycheck.dependency.naming.GenericIdentifier; import org.owasp.dependencycheck.dependency.naming.PurlIdentifier; +import org.owasp.dependencycheck.utils.Checksum; import org.owasp.dependencycheck.utils.FileFilterBuilder; import org.owasp.dependencycheck.utils.Settings; -import org.owasp.dependencycheck.utils.Checksum; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.concurrent.ThreadSafe; +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * This analyzer is used to analyze SWIFT and Objective-C packages by collecting * information from .podspec files. CocoaPods dependency manager see @@ -170,7 +170,7 @@ private void analyzePodfileLockDependencies(Dependency podfileLock, Engine engin final String contents; try { - contents = FileUtils.readFileToString(podfileLock.getActualFile(), Charset.defaultCharset()); + contents = new String(Files.readAllBytes(podfileLock.getActualFile().toPath()), StandardCharsets.UTF_8); } catch (IOException e) { throw new AnalysisException( "Problem occurred while reading dependency file.", e); @@ -229,7 +229,7 @@ private void analyzePodspecDependency(Dependency dependency) dependency.setEcosystem(DEPENDENCY_ECOSYSTEM); String contents; try { - contents = FileUtils.readFileToString(dependency.getActualFile(), Charset.defaultCharset()); + contents = new String(Files.readAllBytes(dependency.getActualFile().toPath()), StandardCharsets.UTF_8); } catch (IOException e) { throw new AnalysisException( "Problem occurred while reading dependency file.", e); @@ -260,6 +260,7 @@ private void analyzePodspecDependency(Dependency dependency) final String summary = determineEvidence(contents, blockVariable, "summary"); if (!summary.isEmpty()) { dependency.addEvidence(EvidenceType.PRODUCT, PODSPEC, "summary", summary, Confidence.HIGHEST); + dependency.addEvidence(EvidenceType.VENDOR, PODSPEC, "summary", summary, Confidence.MEDIUM); } final String author = determineEvidence(contents, blockVariable, "authors?"); @@ -269,6 +270,7 @@ private void analyzePodspecDependency(Dependency dependency) final String homepage = determineEvidence(contents, blockVariable, "homepage"); if (!homepage.isEmpty()) { dependency.addEvidence(EvidenceType.VENDOR, PODSPEC, "homepage", homepage, Confidence.HIGHEST); + dependency.addEvidence(EvidenceType.PRODUCT, PODSPEC, "homepage", homepage, Confidence.LOW); } final String license = determineEvidence(contents, blockVariable, "licen[cs]es?"); if (!license.isEmpty()) { diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/ComposerLockAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/ComposerLockAnalyzer.java index 99f2c200dbf..43be4322194 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/ComposerLockAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/ComposerLockAnalyzer.java @@ -108,7 +108,8 @@ protected void prepareFileTypeAnalyzer(Engine engine) throws InitializationExcep protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException { engine.removeDependency(dependency); try (FileInputStream fis = new FileInputStream(dependency.getActualFile())) { - final ComposerLockParser clp = new ComposerLockParser(fis); + final boolean skipdev = getSettings().getBoolean(Settings.KEYS.ANALYZER_COMPOSER_LOCK_SKIP_DEV, false); + final ComposerLockParser clp = new ComposerLockParser(fis, skipdev); LOGGER.debug("Checking composer.lock file {}", dependency.getActualFilePath()); clp.process(); clp.getDependencies().stream().map((dep) -> { @@ -132,7 +133,9 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An d.setSha256sum(Checksum.getSHA256Checksum(filePath)); d.setMd5sum(Checksum.getMD5Checksum(filePath)); d.addEvidence(EvidenceType.VENDOR, COMPOSER_LOCK, "vendor", dep.getGroup(), Confidence.HIGHEST); + d.addEvidence(EvidenceType.PRODUCT, COMPOSER_LOCK, "vendor", dep.getGroup(), Confidence.MEDIUM); d.addEvidence(EvidenceType.PRODUCT, COMPOSER_LOCK, "product", dep.getProject(), Confidence.HIGHEST); + d.addEvidence(EvidenceType.VENDOR, COMPOSER_LOCK, "product", dep.getProject(), Confidence.HIGH); d.addEvidence(EvidenceType.VERSION, COMPOSER_LOCK, "version", dep.getVersion(), Confidence.HIGHEST); return d; }).forEach((d) -> { diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/DependencyMergingAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/DependencyMergingAnalyzer.java index 07c596275d0..432330fa88e 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/DependencyMergingAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/DependencyMergingAnalyzer.java @@ -47,7 +47,7 @@ public class DependencyMergingAnalyzer extends AbstractDependencyComparingAnalyz /** * The phase that this analyzer is intended to run in. */ - private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.POST_INFORMATION_COLLECTION; + private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.POST_INFORMATION_COLLECTION1; /** * Used for synchronization when merging related dependencies. */ diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/GolangModAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/GolangModAnalyzer.java index b23a63932a3..b87d408cfee 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/GolangModAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/GolangModAnalyzer.java @@ -32,7 +32,7 @@ import java.util.ArrayList; import java.util.List; -import javax.json.stream.JsonParsingException; +import jakarta.json.stream.JsonParsingException; import org.apache.commons.lang3.StringUtils; import org.owasp.dependencycheck.data.nvd.ecosystem.Ecosystem; import org.owasp.dependencycheck.processing.GoModProcessor; diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/HintAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/HintAnalyzer.java index 37787063628..2a4cd757dc5 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/HintAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/HintAnalyzer.java @@ -17,22 +17,12 @@ */ package org.owasp.dependencycheck.analyzer; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.List; -import java.util.Set; -import java.util.regex.Pattern; -import javax.annotation.concurrent.ThreadSafe; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Evidence; import org.owasp.dependencycheck.dependency.EvidenceType; import org.owasp.dependencycheck.exception.InitializationException; -import org.owasp.dependencycheck.xml.suppression.PropertyType; import org.owasp.dependencycheck.utils.DownloadFailedException; import org.owasp.dependencycheck.utils.Downloader; import org.owasp.dependencycheck.utils.FileUtils; @@ -40,14 +30,26 @@ import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.TooManyRequestsException; import org.owasp.dependencycheck.xml.hints.EvidenceMatcher; -import org.owasp.dependencycheck.xml.hints.VendorDuplicatingHintRule; import org.owasp.dependencycheck.xml.hints.HintParseException; import org.owasp.dependencycheck.xml.hints.HintParser; import org.owasp.dependencycheck.xml.hints.HintRule; +import org.owasp.dependencycheck.xml.hints.VendorDuplicatingHintRule; +import org.owasp.dependencycheck.xml.suppression.PropertyType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xml.sax.SAXException; +import javax.annotation.concurrent.ThreadSafe; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.file.Files; +import java.util.List; +import java.util.Set; +import java.util.regex.Pattern; + /** * This analyzer adds evidence to dependencies to enhance the accuracy of * library identification. @@ -80,7 +82,7 @@ public class HintAnalyzer extends AbstractAnalyzer { /** * The phase that this analyzer is intended to run in. */ - private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.PRE_IDENTIFIER_ANALYSIS; + private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.POST_INFORMATION_COLLECTION2; /** * Returns the name of the analyzer. @@ -198,7 +200,7 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An for (VendorDuplicatingHintRule dhr : vendorHints) { if (dhr.getValue().equalsIgnoreCase(e.getValue())) { dependency.addEvidence(EvidenceType.VENDOR, new Evidence(e.getSource() + " (hint)", - e.getName(), dhr.getDuplicate(), e.getConfidence())); + e.getName(), dhr.getDuplicate(), e.getConfidence(), true)); } } } @@ -265,13 +267,12 @@ private void loadHintRules() throws HintParseException { deleteTempFile = true; file = getSettings().getTempFile("hint", "xml"); final URL url = new URL(filePath); - final Downloader downloader = new Downloader(getSettings()); try { - downloader.fetchFile(url, file, false); + Downloader.getInstance().fetchFile(url, file, false); } catch (DownloadFailedException ex) { try { Thread.sleep(500); - downloader.fetchFile(url, file, true); + Downloader.getInstance().fetchFile(url, file, true); } catch (TooManyRequestsException ex1) { throw new HintParseException("Unable to download hint file `" + file + "`; received 429 - too many requests", ex1); } catch (ResourceNotFoundException ex1) { @@ -291,7 +292,7 @@ private void loadHintRules() throws HintParseException { try (InputStream fromClasspath = FileUtils.getResourceAsStream(filePath)) { deleteTempFile = true; file = getSettings().getTempFile("hint", "xml"); - org.apache.commons.io.FileUtils.copyInputStreamToFile(fromClasspath, file); + Files.copy(fromClasspath, file.toPath()); } catch (IOException ex) { throw new HintParseException("Unable to locate hints file in classpath", ex); } diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/JarAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/JarAnalyzer.java index 60e4185f905..8288148c119 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/JarAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/JarAnalyzer.java @@ -54,7 +54,7 @@ import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringUtils; -import org.h2.util.IOUtils; +import org.apache.commons.io.IOUtils; import org.jsoup.Jsoup; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; @@ -160,7 +160,8 @@ public class JarAnalyzer extends AbstractFileTypeAnalyzer { "dstamp", "eclipse-sourcereferences", "kotlin-version", - "require-capability"); + "require-capability", + "require-bundle"); /** * Deprecated Jar manifest attribute, that is, nonetheless, useful for * analysis. diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/LibmanAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/LibmanAnalyzer.java new file mode 100644 index 00000000000..8013e704239 --- /dev/null +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/LibmanAnalyzer.java @@ -0,0 +1,245 @@ +/* + * This file is part of dependency-check-core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2023 The OWASP Foundation. All Rights Reserved. + */ +package org.owasp.dependencycheck.analyzer; + +import com.github.packageurl.MalformedPackageURLException; +import com.github.packageurl.PackageURL; +import com.github.packageurl.PackageURLBuilder; +import org.owasp.dependencycheck.Engine; +import org.owasp.dependencycheck.analyzer.exception.AnalysisException; +import org.owasp.dependencycheck.data.nvd.ecosystem.Ecosystem; +import org.owasp.dependencycheck.dependency.Confidence; +import org.owasp.dependencycheck.dependency.Dependency; +import org.owasp.dependencycheck.dependency.EvidenceType; +import org.owasp.dependencycheck.dependency.naming.PurlIdentifier; +import org.owasp.dependencycheck.exception.InitializationException; +import org.owasp.dependencycheck.utils.Checksum; +import org.owasp.dependencycheck.utils.FileFilterBuilder; +import org.owasp.dependencycheck.utils.Settings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.concurrent.ThreadSafe; +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonException; +import jakarta.json.JsonObject; +import jakarta.json.JsonReader; +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.nio.file.Files; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Analyzer which parses a libman.json file to gather module information. + * + * @author Arjen Korevaar + */ +@ThreadSafe +public class LibmanAnalyzer extends AbstractFileTypeAnalyzer { + + /** + * A descriptor for the type of dependencies processed or added by this + * analyzer. + */ + private static final String DEPENDENCY_ECOSYSTEM = Ecosystem.NODEJS; + + /** + * The logger. + */ + private static final Logger LOGGER = LoggerFactory.getLogger(LibmanAnalyzer.class); + + /** + * The name of the analyzer. + */ + private static final String ANALYZER_NAME = "Libman Analyzer"; + + /** + * The phase in which the analyzer runs. + */ + private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION; + + /** + * The file filter used to determine which files this analyzer supports. + */ + private static final String FILE_NAME = "libman.json"; + + /** + * The file filter used to determine which files this analyzer supports. + */ + private static final FileFilter FILTER = FileFilterBuilder.newInstance().addFilenames(FILE_NAME).build(); + + /** + * Regex used to match Library property. + */ + private static final Pattern LIBRARY_REGEX = Pattern + .compile("(\\@(?[a-zA-Z]+)\\/)?(?.+)\\@(?.+)", Pattern.CASE_INSENSITIVE); + + /** + * Initializes the analyzer once before any analysis is performed. + * + * @param engine a reference to the dependency-check engine + * @throws InitializationException if there's an error during initialization + */ + @Override + public void prepareFileTypeAnalyzer(Engine engine) throws InitializationException { + // nothing to initialize + } + + /** + * Returns the analyzer's name. + * + * @return the name of the analyzer + */ + @Override + public String getName() { + return ANALYZER_NAME; + } + + /** + * Returns the key used in the properties file to reference the analyzer's + * enabled property. + * + * @return the analyzer's enabled property setting key + */ + @Override + protected String getAnalyzerEnabledSettingKey() { + return Settings.KEYS.ANALYZER_LIBMAN_ENABLED; + } + + /** + * Returns the analysis phase under which the analyzer runs. + * + * @return the phase under which this analyzer runs + */ + @Override + public AnalysisPhase getAnalysisPhase() { + return ANALYSIS_PHASE; + } + + /** + * Returns the FileFilter + * + * @return the FileFilter + */ + @Override + protected FileFilter getFileFilter() { + return FILTER; + } + + /** + * Performs the analysis. + * + * @param dependency the dependency to analyze + * @param engine the engine + * @throws AnalysisException when there's an exception during analysis + */ + @Override + public void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException { + LOGGER.debug("Checking file {}", dependency.getActualFilePath()); + + if (FILE_NAME.equals(dependency.getFileName()) && !dependency.isVirtual()) { + engine.removeDependency(dependency); + } + + final File dependencyFile = dependency.getActualFile(); + + if (!dependencyFile.isFile() || dependencyFile.length() == 0) { + return; + } + + try (JsonReader jsonReader = Json.createReader(Files.newInputStream(dependencyFile.toPath()))) { + final JsonObject json = jsonReader.readObject(); + + final String libmanVersion = json.getString("version"); + + if (!"1.0".equals(libmanVersion)) { + LOGGER.warn("The Libman analyzer currently only supports Libman version 1.0"); + return; + } + + final String defaultProvider = json.getString("defaultProvider"); + final JsonArray libraries = json.getJsonArray("libraries"); + + libraries.forEach(e -> { + final JsonObject reference = (JsonObject) e; + + final String provider = reference.getString("provider", defaultProvider); + final String library = reference.getString("library"); + + if ("filesystem".equals(provider)) { + LOGGER.warn("Unable to determine name and version for filesystem package: {}", library); + return; + } + + final Matcher matcher = LIBRARY_REGEX.matcher(library); + + if (!matcher.find()) { + LOGGER.warn("Unable to parse library, unknown format: {}", library); + return; + } + + final String vendor = matcher.group("package"); + final String name = matcher.group("name"); + final String version = matcher.group("version"); + + LOGGER.debug("Found Libman package: vendor {}, name {}, version {}", vendor, name, version); + + final Dependency child = new Dependency(dependency.getActualFile(), true); + + child.setEcosystem(DEPENDENCY_ECOSYSTEM); + child.setName(name); + child.setVersion(version); + + if (vendor != null) { + child.addEvidence(EvidenceType.VENDOR, FILE_NAME, "vendor", vendor, Confidence.HIGHEST); + } + child.addEvidence(EvidenceType.VENDOR, FILE_NAME, "name", name, Confidence.HIGH); + child.addEvidence(EvidenceType.PRODUCT, FILE_NAME, "name", name, Confidence.HIGHEST); + child.addEvidence(EvidenceType.VERSION, FILE_NAME, "version", version, Confidence.HIGHEST); + + final String packagePath = String.format("%s:%s", name, version); + + child.setSha1sum(Checksum.getSHA1Checksum(packagePath)); + child.setSha256sum(Checksum.getSHA256Checksum(packagePath)); + child.setMd5sum(Checksum.getMD5Checksum(packagePath)); + child.setPackagePath(packagePath); + + try { + final PackageURL purl = PackageURLBuilder.aPackageURL() + .withType("libman") + .withName(name) + .withVersion(version) + .build(); + final PurlIdentifier id = new PurlIdentifier(purl, Confidence.HIGHEST); + child.addSoftwareIdentifier(id); + } catch (MalformedPackageURLException ex) { + LOGGER.warn("Unable to build package url for {}", ex.toString()); + } + + engine.addDependency(child); + }); + } catch (JsonException e) { + LOGGER.warn(String.format("Failed to parse %s file", FILE_NAME), e); + } catch (IOException e) { + throw new AnalysisException("Problem occurred while reading dependency file", e); + } + } +} diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/MSBuildProjectAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/MSBuildProjectAnalyzer.java index c7a69aef755..f68718e4947 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/MSBuildProjectAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/MSBuildProjectAnalyzer.java @@ -150,7 +150,7 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An final List packages; try (FileInputStream fis = new FileInputStream(dependency.getActualFilePath()); - BOMInputStream bis = new BOMInputStream(fis)) { + BOMInputStream bis = BOMInputStream.builder().setInputStream(fis).get()) { //skip BOM if it exists bis.getBOM(); packages = parser.parse(bis, props, centrallyManaged); @@ -185,6 +185,7 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An child.setMd5sum(Checksum.getMD5Checksum(String.format("%s:%s", id, version))); child.addEvidence(EvidenceType.PRODUCT, "msbuild", "id", id, Confidence.HIGHEST); + child.addEvidence(EvidenceType.VENDOR, "msbuild", "id", id, Confidence.MEDIUM); child.addEvidence(EvidenceType.VERSION, "msbuild", "version", version, Confidence.HIGHEST); if (id.indexOf('.') > 0) { @@ -193,10 +194,12 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An // example: Microsoft.EntityFrameworkCore child.addEvidence(EvidenceType.VENDOR, "msbuild", "id", parts[0], Confidence.MEDIUM); child.addEvidence(EvidenceType.PRODUCT, "msbuild", "id", parts[1], Confidence.MEDIUM); + child.addEvidence(EvidenceType.VENDOR, "msbuild", "id", parts[1], Confidence.LOW); if (parts.length > 2) { final String rest = id.substring(id.indexOf('.') + 1); child.addEvidence(EvidenceType.PRODUCT, "msbuild", "id", rest, Confidence.MEDIUM); + child.addEvidence(EvidenceType.VENDOR, "msbuild", "id", rest, Confidence.LOW); } } else { // example: jQuery @@ -315,7 +318,7 @@ private Map readDirectoryBuildProps(File directoryProps) throws if (directoryProps != null && directoryProps.isFile()) { final DirectoryBuildPropsParser parser = new DirectoryBuildPropsParser(); try (FileInputStream fis = new FileInputStream(directoryProps); - BOMInputStream bis = new BOMInputStream(fis)) { + BOMInputStream bis = BOMInputStream.builder().setInputStream(fis).get()) { //skip BOM if it exists bis.getBOM(); entries = parser.parse(bis); @@ -344,7 +347,7 @@ private Map loadCentrallyManaged(File folder, Properties props) if (packages != null && packages.isFile()) { final DirectoryPackagesPropsParser parser = new DirectoryPackagesPropsParser(); try (FileInputStream fis = new FileInputStream(packages); - BOMInputStream bis = new BOMInputStream(fis)) { + BOMInputStream bis = BOMInputStream.builder().setInputStream(fis).get()) { //skip BOM if it exists bis.getBOM(); return parser.parse(bis, props); diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/NexusAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/NexusAnalyzer.java index b5828678402..2b1014a113d 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/NexusAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/NexusAnalyzer.java @@ -17,14 +17,17 @@ */ package org.owasp.dependencycheck.analyzer; -import org.apache.commons.io.FileUtils; + import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.data.nexus.MavenArtifact; import org.owasp.dependencycheck.data.nexus.NexusSearch; +import org.owasp.dependencycheck.data.nexus.NexusV2Search; +import org.owasp.dependencycheck.data.nexus.NexusV3Search; import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Evidence; +import org.owasp.dependencycheck.utils.FileUtils; import org.owasp.dependencycheck.xml.pom.PomUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,6 +38,7 @@ import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import java.util.Locale; import javax.annotation.concurrent.ThreadSafe; import org.owasp.dependencycheck.dependency.EvidenceType; import org.owasp.dependencycheck.exception.InitializationException; @@ -169,17 +173,38 @@ public void prepareFileTypeAnalyzer(Engine engine) throws InitializationExceptio if (isEnabled()) { final boolean useProxy = useProxy(); LOGGER.debug("Using proxy: {}", useProxy); - try { - searcher = new NexusSearch(getSettings(), useProxy); - if (!searcher.preflightRequest()) { - setEnabled(false); - throw new InitializationException("There was an issue getting Nexus status. Disabling analyzer."); - } - } catch (MalformedURLException mue) { + searcher = createNexusSearchOrDisable(useProxy); + } + } + + /** + * Creates a NexusSearch for the appropriate Nexus version (Nexus V2 and V3 supported). + *

+ * If errors are encountered creating or validating the NexusSearch it disables this analyzer. + * + * @param useProxy Whether a proxy is to be used + * @return A NexusSearch appropriate for the configured ANALYZER_NEXUS_URL + * @throws InitializationException Upon errors creating of validating the ANALYZER_NEXUS_URL + */ + private NexusSearch createNexusSearchOrDisable(boolean useProxy) throws InitializationException { + final Settings settings = getSettings(); + final String nexusRootURL = settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL); + final NexusSearch result; + try { + if (nexusRootURL.toLowerCase(Locale.ROOT).contains("service/local/")) { + result = new NexusV2Search(settings, useProxy); + } else { + result = new NexusV3Search(settings, useProxy); + } + if (!result.preflightRequest()) { setEnabled(false); - throw new InitializationException("Malformed URL to Nexus", mue); + throw new InitializationException("There was an error getting Nexus status. Disabling NexusAnalyzer."); } + } catch (MalformedURLException mue) { + setEnabled(false); + throw new InitializationException("Malformed URL to Nexus. Disabling NexusAnalyzer", mue); } + return result; } /** @@ -257,8 +282,7 @@ public void analyzeDependency(Dependency dependency, Engine engine) throws Analy LOGGER.debug("Unable to delete temp file"); } LOGGER.debug("Downloading {}", ma.getPomUrl()); - final Downloader downloader = new Downloader(getSettings()); - downloader.fetchFile(new URL(ma.getPomUrl()), pomFile); + Downloader.getInstance().fetchFile(new URL(ma.getPomUrl()), pomFile); PomUtils.analyzePOM(dependency, pomFile); } catch (DownloadFailedException ex) { LOGGER.warn("Unable to download pom.xml for {} from Nexus repository; " @@ -271,7 +295,7 @@ public void analyzeDependency(Dependency dependency, Engine engine) throws Analy LOGGER.warn("pom.xml not found for {} from nexus; " + "this could result in undetected CPE/CVEs.", dependency.getFileName()); } finally { - if (pomFile != null && pomFile.exists() && !FileUtils.deleteQuietly(pomFile)) { + if (pomFile != null && pomFile.exists() && !FileUtils.delete(pomFile)) { LOGGER.debug("Failed to delete temporary pom file {}", pomFile); pomFile.deleteOnExit(); } @@ -297,8 +321,7 @@ public void analyzeDependency(Dependency dependency, Engine engine) throws Analy */ public boolean useProxy() { try { - return getSettings().getString(Settings.KEYS.PROXY_SERVER) != null - && getSettings().getBoolean(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY); + return getSettings().getBoolean(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY); } catch (InvalidSettingException ise) { LOGGER.warn("Failed to parse proxy settings.", ise); return false; diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/NodeAuditAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/NodeAuditAnalyzer.java index b186f0eadf1..c6de926ed56 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/NodeAuditAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/NodeAuditAnalyzer.java @@ -17,34 +17,34 @@ */ package org.owasp.dependencycheck.analyzer; -import org.apache.commons.io.FileUtils; +import org.apache.commons.collections4.MultiValuedMap; +import org.apache.commons.collections4.multimap.HashSetValuedHashMap; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; +import org.owasp.dependencycheck.analyzer.exception.SearchException; +import org.owasp.dependencycheck.analyzer.exception.UnexpectedAnalysisException; import org.owasp.dependencycheck.data.nodeaudit.Advisory; import org.owasp.dependencycheck.data.nodeaudit.NpmPayloadBuilder; +import org.owasp.dependencycheck.data.nvd.ecosystem.Ecosystem; import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.utils.FileFilterBuilder; import org.owasp.dependencycheck.utils.Settings; +import org.owasp.dependencycheck.utils.URLConnectionFailureException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import us.springett.parsers.cpe.exceptions.CpeValidationException; + +import javax.annotation.concurrent.ThreadSafe; +import jakarta.json.Json; +import jakarta.json.JsonException; +import jakarta.json.JsonObject; +import jakarta.json.JsonReader; import java.io.File; import java.io.FileFilter; import java.io.IOException; +import java.nio.file.Files; import java.util.List; -import javax.annotation.concurrent.ThreadSafe; -import javax.json.Json; -import javax.json.JsonException; -import javax.json.JsonObject; -import javax.json.JsonReader; -import org.apache.commons.collections4.MultiValuedMap; -import org.apache.commons.collections4.multimap.HashSetValuedHashMap; -import org.owasp.dependencycheck.analyzer.exception.SearchException; -import org.owasp.dependencycheck.analyzer.exception.UnexpectedAnalysisException; -import org.owasp.dependencycheck.data.nvd.ecosystem.Ecosystem; -import org.owasp.dependencycheck.utils.URLConnectionFailureException; -import us.springett.parsers.cpe.exceptions.CpeValidationException; - /** * Used to analyze Node Package Manager (npm) package-lock.json and * npm-shrinkwrap.json files via NPM Audit API. @@ -171,11 +171,11 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An * submitting the npm audit API payload */ private List analyzePackage(final File lockFile, final File packageFile, - Dependency dependency, MultiValuedMap dependencyMap) + Dependency dependency, MultiValuedMap dependencyMap) throws AnalysisException { try { - final JsonReader packageReader = Json.createReader(FileUtils.openInputStream(packageFile)); - final JsonReader lockReader = Json.createReader(FileUtils.openInputStream(lockFile)); + final JsonReader packageReader = Json.createReader(Files.newInputStream(packageFile.toPath())); + final JsonReader lockReader = Json.createReader(Files.newInputStream(lockFile.toPath())); // Retrieves the contents of package-lock.json from the Dependency final JsonObject lockJson = lockReader.readObject(); // Retrieves the contents of package-lock.json from the Dependency @@ -231,7 +231,7 @@ private List analyzePackage(final File lockFile, final File packageFil private List legacyAnalysis(final File file, Dependency dependency, MultiValuedMap dependencyMap) throws AnalysisException { - try (JsonReader jsonReader = Json.createReader(FileUtils.openInputStream(file))) { + try (JsonReader jsonReader = Json.createReader(Files.newInputStream(file.toPath()))) { // Retrieves the contents of package-lock.json from the Dependency final JsonObject packageJson = jsonReader.readObject(); diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/NodePackageAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/NodePackageAnalyzer.java index 68e2eca3016..650bcf9ce8c 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/NodePackageAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/NodePackageAnalyzer.java @@ -20,39 +20,39 @@ import com.github.packageurl.MalformedPackageURLException; import com.github.packageurl.PackageURL; import com.github.packageurl.PackageURLBuilder; -import org.apache.commons.io.FileUtils; import org.owasp.dependencycheck.Engine; +import org.owasp.dependencycheck.Engine.Mode; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; +import org.owasp.dependencycheck.data.nvd.ecosystem.Ecosystem; +import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Dependency; +import org.owasp.dependencycheck.dependency.EvidenceType; +import org.owasp.dependencycheck.dependency.naming.PurlIdentifier; +import org.owasp.dependencycheck.exception.InitializationException; +import org.owasp.dependencycheck.utils.Checksum; import org.owasp.dependencycheck.utils.FileFilterBuilder; +import org.owasp.dependencycheck.utils.InvalidSettingException; import org.owasp.dependencycheck.utils.Settings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.concurrent.ThreadSafe; +import jakarta.json.Json; +import jakarta.json.JsonException; +import jakarta.json.JsonObject; +import jakarta.json.JsonReader; +import jakarta.json.JsonString; +import jakarta.json.JsonValue; import java.io.File; import java.io.FileFilter; import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Paths; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Objects; -import javax.annotation.concurrent.ThreadSafe; -import javax.json.Json; -import javax.json.JsonException; -import javax.json.JsonObject; -import javax.json.JsonString; -import javax.json.JsonReader; -import javax.json.JsonValue; -import org.owasp.dependencycheck.Engine.Mode; -import org.owasp.dependencycheck.data.nvd.ecosystem.Ecosystem; -import org.owasp.dependencycheck.dependency.Confidence; -import org.owasp.dependencycheck.dependency.EvidenceType; -import org.owasp.dependencycheck.dependency.naming.PurlIdentifier; -import org.owasp.dependencycheck.exception.InitializationException; -import org.owasp.dependencycheck.utils.Checksum; -import org.owasp.dependencycheck.utils.InvalidSettingException; /** * Used to analyze Node Package Manager (npm) package.json files, and collect @@ -93,7 +93,7 @@ public class NodePackageAnalyzer extends AbstractNpmAnalyzer { */ public static final String SHRINKWRAP_JSON = "npm-shrinkwrap.json"; /** - * The name of the directory that contains node modules + * The name of the directory that contains node modules. */ public static final String NODE_MODULES_DIRNAME = "node_modules"; /** @@ -196,7 +196,8 @@ private boolean isNodeAuditEnabled(Engine engine) { try { ((AbstractNpmAnalyzer) a).prepareFileTypeAnalyzer(engine); } catch (InitializationException ex) { - LOGGER.debug("Error initializing the {}", a.getName()); + String message = "Error initializing the " + a.getName(); + LOGGER.debug(message, ex); } } return a.isEnabled(); @@ -252,7 +253,7 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An return; } - try (JsonReader jsonReader = Json.createReader(FileUtils.openInputStream(dependencyFile))) { + try (JsonReader jsonReader = Json.createReader(Files.newInputStream(dependencyFile.toPath()))) { final JsonObject json = jsonReader.readObject(); final String parentName = json.getString("name", ""); final String parentVersion = json.getString("version", ""); @@ -303,7 +304,7 @@ public static boolean shouldSkipDependency(String name, String version, boolean // using a local node_module is not supported by npm audit, it crash if (Objects.nonNull(version) && (version.startsWith("file:") || version.matches("^[.~]{0,2}/.*"))) { LOGGER.warn("dependency skipped: package.json contain an local node_module for {} seems to be " - + "located {} npm audit doesn't support locally referenced modules", + + "located {} npm audit doesn't support locally referenced modules", name, version); return true; } @@ -320,12 +321,12 @@ public static boolean shouldSkipDependency(String name, String version, boolean /** * Checks if the given dependency should be skipped. * - * @see NodePackageAnalyzer#shouldSkipDependency(java.lang.String, - * java.lang.String, boolean, boolean) * @param name the name of the dependency to test * @param version the version of the dependency to test * @return true if the dependency should be skipped; otherwise * false + * @see NodePackageAnalyzer#shouldSkipDependency(java.lang.String, + * java.lang.String, boolean, boolean) */ public static boolean shouldSkipDependency(String name, String version) { return shouldSkipDependency(name, version, false, true); @@ -344,20 +345,20 @@ public static boolean shouldSkipDependency(String name, String version) { * @throws AnalysisException thrown if there is an exception */ private void processDependencies(JsonObject json, File baseDir, File rootFile, - String parentPackage, Engine engine) throws AnalysisException { - final boolean skipDev = getSettings().getBoolean(Settings.KEYS.ANALYZER_NODE_PACKAGE_SKIPDEV, false); - final JsonObject deps; - final File modulesRoot = new File(rootFile.getParentFile(), "node_modules"); - final int lockJsonVersion = json.containsKey("lockfileVersion") ? json.getInt("lockfileVersion") : 1; - if (lockJsonVersion >= 2) { + String parentPackage, Engine engine) throws AnalysisException { + final boolean skipDev = getSettings().getBoolean(Settings.KEYS.ANALYZER_NODE_PACKAGE_SKIPDEV, false); + final JsonObject deps; + final File modulesRoot = new File(rootFile.getParentFile(), "node_modules"); + final int lockJsonVersion = json.containsKey("lockfileVersion") ? json.getInt("lockfileVersion") : 1; + if (lockJsonVersion >= 2) { deps = json.getJsonObject("packages"); - } else if (json.containsKey("dependencies")) { + } else if (json.containsKey("dependencies")) { deps = json.getJsonObject("dependencies"); - } else { + } else { deps = null; - } + } - if (deps != null) { + if (deps != null) { for (Map.Entry entry : deps.entrySet()) { final String pathName = entry.getKey(); String name = pathName; @@ -428,7 +429,7 @@ private void processDependencies(JsonObject json, File baseDir, File rootFile, } catch (IOException | NoSuchAlgorithmException ex) { LOGGER.debug("Error setting hashes:" + ex.getMessage(), ex); } - try (JsonReader jr = Json.createReader(FileUtils.openInputStream(f))) { + try (JsonReader jr = Json.createReader(Files.newInputStream(f.toPath()))) { final JsonObject childJson = jr.readObject(); gatherEvidence(childJson, child); } catch (JsonException e) { @@ -458,18 +459,19 @@ private void processDependencies(JsonObject json, File baseDir, File rootFile, LOGGER.debug("Unable to build package url for `" + packagePath + "`", ex); } } - - final Dependency existing = findDependency(engine, name, version); - if (existing != null) { - if (existing.isVirtual()) { - DependencyMergingAnalyzer.mergeDependencies(child, existing, null); - engine.removeDependency(existing); - engine.addDependency(child); + synchronized (this) { + final Dependency existing = findDependency(engine, name, version); + if (existing != null) { + if (existing.isVirtual()) { + DependencyMergingAnalyzer.mergeDependencies(child, existing, null); + engine.removeDependency(existing); + engine.addDependency(child); + } else { + DependencyBundlingAnalyzer.mergeDependencies(existing, child, null); + } } else { - DependencyBundlingAnalyzer.mergeDependencies(existing, child, null); + engine.addDependency(child); } - } else { - engine.addDependency(child); } } } diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/NpmCPEAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/NpmCPEAnalyzer.java index 0acce56f45c..530a5d669ad 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/NpmCPEAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/NpmCPEAnalyzer.java @@ -49,7 +49,7 @@ public class NpmCPEAnalyzer extends CPEAnalyzer { /** * The Logger. */ - private static final Logger LOGGER = LoggerFactory.getLogger(CPEAnalyzer.class); + private static final Logger LOGGER = LoggerFactory.getLogger(NpmCPEAnalyzer.class); /** * Returns the analysis phase that this analyzer should run in. diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/NugetconfAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/NugetconfAnalyzer.java index 3e98913ef2e..11417208d6e 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/NugetconfAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/NugetconfAnalyzer.java @@ -182,6 +182,7 @@ public void analyzeDependency(Dependency dependency, Engine engine) throws Analy child.setMd5sum(Checksum.getMD5Checksum(String.format("%s:%s", id, version))); child.addEvidence(EvidenceType.VERSION, "packages.config", "version", np.getVersion(), Confidence.HIGHEST); child.addEvidence(EvidenceType.PRODUCT, "packages.config", "id", np.getId(), Confidence.HIGHEST); + child.addEvidence(EvidenceType.VENDOR, "packages.config", "id", np.getId(), Confidence.MEDIUM); // handle package names the same way as the MSBuild analyzer if (id.indexOf('.') > 0) { @@ -190,10 +191,12 @@ public void analyzeDependency(Dependency dependency, Engine engine) throws Analy // example: Microsoft.EntityFrameworkCore child.addEvidence(EvidenceType.VENDOR, "packages.config", "id", parts[0], Confidence.MEDIUM); child.addEvidence(EvidenceType.PRODUCT, "packages.config", "id", parts[1], Confidence.MEDIUM); + child.addEvidence(EvidenceType.VENDOR, "packages.config", "id", parts[1], Confidence.LOW); if (parts.length > 2) { final String rest = id.substring(id.indexOf('.') + 1); child.addEvidence(EvidenceType.PRODUCT, "packages.config", "id", rest, Confidence.MEDIUM); + child.addEvidence(EvidenceType.VENDOR, "packages.config", "id", rest, Confidence.LOW); } } else { // example: jQuery diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzer.java index 5f3124dc0c4..44aeb555023 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/NuspecAnalyzer.java @@ -158,6 +158,7 @@ public void analyzeDependency(Dependency dependency, Engine engine) throws Analy dependency.addEvidence(EvidenceType.VENDOR, "nuspec", "authors", np.getAuthors(), Confidence.HIGH); dependency.addEvidence(EvidenceType.VERSION, "nuspec", "version", np.getVersion(), Confidence.HIGHEST); dependency.addEvidence(EvidenceType.PRODUCT, "nuspec", "id", np.getId(), Confidence.HIGHEST); + dependency.addEvidence(EvidenceType.VENDOR, "nuspec", "id", np.getId(), Confidence.HIGH); dependency.addEvidence(EvidenceType.VENDOR, "nuspec", "description", np.getDescription(), Confidence.LOW); dependency.addEvidence(EvidenceType.PRODUCT, "nuspec", "description", np.getDescription(), Confidence.LOW); dependency.setName(np.getId()); @@ -178,6 +179,7 @@ public void analyzeDependency(Dependency dependency, Engine engine) throws Analy } if (np.getTitle() != null) { dependency.addEvidence(EvidenceType.PRODUCT, "nuspec", "title", np.getTitle(), Confidence.MEDIUM); + dependency.addEvidence(EvidenceType.VENDOR, "nuspec", "title", np.getTitle(), Confidence.LOW); } } catch (Throwable e) { throw new AnalysisException(e); diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/NvdCveAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/NvdCveAnalyzer.java index 1ba5986dd07..bcb5ff6d816 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/NvdCveAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/NvdCveAnalyzer.java @@ -18,7 +18,9 @@ package org.owasp.dependencycheck.analyzer; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import javax.annotation.concurrent.ThreadSafe; import org.owasp.dependencycheck.Engine; @@ -150,17 +152,17 @@ private synchronized List filterEcosystem(String ecosystem, List< final List remove = new ArrayList<>(); vulnerabilities.forEach((v) -> { boolean found = false; - final List removeSoftare = new ArrayList<>(); + final Set removeSoftware = new HashSet<>(); for (VulnerableSoftware s : v.getVulnerableSoftware()) { if (ecosystemMatchesTargetSoftware(ecosystem, s.getTargetSw())) { found = true; } else { - removeSoftare.add(s); + removeSoftware.add(s); } } if (found) { - if (!removeSoftare.isEmpty()) { - removeSoftare.forEach(v.getVulnerableSoftware()::remove); + if (!removeSoftware.isEmpty()) { + v.removeVulnerableSoftware(removeSoftware); } } else { remove.add(v); diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/OpenSSLAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/OpenSSLAnalyzer.java index b1ed360abe6..33f7ce947e0 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/OpenSSLAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/OpenSSLAnalyzer.java @@ -20,27 +20,27 @@ import com.github.packageurl.MalformedPackageURLException; import com.github.packageurl.PackageURL; import com.github.packageurl.PackageURLBuilder; -import org.apache.commons.io.FileUtils; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Dependency; +import org.owasp.dependencycheck.dependency.EvidenceType; +import org.owasp.dependencycheck.dependency.naming.GenericIdentifier; +import org.owasp.dependencycheck.dependency.naming.PurlIdentifier; +import org.owasp.dependencycheck.exception.InitializationException; import org.owasp.dependencycheck.utils.FileFilterBuilder; import org.owasp.dependencycheck.utils.Settings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import javax.annotation.concurrent.ThreadSafe; import java.io.File; import java.io.FileFilter; import java.io.IOException; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.annotation.concurrent.ThreadSafe; -import org.owasp.dependencycheck.dependency.EvidenceType; -import org.owasp.dependencycheck.dependency.naming.GenericIdentifier; -import org.owasp.dependencycheck.dependency.naming.PurlIdentifier; -import org.owasp.dependencycheck.exception.InitializationException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Used to analyze OpenSSL source code present in the file system. @@ -72,7 +72,7 @@ public class OpenSSLAnalyzer extends AbstractFileTypeAnalyzer { */ private static final Pattern VERSION_PATTERN = Pattern.compile( "define\\s+OPENSSL_VERSION_NUMBER\\s+0x([0-9a-zA-Z]{8})L", Pattern.DOTALL - | Pattern.CASE_INSENSITIVE); + | Pattern.CASE_INSENSITIVE); /** * The offset of the major version number. */ @@ -231,7 +231,7 @@ protected void analyzeDependency(Dependency dependency, Engine engine) private String getFileContents(final File actualFile) throws AnalysisException { try { - return FileUtils.readFileToString(actualFile, Charset.defaultCharset()).trim(); + return new String(Files.readAllBytes(actualFile.toPath()), StandardCharsets.UTF_8).trim(); } catch (IOException e) { throw new AnalysisException( "Problem occurred while reading dependency file.", e); diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/OssIndexAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/OssIndexAnalyzer.java index 344d6996c61..cae89d79467 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/OssIndexAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/OssIndexAnalyzer.java @@ -17,27 +17,29 @@ */ package org.owasp.dependencycheck.analyzer; +import io.github.jeremylong.openvulnerability.client.nvd.CvssV2; +import io.github.jeremylong.openvulnerability.client.nvd.CvssV2Data; +import io.github.jeremylong.openvulnerability.client.nvd.CvssV4; import org.sonatype.ossindex.service.api.componentreport.ComponentReport; import org.sonatype.ossindex.service.api.componentreport.ComponentReportVulnerability; import org.sonatype.ossindex.service.api.cvss.Cvss2Severity; import org.sonatype.ossindex.service.api.cvss.Cvss2Vector; -import org.sonatype.ossindex.service.api.cvss.Cvss3Severity; -import org.sonatype.ossindex.service.api.cvss.Cvss3Vector; import org.sonatype.ossindex.service.api.cvss.CvssVector; import org.sonatype.ossindex.service.api.cvss.CvssVectorFactory; import org.sonatype.ossindex.service.client.OssindexClient; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.data.ossindex.OssindexClientFactory; -import org.owasp.dependencycheck.dependency.CvssV2; -import org.owasp.dependencycheck.dependency.CvssV3; + import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.Vulnerability; import org.owasp.dependencycheck.dependency.VulnerableSoftware; import org.owasp.dependencycheck.dependency.VulnerableSoftwareBuilder; import org.owasp.dependencycheck.dependency.naming.Identifier; import org.owasp.dependencycheck.dependency.naming.PurlIdentifier; +import org.owasp.dependencycheck.exception.InitializationException; import org.owasp.dependencycheck.utils.Settings; +import org.owasp.dependencycheck.utils.Settings.KEYS; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import us.springett.parsers.cpe.exceptions.CpeValidationException; @@ -54,8 +56,11 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.net.SocketTimeoutException; + import javax.annotation.Nullable; import org.apache.commons.lang3.StringUtils; +import org.owasp.dependencycheck.utils.CvssUtil; import org.sonatype.goodies.packageurl.InvalidException; import org.sonatype.ossindex.service.client.transport.Transport.TransportException; @@ -124,6 +129,17 @@ protected void closeAnalyzer() throws Exception { } } + @Override + protected void prepareAnalyzer(Engine engine) throws InitializationException { + synchronized (FETCH_MUTIX) { + if (StringUtils.isEmpty(getSettings().getString(KEYS.ANALYZER_OSSINDEX_USER, StringUtils.EMPTY)) || + StringUtils.isEmpty(getSettings().getString(KEYS.ANALYZER_OSSINDEX_PASSWORD, StringUtils.EMPTY))) { + LOG.warn("Disabling OSS Index analyzer due to missing user/password credentials. Authentication is now required: https://ossindex.sonatype.org/doc/auth-required"); + setEnabled(false); + } + } + } + @Override protected void analyzeDependency(final Dependency dependency, final Engine engine) throws AnalysisException { // batch request component-reports for all dependencies @@ -132,31 +148,45 @@ protected void analyzeDependency(final Dependency dependency, final Engine engin try { requestDelay(); reports = requestReports(engine.getDependencies()); - } catch (TransportException ex) { + } catch (SocketTimeoutException e) { + final boolean warnOnly = getSettings().getBoolean(Settings.KEYS.ANALYZER_OSSINDEX_WARN_ONLY_ON_REMOTE_ERRORS, false); + this.setEnabled(false); + if (warnOnly) { + LOG.warn("OSS Index socket timeout, disabling the analyzer", e); + } else { + LOG.debug("OSS Index socket timeout", e); + throw new AnalysisException("Failed to establish socket to OSS Index", e); + } + } catch (Exception ex) { final String message = ex.getMessage(); final boolean warnOnly = getSettings().getBoolean(Settings.KEYS.ANALYZER_OSSINDEX_WARN_ONLY_ON_REMOTE_ERRORS, false); this.setEnabled(false); - if (StringUtils.endsWith(message, "401")) { - LOG.error("Invalid credentials for the OSS Index, disabling the analyzer"); - throw new AnalysisException("Invalid credentials provided for OSS Index", ex); - } else if (StringUtils.endsWith(message, "403")) { - LOG.error("OSS Index access forbidden, disabling the analyzer"); - throw new AnalysisException("OSS Index access forbidden", ex); - } else if (StringUtils.endsWith(message, "429")) { + if (StringUtils.contains(message, "401")) { + if (warnOnly) { + LOG.warn("Invalid credentials for the OSS Index, disabling the analyzer"); + } else { + LOG.error("Invalid credentials for the OSS Index, disabling the analyzer"); + throw new AnalysisException("Invalid credentials provided for OSS Index", ex); + } + } else if (StringUtils.contains(message, "403")) { + if (warnOnly) { + LOG.warn("OSS Index access forbidden, disabling the analyzer"); + } else { + LOG.error("OSS Index access forbidden, disabling the analyzer"); + throw new AnalysisException("OSS Index access forbidden", ex); + } + } else if (StringUtils.contains(message, "429")) { if (warnOnly) { LOG.warn("OSS Index rate limit exceeded, disabling the analyzer", ex); } else { throw new AnalysisException("OSS Index rate limit exceeded, disabling the analyzer", ex); } } else if (warnOnly) { - LOG.warn("Error requesting component reports, disabling the analyzer", ex); + LOG.warn("Error requesting component reports, disabling the analyzer. " + ex.getMessage(), ex); } else { LOG.debug("Error requesting component reports, disabling the analyzer", ex); - throw new AnalysisException("Failed to request component-reports", ex); + throw new AnalysisException("Failed to request component-reports. " + ex.getMessage(), ex); } - } catch (Exception e) { - LOG.debug("Error requesting component reports", e); - throw new AnalysisException("Failed to request component-reports", e); } } @@ -260,7 +290,7 @@ void enrich(final Dependency dependency) { .orElse(null); if (existing != null) { //TODO - can we enhance anything other than the references? - existing.getReferences().addAll(v.getReferences()); + existing.addReferences(v.getReferences()); } else { dependency.addVulnerability(v); } @@ -307,34 +337,63 @@ private Vulnerability transform(final ComponentReport report, final ComponentRep result.setDescription(source.getDescription()); result.addCwe(source.getCwe()); - final float cvssScore = source.getCvssScore() != null ? source.getCvssScore() : -1; + final double cvssScore = source.getCvssScore() != null ? source.getCvssScore().doubleValue() : -1; if (source.getCvssVector() != null) { - if (source.getCvssVector().startsWith("CVSS:3")) { - result.setCvssV3(new CvssV3(source.getCvssVector(), cvssScore)); + if (source.getCvssVector().startsWith("CVSS:4")) { + result.setCvssV4(CvssUtil.vectorToCvssV4("ossindex", CvssV4.Type.PRIMARY, cvssScore, source.getCvssVector())); + } else if (source.getCvssVector().startsWith("CVSS:3")) { + result.setCvssV3(CvssUtil.vectorToCvssV3(source.getCvssVector(), cvssScore)); } else { // convert cvss details final CvssVector cvssVector = CvssVectorFactory.create(source.getCvssVector()); final Map metrics = cvssVector.getMetrics(); if (cvssVector instanceof Cvss2Vector) { - result.setCvssV2(new CvssV2( - cvssScore, - metrics.get(Cvss2Vector.ACCESS_VECTOR), - metrics.get(Cvss2Vector.ACCESS_COMPLEXITY), - metrics.get(Cvss2Vector.AUTHENTICATION), - metrics.get(Cvss2Vector.CONFIDENTIALITY_IMPACT), - metrics.get(Cvss2Vector.INTEGRITY_IMPACT), - metrics.get(Cvss2Vector.AVAILABILITY_IMPACT), - Cvss2Severity.of(cvssScore).name() - )); + String tmp = metrics.get(Cvss2Vector.ACCESS_VECTOR); + CvssV2Data.AccessVectorType accessVector = null; + if (tmp != null) { + accessVector = CvssV2Data.AccessVectorType.fromValue(tmp); + } + tmp = metrics.get(Cvss2Vector.ACCESS_COMPLEXITY); + CvssV2Data.AccessComplexityType accessComplexity = null; + if (tmp != null) { + accessComplexity = CvssV2Data.AccessComplexityType.fromValue(tmp); + } + tmp = metrics.get(Cvss2Vector.AUTHENTICATION); + CvssV2Data.AuthenticationType authentication = null; + if (tmp != null) { + authentication = CvssV2Data.AuthenticationType.fromValue(tmp); + } + tmp = metrics.get(Cvss2Vector.CONFIDENTIALITY_IMPACT); + CvssV2Data.CiaType confidentialityImpact = null; + if (tmp != null) { + confidentialityImpact = CvssV2Data.CiaType.fromValue(tmp); + } + tmp = metrics.get(Cvss2Vector.INTEGRITY_IMPACT); + CvssV2Data.CiaType integrityImpact = null; + if (tmp != null) { + integrityImpact = CvssV2Data.CiaType.fromValue(tmp); + } + tmp = metrics.get(Cvss2Vector.AVAILABILITY_IMPACT); + CvssV2Data.CiaType availabilityImpact = null; + if (tmp != null) { + availabilityImpact = CvssV2Data.CiaType.fromValue(tmp); + } + final String severity = Cvss2Severity.of((float) cvssScore).name().toUpperCase(); + final CvssV2Data cvssData = new CvssV2Data(CvssV2Data.Version._2_0, source.getCvssVector(), accessVector, + accessComplexity, authentication, confidentialityImpact, + integrityImpact, availabilityImpact, cvssScore, + severity, null, null, null, null, null, null, null, null, null, null); + final CvssV2 cvssV2 = new CvssV2(null, null, cvssData, severity, null, null, null, null, null, null, null); + result.setCvssV2(cvssV2); } else { LOG.warn("Unsupported CVSS vector: {}", cvssVector); - result.setUnscoredSeverity(Float.toString(cvssScore)); + result.setUnscoredSeverity(Double.toString(cvssScore)); } } } else { LOG.debug("OSS has no vector for {}", result.getName()); - result.setUnscoredSeverity(Float.toString(cvssScore)); + result.setUnscoredSeverity(Double.toString(cvssScore)); } // generate a reference to the vulnerability details on OSS Index result.addReference(REFERENCE_TYPE, source.getTitle(), source.getReference().toString()); diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/PEAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/PEAnalyzer.java index d097daa7469..3d8f23c76b3 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/PEAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/PEAnalyzer.java @@ -185,6 +185,7 @@ protected void analyzeDependency(final Dependency dependency, final Engine engin break; case "InternalName": dependency.addEvidence(EvidenceType.PRODUCT, "PE Header", "InternalName", value, Confidence.MEDIUM); + dependency.addEvidence(EvidenceType.VENDOR, "PE Header", "InternalName", value, Confidence.LOW); determineDependencyName(dependency, value); break; case "LegalCopyright": @@ -201,6 +202,7 @@ protected void analyzeDependency(final Dependency dependency, final Engine engin break; case "ProductName": dependency.addEvidence(EvidenceType.PRODUCT, "PE Header", "ProductName", value, Confidence.HIGHEST); + dependency.addEvidence(EvidenceType.VENDOR, "PE Header", "ProductName", value, Confidence.MEDIUM); determineDependencyName(dependency, value); break; default: diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/PerlCpanfileAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/PerlCpanfileAnalyzer.java index c2725fc9b64..954e300fa89 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/PerlCpanfileAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/PerlCpanfileAnalyzer.java @@ -20,36 +20,35 @@ import com.github.packageurl.MalformedPackageURLException; import com.github.packageurl.PackageURL; import com.github.packageurl.PackageURLBuilder; -import org.apache.commons.io.FileUtils; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; +import org.owasp.dependencycheck.data.nvd.ecosystem.Ecosystem; +import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Dependency; +import org.owasp.dependencycheck.dependency.EvidenceType; +import org.owasp.dependencycheck.dependency.naming.GenericIdentifier; +import org.owasp.dependencycheck.dependency.naming.Identifier; +import org.owasp.dependencycheck.dependency.naming.PurlIdentifier; +import org.owasp.dependencycheck.exception.InitializationException; +import org.owasp.dependencycheck.utils.Checksum; import org.owasp.dependencycheck.utils.FileFilterBuilder; import org.owasp.dependencycheck.utils.Settings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.concurrent.ThreadSafe; import java.io.File; import java.io.FileFilter; import java.io.IOException; -import javax.annotation.concurrent.ThreadSafe; -import org.owasp.dependencycheck.data.nvd.ecosystem.Ecosystem; -import org.owasp.dependencycheck.dependency.Confidence; -import org.owasp.dependencycheck.dependency.EvidenceType; -import org.owasp.dependencycheck.dependency.naming.PurlIdentifier; -import org.owasp.dependencycheck.exception.InitializationException; -import org.owasp.dependencycheck.utils.Checksum; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.nio.charset.Charset; - +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import static java.util.stream.Collectors.toCollection; -import org.owasp.dependencycheck.dependency.naming.GenericIdentifier; -import org.owasp.dependencycheck.dependency.naming.Identifier; /** *

@@ -127,7 +126,7 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An private String tryReadFile(File file) throws AnalysisException { try { - return FileUtils.readFileToString(file, Charset.defaultCharset()).trim(); + return new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8).trim(); } catch (IOException e) { throw new AnalysisException("Problem occurred while reading dependency file.", e); } diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/PinnedMavenInstallAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/PinnedMavenInstallAnalyzer.java index 34285b80a08..0be4239329f 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/PinnedMavenInstallAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/PinnedMavenInstallAnalyzer.java @@ -19,11 +19,14 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectReader; import com.github.packageurl.MalformedPackageURLException; import com.github.packageurl.PackageURL; import com.github.packageurl.PackageURLBuilder; +import java.util.Map; +import java.util.stream.Collectors; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.data.nvd.ecosystem.Ecosystem; @@ -118,26 +121,47 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An } final DependencyTree tree; + List deps; try { - final InstallFile installFile = INSTALL_FILE_READER.readValue(dependencyFile); - tree = installFile.getDependencyTree(); - } catch (IOException e) { - return; - } + final JsonNode jsonNode = MAPPER.readTree(dependencyFile); + final JsonNode v2Version = jsonNode.path("version"); + final JsonNode v010Version = jsonNode.path("dependency_tree").path("version"); + + if (v2Version.isTextual()) { + final InstallFileV2 installFile = INSTALL_FILE_V2_READER.readValue(dependencyFile); + if (!Objects.equals(installFile.getAutogeneratedSentinel(), "THERE_IS_NO_DATA_ONLY_ZUUL")) { + return; + } + if (!Objects.equals(installFile.getVersion(), "2")) { + LOGGER.warn("Unsupported pinned maven_install.json version {}. Continuing optimistically.", installFile.getVersion()); + } + deps = installFile.getArtifacts().entrySet().stream().map(entry -> new MavenDependency( + entry.getKey() + ":" + entry.getValue().getVersion() + )).collect(Collectors.toList()); + } else if (v010Version.isTextual()) { + final InstallFile installFile = INSTALL_FILE_READER.readValue(dependencyFile); + tree = installFile.getDependencyTree(); + if (tree == null) { + return; + } else if (!Objects.equals(tree.getAutogeneratedSentinel(), "THERE_IS_NO_DATA_ONLY_ZUUL")) { + return; + } + if (!Objects.equals(tree.getVersion(), "0.1.0")) { + LOGGER.warn("Unsupported pinned maven_install.json version {}. Continuing optimistically.", tree.getVersion()); + } + deps = tree.getDependencies(); + } else { + LOGGER.warn("No pinned maven_install.json version found. Cannot Parse"); + return; + } - if (tree == null) { - return; - } else if (!Objects.equals(tree.getAutogeneratedSentinel(), "THERE_IS_NO_DATA_ONLY_ZUUL")) { + } catch (IOException e) { + System.out.println("e"); return; } engine.removeDependency(dependency); - if (!Objects.equals(tree.getVersion(), "0.1.0")) { - LOGGER.warn("Unsupported pinned maven_install.json version {}. Continuing optimistically.", tree.getVersion()); - } - - List deps = tree.getDependencies(); if (deps == null) { deps = Collections.emptyList(); } @@ -183,6 +207,7 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An d.setEcosystem(Ecosystem.JAVA); d.addEvidence(EvidenceType.VENDOR, "project", "groupid", group, Confidence.HIGHEST); d.addEvidence(EvidenceType.PRODUCT, "project", "artifactid", artifact, Confidence.HIGHEST); + d.addEvidence(EvidenceType.VENDOR, "project", "artifactid", artifact, Confidence.HIGH); d.addEvidence(EvidenceType.VERSION, "project", "version", version, Confidence.HIGHEST); d.setName(String.format("%s:%s", group, artifact)); d.setFilePath(String.format("%s>>%s", dependency.getActualFile(), dep.getCoord())); @@ -301,6 +326,12 @@ public String getVersion() { */ private static class MavenDependency { + MavenDependency(String coord) { + this.coord = coord; + } + + MavenDependency() { + } /** * The standard Maven coordinate string * {@code group:artifact[:optional classifier][:optional packaging]:version}. @@ -322,10 +353,106 @@ public String getCoord() { * A reusable reader for {@link InstallFile}. */ private static final ObjectReader INSTALL_FILE_READER; + /** + * A reusable reader for {@link InstallFileV2}. + */ + private static final ObjectReader INSTALL_FILE_V2_READER; + /** + * A reusable object mapper. + */ + private static final ObjectMapper MAPPER; static { - final ObjectMapper mapper = new ObjectMapper(); - mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - INSTALL_FILE_READER = mapper.readerFor(InstallFile.class); + MAPPER = new ObjectMapper(); + MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + INSTALL_FILE_READER = MAPPER.readerFor(InstallFile.class); + INSTALL_FILE_V2_READER = MAPPER.readerFor(InstallFileV2.class); } + + /** + * Represents the entire pinned Maven dependency set in an install.json + * file. + * + *

+ * At the time of writing, the latest version is 2, and the dependencies are + * stored in {@code .artifacts}. + * + *

+ * The top-level keys we care about are {@code .artifacts}. + * {@code .version}. + */ + private static class InstallFileV2 { + + /** + * The file format version. + */ + @JsonProperty("version") + private String version; + + /** + * A list of Maven dependencies made available. Note that this map is + * transitively closed and pinned to a specific version of each + * artifact. + *

+ * The key is the Maven coordinate string, less the version + * {@code group:artifact[:optional classifier][:optional packaging]}. + *

+ * The value contains the version of the artifact. + */ + @JsonProperty("artifacts") + private Map artifacts; + + /** + * A sentinel value placed in the file to indicate that it is an + * auto-generated pinned maven install file. + */ + @JsonProperty("__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY") + private String autogeneratedSentinel; + + /** + * Returns artifacts. + * + * @return artifacts + */ + public Map getArtifacts() { + return artifacts; + } + + /** + * Returns version. + * + * @return version + */ + public String getVersion() { + return version; + } + + /** + * Returns autogeneratedSentinel. + * + * @return autogeneratedSentinel + */ + public String getAutogeneratedSentinel() { + return autogeneratedSentinel; + } + } + + private static class Artifactv2 { + + /** + * The version of the artifact. + */ + @JsonProperty("version") + private String version; + + /** + * Returns the value of version. + * + * @return the value of version + */ + public String getVersion() { + return version; + } + } + } diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/PipAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/PipAnalyzer.java index 90ef79c6491..e4ceb68bf25 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/PipAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/PipAnalyzer.java @@ -17,7 +17,6 @@ */ package org.owasp.dependencycheck.analyzer; -import org.apache.commons.io.FileUtils; import com.github.packageurl.MalformedPackageURLException; import com.github.packageurl.PackageURL; import com.github.packageurl.PackageURLBuilder; @@ -25,23 +24,25 @@ import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Dependency; -import org.owasp.dependencycheck.utils.FileFilterBuilder; -import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.dependency.EvidenceType; -import org.owasp.dependencycheck.exception.InitializationException; import org.owasp.dependencycheck.dependency.naming.GenericIdentifier; import org.owasp.dependencycheck.dependency.naming.PurlIdentifier; +import org.owasp.dependencycheck.exception.InitializationException; import org.owasp.dependencycheck.utils.Checksum; +import org.owasp.dependencycheck.utils.FileFilterBuilder; +import org.owasp.dependencycheck.utils.Settings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import javax.annotation.concurrent.ThreadSafe; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.nio.charset.Charset; +import java.nio.file.Files; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.annotation.concurrent.ThreadSafe; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.util.stream.Collectors; /** * Used to analyze pip dependency files named requirements.txt. @@ -74,7 +75,7 @@ public class PipAnalyzer extends AbstractFileTypeAnalyzer { /** * o * Matches AC_INIT variables in the output configure script. */ - private static final Pattern PACKAGE_VERSION = Pattern.compile("^([^#].*?)(?:[=>]=([\\.\\*0-9]+?))?$", Pattern.MULTILINE); + private static final Pattern PACKAGE_VERSION = Pattern.compile("^([^#].*?)(?:[=~>]=([\\.\\*0-9]+?))?$", Pattern.MULTILINE); /** * The file filter used to determine which files this analyzer supports. @@ -174,7 +175,7 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An } /** - * Retrieves the contents of a given file. + * Retrieves the contents of a given file without blank lines. * * @param actualFile the file to read * @return the contents of the file @@ -182,7 +183,9 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An */ private String getFileContents(final File actualFile) throws AnalysisException { try { - return FileUtils.readFileToString(actualFile, Charset.defaultCharset()).trim(); + return Files.lines(actualFile.toPath(), Charset.defaultCharset()) + .filter(line -> !line.trim().isEmpty()) + .collect(Collectors.joining("\n")); } catch (IOException e) { throw new AnalysisException("Problem occurred while reading dependency file.", e); } diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/PipfileAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/PipfileAnalyzer.java index 76905edf0bb..bb5c66fc75e 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/PipfileAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/PipfileAnalyzer.java @@ -17,7 +17,6 @@ */ package org.owasp.dependencycheck.analyzer; -import org.apache.commons.io.FileUtils; import com.github.packageurl.MalformedPackageURLException; import com.github.packageurl.PackageURL; import com.github.packageurl.PackageURLBuilder; @@ -25,23 +24,24 @@ import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Dependency; -import org.owasp.dependencycheck.utils.FileFilterBuilder; -import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.dependency.EvidenceType; -import org.owasp.dependencycheck.exception.InitializationException; import org.owasp.dependencycheck.dependency.naming.GenericIdentifier; import org.owasp.dependencycheck.dependency.naming.PurlIdentifier; +import org.owasp.dependencycheck.exception.InitializationException; import org.owasp.dependencycheck.utils.Checksum; +import org.owasp.dependencycheck.utils.FileFilterBuilder; +import org.owasp.dependencycheck.utils.Settings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import javax.annotation.concurrent.ThreadSafe; import java.io.File; import java.io.FileFilter; import java.io.IOException; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.annotation.concurrent.ThreadSafe; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Used to analyze dependencies defined in Pipfile. This analyzer works in @@ -81,7 +81,7 @@ public class PipfileAnalyzer extends AbstractFileTypeAnalyzer { /** * o * Matches AC_INIT variables in the output configure script. */ - private static final Pattern PACKAGE_VERSION = Pattern.compile("^([^#].*?) = \"(?:[=>]=([\\.\\*0-9]+?))?\"$", Pattern.MULTILINE); + private static final Pattern PACKAGE_VERSION = Pattern.compile("^([^#].*?) = \"(?:[=~>]=([\\.\\*0-9]+?))?\"$", Pattern.MULTILINE); /** * The file filter used to determine which files this analyzer supports. @@ -192,7 +192,7 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An */ private String getFileContents(final File actualFile) throws AnalysisException { try { - return FileUtils.readFileToString(actualFile, Charset.defaultCharset()).trim(); + return new String(Files.readAllBytes(actualFile.toPath()), StandardCharsets.UTF_8).trim(); } catch (IOException e) { throw new AnalysisException("Problem occurred while reading dependency file.", e); } diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/PipfilelockAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/PipfilelockAnalyzer.java index 525cdcfb6fa..d2a3f8f4719 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/PipfilelockAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/PipfilelockAnalyzer.java @@ -17,39 +17,38 @@ */ package org.owasp.dependencycheck.analyzer; -import org.apache.commons.io.FileUtils; import com.github.packageurl.MalformedPackageURLException; import com.github.packageurl.PackageURL; import com.github.packageurl.PackageURLBuilder; -import java.io.BufferedInputStream; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Dependency; -import org.owasp.dependencycheck.utils.FileFilterBuilder; -import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.dependency.EvidenceType; -import org.owasp.dependencycheck.exception.InitializationException; import org.owasp.dependencycheck.dependency.naming.GenericIdentifier; import org.owasp.dependencycheck.dependency.naming.PurlIdentifier; +import org.owasp.dependencycheck.exception.InitializationException; import org.owasp.dependencycheck.utils.Checksum; +import org.owasp.dependencycheck.utils.FileFilterBuilder; +import org.owasp.dependencycheck.utils.Settings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import javax.annotation.concurrent.ThreadSafe; +import jakarta.json.Json; +import jakarta.json.JsonException; +import jakarta.json.JsonObject; +import jakarta.json.JsonReader; +import java.io.BufferedInputStream; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.Set; -import javax.annotation.concurrent.ThreadSafe; -import javax.json.Json; -import javax.json.JsonException; -import javax.json.JsonObject; -import javax.json.JsonReader; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Used to analyze dependencies defined in Pipfile.lock. This analyzer works in @@ -199,7 +198,7 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An */ private String getFileContents(final File actualFile) throws AnalysisException { try { - return FileUtils.readFileToString(actualFile, Charset.defaultCharset()).trim(); + return new String(Files.readAllBytes(actualFile.toPath()), StandardCharsets.UTF_8).trim(); } catch (IOException e) { throw new AnalysisException("Problem occurred while reading dependency file.", e); } diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/PnpmAuditAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/PnpmAuditAnalyzer.java index ef2a9c7ba79..74202cdc85c 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/PnpmAuditAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/PnpmAuditAnalyzer.java @@ -17,7 +17,8 @@ */ package org.owasp.dependencycheck.analyzer; -import org.apache.commons.io.FileUtils; +import org.apache.commons.collections4.MultiValuedMap; +import org.apache.commons.collections4.multimap.HashSetValuedHashMap; import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; import org.json.JSONException; @@ -42,10 +43,9 @@ import java.io.FileFilter; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.ArrayList; import java.util.List; -import org.apache.commons.collections4.MultiValuedMap; -import org.apache.commons.collections4.multimap.HashSetValuedHashMap; @ThreadSafe public class PnpmAuditAnalyzer extends AbstractNpmAnalyzer { @@ -219,7 +219,7 @@ private JSONObject fetchPnpmAuditJson(Dependency dependency, boolean skipDevDepe if (!StringUtils.isBlank(errOutput)) { LOGGER.error("Process error output: {}", errOutput); } - String verboseJson = FileUtils.readFileToString(tmpFile, StandardCharsets.UTF_8); + String verboseJson = new String(Files.readAllBytes(tmpFile.toPath()), StandardCharsets.UTF_8); // Workaround implicit creation of .pnpm-debug.log, see https://github.com/pnpm/pnpm/issues/3832 // affects usage of docker container to analyze mounted directories without privileges if (verboseJson.contains("EACCES: permission denied, open 'node_modules/.pnpm-debug.log'")) { diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/PoetryAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/PoetryAnalyzer.java index 0d29b5f8875..87be9cda21a 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/PoetryAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/PoetryAnalyzer.java @@ -12,8 +12,6 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - * - * Copyright (c) 2019 Nima Yahyazadeh. All Rights Reserved. */ package org.owasp.dependencycheck.analyzer; @@ -36,6 +34,8 @@ import com.moandjiezana.toml.Toml; import java.io.File; +import java.util.Optional; + import org.owasp.dependencycheck.data.nvd.ecosystem.Ecosystem; import org.owasp.dependencycheck.dependency.naming.GenericIdentifier; import org.owasp.dependencycheck.dependency.naming.PurlIdentifier; @@ -147,14 +147,24 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An //do not report on the build file itself engine.removeDependency(dependency); + final Optional potentiallyParsedToml = parseDependencyFile(dependency); + if (potentiallyParsedToml.isEmpty()) { + LOGGER.warn("toml file skipped: {} could not be parsed", dependency.getActualFilePath()); + return; + } + final Toml result = potentiallyParsedToml.get(); if (PYPROJECT_TOML.equals(dependency.getActualFile().getName())) { + if (result.getTable("tool.poetry") == null) { + LOGGER.debug("skipping {} as it does not contain `tool.poetry`", dependency.getDisplayFileName()); + return; + } + final File parentPath = dependency.getActualFile().getParentFile(); ensureLock(parentPath); //exit as we can't analyze pyproject.toml - insufficient version information return; } - final Toml result = new Toml().read(dependency.getActualFile()); final List projectsLocks = result.getTables("package"); if (projectsLocks == null) { return; @@ -195,6 +205,30 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An }); } + private Optional parseDependencyFile(Dependency dependency) { + try { + final Toml toml = new Toml().read(dependency.getActualFile()); + return Optional.of(toml); + } catch (RuntimeException e) { + final Optional unparsableFileErrorMessage = Optional.ofNullable(e.getCause()) + .filter(c -> c instanceof IllegalStateException) + .map(Throwable::getMessage) + .filter(PoetryAnalyzer::isInvalidKeyErrorMessage); + + if (unparsableFileErrorMessage.isPresent()) { + final String message = String.format("Invalid toml file, cannot parse '%s'", dependency.getActualFile()); + LOGGER.debug(message, e); + return Optional.empty(); + } + + throw e; + } + } + + private static boolean isInvalidKeyErrorMessage(String m) { + return m.startsWith("Invalid key"); + } + private void ensureLock(File parent) throws AnalysisException { final File lock = new File(parent, POETRY_LOCK); final File requirements = new File(parent, "requirements.txt"); diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/PythonPackageAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/PythonPackageAnalyzer.java index ecd7c727c85..8396fb8f6e2 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/PythonPackageAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/PythonPackageAnalyzer.java @@ -20,31 +20,31 @@ import com.github.packageurl.MalformedPackageURLException; import com.github.packageurl.PackageURL; import com.github.packageurl.PackageURLBuilder; -import org.apache.commons.io.FileUtils; import org.apache.commons.io.filefilter.NameFileFilter; import org.apache.commons.io.filefilter.SuffixFileFilter; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; +import org.owasp.dependencycheck.data.nvd.ecosystem.Ecosystem; import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Dependency; +import org.owasp.dependencycheck.dependency.EvidenceType; +import org.owasp.dependencycheck.dependency.naming.GenericIdentifier; +import org.owasp.dependencycheck.dependency.naming.PurlIdentifier; +import org.owasp.dependencycheck.exception.InitializationException; import org.owasp.dependencycheck.utils.FileFilterBuilder; import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.UrlStringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import javax.annotation.concurrent.ThreadSafe; import java.io.File; import java.io.FileFilter; import java.io.IOException; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.annotation.concurrent.ThreadSafe; -import org.owasp.dependencycheck.data.nvd.ecosystem.Ecosystem; -import org.owasp.dependencycheck.dependency.EvidenceType; -import org.owasp.dependencycheck.dependency.naming.GenericIdentifier; -import org.owasp.dependencycheck.dependency.naming.PurlIdentifier; -import org.owasp.dependencycheck.exception.InitializationException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Used to analyze a Python package, and collect information that can be used to @@ -211,6 +211,7 @@ protected void analyzeDependency(Dependency dependency, Engine engine) //"The __init__.py files are required to make Python treat the directories as containing packages" //see section "6.4 Packages" from https://docs.python.org/2/tutorial/modules.html; dependency.addEvidence(EvidenceType.PRODUCT, file.getName(), "PackageName", parentName, Confidence.HIGHEST); + dependency.addEvidence(EvidenceType.VENDOR, file.getName(), "PackageName", parentName, Confidence.MEDIUM); dependency.setName(parentName); final File[] fileList = parent.listFiles(PY_FILTER); @@ -237,13 +238,13 @@ private void analyzeFileContents(Dependency dependency, File file) throws AnalysisException { final String contents; try { - contents = FileUtils.readFileToString(file, Charset.defaultCharset()).trim(); + contents = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8).trim(); } catch (IOException e) { throw new AnalysisException("Problem occurred while reading dependency file.", e); } if (!contents.isEmpty()) { final String source = file.getName(); - gatherEvidence(dependency, EvidenceType.VERSION, VERSION_PATTERN, contents, + gatherEvidence(dependency, EvidenceType.VERSION, VERSION_PATTERN, contents, source, "SourceVersion", Confidence.MEDIUM); addSummaryInfo(dependency, SUMMARY_PATTERN, 4, contents, source, "summary"); @@ -292,7 +293,7 @@ private void analyzeFileContents(Dependency dependency, File file) * @param key the key name to use when recording the evidence */ private void addSummaryInfo(Dependency dependency, Pattern pattern, - int group, String contents, String source, String key) { + int group, String contents, String source, String key) { final Matcher matcher = pattern.matcher(contents); final boolean found = matcher.find(); if (found) { @@ -312,7 +313,7 @@ private void addSummaryInfo(Dependency dependency, Pattern pattern, * @param contents the home page URL */ private void gatherHomePageEvidence(Dependency dependency, EvidenceType type, Pattern pattern, - String source, String name, String contents) { + String source, String name, String contents) { final Matcher matcher = pattern.matcher(contents); if (matcher.find()) { final String url = matcher.group(4); @@ -335,7 +336,7 @@ private void gatherHomePageEvidence(Dependency dependency, EvidenceType type, Pa * @param confidence in evidence */ private void gatherEvidence(Dependency dependency, EvidenceType type, Pattern pattern, String contents, - String source, String name, Confidence confidence) { + String source, String name, Confidence confidence) { final Matcher matcher = pattern.matcher(contents); final boolean found = matcher.find(); if (found) { diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/RetireJsAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/RetireJsAnalyzer.java index 7961f8f77c5..0c329a9e729 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/RetireJsAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/RetireJsAnalyzer.java @@ -182,7 +182,7 @@ public void initialize(Settings settings) { protected void prepareFileTypeAnalyzer(Engine engine) throws InitializationException { // RetireJS outputs a bunch of repeated output like the following for // vulnerable dependencies, with little context: - // + // // INFO: Vulnerability found: jquery below 1.6.3 // // This logging is suppressed because it isn't particularly useful, and @@ -216,7 +216,7 @@ protected void prepareFileTypeAnalyzer(Engine engine) throws InitializationExcep try { ds.update(engine); } catch (UpdateException ex) { - throw new InitializationException("Unable to initialize the Retire JS respository", ex); + throw new InitializationException("Unable to initialize the Retire JS repository", ex); } } diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/RubyGemspecAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/RubyGemspecAnalyzer.java index 002eb6dc283..ab5c54a3e8d 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/RubyGemspecAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/RubyGemspecAnalyzer.java @@ -20,16 +20,6 @@ import com.github.packageurl.MalformedPackageURLException; import com.github.packageurl.PackageURL; import com.github.packageurl.PackageURLBuilder; -import java.io.File; -import java.io.FileFilter; -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.annotation.concurrent.ThreadSafe; - -import org.apache.commons.io.FileUtils; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.data.nvd.ecosystem.Ecosystem; @@ -44,6 +34,16 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.concurrent.ThreadSafe; +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * Used to analyze Ruby Gem specifications and collect information that can be * used to determine the associated CPE. Regular expressions are used to parse @@ -143,7 +143,7 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An dependency.setEcosystem(DEPENDENCY_ECOSYSTEM); String contents; try { - contents = FileUtils.readFileToString(dependency.getActualFile(), Charset.defaultCharset()); + contents = new String(Files.readAllBytes(dependency.getActualFile().toPath()), StandardCharsets.UTF_8); } catch (IOException e) { throw new AnalysisException( "Problem occurred while reading dependency file.", e); @@ -265,7 +265,7 @@ private String addEvidenceFromVersionFile(Dependency dependency, EvidenceType ty } for (File f : matchingFiles) { try { - final List lines = FileUtils.readLines(f, Charset.defaultCharset()); + final List lines = Files.readAllLines(f.toPath(), StandardCharsets.UTF_8); if (lines.size() == 1) { //TODO other checking? final String value = lines.get(0).trim(); if (version == null || !version.equals(value)) { diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/SwiftPackageManagerAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/SwiftPackageManagerAnalyzer.java index 805a32a8c49..7e9baaeef61 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/SwiftPackageManagerAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/SwiftPackageManagerAnalyzer.java @@ -20,15 +20,6 @@ import com.github.packageurl.MalformedPackageURLException; import com.github.packageurl.PackageURL; import com.github.packageurl.PackageURLBuilder; -import java.io.File; -import java.io.FileFilter; -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.annotation.concurrent.ThreadSafe; - -import org.apache.commons.io.FileUtils; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.data.nvd.ecosystem.Ecosystem; @@ -42,6 +33,15 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.concurrent.ThreadSafe; +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * This analyzer is used to analyze the SWIFT Package Manager * (https://swift.org/package-manager/). It collects information about a package @@ -158,7 +158,7 @@ private void analyzeSpmFileDependency(Dependency dependency) throws AnalysisException, IOException { dependency.setEcosystem(DEPENDENCY_ECOSYSTEM); - final String contents = FileUtils.readFileToString(dependency.getActualFile(), Charset.defaultCharset()); + final String contents = new String(Files.readAllBytes(dependency.getActualFile().toPath()), StandardCharsets.UTF_8); final Matcher matcher = SPM_BLOCK_PATTERN.matcher(contents); if (matcher.find()) { @@ -220,7 +220,7 @@ private void analyzeSpmFileDependency(Dependency dependency) * @return the string that was added as evidence */ private String addStringEvidence(Dependency dependency, EvidenceType type, - String packageDescription, String field, String fieldPattern, Confidence confidence) { + String packageDescription, String field, String fieldPattern, Confidence confidence) { String value = ""; final Matcher matcher = Pattern.compile( diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/SwiftPackageResolvedAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/SwiftPackageResolvedAnalyzer.java index 575aaa597ce..ccd10ec48d1 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/SwiftPackageResolvedAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/SwiftPackageResolvedAnalyzer.java @@ -20,16 +20,6 @@ import com.github.packageurl.MalformedPackageURLException; import com.github.packageurl.PackageURL; import com.github.packageurl.PackageURLBuilder; -import java.io.FileFilter; -import java.io.IOException; -import java.io.InputStream; -import javax.annotation.concurrent.ThreadSafe; -import javax.json.Json; -import javax.json.JsonArray; -import javax.json.JsonObject; -import javax.json.JsonReader; - -import org.apache.commons.io.FileUtils; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.data.nvd.ecosystem.Ecosystem; @@ -44,6 +34,16 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.concurrent.ThreadSafe; +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.json.JsonReader; +import java.io.FileFilter; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; + /** * This analyzer is used to analyze the SWIFT Package Resolved * (https://swift.org/package-manager/). It collects information about a package @@ -155,8 +155,8 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An private void analyzeSpmResolvedDependencies(Dependency spmResolved, Engine engine) throws AnalysisException, IOException { - try (InputStream in = FileUtils.openInputStream(spmResolved.getActualFile()); - JsonReader resolved = Json.createReader(in)) { + try (InputStream in = Files.newInputStream(spmResolved.getActualFile().toPath()); + JsonReader resolved = Json.createReader(in)) { final JsonObject file = resolved.readObject(); final int fileVersion = file.getInt("version"); @@ -165,7 +165,8 @@ private void analyzeSpmResolvedDependencies(Dependency spmResolved, Engine engin analyzeSpmResolvedDependenciesV1(spmResolved, engine, file); break; case 2: - analyzeSpmResolvedDependenciesV2(spmResolved, engine, file); + case 3: + analyzeSpmResolvedDependenciesV2And3(spmResolved, engine, file); break; default: return; @@ -209,14 +210,14 @@ private void analyzeSpmResolvedDependenciesV1(Dependency spmResolved, Engine eng } /** - * Analyzes the version 2 of the Package.resolved file to extract evidence + * Analyzes the versions 2 and 3 of the Package.resolved file to extract evidence * for the dependency. * * @param spmResolved the dependency to analyze * @param engine the analysis engine * @param resolved the json object of the file to analyze */ - private void analyzeSpmResolvedDependenciesV2(Dependency spmResolved, Engine engine, JsonObject resolved) { + private void analyzeSpmResolvedDependenciesV2And3(Dependency spmResolved, Engine engine, JsonObject resolved) { final JsonArray pins = resolved.getJsonArray("pins"); if (pins == null) { return; diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/UnusedSuppressionRuleAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/UnusedSuppressionRuleAnalyzer.java index 4c95fdbb78d..9f5188e06ad 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/UnusedSuppressionRuleAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/UnusedSuppressionRuleAnalyzer.java @@ -34,6 +34,11 @@ */ public class UnusedSuppressionRuleAnalyzer extends AbstractAnalyzer { + /** + * Exception message. + */ + protected static final String EXCEPTION_MSG = "There are %d unused suppression rule(s): check logs."; + /** * The Logger for use throughout the class. */ @@ -43,27 +48,54 @@ public class UnusedSuppressionRuleAnalyzer extends AbstractAnalyzer { * been reported. */ private boolean reported = false; + /** + * A flag indicating whether build should fail on unused suppression rule + */ + private boolean shouldFailForUnusedSuppressionRule = false; + /** + * unused suppression rule count + */ + private int unusedSuppressionRuleCount = 0; + + @Override + public synchronized void initialize(Settings settings) { + super.initialize(settings); + if (settings.getBoolean(Settings.KEYS.FAIL_ON_UNUSED_SUPPRESSION_RULE, false)) { + this.shouldFailForUnusedSuppressionRule = true; + } + } @Override protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException { if (!reported) { - logUnusedRules(engine); + checkUnusedRules(engine); reported = true; + if (unusedSuppressionRuleCount > 0 && failsForUnusedSuppressionRule()) { + final String message = String.format(EXCEPTION_MSG, unusedSuppressionRuleCount); + LOGGER.error(message); + throw new AnalysisException(message); + } } } /** - * Logs unused suppression RULES. + * check unused suppression RULES. * * @param engine a reference to the ODC engine */ - private void logUnusedRules(Engine engine) { + protected void checkUnusedRules(Engine engine) { if (engine.hasObject(SUPPRESSION_OBJECT_KEY)) { @SuppressWarnings("unchecked") final List rules = (List) engine.getObject(SUPPRESSION_OBJECT_KEY); rules.forEach((rule) -> { if (!rule.isMatched() && !rule.isBase()) { - LOGGER.info("Suppression Rule had zero matches: {}", rule.toString()); + final String message = String.format("Suppression Rule had zero matches: %s", rule); + if (failsForUnusedSuppressionRule()) { + LOGGER.error(message); + } else { + LOGGER.info(message); + } + increaseUnusedSuppressionRuleCount(); } }); } @@ -89,4 +121,25 @@ public AnalysisPhase getAnalysisPhase() { public boolean supportsParallelProcessing() { return false; } + + /** + * increases the count of unused suppression rules. + */ + public void increaseUnusedSuppressionRuleCount() { + unusedSuppressionRuleCount++; + } + + /** + * @return the count of unused suppression rules. + */ + public int getUnusedSuppressionRuleCount() { + return unusedSuppressionRuleCount; + } + + /** + * @return whether the analyzer will fail for a unused suppression rule. + */ + public boolean failsForUnusedSuppressionRule() { + return shouldFailForUnusedSuppressionRule; + } } diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/VersionFilterAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/VersionFilterAnalyzer.java index 584b9b2a163..1cd1ad432f2 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/VersionFilterAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/VersionFilterAnalyzer.java @@ -86,7 +86,7 @@ public class VersionFilterAnalyzer extends AbstractAnalyzer { /** * The phase that this analyzer is intended to run in. */ - private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.POST_INFORMATION_COLLECTION; + private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.POST_INFORMATION_COLLECTION3; // // @@ -136,7 +136,7 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An final Set remove; if (dependency.getVersion() != null) { remove = dependency.getEvidence(EvidenceType.VERSION).stream() - .filter(e -> !dependency.getVersion().equals(e.getValue())) + .filter(e -> !e.isFromHint() && !dependency.getVersion().equals(e.getValue())) .collect(Collectors.toSet()); } else { remove = new HashSet<>(); @@ -165,7 +165,8 @@ protected void analyzeDependency(Dependency dependency, Engine engine) throws An LOGGER.debug("filtering evidence from {}", dependency.getFileName()); for (Evidence e : dependency.getEvidence(EvidenceType.VERSION)) { - if (!(pomMatch && VERSION.equals(e.getName()) + if (!e.isFromHint() + && !(pomMatch && VERSION.equals(e.getName()) && (NEXUS.equals(e.getSource()) || CENTRAL.equals(e.getSource()) || POM.equals(e.getSource()))) && !(fileMatch && VERSION.equals(e.getName()) && FILE.equals(e.getSource())) && !(manifestMatch && MANIFEST.equals(e.getSource()) && IMPLEMENTATION_VERSION.equals(e.getName()))) { diff --git a/core/src/main/java/org/owasp/dependencycheck/analyzer/YarnAuditAnalyzer.java b/core/src/main/java/org/owasp/dependencycheck/analyzer/YarnAuditAnalyzer.java index 2e52ad8bc43..25c7f0b58e6 100644 --- a/core/src/main/java/org/owasp/dependencycheck/analyzer/YarnAuditAnalyzer.java +++ b/core/src/main/java/org/owasp/dependencycheck/analyzer/YarnAuditAnalyzer.java @@ -17,25 +17,12 @@ */ package org.owasp.dependencycheck.analyzer; -import java.io.File; -import java.io.FileFilter; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import javax.annotation.concurrent.ThreadSafe; -import javax.json.Json; -import javax.json.JsonException; -import javax.json.JsonObject; -import javax.json.JsonReader; import org.apache.commons.collections4.MultiValuedMap; import org.apache.commons.collections4.multimap.HashSetValuedHashMap; - -import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; +import org.json.JSONException; +import org.json.JSONObject; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.analyzer.exception.SearchException; @@ -48,18 +35,41 @@ import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.URLConnectionFailureException; import org.owasp.dependencycheck.utils.processing.ProcessReader; +import org.semver4j.Semver; +import org.semver4j.SemverException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import us.springett.parsers.cpe.exceptions.CpeValidationException; +import jakarta.json.Json; +import jakarta.json.JsonException; +import jakarta.json.JsonObject; +import jakarta.json.JsonReader; + +import javax.annotation.concurrent.ThreadSafe; +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; + @ThreadSafe public class YarnAuditAnalyzer extends AbstractNpmAnalyzer { /** - * The logger. + * The Logger for use throughout the class. */ private static final Logger LOGGER = LoggerFactory.getLogger(YarnAuditAnalyzer.class); + /** + * The major version of the Yarn Classic CLI. + */ + private static final int YARN_CLASSIC_MAJOR_VERSION = 1; + /** * The file name to scan. */ @@ -83,34 +93,6 @@ public class YarnAuditAnalyzer extends AbstractNpmAnalyzer { */ private String yarnPath; - /** - * Analyzes the yarn lock file to determine vulnerable dependencies. Uses - * yarn audit --offline to generate the payload to be sent to the NPM API. - * - * @param dependency the yarn lock file - * @param engine the analysis engine - * @throws AnalysisException thrown if there is an error analyzing the file - */ - @Override - protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException { - if (dependency.getDisplayFileName().equals(dependency.getFileName())) { - engine.removeDependency(dependency); - } - final File packageLock = dependency.getActualFile(); - if (!packageLock.isFile() || packageLock.length() == 0 || !shouldProcess(packageLock)) { - return; - } - final File packageJson = new File(packageLock.getParentFile(), "package.json"); - final List advisories; - final MultiValuedMap dependencyMap = new HashSetValuedHashMap<>(); - advisories = analyzePackage(packageLock, packageJson, dependency, dependencyMap); - try { - processResults(advisories, engine, dependency, dependencyMap); - } catch (CpeValidationException ex) { - throw new UnexpectedAnalysisException(ex); - } - } - @Override protected String getAnalyzerEnabledSettingKey() { return Settings.KEYS.ANALYZER_YARN_AUDIT_ENABLED; @@ -131,6 +113,49 @@ public AnalysisPhase getAnalysisPhase() { return AnalysisPhase.FINDING_ANALYSIS; } + /** + * Extracts the major version from a version string. + * + * @param dependency the dependency to extract the yarn version from + * @return the major version (e.g., `4` from "4.2.1") + */ + private int getYarnMajorVersion(Dependency dependency) { + final var yarnVersion = getYarnVersion(dependency); + try { + final var semver = Semver.coerce(yarnVersion); + return semver.getMajor(); + } catch (SemverException e) { + throw new IllegalStateException("Invalid version string format", e); + } + } + + private String getYarnVersion(Dependency dependency) { + final List args = new ArrayList<>(); + args.add(getYarn()); + args.add("--version"); + final ProcessBuilder builder = new ProcessBuilder(args); + builder.directory(getDependencyDirectory(dependency)); + LOGGER.debug("Launching: {}", args); + try { + final Process process = builder.start(); + try (ProcessReader processReader = new ProcessReader(process)) { + processReader.readAll(); + final int exitValue = process.waitFor(); + if (exitValue != 0) { + throw new IllegalStateException("Unable to determine yarn version, unexpected response."); + } + final var yarnVersion = processReader.getOutput(); + if (StringUtils.isBlank(yarnVersion)) { + throw new IllegalStateException("Unable to determine yarn version, blank output."); + } + return yarnVersion; + } + } catch (Exception ex) { + throw new IllegalStateException("Unable to determine yarn version.", ex); + } + } + + /** * Initializes the analyzer once before any analysis is performed. * @@ -163,12 +188,14 @@ protected void prepareFileTypeAnalyzer(Engine engine) throws InitializationExcep case yarnExecutableNotFoundExitValue: default: this.setEnabled(false); - LOGGER.warn("The {} has been disabled. Yarn executable was not found.", getName()); + LOGGER.warn("The {} has been disabled after receiving exit value {}. Yarn executable was not " + + "found or received a non-zero exit value.", getName(), exitValue); } } } catch (Exception ex) { this.setEnabled(false); - LOGGER.warn("The {} has been disabled. Yarn executable was not found.", getName()); + LOGGER.warn("The {} has been disabled after receiving an exception. This can occur when Yarn executable " + + "is not found.", getName()); throw new InitializationException("Unable to read yarn audit output.", ex); } } @@ -200,30 +227,15 @@ private String getYarn() { return value; } - private JsonObject fetchYarnAuditJson(Dependency dependency, boolean skipDevDependencies) throws AnalysisException { - final File folder = dependency.getActualFile().getParentFile(); - if (!folder.isDirectory()) { - throw new AnalysisException(String.format("%s should have been a directory.", folder.getAbsolutePath())); - } + /** + * Workaround 64k limitation of InputStream, redirect stdout to a file that we will read later + * instead of reading directly stdout from Process's InputStream which is topped at 64k + * + * @param builder a reference to the process builder + * @return returns the standard out from the process + */ + private String startAndReadStdoutToString(ProcessBuilder builder) throws AnalysisException { try { - final List args = new ArrayList<>(); - - args.add(getYarn()); - args.add("audit"); - //offline audit is not supported - but the audit request is generated in the verbose output - args.add("--offline"); - if (skipDevDependencies) { - args.add("--groups"); - args.add("dependencies"); - } - args.add("--json"); - args.add("--verbose"); - final ProcessBuilder builder = new ProcessBuilder(args); - builder.directory(folder); - LOGGER.debug("Launching: {}", args); - // Workaround 64k limitation of InputStream, redirect stdout to a file that we will read later - // instead of reading directly stdout from Process's InputStream which is topped at 64k - final File tmpFile = getSettings().getTempFile("yarn_audit", "json"); builder.redirectOutput(tmpFile); final Process process = builder.start(); @@ -235,19 +247,7 @@ private JsonObject fetchYarnAuditJson(Dependency dependency, boolean skipDevDepe LOGGER.debug("Process Error Out: {}", errOutput); LOGGER.debug("Process Out: {}", processReader.getOutput()); } - final String verboseJson = FileUtils.readFileToString(tmpFile, StandardCharsets.UTF_8); - final String auditRequestJson = Arrays.stream(verboseJson.split("\n")) - .filter(line -> line.contains("Audit Request")) - .findFirst().get(); - String auditRequest; - try (JsonReader reader = Json.createReader(IOUtils.toInputStream(auditRequestJson, StandardCharsets.UTF_8))) { - final JsonObject jsonObject = reader.readObject(); - auditRequest = jsonObject.getString("data"); - auditRequest = auditRequest.substring(15); - } - LOGGER.debug("Audit Request: {}", auditRequest); - - return Json.createReader(IOUtils.toInputStream(auditRequest, StandardCharsets.UTF_8)).readObject(); + return new String(Files.readAllBytes(tmpFile.toPath()), StandardCharsets.UTF_8); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); throw new AnalysisException("Yarn audit process was interrupted.", ex); @@ -257,6 +257,80 @@ private JsonObject fetchYarnAuditJson(Dependency dependency, boolean skipDevDepe } } + /** + * Analyzes the yarn lock file to determine vulnerable dependencies. Uses + * yarn audit --offline to generate the payload to be sent to the NPM API. + * + * @param dependency the yarn lock file + * @param engine the analysis engine + * @throws AnalysisException thrown if there is an error analyzing the file + */ + @Override + protected void analyzeDependency(Dependency dependency, Engine engine) throws AnalysisException { + if (dependency.getDisplayFileName().equals(dependency.getFileName())) { + engine.removeDependency(dependency); + } + final File packageLock = dependency.getActualFile(); + if (!packageLock.isFile() || packageLock.length() == 0 || !shouldProcess(packageLock)) { + return; + } + final File packageJson = new File(packageLock.getParentFile(), "package.json"); + final List advisories; + final MultiValuedMap dependencyMap = new HashSetValuedHashMap<>(); + final var yarnMajorVersion = getYarnMajorVersion(dependency); + if (YARN_CLASSIC_MAJOR_VERSION < yarnMajorVersion) { + LOGGER.info("Analyzing using Yarn Berry audit"); + advisories = analyzePackageWithYarnBerry(dependency); + } else { + LOGGER.info("Analyzing using Yarn Classic audit"); + advisories = analyzePackageWithYarnClassic(packageLock, packageJson, dependency, dependencyMap); + } + try { + processResults(advisories, engine, dependency, dependencyMap); + } catch (CpeValidationException ex) { + throw new UnexpectedAnalysisException(ex); + } + } + + private JsonObject fetchYarnAuditJson(Dependency dependency, boolean skipDevDependencies) throws AnalysisException { + final List args = new ArrayList<>(); + args.add(getYarn()); + args.add("audit"); + //offline audit is not supported - but the audit request is generated in the verbose output + args.add("--offline"); + if (skipDevDependencies) { + args.add("--groups"); + args.add("dependencies"); + } + args.add("--json"); + args.add("--verbose"); + final ProcessBuilder builder = new ProcessBuilder(args); + builder.directory(getDependencyDirectory(dependency)); + LOGGER.debug("Launching: {}", args); + + final String verboseJson = startAndReadStdoutToString(builder); + final String auditRequestJson = Arrays.stream(verboseJson.split("\n")) + .filter(line -> line.contains("Audit Request")) + .findFirst().get(); + String auditRequest; + try (JsonReader reader = Json.createReader(IOUtils.toInputStream(auditRequestJson, StandardCharsets.UTF_8))) { + final JsonObject jsonObject = reader.readObject(); + auditRequest = jsonObject.getString("data"); + auditRequest = auditRequest.substring(15); + } + LOGGER.debug("Audit Request: {}", auditRequest); + + return Json.createReader(IOUtils.toInputStream(auditRequest, StandardCharsets.UTF_8)).readObject(); + } + + private static File getDependencyDirectory(Dependency dependency) { + final File folder = dependency.getActualFile().getParentFile(); + if (!folder.isDirectory()) { + throw new IllegalArgumentException(String.format("%s should have been a directory.", folder.getAbsolutePath())); + } + return folder; + } + /** * Analyzes the package and yarn lock files by extracting dependency * information, creating a payload to submit to the npm audit API, @@ -272,17 +346,18 @@ private JsonObject fetchYarnAuditJson(Dependency dependency, boolean skipDevDepe * @throws AnalysisException thrown when there is an error creating or * submitting the npm audit API payload */ - private List analyzePackage(final File lockFile, final File packageFile, - Dependency dependency, MultiValuedMap dependencyMap) + private List analyzePackageWithYarnClassic(final File lockFile, final File packageFile, + Dependency dependency, MultiValuedMap dependencyMap) throws AnalysisException { try { final boolean skipDevDependencies = getSettings().getBoolean(Settings.KEYS.ANALYZER_NODE_AUDIT_SKIPDEV, false); // Retrieves the contents of package-lock.json from the Dependency final JsonObject lockJson = fetchYarnAuditJson(dependency, skipDevDependencies); // Retrieves the contents of package-lock.json from the Dependency - final JsonReader packageReader = Json.createReader(FileUtils.openInputStream(packageFile)); - final JsonObject packageJson = packageReader.readObject(); - + final JsonObject packageJson; + try (JsonReader packageReader = Json.createReader(Files.newInputStream(packageFile.toPath()))) { + packageJson = packageReader.readObject(); + } // Modify the payload to meet the NPM Audit API requirements final JsonObject payload = NpmPayloadBuilder.build(lockJson, packageJson, dependencyMap, skipDevDependencies); @@ -306,4 +381,106 @@ private List analyzePackage(final File lockFile, final File packageFil throw ex; } } + + private List fetchYarnAdvisories(Dependency dependency, boolean skipDevDependencies) throws AnalysisException { + final List args = new ArrayList<>(); + + args.add(getYarn()); + args.add("npm"); + args.add("audit"); + if (skipDevDependencies) { + args.add("--environment"); + args.add("production"); + } + args.add("--all"); + args.add("--recursive"); + args.add("--json"); + final ProcessBuilder builder = new ProcessBuilder(args); + builder.directory(getDependencyDirectory(dependency)); + + final String advisoriesJsons = startAndReadStdoutToString(builder); + + LOGGER.debug("Advisories JSON: {}", advisoriesJsons); + final String[] advisoriesJsonArray = Stream.of(advisoriesJsons.split("\n")) + .filter(s -> !s.isBlank()) + .toArray(String[]::new); + try { + final List advisories = new ArrayList<>(); + for (String advisoriesJson : advisoriesJsonArray) { + advisories.add(new JSONObject(advisoriesJson)); + } + + return advisories; + } catch (JSONException e) { + throw new AnalysisException("Failed to parse the response from NPM Audit API " + + "(YarnBerryAuditAnalyzer).", e); + } + } + + /** + * Analyzes the package and yarn lock files by calling yarn npm audit and returning the identified advisories. + * + * @param dependency a reference to the dependency-object for the yarn.lock + * @return a list of advisories + */ + private List analyzePackageWithYarnBerry(Dependency dependency) throws AnalysisException { + try { + final var skipDevDependencies = getSettings().getBoolean(Settings.KEYS.ANALYZER_NODE_AUDIT_SKIPDEV, false); + final var advisoryJsons = fetchYarnAdvisories(dependency, skipDevDependencies); + return parseAdvisoryJsons(advisoryJsons); + } catch (JSONException e) { + throw new AnalysisException("Failed to parse the response from NPM Audit API " + + "(YarnBerryAuditAnalyzer).", e); + } catch (SearchException ex) { + LOGGER.error("YarnBerryAuditAnalyzer failed on {}", dependency.getActualFilePath()); + throw ex; + } + } + + private static List parseAdvisoryJsons(List advisoryJsons) throws JSONException { + final List advisories = new ArrayList<>(); + for (JSONObject advisoryJson : advisoryJsons) { + final var advisory = new Advisory(); + final var object = advisoryJson.getJSONObject("children"); + final var moduleName = advisoryJson.optString("value", null); + final var id = object.getString("ID"); + final var url = object.optString("URL", null); + final var ghsaId = extractGhsaId(url); + final var issue = object.optString("Issue", null); + final var severity = object.optString("Severity", null); + final var vulnerableVersions = object.optString("Vulnerable Versions", null); + final var treeVersions = object.optJSONArray("Tree Versions"); + final var treeVersionsLength = treeVersions == null ? 0 : treeVersions.length(); + final var versions = new ArrayList(); + for (int i = 0; i < treeVersionsLength; i++) { + versions.add(treeVersions.getString(i)); + } + if (versions.isEmpty()) { + versions.add(null); + } + for (String version : versions) { + advisory.setGhsaId(ghsaId); + advisory.setTitle(issue); + advisory.setOverview("URL:" + url + "ID: " + id); + advisory.setSeverity(severity); + advisory.setVulnerableVersions(vulnerableVersions); + advisory.setModuleName(moduleName); + advisory.setVersion(version); + advisory.setCwes(new ArrayList<>()); + advisories.add(advisory); + } + } + return advisories; + } + + private static String extractGhsaId(String url) { + if (url == null || url.isEmpty()) { + return null; + } + final int lastSlashIndex = url.lastIndexOf('/'); + if (lastSlashIndex == -1 || lastSlashIndex == url.length() - 1) { + return null; + } + return url.substring(lastSlashIndex + 1); + } } diff --git a/core/src/main/java/org/owasp/dependencycheck/data/artifactory/ArtifactorySearch.java b/core/src/main/java/org/owasp/dependencycheck/data/artifactory/ArtifactorySearch.java index ef895fc7800..630e8af0d0b 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/artifactory/ArtifactorySearch.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/artifactory/ArtifactorySearch.java @@ -19,59 +19,51 @@ import java.io.FileNotFoundException; import java.io.IOException; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; import java.net.MalformedURLException; +import java.net.URISyntaxException; import java.net.URL; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Base64; import java.util.List; import java.util.UUID; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import javax.annotation.concurrent.ThreadSafe; +import org.apache.hc.core5.http.message.BasicHeader; import org.owasp.dependencycheck.data.nexus.MavenArtifact; import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.utils.Checksum; -import org.owasp.dependencycheck.utils.InvalidSettingException; +import org.owasp.dependencycheck.utils.Downloader; +import org.owasp.dependencycheck.utils.ForbiddenException; +import org.owasp.dependencycheck.utils.ResourceNotFoundException; import org.owasp.dependencycheck.utils.Settings; -import org.owasp.dependencycheck.utils.URLConnectionFactory; +import org.owasp.dependencycheck.utils.TooManyRequestsException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectReader; /** * Class of methods to search Artifactory for hashes and determine Maven GAV * from there. * - * Data classes copied from JFrog's artifactory-client-java project. + *

Data classes copied from JFrog's artifactory-client-java project.

* * @author nhenneaux */ @ThreadSafe -@SuppressWarnings("squid:S2647") public class ArtifactorySearch { /** - * Used for logging. + * Required to add all extra information of the found artifact. + * Source: https://jfrog.com/help/r/jfrog-rest-apis/property-search */ - private static final Logger LOGGER = LoggerFactory.getLogger(ArtifactorySearch.class); + @SuppressWarnings("JavadocLinkAsPlainText") + public static final String X_RESULT_DETAIL_HEADER = "X-Result-Detail"; /** - * Pattern to match the path returned by the Artifactory AQL API. - */ - private static final Pattern PATH_PATTERN = Pattern.compile("^/(?.+)/(?[^/]+)/(?[^/]+)/[^/]+$"); - /** - * Extracted duplicateArtifactorySearchIT.java comment. + * Used for logging. */ - private static final String WHILE_ACTUAL_IS = " while actual is "; + private static final Logger LOGGER = LoggerFactory.getLogger(ArtifactorySearch.class); + /** * The URL for the Central service. */ @@ -80,25 +72,15 @@ public class ArtifactorySearch { /** * Whether to use the Proxy when making requests. */ - private final boolean useProxy; + private final boolean allowUsingProxy; - /** - * The configured settings. - */ - private final Settings settings; /** - * Search result reader - */ - private final ObjectReader objectReader; - - /** - * Creates a NexusSearch for the given repository URL. + * Creates a ArtifactorySearch for the given repository URL. * * @param settings the configured settings */ public ArtifactorySearch(Settings settings) { - this.settings = settings; final String searchUrl = settings.getString(Settings.KEYS.ANALYZER_ARTIFACTORY_URL); @@ -106,20 +88,13 @@ public ArtifactorySearch(Settings settings) { LOGGER.debug("Artifactory Search URL {}", searchUrl); if (null != settings.getString(Settings.KEYS.PROXY_SERVER)) { - boolean useProxySettings = false; - try { - useProxySettings = settings.getBoolean(Settings.KEYS.ANALYZER_ARTIFACTORY_USES_PROXY); - } catch (InvalidSettingException e) { - LOGGER.error("Settings {} is invalid, only, true/false is valid", Settings.KEYS.ANALYZER_ARTIFACTORY_USES_PROXY, e); - } - this.useProxy = useProxySettings; - LOGGER.debug("Using proxy? {}", useProxy); + this.allowUsingProxy = settings.getBoolean(Settings.KEYS.ANALYZER_ARTIFACTORY_USES_PROXY, false); + LOGGER.debug("Using proxy configuration? {}", allowUsingProxy); } else { - useProxy = false; - LOGGER.debug("Not using proxy"); + this.allowUsingProxy = settings.getBoolean(Settings.KEYS.ANALYZER_ARTIFACTORY_USES_PROXY, true); + LOGGER.debug("Using default non-legacy proxy configuration"); } - objectReader = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).readerFor(FileImpl.class); } /** @@ -137,50 +112,25 @@ public List search(Dependency dependency) throws IOException { final String sha1sum = dependency.getSha1sum(); final URL url = buildUrl(sha1sum); - final HttpURLConnection conn = connect(url); - final int responseCode = conn.getResponseCode(); - if (responseCode == 200) { - return processResponse(dependency, conn); - } - throw new IOException("Could not connect to Artifactory " + url + " (" + responseCode + "): " + conn.getResponseMessage()); - - } - - /** - * Makes an connection to the given URL. - * - * @param url the URL to connect to - * @return the HTTP URL Connection - * @throws IOException thrown if there is an error making the connection - */ - private HttpURLConnection connect(URL url) throws IOException { - LOGGER.debug("Searching Artifactory url {}", url); - - // Determine if we need to use a proxy. The rules: - // 1) If the proxy is set, AND the setting is set to true, use the proxy - // 2) Otherwise, don't use the proxy (either the proxy isn't configured, - // or proxy is specifically set to false) - final URLConnectionFactory factory = new URLConnectionFactory(settings); - final HttpURLConnection conn = factory.createHttpURLConnection(url, useProxy); - conn.setDoOutput(true); - - conn.addRequestProperty("X-Result-Detail", "info"); - - final String username = settings.getString(Settings.KEYS.ANALYZER_ARTIFACTORY_API_USERNAME); - final String apiToken = settings.getString(Settings.KEYS.ANALYZER_ARTIFACTORY_API_TOKEN); - if (username != null && apiToken != null) { - final String userpassword = username + ":" + apiToken; - final String encodedAuthorization = Base64.getEncoder().encodeToString(userpassword.getBytes(StandardCharsets.UTF_8)); - conn.addRequestProperty("Authorization", "Basic " + encodedAuthorization); - } else { - final String bearerToken = settings.getString(Settings.KEYS.ANALYZER_ARTIFACTORY_BEARER_TOKEN); - if (bearerToken != null) { - conn.addRequestProperty("Authorization", "Bearer " + bearerToken); - } + final StringBuilder msg = new StringBuilder("Could not connect to Artifactory at") + .append(url); + try { + final BasicHeader artifactoryResultDetail = new BasicHeader(X_RESULT_DETAIL_HEADER, "info"); + return Downloader.getInstance().fetchAndHandle( + url, + new ArtifactorySearchResponseHandler(url, dependency), + List.of(artifactoryResultDetail), + allowUsingProxy + ); + } catch (TooManyRequestsException e) { + throw new IOException(msg.append(" (429): Too manu requests").toString(), e); + } catch (URISyntaxException e) { + throw new IOException(msg.append(" (400): Invalid URL").toString(), e); + } catch (ResourceNotFoundException e) { + throw new IOException(msg.append(" (404): Not found").toString(), e); + } catch (ForbiddenException e) { + throw new IOException(msg.append(" (403): Forbidden").toString(), e); } - - conn.connect(); - return conn; } /** @@ -196,99 +146,6 @@ private URL buildUrl(String sha1sum) throws MalformedURLException { return new URL(rootURL + "/api/search/checksum?sha1=" + sha1sum); } - /** - * Process the Artifactory response. - * - * @param dependency the dependency - * @param conn the HTTP URL Connection - * @return a list of the Maven Artifact information - * @throws IOException thrown if there is an I/O error - */ - protected List processResponse(Dependency dependency, HttpURLConnection conn) throws IOException { - final List result = new ArrayList<>(); - - try (InputStreamReader streamReader = new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8); - JsonParser parser = objectReader.getFactory().createParser(streamReader)) { - - if (init(parser) && parser.nextToken() == com.fasterxml.jackson.core.JsonToken.START_OBJECT) { - // at least one result - do { - final FileImpl file = objectReader.readValue(parser); - - checkHashes(dependency, file.getChecksums()); - - final Matcher pathMatcher = PATH_PATTERN.matcher(file.getPath()); - if (!pathMatcher.matches()) { - throw new IllegalStateException("Cannot extract the Maven information from the path " - + "retrieved in Artifactory " + file.getPath()); - } - - final String groupId = pathMatcher.group("groupId").replace('/', '.'); - final String artifactId = pathMatcher.group("artifactId"); - final String version = pathMatcher.group("version"); - - result.add(new MavenArtifact(groupId, artifactId, version, file.getDownloadUri(), - MavenArtifact.derivePomUrl(artifactId, version, file.getDownloadUri()))); - - } while (parser.nextToken() == com.fasterxml.jackson.core.JsonToken.START_OBJECT); - } else { - throw new FileNotFoundException("Artifact " + dependency + " not found in Artifactory"); - } - } - - return result; - } - - protected boolean init(JsonParser parser) throws IOException { - com.fasterxml.jackson.core.JsonToken nextToken = parser.nextToken(); - if (nextToken != com.fasterxml.jackson.core.JsonToken.START_OBJECT) { - throw new IOException("Expected " + com.fasterxml.jackson.core.JsonToken.START_OBJECT + ", got " + nextToken); - } - - do { - nextToken = parser.nextToken(); - if (nextToken == null) { - break; - } - - if (nextToken.isStructStart()) { - if (nextToken == com.fasterxml.jackson.core.JsonToken.START_ARRAY && "results".equals(parser.currentName())) { - return true; - } else { - parser.skipChildren(); - } - } - } while (true); - - return false; - } - - /** - * Validates the hashes of the dependency. - * - * @param dependency the dependency - * @param checksums the collection of checksums (md5, sha1, sha256) - * @throws FileNotFoundException thrown if one of the checksums does not - * match - */ - private void checkHashes(Dependency dependency, ChecksumsImpl checksums) throws FileNotFoundException { - final String md5sum = dependency.getMd5sum(); - if (!checksums.getMd5().equals(md5sum)) { - throw new FileNotFoundException("Artifact found by API is not matching the md5 " - + "of the artifact (repository hash is " + checksums.getMd5() + WHILE_ACTUAL_IS + md5sum + ") !"); - } - final String sha1sum = dependency.getSha1sum(); - if (!checksums.getSha1().equals(sha1sum)) { - throw new FileNotFoundException("Artifact found by API is not matching the SHA1 " - + "of the artifact (repository hash is " + checksums.getSha1() + WHILE_ACTUAL_IS + sha1sum + ") !"); - } - final String sha256sum = dependency.getSha256sum(); - if (checksums.getSha256() != null && !checksums.getSha256().equals(sha256sum)) { - throw new FileNotFoundException("Artifact found by API is not matching the SHA-256 " - + "of the artifact (repository hash is " + checksums.getSha256() + WHILE_ACTUAL_IS + sha256sum + ") !"); - } - } - /** * Performs a pre-flight request to ensure the Artifactory service is * reachable. @@ -297,17 +154,20 @@ private void checkHashes(Dependency dependency, ChecksumsImpl checksums) throws * false. */ public boolean preflightRequest() { + URL url = null; try { - final URL url = buildUrl(Checksum.getSHA1Checksum(UUID.randomUUID().toString())); - final HttpURLConnection connection = connect(url); - if (connection.getResponseCode() != 200) { - LOGGER.warn("Expected 200 result from Artifactory ({}), got {}", url, connection.getResponseCode()); - return false; - } + url = buildUrl(Checksum.getSHA1Checksum(UUID.randomUUID().toString())); + Downloader.getInstance().fetchContent(url, StandardCharsets.UTF_8); return true; } catch (IOException e) { LOGGER.error("Cannot connect to Artifactory", e); return false; + } catch (TooManyRequestsException e) { + LOGGER.warn("Expected 200 result from Artifactory ({}), got 429", url); + return false; + } catch (ResourceNotFoundException e) { + LOGGER.warn("Expected 200 result from Artifactory ({}), got 404", url); + return false; } } diff --git a/core/src/main/java/org/owasp/dependencycheck/data/artifactory/ArtifactorySearchResponseHandler.java b/core/src/main/java/org/owasp/dependencycheck/data/artifactory/ArtifactorySearchResponseHandler.java new file mode 100644 index 00000000000..711bfc657e0 --- /dev/null +++ b/core/src/main/java/org/owasp/dependencycheck/data/artifactory/ArtifactorySearchResponseHandler.java @@ -0,0 +1,219 @@ +/* + * This file is part of dependency-check-core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2018 - 2024 Nicolas Henneaux; Hans Aikema. All Rights Reserved. + */ +package org.owasp.dependencycheck.data.artifactory; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectReader; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.io.HttpClientResponseHandler; +import org.owasp.dependencycheck.data.nexus.MavenArtifact; +import org.owasp.dependencycheck.dependency.Dependency; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static org.owasp.dependencycheck.data.artifactory.ArtifactorySearch.X_RESULT_DETAIL_HEADER; + +class ArtifactorySearchResponseHandler implements HttpClientResponseHandler> { + /** + * Pattern to match the path returned by the Artifactory AQL API. + */ + private static final Pattern PATH_PATTERN = Pattern.compile("^/(?.+)/(?[^/]+)/(?[^/]+)/[^/]+$"); + + /** + * Used for logging. + */ + private static final Logger LOGGER = LoggerFactory.getLogger(ArtifactorySearchResponseHandler.class); + + /** + * Search result reader + */ + private final ObjectReader fileImplReader; + + /** + * The dependency that is expected to be in the response from Artifactory (if found) + */ + private final Dependency expectedDependency; + + /** + * The search request URL i.e., the location at which to search artifacts with checksum information + */ + private final URL sourceUrl; + + /** + * Creates a response handler for the response on a single dependency-search attempt. + * + * @param sourceUrl The search request URL + * @param dependency The dependency that is expected to be in the response when found (for validating the FileItem(s) in the response) + */ + ArtifactorySearchResponseHandler(URL sourceUrl, Dependency dependency) { + this.fileImplReader = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).readerFor(FileImpl.class); + this.expectedDependency = dependency; + this.sourceUrl = sourceUrl; + } + + protected boolean init(JsonParser parser) throws IOException { + com.fasterxml.jackson.core.JsonToken nextToken = parser.nextToken(); + if (nextToken != com.fasterxml.jackson.core.JsonToken.START_OBJECT) { + throw new IOException("Expected " + com.fasterxml.jackson.core.JsonToken.START_OBJECT + ", got " + nextToken); + } + + do { + nextToken = parser.nextToken(); + if (nextToken == null) { + break; + } + + if (nextToken.isStructStart()) { + if (nextToken == com.fasterxml.jackson.core.JsonToken.START_ARRAY && "results".equals(parser.currentName())) { + return true; + } else { + parser.skipChildren(); + } + } + } while (true); + + return false; + } + + /** + * Validates the hashes of the dependency. + * + * @param checksums the collection of checksums (md5, sha1, [sha256]) + * @return Whether all available hashes match + */ + private boolean checkHashes(ChecksumsImpl checksums) { + final String md5sum = expectedDependency.getMd5sum(); + final String hashMismatchFormat = "Artifact found by API is not matching the {} of the artifact (repository hash is {} while actual is {}) !"; + boolean match = true; + if (!checksums.getMd5().equals(md5sum)) { + LOGGER.warn(hashMismatchFormat, "md5", md5sum, checksums.getMd5()); + match = false; + } + final String sha1sum = expectedDependency.getSha1sum(); + if (!checksums.getSha1().equals(sha1sum)) { + LOGGER.warn(hashMismatchFormat, "sha1", sha1sum, checksums.getSha1()); + match = false; + } + final String sha256sum = expectedDependency.getSha256sum(); + /* For SHA-256, we need to validate that the checksum is non-null in the artifactory response. + * Extract from Artifactory documentation: + * New artifacts that are uploaded to Artifactory 5.5 and later will automatically have their SHA-256 checksum calculated. + * However, artifacts that were already hosted in Artifactory before the upgrade will not have their SHA-256 checksum in the database yet. + * To make full use of Artifactory's SHA-256 capabilities, you need to Migrate the Database to Include SHA-256 making sure that the record + * for each artifact includes its SHA-256 checksum. + */ + if (checksums.getSha256() != null && !checksums.getSha256().equals(sha256sum)) { + LOGGER.warn(hashMismatchFormat, "sha256", sha256sum, checksums.getSha256()); + match = false; + } + return match; + } + + /** + * Process the Artifactory response. + * + * @param response the HTTP response + * @return a list of the Maven Artifact information that matches the searched dependency hash + * @throws FileNotFoundException When a matching artifact is not found + * @throws IOException thrown if there is an I/O error + */ + @Override + public List handleResponse(ClassicHttpResponse response) throws IOException { + final List result = new ArrayList<>(); + + try (InputStreamReader streamReader = new InputStreamReader(response.getEntity().getContent(), StandardCharsets.UTF_8); + JsonParser parser = fileImplReader.getFactory().createParser(streamReader)) { + + if (init(parser) && parser.nextToken() == JsonToken.START_OBJECT) { + // at least one result + do { + final FileImpl file = fileImplReader.readValue(parser); + + if (file.getChecksums() == null) { + LOGGER.warn( + "No checksums found in Artifactory search result for '{}'. " + + "Specifically, the result set contains URI '{}' but it is missing the 'checksums' property. " + + "Please make sure that the '{}' header is retained on any (reverse-)proxy, load-balancer or Web Application Firewall in the network path to your Artifactory server.", + sourceUrl, file.getUri(), X_RESULT_DETAIL_HEADER); + continue; + } + + final Optional validationResult = validateUsability(file); + if (validationResult.isEmpty()) { + continue; + } + final Matcher pathMatcher = validationResult.get(); + + final String groupId = pathMatcher.group("groupId").replace('/', '.'); + final String artifactId = pathMatcher.group("artifactId"); + final String version = pathMatcher.group("version"); + + result.add(new MavenArtifact(groupId, artifactId, version, file.getDownloadUri(), + MavenArtifact.derivePomUrl(artifactId, version, file.getDownloadUri()))); + + } while (parser.nextToken() == JsonToken.START_OBJECT); + } else { + throw new FileNotFoundException("Artifact " + expectedDependency + " not found in Artifactory"); + } + } + if (result.isEmpty()) { + throw new FileNotFoundException("Artifact " + expectedDependency + + " not found in Artifactory; discovered SHA1 hits not recognized as matching Maven artifacts"); + } + return result; + } + + /** + * Validate the FileImpl result for usability as a dependency. + *
+ * Checks that the file actually matches all known hashes and the path appears to match a maven repository G/A/V pattern. + * + * @param file The FileImpl from an Artifactory search response + * @return An Optional with the Matcher for the file path to retrieve the Maven G/A/V coordinates in case the result is usable for further + * processing, otherwise an empty Optional. + */ + private Optional validateUsability(FileImpl file) { + final Optional result; + if (!checkHashes(file.getChecksums())) { + result = Optional.empty(); + } else { + final Matcher pathMatcher = PATH_PATTERN.matcher(file.getPath()); + if (!pathMatcher.matches()) { + LOGGER.debug("Cannot extract the Maven information from the path retrieved in Artifactory {}", file.getPath()); + result = Optional.empty(); + } else { + result = Optional.of(pathMatcher); + } + } + return result; + } +} diff --git a/core/src/main/java/org/owasp/dependencycheck/data/cache/DataCache.java b/core/src/main/java/org/owasp/dependencycheck/data/cache/DataCache.java index 9a86e1e74e5..d82f8482d42 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/cache/DataCache.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/cache/DataCache.java @@ -17,7 +17,7 @@ */ package org.owasp.dependencycheck.data.cache; -import org.apache.commons.jcs.access.CacheAccess; +import org.apache.commons.jcs3.access.CacheAccess; /** * A generic wrapper for the Java Caching System (JCS). diff --git a/core/src/main/java/org/owasp/dependencycheck/data/cache/DataCacheFactory.java b/core/src/main/java/org/owasp/dependencycheck/data/cache/DataCacheFactory.java index a0c63862f75..b5e8f6b8ddc 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/cache/DataCacheFactory.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/cache/DataCacheFactory.java @@ -22,11 +22,11 @@ import java.io.InputStream; import java.util.List; import java.util.Properties; -import org.apache.commons.jcs.JCS; -import org.apache.commons.jcs.access.CacheAccess; -import org.apache.commons.jcs.access.exception.CacheException; -import org.apache.commons.jcs.engine.CompositeCacheAttributes; -import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes; +import org.apache.commons.jcs3.JCS; +import org.apache.commons.jcs3.access.CacheAccess; +import org.apache.commons.jcs3.access.exception.CacheException; +import org.apache.commons.jcs3.engine.CompositeCacheAttributes; +import org.apache.commons.jcs3.engine.behavior.ICompositeCacheAttributes; import org.owasp.dependencycheck.data.nexus.MavenArtifact; import org.owasp.dependencycheck.data.nodeaudit.Advisory; import org.owasp.dependencycheck.utils.FileUtils; diff --git a/core/src/main/java/org/owasp/dependencycheck/data/central/CentralSearch.java b/core/src/main/java/org/owasp/dependencycheck/data/central/CentralSearch.java index 2ad37f41906..3ee1135a1ec 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/central/CentralSearch.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/central/CentralSearch.java @@ -17,34 +17,35 @@ */ package org.owasp.dependencycheck.data.central; +import org.apache.hc.client5.http.impl.classic.AbstractHttpClientResponseHandler; +import org.apache.hc.core5.http.message.BasicHeader; +import org.owasp.dependencycheck.utils.DownloadFailedException; +import org.owasp.dependencycheck.utils.Downloader; +import org.owasp.dependencycheck.utils.ForbiddenException; +import org.owasp.dependencycheck.utils.ResourceNotFoundException; import org.owasp.dependencycheck.utils.TooManyRequestsException; import java.io.FileNotFoundException; import java.io.IOException; -import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.List; import javax.annotation.concurrent.ThreadSafe; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; -import org.apache.commons.jcs.access.exception.CacheException; +import org.apache.commons.jcs3.access.exception.CacheException; import org.owasp.dependencycheck.data.cache.DataCache; import org.owasp.dependencycheck.data.cache.DataCacheFactory; import org.owasp.dependencycheck.data.nexus.MavenArtifact; import org.owasp.dependencycheck.utils.Settings; -import org.owasp.dependencycheck.utils.URLConnectionFactory; -import org.owasp.dependencycheck.utils.XmlUtils; +import org.owasp.dependencycheck.utils.ToXMLDocumentResponseHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; /** * Class of methods to search Maven Central via Central. @@ -105,7 +106,7 @@ public CentralSearch(Settings settings) throws MalformedURLException { } this.query = queryStr; LOGGER.debug("Central Search Full URL: {}", String.format(query, rootURL, "[SHA1]")); - if (null != settings.getString(Settings.KEYS.PROXY_SERVER)) { + if (null != settings.getString(Settings.KEYS.PROXY_SERVER) || null != System.getProperty("https.proxyHost")) { useProxy = true; LOGGER.debug("Using proxy"); } else { @@ -135,14 +136,14 @@ public CentralSearch(Settings settings) throws MalformedURLException { * @throws TooManyRequestsException if Central has received too many * requests. */ - public List searchSha1(String sha1) throws IOException, TooManyRequestsException { + public List searchSha1(String sha1) throws IOException, TooManyRequestsException, ForbiddenException { if (null == sha1 || !sha1.matches("^[0-9A-Fa-f]{40}$")) { throw new IllegalArgumentException("Invalid SHA1 format"); } if (cache != null) { final List cached = cache.get(sha1); if (cached != null) { - LOGGER.debug("cache hit for Central: " + sha1); + LOGGER.debug("cache hit for Central: {}", sha1); if (cached.isEmpty()) { throw new FileNotFoundException("Artifact not found in Central"); } @@ -154,68 +155,13 @@ public List searchSha1(String sha1) throws IOException, TooManyRe LOGGER.trace("Searching Central url {}", url); - // Determine if we need to use a proxy. The rules: - // 1) If the proxy is set, AND the setting is set to true, use the proxy - // 2) Otherwise, don't use the proxy (either the proxy isn't configured, - // or proxy is specifically set to false) - final URLConnectionFactory factory = new URLConnectionFactory(settings); - final HttpURLConnection conn = factory.createHttpURLConnection(url, useProxy); - - conn.setDoOutput(true); - // JSON would be more elegant, but there's not currently a dependency // on JSON, so don't want to add one just for this - conn.addRequestProperty("Accept", "application/xml"); - conn.connect(); - - if (conn.getResponseCode() == 200) { - boolean missing = false; - try { - final DocumentBuilder builder = XmlUtils.buildSecureDocumentBuilder(); - final Document doc = builder.parse(conn.getInputStream()); - final XPath xpath = XPathFactory.newInstance().newXPath(); - final String numFound = xpath.evaluate("/response/result/@numFound", doc); - if ("0".equals(numFound)) { - missing = true; - } else { - final NodeList docs = (NodeList) xpath.evaluate("/response/result/doc", doc, XPathConstants.NODESET); - for (int i = 0; i < docs.getLength(); i++) { - final String g = xpath.evaluate("./str[@name='g']", docs.item(i)); - LOGGER.trace("GroupId: {}", g); - final String a = xpath.evaluate("./str[@name='a']", docs.item(i)); - LOGGER.trace("ArtifactId: {}", a); - final String v = xpath.evaluate("./str[@name='v']", docs.item(i)); - final NodeList attributes = (NodeList) xpath.evaluate("./arr[@name='ec']/str", docs.item(i), XPathConstants.NODESET); - boolean pomAvailable = false; - boolean jarAvailable = false; - for (int x = 0; x < attributes.getLength(); x++) { - final String tmp = xpath.evaluate(".", attributes.item(x)); - if (".pom".equals(tmp)) { - pomAvailable = true; - } else if (".jar".equals(tmp)) { - jarAvailable = true; - } - } - final String centralContentUrl = settings.getString(Settings.KEYS.CENTRAL_CONTENT_URL); - String artifactUrl = null; - String pomUrl = null; - if (jarAvailable) { - //org/springframework/spring-core/3.2.0.RELEASE/spring-core-3.2.0.RELEASE.pom - artifactUrl = centralContentUrl + g.replace('.', '/') + '/' + a + '/' - + v + '/' + a + '-' + v + ".jar"; - } - if (pomAvailable) { - //org/springframework/spring-core/3.2.0.RELEASE/spring-core-3.2.0.RELEASE.pom - pomUrl = centralContentUrl + g.replace('.', '/') + '/' + a + '/' - + v + '/' + a + '-' + v + ".pom"; - } - result.add(new MavenArtifact(g, a, v, artifactUrl, pomUrl)); - } - } - } catch (ParserConfigurationException | IOException | SAXException | XPathExpressionException e) { - // Anything else is jacked up XML stuff that we really can't recover from well - throw new IOException(e.getMessage(), e); - } + final BasicHeader acceptHeader = new BasicHeader("Accept", "application/xml"); + final AbstractHttpClientResponseHandler handler = new ToXMLDocumentResponseHandler(); + try { + final Document doc = Downloader.getInstance().fetchAndHandle(url, handler, List.of(acceptHeader), useProxy); + final boolean missing = addMavenArtifacts(doc, result); if (missing) { if (cache != null) { @@ -223,12 +169,21 @@ public List searchSha1(String sha1) throws IOException, TooManyRe } throw new FileNotFoundException("Artifact not found in Central"); } - } else if (conn.getResponseCode() == 429) { + } catch (XPathExpressionException e) { + final String errorMessage = "Failed to parse MavenCentral XML Response: " + e.getMessage(); + throw new IOException(errorMessage, e); + } catch (TooManyRequestsException e) { final String errorMessage = "Too many requests sent to MavenCentral; additional requests are being rejected."; - throw new TooManyRequestsException(errorMessage); - } else { - final String errorMessage = "Could not connect to MavenCentral (" + conn.getResponseCode() + "): " + conn.getResponseMessage(); - throw new IOException(errorMessage); + throw new TooManyRequestsException(errorMessage, e); + } catch (ResourceNotFoundException | DownloadFailedException e) { + final String errorMessage = "Could not connect to MavenCentral " + e.getMessage(); + throw new IOException(errorMessage, e); + } catch (URISyntaxException e) { + final String errorMessage = "Could not convert central search URL to a URI " + e.getMessage(); + throw new IOException(errorMessage, e); + } catch (ForbiddenException e) { + final String errorMessage = "Forbidden access to MavenCentral " + e.getMessage(); + throw new ForbiddenException(errorMessage, e); } if (cache != null) { cache.put(sha1, result); @@ -236,6 +191,56 @@ public List searchSha1(String sha1) throws IOException, TooManyRe return result; } + /** + * Collect the artifacts from a MavenCentral search result and add them to the list. + * @param doc The Document received in response to the SHA1 search-request + * @param result The list of MavenArtifacts to which found artifacts will be added + * @return Whether the given document holds no search results + */ + private boolean addMavenArtifacts(Document doc, List result) throws XPathExpressionException { + boolean missing = false; + final XPath xpath = XPathFactory.newInstance().newXPath(); + final String numFound = xpath.evaluate("/response/result/@numFound", doc); + if ("0".equals(numFound)) { + missing = true; + } else { + final NodeList docs = (NodeList) xpath.evaluate("/response/result/doc", doc, XPathConstants.NODESET); + for (int i = 0; i < docs.getLength(); i++) { + final String g = xpath.evaluate("./str[@name='g']", docs.item(i)); + LOGGER.trace("GroupId: {}", g); + final String a = xpath.evaluate("./str[@name='a']", docs.item(i)); + LOGGER.trace("ArtifactId: {}", a); + final String v = xpath.evaluate("./str[@name='v']", docs.item(i)); + final NodeList attributes = (NodeList) xpath.evaluate("./arr[@name='ec']/str", docs.item(i), XPathConstants.NODESET); + boolean pomAvailable = false; + boolean jarAvailable = false; + for (int x = 0; x < attributes.getLength(); x++) { + final String tmp = xpath.evaluate(".", attributes.item(x)); + if (".pom".equals(tmp)) { + pomAvailable = true; + } else if (".jar".equals(tmp)) { + jarAvailable = true; + } + } + final String centralContentUrl = settings.getString(Settings.KEYS.CENTRAL_CONTENT_URL); + String artifactUrl = null; + String pomUrl = null; + if (jarAvailable) { + //org/springframework/spring-core/3.2.0.RELEASE/spring-core-3.2.0.RELEASE.pom + artifactUrl = centralContentUrl + g.replace('.', '/') + '/' + a + '/' + + v + '/' + a + '-' + v + ".jar"; + } + if (pomAvailable) { + //org/springframework/spring-core/3.2.0.RELEASE/spring-core-3.2.0.RELEASE.pom + pomUrl = centralContentUrl + g.replace('.', '/') + '/' + a + '/' + + v + '/' + a + '-' + v + ".pom"; + } + result.add(new MavenArtifact(g, a, v, artifactUrl, pomUrl)); + } + } + return missing; + } + /** * Tests to determine if the given URL is invalid. * @@ -252,4 +257,5 @@ private boolean isInvalidURL(String url) { } return false; } + } diff --git a/core/src/main/java/org/owasp/dependencycheck/data/composer/ComposerLockParser.java b/core/src/main/java/org/owasp/dependencycheck/data/composer/ComposerLockParser.java index e3b4bae65f5..2155b30fcef 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/composer/ComposerLockParser.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/composer/ComposerLockParser.java @@ -20,19 +20,20 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.json.Json; -import javax.json.JsonArray; -import javax.json.JsonException; -import javax.json.JsonObject; -import javax.json.JsonReader; -import javax.json.stream.JsonParsingException; +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonException; +import jakarta.json.JsonObject; +import jakarta.json.JsonReader; +import jakarta.json.stream.JsonParsingException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import javax.annotation.concurrent.NotThreadSafe; /** - * Parses a Composer.lock file from an input stream. In a separate class so it can hopefully be injected. + * Parses a Composer.lock file from an input stream. In a separate class so it + * can hopefully be injected. * * @author colezlaw */ @@ -43,12 +44,14 @@ public class ComposerLockParser { * The JsonReader for parsing JSON */ private final JsonReader jsonReader; - /** * The List of ComposerDependencies found */ private final List composerDependencies; - + /** + * Whether to skip dev dependencies. + */ + private final boolean skipDev; /** * The LOGGER */ @@ -58,11 +61,13 @@ public class ComposerLockParser { * Creates a ComposerLockParser from a JsonReader and an InputStream. * * @param inputStream the InputStream to parse + * @param skipDev whether to skip dev dependencies */ - public ComposerLockParser(InputStream inputStream) { + public ComposerLockParser(InputStream inputStream, boolean skipDev) { LOGGER.debug("Creating a ComposerLockParser"); this.jsonReader = Json.createReader(inputStream); this.composerDependencies = new ArrayList<>(); + this.skipDev = skipDev; } /** @@ -76,26 +81,14 @@ public void process() { LOGGER.debug("Found packages"); final JsonArray packages = composer.getJsonArray("packages"); for (JsonObject pkg : packages.getValuesAs(JsonObject.class)) { - if (pkg.containsKey("name")) { - final String groupName = pkg.getString("name"); - if (groupName.indexOf('/') >= 0 && groupName.indexOf('/') <= groupName.length() - 1) { - if (pkg.containsKey("version")) { - final String group = groupName.substring(0, groupName.indexOf('/')); - final String project = groupName.substring(groupName.indexOf('/') + 1); - String version = pkg.getString("version"); - // Some version numbers begin with v - which doesn't end up matching CPE's - if (version.startsWith("v")) { - version = version.substring(1); - } - LOGGER.debug("Got package {}/{}/{}", group, project, version); - composerDependencies.add(new ComposerDependency(group, project, version)); - } else { - LOGGER.debug("Group/package {} does not have a version", groupName); - } - } else { - LOGGER.debug("Got a dependency with no name"); - } - } + processPackageEntry(pkg); + } + } + if (composer.containsKey("packages-dev") && !skipDev) { + LOGGER.debug("Found packages-dev"); + final JsonArray devPackages = composer.getJsonArray("packages-dev"); + for (JsonObject pkg : devPackages.getValuesAs(JsonObject.class)) { + processPackageEntry(pkg); } } } catch (JsonParsingException jsonpe) { @@ -109,6 +102,29 @@ public void process() { } } + protected void processPackageEntry(JsonObject pkg) { + if (pkg.containsKey("name")) { + final String groupName = pkg.getString("name"); + if (groupName.indexOf('/') >= 0 && groupName.indexOf('/') <= groupName.length() - 1) { + if (pkg.containsKey("version")) { + final String group = groupName.substring(0, groupName.indexOf('/')); + final String project = groupName.substring(groupName.indexOf('/') + 1); + String version = pkg.getString("version"); + // Some version numbers begin with v - which doesn't end up matching CPE's + if (version.startsWith("v")) { + version = version.substring(1); + } + LOGGER.debug("Got package {}/{}/{}", group, project, version); + composerDependencies.add(new ComposerDependency(group, project, version)); + } else { + LOGGER.debug("Group/package {} does not have a version", groupName); + } + } else { + LOGGER.debug("Got a dependency with no name"); + } + } + } + /** * Gets the list of dependencies. * diff --git a/core/src/main/java/org/owasp/dependencycheck/data/cpe/AbstractMemoryIndex.java b/core/src/main/java/org/owasp/dependencycheck/data/cpe/AbstractMemoryIndex.java index d3613a73c8c..5f1b35c5fff 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/cpe/AbstractMemoryIndex.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/cpe/AbstractMemoryIndex.java @@ -50,6 +50,7 @@ import org.owasp.dependencycheck.utils.Settings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.slf4j.bridge.SLF4JBridgeHandler; /** *

@@ -67,6 +68,12 @@ @ThreadSafe public abstract class AbstractMemoryIndex implements MemoryIndex { + static { + // Ensure Lucene uses SLF4J for logging + SLF4JBridgeHandler.removeHandlersForRootLogger(); + SLF4JBridgeHandler.install(); + } + /** * The logger. */ diff --git a/core/src/main/java/org/owasp/dependencycheck/data/elixir/MixAuditJsonParser.java b/core/src/main/java/org/owasp/dependencycheck/data/elixir/MixAuditJsonParser.java index c6c85dab80f..3832cf0d82e 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/elixir/MixAuditJsonParser.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/elixir/MixAuditJsonParser.java @@ -23,16 +23,16 @@ import javax.annotation.concurrent.NotThreadSafe; -import javax.json.stream.JsonParsingException; +import jakarta.json.stream.JsonParsingException; import java.io.Reader; import java.util.ArrayList; import java.util.List; -import javax.json.Json; -import javax.json.JsonArray; -import javax.json.JsonException; -import javax.json.JsonObject; -import javax.json.JsonReader; -import javax.json.JsonString; +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonException; +import jakarta.json.JsonObject; +import jakarta.json.JsonReader; +import jakarta.json.JsonString; /** * Parses json output from `mix_audit --format json`. diff --git a/core/src/main/java/org/owasp/dependencycheck/data/golang/GoModDependency.java b/core/src/main/java/org/owasp/dependencycheck/data/golang/GoModDependency.java index 9975329210d..4fa77a00cef 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/golang/GoModDependency.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/golang/GoModDependency.java @@ -19,13 +19,6 @@ import com.github.packageurl.MalformedPackageURLException; import com.github.packageurl.PackageURLBuilder; -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Dependency; @@ -33,12 +26,20 @@ import org.owasp.dependencycheck.dependency.naming.GenericIdentifier; import org.owasp.dependencycheck.dependency.naming.Identifier; import org.owasp.dependencycheck.dependency.naming.PurlIdentifier; +import org.owasp.dependencycheck.utils.Checksum; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + import static org.owasp.dependencycheck.analyzer.GolangModAnalyzer.DEPENDENCY_ECOSYSTEM; import static org.owasp.dependencycheck.analyzer.GolangModAnalyzer.GO_MOD; -import org.owasp.dependencycheck.utils.Checksum; /** * Represents a Go module dependency. @@ -185,7 +186,6 @@ private Dependency createDependency(Dependency parentDependency, String name, St * Extracts the content of the license file into the dependency's license * field. * - * * @param dependency the dependency being analyzed * @param file the license file */ @@ -195,7 +195,7 @@ private void extractLicense(Dependency dependency, File file) { for (File f : files) { if (LICENSE_FILES.contains(f.getName().toUpperCase())) { try { - final String license = FileUtils.readFileToString(f, StandardCharsets.UTF_8); + final String license = new String(Files.readAllBytes(f.toPath()), StandardCharsets.UTF_8); dependency.setLicense(license); break; } catch (IOException ex) { diff --git a/core/src/main/java/org/owasp/dependencycheck/data/golang/GoModJsonParser.java b/core/src/main/java/org/owasp/dependencycheck/data/golang/GoModJsonParser.java index 17d9d9d1a40..7f683295cea 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/golang/GoModJsonParser.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/golang/GoModJsonParser.java @@ -23,13 +23,13 @@ import java.util.List; import javax.annotation.concurrent.ThreadSafe; -import javax.json.Json; -import javax.json.JsonArray; -import javax.json.JsonException; -import javax.json.JsonObject; -import javax.json.JsonReader; -import javax.json.JsonReaderFactory; -import javax.json.stream.JsonParsingException; +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonException; +import jakarta.json.JsonObject; +import jakarta.json.JsonReader; +import jakarta.json.JsonReaderFactory; +import jakarta.json.stream.JsonParsingException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/core/src/main/java/org/owasp/dependencycheck/data/lucene/AlphaNumericFilter.java b/core/src/main/java/org/owasp/dependencycheck/data/lucene/AlphaNumericFilter.java index ae0e8862dea..aa5b326248c 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/lucene/AlphaNumericFilter.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/lucene/AlphaNumericFilter.java @@ -28,9 +28,10 @@ /** * A simple alphanumeric filter that removes non-alphanumeric characters from * the terms. If a term contains a non-alphanumeric character it may be split - * into multiple terms: + * into multiple terms. * - * + *
+ * * * * diff --git a/core/src/main/java/org/owasp/dependencycheck/data/nexus/NexusSearch.java b/core/src/main/java/org/owasp/dependencycheck/data/nexus/NexusSearch.java index 4670966fe19..264d0a84c09 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/nexus/NexusSearch.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/nexus/NexusSearch.java @@ -13,76 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright (c) 2014 Jeremy Long. All Rights Reserved. + * Copyright (c) 2023 Jeremy Long. All Rights Reserved. */ package org.owasp.dependencycheck.data.nexus; -import java.io.FileNotFoundException; import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.Base64; -import javax.annotation.concurrent.ThreadSafe; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; -import org.owasp.dependencycheck.utils.Settings; - -import org.owasp.dependencycheck.utils.URLConnectionFactory; -import org.owasp.dependencycheck.utils.XmlUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Document; -import org.xml.sax.SAXException; - -/** - * Class of methods to search Nexus repositories. - * - * @author colezlaw - */ -@ThreadSafe -public class NexusSearch { - - /** - * The root URL for the Nexus repository service. - */ - private final URL rootURL; - - /** - * Whether to use the Proxy when making requests. - */ - private final boolean useProxy; - /** - * The configured settings. - */ - private final Settings settings; - /** - * Used for logging. - */ - private static final Logger LOGGER = LoggerFactory.getLogger(NexusSearch.class); - - /** - * Creates a NexusSearch for the given repository URL. - * - * @param settings the configured settings - * @param useProxy flag indicating if the proxy settings should be used - * @throws java.net.MalformedURLException thrown if the configured URL is - * invalid - */ - public NexusSearch(Settings settings, boolean useProxy) throws MalformedURLException { - this.settings = settings; - this.useProxy = useProxy; - - final String searchUrl = settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL); - LOGGER.debug("Nexus Search URL: {}", searchUrl); - this.rootURL = new URL(searchUrl); - - } +public interface NexusSearch { /** * Searches the configured Nexus repository for the given sha1 hash. If the * artifact is found, a MavenArtifact is populated with the @@ -91,135 +28,14 @@ public NexusSearch(Settings settings, boolean useProxy) throws MalformedURLExcep * @param sha1 The SHA-1 hash string for which to search * @return the populated Maven coordinates * @throws IOException if it's unable to connect to the specified repository - * or if the specified artifact is not found. + * or if the specified artifact is not found. */ - public MavenArtifact searchSha1(String sha1) throws IOException { - if (null == sha1 || !sha1.matches("^[0-9A-Fa-f]{40}$")) { - throw new IllegalArgumentException("Invalid SHA1 format"); - } - - final URL url = new URL(rootURL, String.format("identify/sha1/%s", - sha1.toLowerCase())); - - LOGGER.debug("Searching Nexus url {}", url); - - // Determine if we need to use a proxy. The rules: - // 1) If the proxy is set, AND the setting is set to true, use the proxy - // 2) Otherwise, don't use the proxy (either the proxy isn't configured, - // or proxy is specifically set to false - final HttpURLConnection conn; - final URLConnectionFactory factory = new URLConnectionFactory(settings); - conn = factory.createHttpURLConnection(url, useProxy); - conn.setDoOutput(true); - final String authHeader = buildHttpAuthHeaderValue(); - if (!authHeader.isEmpty()) { - conn.addRequestProperty("Authorization", authHeader); - } - - // JSON would be more elegant, but there's not currently a dependency - // on JSON, so don't want to add one just for this - conn.addRequestProperty("Accept", "application/xml"); - conn.connect(); - - switch (conn.getResponseCode()) { - case 200: - try { - final DocumentBuilder builder = XmlUtils.buildSecureDocumentBuilder(); - final Document doc = builder.parse(conn.getInputStream()); - final XPath xpath = XPathFactory.newInstance().newXPath(); - final String groupId = xpath - .evaluate( - "/org.sonatype.nexus.rest.model.NexusArtifact/groupId", - doc); - final String artifactId = xpath.evaluate( - "/org.sonatype.nexus.rest.model.NexusArtifact/artifactId", - doc); - final String version = xpath - .evaluate( - "/org.sonatype.nexus.rest.model.NexusArtifact/version", - doc); - final String link = xpath - .evaluate( - "/org.sonatype.nexus.rest.model.NexusArtifact/artifactLink", - doc); - final String pomLink = xpath - .evaluate( - "/org.sonatype.nexus.rest.model.NexusArtifact/pomLink", - doc); - final MavenArtifact ma = new MavenArtifact(groupId, artifactId, version); - if (link != null && !link.isEmpty()) { - ma.setArtifactUrl(link); - } - if (pomLink != null && !pomLink.isEmpty()) { - ma.setPomUrl(pomLink); - } - return ma; - } catch (ParserConfigurationException | IOException | SAXException | XPathExpressionException e) { - // Anything else is jacked-up XML stuff that we really can't recover - // from well - throw new IOException(e.getMessage(), e); - } - case 404: - throw new FileNotFoundException("Artifact not found in Nexus"); - default: - LOGGER.debug("Could not connect to Nexus received response code: {} {}", - conn.getResponseCode(), conn.getResponseMessage()); - throw new IOException("Could not connect to Nexus"); - } - } + MavenArtifact searchSha1(String sha1) throws IOException; /** * Do a preflight request to see if the repository is actually working. * - * @return whether the repository is listening and returns the /status URL - * correctly - */ - public boolean preflightRequest() { - final HttpURLConnection conn; - try { - final URL url = new URL(rootURL, "status"); - final URLConnectionFactory factory = new URLConnectionFactory(settings); - conn = factory.createHttpURLConnection(url, useProxy); - conn.addRequestProperty("Accept", "application/xml"); - final String authHeader = buildHttpAuthHeaderValue(); - if (!authHeader.isEmpty()) { - conn.addRequestProperty("Authorization", authHeader); - } - conn.connect(); - if (conn.getResponseCode() != 200) { - LOGGER.warn("Expected 200 result from Nexus, got {}", conn.getResponseCode()); - return false; - } - final DocumentBuilder builder = XmlUtils.buildSecureDocumentBuilder(); - - final Document doc = builder.parse(conn.getInputStream()); - if (!"status".equals(doc.getDocumentElement().getNodeName())) { - LOGGER.warn("Expected root node name of status, got {}", doc.getDocumentElement().getNodeName()); - return false; - } - } catch (IOException | ParserConfigurationException | SAXException e) { - LOGGER.warn("Pre-flight request to Nexus failed: ", e); - return false; - } - return true; - } - - /** - * Constructs the base64 encoded basic authentication header value. - * - * @return the base64 encoded basic authentication header value + * @return whether the repository is listening and returns the expected status response */ - private String buildHttpAuthHeaderValue() { - final String user = settings.getString(Settings.KEYS.ANALYZER_NEXUS_USER, ""); - final String pass = settings.getString(Settings.KEYS.ANALYZER_NEXUS_PASSWORD, ""); - String result = ""; - if (user.isEmpty() || pass.isEmpty()) { - LOGGER.debug("Skip authentication as user and/or password for nexus is empty"); - } else { - final String auth = user + ':' + pass; - final String base64Auth = Base64.getEncoder().encodeToString(auth.getBytes(StandardCharsets.UTF_8)); - result = "Basic " + base64Auth; - } - return result; - } + boolean preflightRequest(); } diff --git a/core/src/main/java/org/owasp/dependencycheck/data/nexus/NexusV2Search.java b/core/src/main/java/org/owasp/dependencycheck/data/nexus/NexusV2Search.java new file mode 100644 index 00000000000..9e2401fc3e8 --- /dev/null +++ b/core/src/main/java/org/owasp/dependencycheck/data/nexus/NexusV2Search.java @@ -0,0 +1,174 @@ +/* + * This file is part of dependency-check-core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2014 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.data.nexus; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.List; +import javax.annotation.concurrent.ThreadSafe; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; + +import org.apache.hc.client5.http.HttpResponseException; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpHeaders; +import org.apache.hc.core5.http.message.BasicHeader; +import org.owasp.dependencycheck.utils.DownloadFailedException; +import org.owasp.dependencycheck.utils.Downloader; +import org.owasp.dependencycheck.utils.ForbiddenException; +import org.owasp.dependencycheck.utils.ResourceNotFoundException; +import org.owasp.dependencycheck.utils.Settings; + +import org.owasp.dependencycheck.utils.ToXMLDocumentResponseHandler; +import org.owasp.dependencycheck.utils.TooManyRequestsException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; + +/** + * Class of methods to search Nexus repositories. + * + * @author colezlaw + */ +@ThreadSafe +public class NexusV2Search implements NexusSearch { + + /** + * The root URL for the Nexus repository service. + */ + private final URL rootURL; + + /** + * Whether to use the Proxy when making requests. + */ + private final boolean useProxy; + /** + * The configured settings. + */ + private final Settings settings; + /** + * Used for logging. + */ + private static final Logger LOGGER = LoggerFactory.getLogger(NexusV2Search.class); + + /** + * Creates a NexusSearch for the given repository URL. + * + * @param settings the configured settings + * @param useProxy flag indicating if the proxy settings should be used + * @throws java.net.MalformedURLException thrown if the configured URL is + * invalid + */ + public NexusV2Search(Settings settings, boolean useProxy) throws MalformedURLException { + this.settings = settings; + this.useProxy = useProxy; + + final String searchUrl = settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL); + LOGGER.debug("Nexus Search URL: {}", searchUrl); + this.rootURL = new URL(searchUrl); + + } + + @Override + public MavenArtifact searchSha1(String sha1) throws IOException { + if (null == sha1 || !sha1.matches("^[0-9A-Fa-f]{40}$")) { + throw new IllegalArgumentException("Invalid SHA1 format"); + } + + final URL url = new URL(rootURL, String.format("identify/sha1/%s", + sha1.toLowerCase())); + + LOGGER.debug("Searching Nexus url {}", url); + + try { + // JSON would be more elegant, but there's not currently a dependency + // on JSON, so don't want to add one just for this + final ToXMLDocumentResponseHandler handler = new ToXMLDocumentResponseHandler(); + final Document doc = Downloader.getInstance().fetchAndHandle(url, handler, List.of(new BasicHeader(HttpHeaders.ACCEPT, + ContentType.APPLICATION_XML))); + final XPath xpath = XPathFactory.newInstance().newXPath(); + final String groupId = xpath + .evaluate( + "/org.sonatype.nexus.rest.model.NexusArtifact/groupId", + doc); + final String artifactId = xpath.evaluate( + "/org.sonatype.nexus.rest.model.NexusArtifact/artifactId", + doc); + final String version = xpath + .evaluate( + "/org.sonatype.nexus.rest.model.NexusArtifact/version", + doc); + final String link = xpath + .evaluate( + "/org.sonatype.nexus.rest.model.NexusArtifact/artifactLink", + doc); + final String pomLink = xpath + .evaluate( + "/org.sonatype.nexus.rest.model.NexusArtifact/pomLink", + doc); + final MavenArtifact ma = new MavenArtifact(groupId, artifactId, version); + if (link != null && !link.isEmpty()) { + ma.setArtifactUrl(link); + } + if (pomLink != null && !pomLink.isEmpty()) { + ma.setPomUrl(pomLink); + } + return ma; + } catch (DownloadFailedException | TooManyRequestsException e) { + if (LOGGER.isDebugEnabled()) { + int responseCode = -1; + String responseMessage = ""; + if (e.getCause() instanceof HttpResponseException) { + final HttpResponseException cause = (HttpResponseException) e.getCause(); + responseCode = cause.getStatusCode(); + responseMessage = cause.getReasonPhrase(); + } + LOGGER.debug("Could not connect to Nexus received response code: {} {}", + responseCode, responseMessage); + } + throw new IOException("Could not connect to Nexus"); + } catch (ResourceNotFoundException e) { + throw new FileNotFoundException("Artifact not found in Nexus"); + } catch (XPathExpressionException | URISyntaxException | ForbiddenException e) { + throw new IOException(e.getMessage(), e); + } + } + + @Override + public boolean preflightRequest() { + try { + final URL url = new URL(rootURL, "status"); + final ToXMLDocumentResponseHandler handler = new ToXMLDocumentResponseHandler(); + final Document doc = Downloader.getInstance().fetchAndHandle(url, handler, List.of(new BasicHeader(HttpHeaders.ACCEPT, + ContentType.APPLICATION_XML))); + if (!"status".equals(doc.getDocumentElement().getNodeName())) { + LOGGER.warn("Pre-flight request to Nexus failed; expected root node name of status, got {}", doc.getDocumentElement().getNodeName()); + return false; + } + } catch (IOException | TooManyRequestsException | ResourceNotFoundException | URISyntaxException e) { + LOGGER.warn("Pre-flight request to Nexus failed: ", e); + return false; + } + return true; + } + +} diff --git a/core/src/main/java/org/owasp/dependencycheck/data/nexus/NexusV3Search.java b/core/src/main/java/org/owasp/dependencycheck/data/nexus/NexusV3Search.java new file mode 100644 index 00000000000..8bb31bc7573 --- /dev/null +++ b/core/src/main/java/org/owasp/dependencycheck/data/nexus/NexusV3Search.java @@ -0,0 +1,287 @@ +/* + * This file is part of dependency-check-core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2023 Hans Aikema. All Rights Reserved. + */ +package org.owasp.dependencycheck.data.nexus; + +import org.apache.hc.client5.http.HttpResponseException; +import org.apache.hc.client5.http.impl.classic.AbstractHttpClientResponseHandler; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.HttpHeaders; +import org.apache.hc.core5.http.message.BasicHeader; +import org.jetbrains.annotations.Nullable; +import org.owasp.dependencycheck.utils.DownloadFailedException; +import org.owasp.dependencycheck.utils.Downloader; +import org.owasp.dependencycheck.utils.ForbiddenException; +import org.owasp.dependencycheck.utils.ResourceNotFoundException; +import org.owasp.dependencycheck.utils.Settings; +import org.owasp.dependencycheck.utils.TooManyRequestsException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.concurrent.ThreadSafe; +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.json.JsonReader; +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StringReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Class of methods to search Nexus v3 repositories. + * + * @author Hans Aikema + */ +@ThreadSafe +public class NexusV3Search implements NexusSearch { + + /** + * By default, NexusV3Search accepts only classifier-less artifacts. + *

+ * This prevents, among others, sha1-collisions for empty jars on empty javadoc/sources jars. + * See e.g. issues #5559 and #5118 + */ + private final Set acceptedClassifiers = new HashSet<>(); + + /** + * The root URL for the Nexus repository service. + */ + private final URL rootURL; + + /** + * Whether to use the Proxy when making requests. + */ + private final boolean useProxy; + /** + * The configured settings. + */ + private final Settings settings; + /** + * Used for logging. + */ + private static final Logger LOGGER = LoggerFactory.getLogger(NexusV3Search.class); + + /** + * Creates a NexusV3Search for the given repository URL. + * + * @param settings the configured settings + * @param useProxy flag indicating if the proxy settings should be used + * @throws MalformedURLException thrown if the configured URL is + * invalid + */ + public NexusV3Search(Settings settings, boolean useProxy) throws MalformedURLException { + this.settings = settings; + this.useProxy = useProxy; + this.acceptedClassifiers.add(null); + final String searchUrl = settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL); + LOGGER.debug("Nexus Search URL: {}", searchUrl); + this.rootURL = new URL(searchUrl); + + } + + @Override + public MavenArtifact searchSha1(String sha1) throws IOException { + if (null == sha1 || !sha1.matches("^[0-9A-Fa-f]{40}$")) { + throw new IllegalArgumentException("Invalid SHA1 format"); + } + + final List collectedMatchingArtifacts = new ArrayList<>(1); + try (CloseableHttpClient client = Downloader.getInstance().getHttpClient(useProxy)) { + String continuationToken = retrievePageAndAddMatchingArtifact(client, collectedMatchingArtifacts, sha1, null); + while (continuationToken != null && collectedMatchingArtifacts.isEmpty()) { + continuationToken = retrievePageAndAddMatchingArtifact(client, collectedMatchingArtifacts, sha1, continuationToken); + } + } + if (collectedMatchingArtifacts.isEmpty()) { + throw new FileNotFoundException("Artifact not found in Nexus"); + } else { + return collectedMatchingArtifacts.get(0); + } + } + + private String retrievePageAndAddMatchingArtifact(CloseableHttpClient client, List collectedMatchingArtifacts, String sha1, + @Nullable String continuationToken) throws IOException { + final URL url; + LOGGER.debug("Search with continuation token {}", continuationToken); + if (continuationToken == null) { + url = new URL(rootURL, String.format("v1/search/?sha1=%s", + sha1.toLowerCase())); + } else { + url = new URL(rootURL, String.format("v1/search/?sha1=%s&continuationToken=%s", + sha1.toLowerCase(), continuationToken)); + } + + LOGGER.debug("Searching Nexus url {}", url); + // Determine if we need to use a proxy. The rules: + // 1) If the proxy is set, AND the setting is set to true, use the proxy + // 2) Otherwise, don't use the proxy (either the proxy isn't configured, + // or proxy is specifically set to false + final NexusV3SearchResponseHandler handler = new NexusV3SearchResponseHandler(collectedMatchingArtifacts, sha1, acceptedClassifiers); + try { + return Downloader.getInstance().fetchAndHandle(client, url, handler, List.of(new BasicHeader(HttpHeaders.ACCEPT, + ContentType.APPLICATION_JSON))); + } catch (TooManyRequestsException | ResourceNotFoundException | DownloadFailedException | ForbiddenException e) { + if (LOGGER.isDebugEnabled()) { + int responseCode = -1; + String responseMessage = ""; + if (e.getCause() instanceof HttpResponseException) { + final HttpResponseException cause = (HttpResponseException) e.getCause(); + responseCode = cause.getStatusCode(); + responseMessage = cause.getReasonPhrase(); + } + LOGGER.debug("Could not connect to Nexus received response code: {} {}", + responseCode, responseMessage); + } + throw new IOException("Could not connect to Nexus", e); + } + } + + private static final class NexusV3SearchResponseHandler extends AbstractHttpClientResponseHandler { + + /** + * The list to which matching artifacts are to be added + */ + private final List matchingArtifacts; + /** + * The sha1 for which the search results are being handled + */ + private final String sha1; + /** + * The classifiers to be accepted + */ + private final Set acceptedClassifiers; + + private NexusV3SearchResponseHandler(List matchingArtifacts, String sha1, Set acceptedClassifiers) { + this.matchingArtifacts = matchingArtifacts; + this.sha1 = sha1; + this.acceptedClassifiers = acceptedClassifiers; + } + + @Override + public @Nullable String handleEntity(HttpEntity entity) throws IOException { + try (InputStream in = entity.getContent(); + InputStreamReader isReader = new InputStreamReader(in, StandardCharsets.UTF_8); + BufferedReader reader = new BufferedReader(isReader); + ) { + final String jsonString = reader.lines().collect(Collectors.joining("\n")); + LOGGER.debug("JSON String was >>>{}<<<", jsonString); + final JsonObject jsonResponse; + try ( + StringReader stringReader = new StringReader(jsonString); + JsonReader jsonReader = Json.createReader(stringReader) + ) { + jsonResponse = jsonReader.readObject(); + } + LOGGER.debug("Response: {}", jsonResponse); + final JsonArray components = jsonResponse.getJsonArray("items"); + LOGGER.debug("Items: {}", components); + final String continuationToken = jsonResponse.getString("continuationToken", null); + boolean found = false; + for (int i = 0; i < components.size() && !found; i++) { + boolean jarFound = false; + boolean pomFound = false; + String downloadUrl = null; + String groupId = null; + String artifactId = null; + String version = null; + String pomUrl = null; + + final JsonObject component = components.getJsonObject(i); + + final String format = component.getString("format", "unknown"); + if ("maven2".equals(format)) { + LOGGER.debug("Checking Maven2 artifact for {}", component); + final JsonArray assets = component.getJsonArray("assets"); + for (int j = 0; !found && j < assets.size(); j++) { + final JsonObject asset = assets.getJsonObject(j); + LOGGER.debug("Checking {}", asset); + final JsonObject checksums = asset.getJsonObject("checksum"); + final JsonObject maven2 = asset.getJsonObject("maven2"); + if (maven2 != null) { + // logical names for the jar acceptance routine + final boolean shaMatch = checksums != null && sha1.equals(checksums.getString("sha1", null)); + final boolean hasAcceptedClassifier = acceptedClassifiers.contains(maven2.getString("classifier", null)); + final boolean isAJar = "jar".equals(maven2.getString("extension", null)); + LOGGER.debug("shaMatch {}", shaMatch); + LOGGER.debug("hasAcceptedClassifier {}", hasAcceptedClassifier); + LOGGER.debug("isAJar {}", isAJar); + if ( + isAJar + && hasAcceptedClassifier + && shaMatch + ) { + downloadUrl = asset.getString("downloadUrl"); + groupId = maven2.getString("groupId"); + artifactId = maven2.getString("artifactId"); + version = maven2.getString("version"); + + jarFound = true; + } else if ("pom".equals(maven2.getString("extension"))) { + LOGGER.debug("pom found {}", asset); + pomFound = true; + pomUrl = asset.getString("downloadUrl"); + } + } + if (pomFound && jarFound) { + found = true; + } + } + if (found) { + matchingArtifacts.add(new MavenArtifact(groupId, artifactId, version, downloadUrl, pomUrl)); + } else if (jarFound) { + final MavenArtifact ma = new MavenArtifact(groupId, artifactId, version, downloadUrl); + ma.setPomUrl(MavenArtifact.derivePomUrl(artifactId, version, downloadUrl)); + matchingArtifacts.add(ma); + found = true; + } + } + } + return continuationToken; + } + } + } + + @Override + public boolean preflightRequest() { + try { + final URL url = new URL(rootURL, "v1/status"); + final String response = Downloader.getInstance().fetchContent(url, useProxy, StandardCharsets.UTF_8); + if (response == null || !response.isEmpty()) { + LOGGER.warn("Expected empty OK response (content-length 0), got {}", response == null ? "null" : response.length()); + return false; + } + } catch (IOException | TooManyRequestsException | ResourceNotFoundException e) { + LOGGER.warn("Pre-flight request to Nexus failed: ", e); + return false; + } + return true; + } + +} diff --git a/core/src/main/java/org/owasp/dependencycheck/data/nodeaudit/Advisory.java b/core/src/main/java/org/owasp/dependencycheck/data/nodeaudit/Advisory.java index a6f044f9dbe..97fab27f268 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/nodeaudit/Advisory.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/nodeaudit/Advisory.java @@ -17,8 +17,9 @@ */ package org.owasp.dependencycheck.data.nodeaudit; -import org.owasp.dependencycheck.dependency.CvssV3; + +import io.github.jeremylong.openvulnerability.client.nvd.CvssV3; import java.io.Serializable; import java.util.List; import javax.annotation.concurrent.ThreadSafe; diff --git a/core/src/main/java/org/owasp/dependencycheck/data/nodeaudit/NodeAuditSearch.java b/core/src/main/java/org/owasp/dependencycheck/data/nodeaudit/NodeAuditSearch.java index 2d4b7aefbbb..c1f058ca6eb 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/nodeaudit/NodeAuditSearch.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/nodeaudit/NodeAuditSearch.java @@ -17,29 +17,32 @@ */ package org.owasp.dependencycheck.data.nodeaudit; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.HttpURLConnection; import java.net.MalformedURLException; +import java.net.URISyntaxException; import java.net.URL; -import java.nio.charset.StandardCharsets; import java.security.SecureRandom; +import java.util.ArrayList; import java.util.List; import javax.annotation.concurrent.ThreadSafe; +import org.apache.hc.client5.http.HttpResponseException; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpHeaders; +import org.apache.hc.core5.http.message.BasicHeader; +import org.json.JSONException; import org.json.JSONObject; +import org.owasp.dependencycheck.utils.DownloadFailedException; +import org.owasp.dependencycheck.utils.Downloader; +import org.owasp.dependencycheck.utils.ResourceNotFoundException; import org.owasp.dependencycheck.utils.Settings; -import org.owasp.dependencycheck.utils.URLConnectionFactory; +import org.owasp.dependencycheck.utils.TooManyRequestsException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.json.Json; -import javax.json.JsonObject; -import javax.json.JsonReader; -import org.apache.commons.jcs.access.exception.CacheException; +import jakarta.json.JsonObject; +import org.apache.commons.jcs3.access.exception.CacheException; import static org.owasp.dependencycheck.analyzer.NodeAuditAnalyzer.DEFAULT_URL; @@ -48,7 +51,6 @@ import org.owasp.dependencycheck.data.cache.DataCache; import org.owasp.dependencycheck.data.cache.DataCacheFactory; import org.owasp.dependencycheck.utils.Checksum; -import org.owasp.dependencycheck.utils.URLConnectionFailureException; /** * Class of methods to search via Node Audit API. @@ -146,80 +148,64 @@ public List submitPackage(JsonObject packageJson) throws SearchExcepti * @throws IOException if it's unable to connect to Node Audit API */ private List submitPackage(JsonObject packageJson, String key, int count) throws SearchException, IOException { - try { - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("----------------------------------------"); - LOGGER.trace("Node Audit Payload:"); - LOGGER.trace(packageJson.toString()); - LOGGER.trace("----------------------------------------"); - LOGGER.trace("----------------------------------------"); - } - final byte[] packageDatabytes = packageJson.toString().getBytes(StandardCharsets.UTF_8); - final URLConnectionFactory factory = new URLConnectionFactory(settings); - final HttpURLConnection conn = factory.createHttpURLConnection(nodeAuditUrl, useProxy); - conn.setDoOutput(true); - conn.setDoInput(true); - conn.setRequestMethod("POST"); - conn.setRequestProperty("user-agent", "npm/6.1.0 node/v10.5.0 linux x64"); - conn.setRequestProperty("npm-in-ci", "false"); - conn.setRequestProperty("npm-scope", ""); - conn.setRequestProperty("npm-session", generateRandomSession()); - conn.setRequestProperty("content-type", "application/json"); - conn.setRequestProperty("Content-Length", Integer.toString(packageDatabytes.length)); - conn.connect(); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("----------------------------------------"); + LOGGER.trace("Node Audit Payload:"); + LOGGER.trace(packageJson.toString()); + LOGGER.trace("----------------------------------------"); + LOGGER.trace("----------------------------------------"); + } + final List

additionalHeaders = new ArrayList<>(); + additionalHeaders.add(new BasicHeader(HttpHeaders.USER_AGENT, "npm/6.1.0 node/v10.5.0 linux x64")); + additionalHeaders.add(new BasicHeader("npm-in-ci", "false")); + additionalHeaders.add(new BasicHeader("npm-scope", "")); + additionalHeaders.add(new BasicHeader("npm-session", generateRandomSession())); - try (OutputStream os = new BufferedOutputStream(conn.getOutputStream())) { - os.write(packageDatabytes); - os.flush(); + try { + final String response = Downloader.getInstance().postBasedFetchContent(nodeAuditUrl.toURI(), + packageJson.toString(), ContentType.APPLICATION_JSON, additionalHeaders); + final JSONObject jsonResponse = new JSONObject(response); + final NpmAuditParser parser = new NpmAuditParser(); + final List advisories = parser.parse(jsonResponse); + if (cache != null) { + cache.put(key, advisories); } - - switch (conn.getResponseCode()) { - case 200: - try (InputStream in = new BufferedInputStream(conn.getInputStream()); - JsonReader jsonReader = Json.createReader(in)) { - final JSONObject jsonResponse = new JSONObject(jsonReader.readObject().toString()); - final NpmAuditParser parser = new NpmAuditParser(); - final List advisories = parser.parse(jsonResponse); - if (cache != null) { - cache.put(key, advisories); - } - return advisories; - } catch (Exception ex) { - LOGGER.debug("Error connecting to Node Audit API. Error: {}", - ex.getMessage()); - throw new SearchException("Could not connect to Node Audit API: " + ex.getMessage(), ex); - } - case 503: - LOGGER.debug("Node Audit API returned `{} {}` - retrying request.", - conn.getResponseCode(), conn.getResponseMessage()); - if (count < 5) { - final int next = count + 1; - try { - Thread.sleep(1500L * next); - } catch (InterruptedException ex) { - Thread.currentThread().interrupt(); - throw new UnexpectedAnalysisException(ex); + return advisories; + } catch (RuntimeException | URISyntaxException | JSONException | TooManyRequestsException | ResourceNotFoundException ex) { + LOGGER.debug("Error connecting to Node Audit API. Error: {}", + ex.getMessage()); + throw new SearchException("Could not connect to Node Audit API: " + ex.getMessage(), ex); + } catch (DownloadFailedException e) { + if (e.getCause() instanceof HttpResponseException) { + final HttpResponseException hre = (HttpResponseException) e.getCause(); + switch (hre.getStatusCode()) { + case 503: + LOGGER.debug("Node Audit API returned `{} {}` - retrying request.", + hre.getStatusCode(), hre.getReasonPhrase()); + if (count < 5) { + final int next = count + 1; + try { + Thread.sleep(1500L * next); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + throw new UnexpectedAnalysisException(ex); + } + return submitPackage(packageJson, key, next); } - return submitPackage(packageJson, key, next); - } - throw new SearchException("Could not perform Node Audit analysis - service returned a 503."); - case 400: - LOGGER.debug("Invalid payload submitted to Node Audit API. Received response code: {} {}", - conn.getResponseCode(), conn.getResponseMessage()); - throw new SearchException("Could not perform Node Audit analysis. Invalid payload submitted to Node Audit API."); - default: - LOGGER.debug("Could not connect to Node Audit API. Received response code: {} {}", - conn.getResponseCode(), conn.getResponseMessage()); - throw new IOException("Could not connect to Node Audit API"); - } - } catch (IOException ex) { - if (ex instanceof javax.net.ssl.SSLHandshakeException - && ex.getMessage().contains("unable to find valid certification path to requested target")) { - final String msg = String.format("Unable to connect to '%s' - the Java trust store does not contain a trusted root for the cert. " - + " Please see https://github.com/jeremylong/InstallCert for one method of updating the trusted certificates.", nodeAuditUrl); - throw new URLConnectionFailureException(msg, ex); + throw new SearchException("Could not perform Node Audit analysis - service returned a 503.", e); + case 400: + LOGGER.debug("Invalid payload submitted to Node Audit API. Received response code: {} {}", + hre.getStatusCode(), hre.getReasonPhrase()); + throw new SearchException("Could not perform Node Audit analysis. Invalid payload submitted to Node Audit API.", e); + default: + LOGGER.debug("Could not connect to Node Audit API. Received response code: {} {}", + hre.getStatusCode(), hre.getReasonPhrase()); + throw new IOException("Could not connect to Node Audit API", e); + } + } else { + LOGGER.debug("Could not connect to Node Audit API. Received generic DownloadException", e); + throw new IOException("Could not connect to Node Audit API", e); } - throw ex; } } @@ -235,6 +221,6 @@ private String generateRandomSession() { while (sb.length() < length) { sb.append(Integer.toHexString(r.nextInt())); } - return sb.toString().substring(0, length); + return sb.substring(0, length); } } diff --git a/core/src/main/java/org/owasp/dependencycheck/data/nodeaudit/NpmAuditParser.java b/core/src/main/java/org/owasp/dependencycheck/data/nodeaudit/NpmAuditParser.java index 5f0cf87d155..5c5b01fc416 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/nodeaudit/NpmAuditParser.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/nodeaudit/NpmAuditParser.java @@ -17,15 +17,17 @@ */ package org.owasp.dependencycheck.data.nodeaudit; +import io.github.jeremylong.openvulnerability.client.nvd.CvssV3; import org.json.JSONArray; import org.json.JSONObject; -import org.owasp.dependencycheck.dependency.CvssV3; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.json.JSONException; +import org.owasp.dependencycheck.utils.CvssUtil; /** * Parser for NPM Audit API response. This parser is derived from: @@ -118,7 +120,7 @@ private Advisory parseAdvisory(JSONObject object) throws JSONException { } final JSONObject jsonCvss = object.optJSONObject("cvss"); if (jsonCvss != null) { - float baseScore = -1.0f; + double baseScore = -1.0; final String score = jsonCvss.optString("score"); if (score != null) { try { @@ -130,17 +132,17 @@ private Advisory parseAdvisory(JSONObject object) throws JSONException { } if (baseScore >= 0.0) { final String vector = jsonCvss.optString("vectorString"); - if (vector != null) { + if (vector != null && !"null".equals(vector)) { if (vector.startsWith("CVSS:3") && baseScore >= 0.0) { try { - final CvssV3 cvss = new CvssV3(vector, baseScore); + final CvssV3 cvss = CvssUtil.vectorToCvssV3(vector, baseScore); advisory.setCvssV3(cvss); } catch (IllegalArgumentException iae) { - LOGGER.warn("Invalid CVSS vector format encountered in NPM Audit results '{}' ", vector, iae); + LOGGER.warn("Invalid CVSS vector format encountered in NPM Audit results '{}': {} ", vector, iae.getMessage()); } } else { LOGGER.warn("Unsupported CVSS vector format in NPM Audit results, please file a feature " - + "request at https://github.com/jeremylong/DependencyCheck/issues/new/choose to " + + "request at https://github.com/dependency-check/DependencyCheck/issues/new/choose to " + "support vector format '{}' ", vector); } } diff --git a/core/src/main/java/org/owasp/dependencycheck/data/nodeaudit/NpmPayloadBuilder.java b/core/src/main/java/org/owasp/dependencycheck/data/nodeaudit/NpmPayloadBuilder.java index 982c9896585..478c1d5f2bc 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/nodeaudit/NpmPayloadBuilder.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/nodeaudit/NpmPayloadBuilder.java @@ -24,11 +24,11 @@ import java.util.Optional; import java.util.TreeMap; import java.util.stream.Collectors; -import javax.json.Json; -import javax.json.JsonObject; -import javax.json.JsonObjectBuilder; -import javax.json.JsonString; -import javax.json.JsonValue; +import jakarta.json.Json; +import jakarta.json.JsonObject; +import jakarta.json.JsonObjectBuilder; +import jakarta.json.JsonString; +import jakarta.json.JsonValue; import javax.annotation.concurrent.ThreadSafe; import org.apache.commons.collections4.MultiValuedMap; @@ -40,6 +40,7 @@ */ @ThreadSafe public final class NpmPayloadBuilder { + /** * Private constructor for utility class. */ @@ -108,13 +109,23 @@ public static JsonObject build(JsonObject lockJson, JsonObject packageJson, } if (dependencies != null) { - dependencies.forEach((key, value) -> { + dependencies.forEach((k, value) -> { + String key = k; final int indexOfNodeModule = key.lastIndexOf(NodePackageAnalyzer.NODE_MODULES_DIRNAME + "/"); if (indexOfNodeModule >= 0) { key = key.substring(indexOfNodeModule + NodePackageAnalyzer.NODE_MODULES_DIRNAME.length() + 1); } - final JsonObject dep = ((JsonObject) value); + JsonObject dep = ((JsonObject) value); + + //After Version 3, dependencies can't be taken directly from package-lock.json + if (lockJsonVersion > 2 && dep.containsKey("dependencies") && dep.get("dependencies") instanceof JsonObject) { + final JsonObjectBuilder depBuilder = Json.createObjectBuilder(dep); + depBuilder.remove("dependencies"); + depBuilder.add("requires", dep.get("dependencies")); + dep = depBuilder.build(); + } + final String version = dep.getString("version", ""); final boolean isDev = dep.getBoolean("dev", false); if (skipDevDependencies && isDev) { @@ -144,7 +155,7 @@ public static JsonObject build(JsonObject lockJson, JsonObject packageJson, * @return the JSON payload for NPN Audit */ public static JsonObject build(JsonObject packageJson, MultiValuedMap dependencyMap, - final boolean skipDevDependencies) { + final boolean skipDevDependencies) { final JsonObjectBuilder payloadBuilder = Json.createObjectBuilder(); addProjectInfo(packageJson, payloadBuilder); @@ -236,15 +247,23 @@ private static void addConstantElements(final JsonObjectBuilder payloadBuilder) private static JsonObject buildDependencies(JsonObject dep, MultiValuedMap dependencyMap) { final JsonObjectBuilder depBuilder = Json.createObjectBuilder(); Optional.ofNullable(dep.getJsonString("version")) - .map(JsonString::getString) - .ifPresent(version -> depBuilder.add("version", version)); + .map(JsonString::getString) + .ifPresent(version -> depBuilder.add("version", version)); //not installed package (like, dependency of an optional dependency) doesn't contains integrity if (dep.containsKey("integrity")) { depBuilder.add("integrity", dep.getString("integrity")); } if (dep.containsKey("requires")) { - depBuilder.add("requires", dep.getJsonObject("requires")); + final JsonObjectBuilder requiresBuilder = Json.createObjectBuilder(); + dep.getJsonObject("requires").forEach((key, value) -> { + if (NodePackageAnalyzer.shouldSkipDependency(key, ((JsonString) value).getString())) { + return; + } + + requiresBuilder.add(key, value); + }); + depBuilder.add("requires", requiresBuilder.build()); } if (dep.containsKey("dependencies")) { final JsonObjectBuilder dependeciesBuilder = Json.createObjectBuilder(); diff --git a/core/src/main/java/org/owasp/dependencycheck/data/nvd/ecosystem/CveEcosystemMapper.java b/core/src/main/java/org/owasp/dependencycheck/data/nvd/ecosystem/CveEcosystemMapper.java index 8424707b425..f201ffddae7 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/nvd/ecosystem/CveEcosystemMapper.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/nvd/ecosystem/CveEcosystemMapper.java @@ -13,18 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright (c) 2020 The OWASP Foundation. All Rights Reserved. + * Copyright (c) 2023 Jeremy Long. All Rights Reserved. */ package org.owasp.dependencycheck.data.nvd.ecosystem; +import io.github.jeremylong.openvulnerability.client.nvd.Config; +import io.github.jeremylong.openvulnerability.client.nvd.CpeMatch; +import io.github.jeremylong.openvulnerability.client.nvd.Node; +import io.github.jeremylong.openvulnerability.client.nvd.DefCveItem; import java.util.List; import java.util.stream.Collectors; import javax.annotation.concurrent.NotThreadSafe; -import org.owasp.dependencycheck.data.nvd.json.CpeMatchStreamCollector; -import org.owasp.dependencycheck.data.nvd.json.DefCpeMatch; - -import org.owasp.dependencycheck.data.nvd.json.DefCveItem; -import org.owasp.dependencycheck.data.nvd.json.NodeFlatteningCollector; /** * Utility for mapping CVEs to their ecosystems. @@ -83,17 +82,23 @@ public String getEcosystem(DefCveItem cve) { * null */ private boolean hasMultipleVendorProductConfigurations(DefCveItem cve) { - final List cpeEntries = cve.getConfigurations().getNodes().stream() - .collect(NodeFlatteningCollector.getInstance()) - .collect(CpeMatchStreamCollector.getInstance()) - .filter(defCpeMatch -> defCpeMatch.getCpe23Uri() != null) - .collect(Collectors.toList()); - if (!cpeEntries.isEmpty() && cpeEntries.size() > 1) { - final DefCpeMatch firstMatch = cpeEntries.get(0); - final String uri = firstMatch.getCpe23Uri(); - final int pos = uri.indexOf(":", uri.indexOf(":", 10) + 1); - final String match = uri.substring(0, pos + 1); - return !cpeEntries.stream().allMatch(e -> e.getCpe23Uri().startsWith(match)); + if (cve.getCve().getConfigurations() != null && !cve.getCve().getConfigurations().isEmpty()) { + final List cpeEntries = cve.getCve().getConfigurations().stream() + .filter(config -> config.getNodes() != null) + .map(Config::getNodes) + .flatMap(List::stream) + .filter(cpe -> cpe.getCpeMatch() != null) + .map(Node::getCpeMatch) + .flatMap(List::stream) + .filter(match -> match.getCriteria() != null) + .collect(Collectors.toList()); + if (!cpeEntries.isEmpty() && cpeEntries.size() > 1) { + final CpeMatch firstMatch = cpeEntries.get(0); + final String uri = firstMatch.getCriteria(); + final int pos = uri.indexOf(":", uri.indexOf(":", 10) + 1); + final String match = uri.substring(0, pos + 1); + return !cpeEntries.stream().allMatch(e -> e.getCriteria().startsWith(match)); + } } return false; } diff --git a/core/src/main/java/org/owasp/dependencycheck/data/nvd/ecosystem/DescriptionEcosystemMapper.java b/core/src/main/java/org/owasp/dependencycheck/data/nvd/ecosystem/DescriptionEcosystemMapper.java index d4dae989047..1d325ec8bff 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/nvd/ecosystem/DescriptionEcosystemMapper.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/nvd/ecosystem/DescriptionEcosystemMapper.java @@ -18,7 +18,7 @@ package org.owasp.dependencycheck.data.nvd.ecosystem; import org.apache.commons.lang3.StringUtils; -import org.owasp.dependencycheck.data.nvd.json.DefCveItem; +import io.github.jeremylong.openvulnerability.client.nvd.DefCveItem; import java.util.HashMap; import java.util.Map; @@ -179,7 +179,7 @@ protected void increment(int i, int[] ecosystemMap) { */ public String getEcosystem(DefCveItem cve) { final int[] ecosystemMap = new int[ECOSYSTEMS.length]; - cve.getCve().getDescription().getDescriptionData().stream() + cve.getCve().getDescriptions().stream() .filter((langString) -> (langString.getLang().equals("en"))) .forEachOrdered((langString) -> search(langString.getValue(), ecosystemMap)); return getResult(ecosystemMap); diff --git a/core/src/main/java/org/owasp/dependencycheck/data/nvd/ecosystem/UrlEcosystemMapper.java b/core/src/main/java/org/owasp/dependencycheck/data/nvd/ecosystem/UrlEcosystemMapper.java index 8721ed54b1c..bd48613e95f 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/nvd/ecosystem/UrlEcosystemMapper.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/nvd/ecosystem/UrlEcosystemMapper.java @@ -23,13 +23,13 @@ import javax.annotation.concurrent.NotThreadSafe; -import org.owasp.dependencycheck.data.nvd.json.CVEJSON40Min11; -import org.owasp.dependencycheck.data.nvd.json.DefCveItem; -import org.owasp.dependencycheck.data.nvd.json.Reference; -import org.owasp.dependencycheck.data.nvd.json.References; +import io.github.jeremylong.openvulnerability.client.nvd.DefCveItem; +import io.github.jeremylong.openvulnerability.client.nvd.Reference; import com.hankcs.algorithm.AhoCorasickDoubleArrayTrie; import com.hankcs.algorithm.AhoCorasickDoubleArrayTrie.Hit; +import io.github.jeremylong.openvulnerability.client.nvd.CveItem; +import java.util.List; @NotThreadSafe public class UrlEcosystemMapper { @@ -69,14 +69,13 @@ public UrlEcosystemMapper() { * @return the ecosystem */ public String getEcosystem(DefCveItem cve) { - final References references = Optional.ofNullable(cve) + final List references = Optional.ofNullable(cve) .map(DefCveItem::getCve) - .map(CVEJSON40Min11::getReferences) + .map(CveItem::getReferences) .orElse(null); if (Objects.nonNull(references)) { - for (Reference r : references.getReferenceData()) { - + for (Reference r : references) { final Hit ecosystem = search.findFirst(r.getUrl()); if (ecosystem != null) { return ecosystem.value; diff --git a/core/src/main/java/org/owasp/dependencycheck/data/nvd/json/CpeMatchStreamCollector.java b/core/src/main/java/org/owasp/dependencycheck/data/nvd/json/CpeMatchStreamCollector.java deleted file mode 100644 index 652e45a2ef2..00000000000 --- a/core/src/main/java/org/owasp/dependencycheck/data/nvd/json/CpeMatchStreamCollector.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * This file is part of dependency-check-core. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright (c) 2018 Jeremy Long. All Rights Reserved. - */ -package org.owasp.dependencycheck.data.nvd.json; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.EnumSet; -import java.util.Set; -import java.util.function.BiConsumer; -import java.util.function.BinaryOperator; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.stream.Collector; -import java.util.stream.Stream; - -import javax.annotation.concurrent.ThreadSafe; - -/** - * - * @author Jeremy Long - * - */ -@ThreadSafe -public final class CpeMatchStreamCollector implements Collector, Stream> { - - /** - * The singleton instance. - */ - private static final CpeMatchStreamCollector INSTANCE; - - static { - INSTANCE = new CpeMatchStreamCollector(); - } - - public static CpeMatchStreamCollector getInstance() { - return INSTANCE; - } - - private CpeMatchStreamCollector() { - } - - @Override - public Supplier> supplier() { - return ArrayList::new; - } - - @Override - public BiConsumer, DefNode> accumulator() { - return (match, nodes) -> match.addAll(nodes.getCpeMatch()); - } - - @Override - public BinaryOperator> combiner() { - return (map, other) -> { - map.addAll(other); - return map; - }; - } - - @Override - public Function, Stream> finisher() { - return Collection::stream; - } - - @Override - public Set characteristics() { - return EnumSet.of(Characteristics.UNORDERED); - } - -} diff --git a/core/src/main/java/org/owasp/dependencycheck/data/nvd/json/MetaProperties.java b/core/src/main/java/org/owasp/dependencycheck/data/nvd/json/MetaProperties.java deleted file mode 100644 index 322ba5c02da..00000000000 --- a/core/src/main/java/org/owasp/dependencycheck/data/nvd/json/MetaProperties.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * This file is part of dependency-check-core. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright (c) 2019 Jeremy Long. All Rights Reserved. - */ -package org.owasp.dependencycheck.data.nvd.json; - -import java.io.IOException; -import java.io.Reader; -import java.io.StringReader; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; -import java.util.Properties; -import org.owasp.dependencycheck.data.update.exception.InvalidDataException; - -/** - * Meta properties object to hold information about the NVD CVE data. - * - * @author Jeremy Long - */ -public class MetaProperties { - - /** - * The SHA256 of the NVD file. - */ - private final String sha256; - /** - * The last modified date of the NVD file in epoch time. - */ - private final long lastModifiedDate; - /** - * The size of the NVD file. - */ - private final long size; - /** - * The size of the zipped NVD file. - */ - private final long zipSize; - /** - * The size of the gzipped NVD file. - */ - private final long gzSize; - - /** - * Get the value of gzSize. - * - * @return the value of gzSize - */ - public long getGzSize() { - return gzSize; - } - - /** - * Get the value of zipSize. - * - * @return the value of zipSize - */ - public long getZipSize() { - return zipSize; - } - - /** - * Get the value of size. - * - * @return the value of size - */ - public long getSize() { - return size; - } - - /** - * Get the value of lastModifiedDate in epoch time. - * - * @return the value of lastModifiedDate - */ - public long getLastModifiedDate() { - return lastModifiedDate; - } - - /** - * Get the value of SHA256. - * - * @return the value of SHA256 - */ - public String getSha256() { - return sha256; - } - - /** - * Constructs a new MetaProperties object to hold information about the NVD - * data. - * - * @param contents the contents of the meta file - * @throws InvalidDataException thrown if the meta file contents cannot be - * parsed - */ - public MetaProperties(String contents) throws InvalidDataException { - final Properties properties = new Properties(); - try (Reader r = new StringReader(contents)) { - properties.load(r); - } catch (IOException ex) { - throw new InvalidDataException("Unable to parse meta file data", ex); - } - this.sha256 = properties.getProperty("sha256"); - try { - final String date = properties.getProperty("lastModifiedDate"); - if (date == null) { - throw new InvalidDataException("lastModifiedDate not found in meta file"); - } - this.lastModifiedDate = ZonedDateTime.parse(date, DateTimeFormatter.ISO_OFFSET_DATE_TIME).toEpochSecond(); - } catch (DateTimeParseException ex) { - throw new InvalidDataException("Meta file lastModifiedDate cannot be parsed: " - + properties.getProperty("lastModifiedDate"), ex); - } - try { - this.zipSize = Long.parseLong(properties.getProperty("zipSize")); - } catch (NumberFormatException ex) { - throw new InvalidDataException("Meta file zip size cannot be parsed: " - + properties.getProperty("zipSize"), ex); - } - try { - this.gzSize = Long.parseLong(properties.getProperty("gzSize")); - } catch (NumberFormatException ex) { - throw new InvalidDataException("Meta file gz size cannot be parsed: " - + properties.getProperty("gzSize"), ex); - } - try { - this.size = Long.parseLong(properties.getProperty("size")); - } catch (NumberFormatException ex) { - throw new InvalidDataException("Meta file size cannot be parsed: " - + properties.getProperty("size"), ex); - } - } -} diff --git a/core/src/main/java/org/owasp/dependencycheck/data/nvd/json/NodeFlatteningCollector.java b/core/src/main/java/org/owasp/dependencycheck/data/nvd/json/NodeFlatteningCollector.java deleted file mode 100644 index 7dfe7e291ff..00000000000 --- a/core/src/main/java/org/owasp/dependencycheck/data/nvd/json/NodeFlatteningCollector.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * This file is part of dependency-check-core. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright (c) 2018 Jeremy Long. All Rights Reserved. - */ -package org.owasp.dependencycheck.data.nvd.json; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.EnumSet; -import java.util.List; -import java.util.Set; -import java.util.function.BiConsumer; -import java.util.function.BinaryOperator; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.stream.Collector; -import java.util.stream.Stream; - -import javax.annotation.concurrent.ThreadSafe; - -/** - * Used to flatten a hierarchical list of nodes with children. - * - * @author Jeremy Long - */ -@ThreadSafe -public final class NodeFlatteningCollector implements Collector, Stream> { - - /** - * Singleton instance variable. - */ - private static final NodeFlatteningCollector INSTANCE; - - static { - INSTANCE = new NodeFlatteningCollector(); - } - - public static NodeFlatteningCollector getInstance() { - return INSTANCE; - } - - private NodeFlatteningCollector() { - } - - /** - * Flattens the hierarchical list of nodes. - * - * @param node the node with children to flatten - * @return the flattened list of nodes - */ - private List flatten(DefNode node) { - final List result = new ArrayList<>(); - result.add(node); - return flatten(result, node.getChildren()); - } - - /** - * Flattens the hierarchical list of nodes. - * - * @param result the results - * @param nodes the nodes - * @return the flattened list of nodes - */ - private List flatten(List result, List nodes) { - nodes.forEach(n -> { - flatten(result, n.getChildren()); - result.add(n); - }); - return result; - } - - @Override - public Supplier> supplier() { - return ArrayList::new; - } - - @Override - public BiConsumer, DefNode> accumulator() { - return (nodes, n) -> nodes.addAll(flatten(n)); - } - - @Override - public BinaryOperator> combiner() { - return (map, other) -> { - map.addAll(other); - return map; - }; - } - - @Override - public Function, Stream> finisher() { - return Collection::stream; - } - - @Override - public Set characteristics() { - return EnumSet.of(Characteristics.UNORDERED); - } -} diff --git a/core/src/main/java/org/owasp/dependencycheck/data/nvd/json/package-info.java b/core/src/main/java/org/owasp/dependencycheck/data/nvd/json/package-info.java deleted file mode 100644 index cd090a6f6c0..00000000000 --- a/core/src/main/java/org/owasp/dependencycheck/data/nvd/json/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -/** - * Contains utility classes used to work with the generated code from the - * NVD CVE JSON data. - */ -package org.owasp.dependencycheck.data.nvd.json; diff --git a/core/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveDB.java b/core/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveDB.java index 752597623ef..1e4b64baff1 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveDB.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveDB.java @@ -20,7 +20,9 @@ import com.google.common.io.Resources; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import org.apache.commons.collections.map.ReferenceMap; +import io.github.jeremylong.openvulnerability.client.nvd.Config; +import io.github.jeremylong.openvulnerability.client.nvd.CpeMatch; +import org.apache.commons.collections4.map.ReferenceMap; import org.owasp.dependencycheck.dependency.Vulnerability; import org.owasp.dependencycheck.dependency.VulnerableSoftware; import org.owasp.dependencycheck.utils.*; @@ -42,24 +44,24 @@ import java.util.stream.Collectors; import org.anarres.jdiagnostics.DefaultQuery; -import static org.apache.commons.collections.map.AbstractReferenceMap.HARD; -import static org.apache.commons.collections.map.AbstractReferenceMap.SOFT; +import static org.apache.commons.collections4.map.AbstractReferenceMap.ReferenceStrength.HARD; +import static org.apache.commons.collections4.map.AbstractReferenceMap.ReferenceStrength.SOFT; import org.owasp.dependencycheck.analyzer.exception.LambdaExceptionWrapper; import org.owasp.dependencycheck.analyzer.exception.UnexpectedAnalysisException; -import org.owasp.dependencycheck.data.nvd.json.BaseMetricV2; -import org.owasp.dependencycheck.data.nvd.json.BaseMetricV3; -import org.owasp.dependencycheck.data.nvd.json.CpeMatchStreamCollector; -import org.owasp.dependencycheck.data.nvd.json.DefCpeMatch; -import org.owasp.dependencycheck.data.nvd.json.DefCveItem; -import org.owasp.dependencycheck.data.nvd.json.LangString; -import org.owasp.dependencycheck.data.nvd.json.NodeFlatteningCollector; -import org.owasp.dependencycheck.data.nvd.json.ProblemtypeDatum; -import org.owasp.dependencycheck.data.nvd.json.Reference; +import io.github.jeremylong.openvulnerability.client.nvd.DefCveItem; import static org.owasp.dependencycheck.data.nvdcve.CveDB.PreparedStatementCveDb.*; import org.owasp.dependencycheck.data.update.cpe.CpeEcosystemCache; import org.owasp.dependencycheck.data.update.cpe.CpePlus; -import org.owasp.dependencycheck.dependency.CvssV2; -import org.owasp.dependencycheck.dependency.CvssV3; +import io.github.jeremylong.openvulnerability.client.nvd.CvssV2; +import io.github.jeremylong.openvulnerability.client.nvd.CvssV2Data; +import io.github.jeremylong.openvulnerability.client.nvd.CvssV3; +import io.github.jeremylong.openvulnerability.client.nvd.CvssV3Data; +import io.github.jeremylong.openvulnerability.client.nvd.CvssV4; +import io.github.jeremylong.openvulnerability.client.nvd.CvssV4Data; +import io.github.jeremylong.openvulnerability.client.nvd.LangString; +import io.github.jeremylong.openvulnerability.client.nvd.Node; +import io.github.jeremylong.openvulnerability.client.nvd.Reference; +import io.github.jeremylong.openvulnerability.client.nvd.Weakness; import org.owasp.dependencycheck.dependency.VulnerableSoftwareBuilder; import us.springett.parsers.cpe.Cpe; import us.springett.parsers.cpe.CpeBuilder; @@ -143,8 +145,7 @@ public int updateEcosystemCache() { final URL url = Resources.getResource(DB_ECOSYSTEM_CACHE); final List sql = Resources.readLines(url, StandardCharsets.UTF_8); - try (Connection conn = databaseManager.getConnection(); - Statement statement = conn.createStatement()) { + try (Connection conn = databaseManager.getConnection(); Statement statement = conn.createStatement()) { for (String single : sql) { updateCount += statement.executeUpdate(single); } @@ -461,8 +462,7 @@ DatabaseProperties reloadProperties() { */ public Set getCPEs(String vendor, String product) { final Set cpe = new HashSet<>(); - try (Connection conn = databaseManager.getConnection(); - PreparedStatement ps = getPreparedStatement(conn, SELECT_CPE_ENTRIES)) { + try (Connection conn = databaseManager.getConnection(); PreparedStatement ps = getPreparedStatement(conn, SELECT_CPE_ENTRIES)) { //part, vendor, product, version, update_version, edition, //lang, sw_edition, target_sw, target_hw, other, ecosystem ps.setString(1, vendor); @@ -567,8 +567,7 @@ public Properties getProperties() { */ public void saveProperty(String key, String value) { clearCache(); - try (Connection conn = databaseManager.getConnection(); - PreparedStatement mergeProperty = getPreparedStatement(conn, MERGE_PROPERTY)) { + try (Connection conn = databaseManager.getConnection(); PreparedStatement mergeProperty = getPreparedStatement(conn, MERGE_PROPERTY)) { if (mergeProperty != null) { mergeProperty.setString(1, key); mergeProperty.setString(2, value); @@ -623,8 +622,7 @@ public List getVulnerabilities(Cpe cpe) throws DatabaseException } final List vulnerabilities = new ArrayList<>(); - try (Connection conn = databaseManager.getConnection(); - PreparedStatement ps = getPreparedStatement(conn, SELECT_CVE_FROM_SOFTWARE)) { + try (Connection conn = databaseManager.getConnection(); PreparedStatement ps = getPreparedStatement(conn, SELECT_CVE_FROM_SOFTWARE)) { ps.setString(1, cpe.getVendor()); ps.setString(2, cpe.getProduct()); try (ResultSet rs = ps.executeQuery()) { @@ -714,8 +712,7 @@ public Vulnerability getVulnerability(String cve, Connection conn) throws Databa final VulnerableSoftwareBuilder vulnerableSoftwareBuilder = new VulnerableSoftwareBuilder(); Vulnerability vuln = null; try { - try (PreparedStatement psV = getPreparedStatement(conn, SELECT_VULNERABILITY, cve); - ResultSet rsV = psV.executeQuery()) { + try (PreparedStatement psV = getPreparedStatement(conn, SELECT_VULNERABILITY, cve); ResultSet rsV = psV.executeQuery()) { if (rsV.next()) { //1.id, 2.description, cveId = rsV.getInt(1); @@ -729,44 +726,320 @@ public Vulnerability getVulnerability(String cve, Connection conn) throws Databa //12.v2AccessVector, 13.v2AccessComplexity, 14.v2Authentication, 15.v2ConfidentialityImpact, //16.v2IntegrityImpact, 17.v2AvailabilityImpact, 18.v2Version, if (rsV.getObject(11) != null) { - final CvssV2 cvss = new CvssV2(rsV.getFloat(11), rsV.getString(12), - rsV.getString(13), rsV.getString(14), rsV.getString(15), - rsV.getString(16), rsV.getString(17), rsV.getString(3), - getFloatValue(rsV, 4), getFloatValue(rsV, 5), - getBooleanValue(rsV, 6), getBooleanValue(rsV, 7), getBooleanValue(rsV, 8), - getBooleanValue(rsV, 9), getBooleanValue(rsV, 10), rsV.getString(18)); + + final CvssV2Data.AccessVectorType accessVector = CvssV2Data.AccessVectorType.fromValue(rsV.getString(12)); + final CvssV2Data.AccessComplexityType accessComplexity = CvssV2Data.AccessComplexityType.fromValue(rsV.getString(13)); + final CvssV2Data.AuthenticationType authentication = CvssV2Data.AuthenticationType.fromValue(rsV.getString(14)); + final CvssV2Data.CiaType confidentialityImpact = CvssV2Data.CiaType.fromValue(rsV.getString(15)); + final CvssV2Data.CiaType integrityImpact = CvssV2Data.CiaType.fromValue(rsV.getString(16)); + final CvssV2Data.CiaType availabilityImpact = CvssV2Data.CiaType.fromValue(rsV.getString(17)); + final String vector = String.format("/AV:%s/AC:%s/Au:%s/C:%s/I:%s/A:%s", + accessVector == null ? "" : accessVector.value().substring(0, 1), + accessComplexity == null ? "" : accessComplexity.value().substring(0, 1), + authentication == null ? "" : authentication.value().substring(0, 1), + confidentialityImpact == null ? "" : confidentialityImpact.value().substring(0, 1), + integrityImpact == null ? "" : integrityImpact.value().substring(0, 1), + availabilityImpact == null ? "" : availabilityImpact.value().substring(0, 1)); + + final CvssV2Data cvssData = new CvssV2Data(CvssV2Data.Version._2_0, vector, accessVector, + accessComplexity, authentication, confidentialityImpact, + integrityImpact, availabilityImpact, rsV.getDouble(11), rsV.getString(3), + null, null, null, null, null, null, null, null, null, null); + final CvssV2 cvss = new CvssV2(null, CvssV2.Type.PRIMARY, cvssData, rsV.getString(3), + rsV.getDouble(4), rsV.getDouble(5), rsV.getBoolean(6), rsV.getBoolean(7), + rsV.getBoolean(8), rsV.getBoolean(9), rsV.getBoolean(10)); vuln.setCvssV2(cvss); } //19.v3ExploitabilityScore, 20.v3ImpactScore, 21.v3AttackVector, 22.v3AttackComplexity, 23.v3PrivilegesRequired, //24.v3UserInteraction, 25.v3Scope, 26.v3ConfidentialityImpact, 27.v3IntegrityImpact, 28.v3AvailabilityImpact, - //29.v3BaseScore, 30.v3BaseSeverity, 21.v3Version + //29.v3BaseScore, 30.v3BaseSeverity, 31.v3Version if (rsV.getObject(21) != null) { - final CvssV3 cvss = new CvssV3(rsV.getString(21), rsV.getString(22), - rsV.getString(23), rsV.getString(24), rsV.getString(25), - rsV.getString(26), rsV.getString(27), rsV.getString(28), - rsV.getFloat(29), rsV.getString(30), getFloatValue(rsV, 19), - getFloatValue(rsV, 20), rsV.getString(31)); + //some older test data may not correctly have the version set. + String cveVersion = "3.1"; + if (rsV.getString(31) != null) { + cveVersion = rsV.getString(31); + } + final CvssV3Data.Version version = CvssV3Data.Version.fromValue(cveVersion); + final CvssV3Data.AttackVectorType attackVector = CvssV3Data.AttackVectorType.fromValue(rsV.getString(21)); + final CvssV3Data.AttackComplexityType attackComplexity = CvssV3Data.AttackComplexityType.fromValue(rsV.getString(22)); + final CvssV3Data.PrivilegesRequiredType privilegesRequired = CvssV3Data.PrivilegesRequiredType.fromValue(rsV.getString(23)); + final CvssV3Data.UserInteractionType userInteraction = CvssV3Data.UserInteractionType.fromValue(rsV.getString(24)); + final CvssV3Data.ScopeType scope = CvssV3Data.ScopeType.fromValue(rsV.getString(25)); + final CvssV3Data.CiaType confidentialityImpact = CvssV3Data.CiaType.fromValue(rsV.getString(26)); + final CvssV3Data.CiaType integrityImpact = CvssV3Data.CiaType.fromValue(rsV.getString(27)); + final CvssV3Data.CiaType availabilityImpact = CvssV3Data.CiaType.fromValue(rsV.getString(28)); + final CvssV3Data.SeverityType baseSeverity = CvssV3Data.SeverityType.fromValue(rsV.getString(30)); + final String vector = String.format("CVSS:%s/AV:%s/AC:%s/PR:%s/UI:%s/S:%s/C:%s/I:%s/A:%s", + version == null ? "" : version, + attackVector == null ? "" : attackVector.value().substring(0, 1), + attackComplexity == null ? "" : attackComplexity.value().substring(0, 1), + privilegesRequired == null ? "" : privilegesRequired.value().substring(0, 1), + userInteraction == null ? "" : userInteraction.value().substring(0, 1), + scope == null ? "" : scope.value().substring(0, 1), + confidentialityImpact == null ? "" : confidentialityImpact.value().substring(0, 1), + integrityImpact == null ? "" : integrityImpact.value().substring(0, 1), + availabilityImpact == null ? "" : availabilityImpact.value().substring(0, 1)); + + final CvssV3Data cvssData = new CvssV3Data(version, vector, attackVector, attackComplexity, privilegesRequired, + userInteraction, scope, confidentialityImpact, integrityImpact, availabilityImpact, + rsV.getDouble(29), baseSeverity, CvssV3Data.ExploitCodeMaturityType.PROOF_OF_CONCEPT, + CvssV3Data.RemediationLevelType.NOT_DEFINED, CvssV3Data.ConfidenceType.REASONABLE, 0.0, + CvssV3Data.SeverityType.MEDIUM, CvssV3Data.CiaRequirementType.NOT_DEFINED, + CvssV3Data.CiaRequirementType.NOT_DEFINED, CvssV3Data.CiaRequirementType.NOT_DEFINED, + CvssV3Data.ModifiedAttackVectorType.ADJACENT_NETWORK, CvssV3Data.ModifiedAttackComplexityType.NOT_DEFINED, + CvssV3Data.ModifiedPrivilegesRequiredType.NOT_DEFINED, CvssV3Data.ModifiedUserInteractionType.NOT_DEFINED, + CvssV3Data.ModifiedScopeType.NOT_DEFINED, CvssV3Data.ModifiedCiaType.NOT_DEFINED, + CvssV3Data.ModifiedCiaType.NOT_DEFINED, CvssV3Data.ModifiedCiaType.NOT_DEFINED, 1.0, + CvssV3Data.SeverityType.NONE); + final CvssV3 cvss = new CvssV3(null, null, cvssData, rsV.getDouble(19), rsV.getDouble(20)); vuln.setCvssV3(cvss); } +// 32.v4version, 33.v4attackVector, 34.v4attackComplexity, 35.v4attackRequirements, 36.v4privilegesRequired, +// 37.v4userInteraction, 38.v4vulnConfidentialityImpact, 39.v4vulnIntegrityImpact, 40.v4vulnAvailabilityImpact, +// 41.v4subConfidentialityImpact, 42.v4subIntegrityImpact, 43.v4subAvailabilityImpact, 44.v4exploitMaturity, +// 45.v4confidentialityRequirement, 46.v4integrityRequirement, 47.v4availabilityRequirement, 48.v4modifiedAttackVector, +// 49.v4modifiedAttackComplexity, 50.v4modifiedAttackRequirements, 51.v4modifiedPrivilegesRequired, 52.v4modifiedUserInteraction, +// 53.v4modifiedVulnConfidentialityImpact, 54.v4modifiedVulnIntegrityImpact, 55.v4modifiedVulnAvailabilityImpact, +// 56.v4modifiedSubConfidentialityImpact, 57.v4modifiedSubIntegrityImpact, 58.v4modifiedSubAvailabilityImpact, +// 59.v4safety, 60.v4automatable, 61.v4recovery, 62.v4valueDensity, 63.v4vulnerabilityResponseEffort, 64.v4providerUrgency, +// 65.v4baseScore, 66.v4baseSeverity, 67.v4threatScore, 68.v4threatSeverity, 69.v4environmentalScore, 70.v4environmentalSeverity +// 71.v4source, 72.v4type + if (rsV.getObject(33) != null) { + String vectorString = null; + + String value = rsV.getString(32); + final CvssV4Data.Version version = CvssV4Data.Version.fromValue(value); + CvssV4Data.AttackVectorType attackVector = null; + value = rsV.getString(33); + if (value != null) { + attackVector = CvssV4Data.AttackVectorType.fromValue(value); + } + CvssV4Data.AttackComplexityType attackComplexity = null; + value = rsV.getString(34); + if (value != null) { + attackComplexity = CvssV4Data.AttackComplexityType.fromValue(value); + } + CvssV4Data.AttackRequirementsType attackRequirements = null; + value = rsV.getString(35); + if (value != null) { + attackRequirements = CvssV4Data.AttackRequirementsType.fromValue(value); + } + CvssV4Data.PrivilegesRequiredType privilegesRequired = null; + value = rsV.getString(36); + if (value != null) { + privilegesRequired = CvssV4Data.PrivilegesRequiredType.fromValue(value); + } + CvssV4Data.UserInteractionType userInteraction = null; + value = rsV.getString(37); + if (value != null) { + userInteraction = CvssV4Data.UserInteractionType.fromValue(value); + } + CvssV4Data.CiaType vulnConfidentialityImpact = null; + value = rsV.getString(38); + if (value != null) { + vulnConfidentialityImpact = CvssV4Data.CiaType.fromValue(value); + } + CvssV4Data.CiaType vulnIntegrityImpact = null; + value = rsV.getString(39); + if (value != null) { + vulnIntegrityImpact = CvssV4Data.CiaType.fromValue(value); + } + CvssV4Data.CiaType vulnAvailabilityImpact = null; + value = rsV.getString(40); + if (value != null) { + vulnAvailabilityImpact = CvssV4Data.CiaType.fromValue(value); + } + CvssV4Data.CiaType subConfidentialityImpact = null; + value = rsV.getString(41); + if (value != null) { + subConfidentialityImpact = CvssV4Data.CiaType.fromValue(value); + } + CvssV4Data.CiaType subIntegrityImpact = null; + value = rsV.getString(42); + if (value != null) { + subIntegrityImpact = CvssV4Data.CiaType.fromValue(value); + } + CvssV4Data.CiaType subAvailabilityImpact = null; + value = rsV.getString(43); + if (value != null) { + subAvailabilityImpact = CvssV4Data.CiaType.fromValue(value); + } + CvssV4Data.ExploitMaturityType exploitMaturity = null; + value = rsV.getString(44); + if (value != null) { + exploitMaturity = CvssV4Data.ExploitMaturityType.fromValue(value); + } + CvssV4Data.CiaRequirementType confidentialityRequirement = null; + value = rsV.getString(45); + if (value != null) { + confidentialityRequirement = CvssV4Data.CiaRequirementType.fromValue(value); + } + CvssV4Data.CiaRequirementType integrityRequirement = null; + value = rsV.getString(46); + if (value != null) { + integrityRequirement = CvssV4Data.CiaRequirementType.fromValue(value); + } + CvssV4Data.CiaRequirementType availabilityRequirement = null; + value = rsV.getString(47); + if (value != null) { + availabilityRequirement = CvssV4Data.CiaRequirementType.fromValue(value); + } + CvssV4Data.ModifiedAttackVectorType modifiedAttackVector = null; + value = rsV.getString(48); + if (value != null) { + modifiedAttackVector = CvssV4Data.ModifiedAttackVectorType.fromValue(value); + } + CvssV4Data.ModifiedAttackComplexityType modifiedAttackComplexity = null; + value = rsV.getString(49); + if (value != null) { + modifiedAttackComplexity = CvssV4Data.ModifiedAttackComplexityType.fromValue(value); + } + CvssV4Data.ModifiedAttackRequirementsType modifiedAttackRequirements = null; + value = rsV.getString(50); + if (value != null) { + modifiedAttackRequirements = CvssV4Data.ModifiedAttackRequirementsType.fromValue(value); + } + CvssV4Data.ModifiedPrivilegesRequiredType modifiedPrivilegesRequired = null; + value = rsV.getString(51); + if (value != null) { + modifiedPrivilegesRequired = CvssV4Data.ModifiedPrivilegesRequiredType.fromValue(value); + } + CvssV4Data.ModifiedUserInteractionType modifiedUserInteraction = null; + value = rsV.getString(52); + if (value != null) { + modifiedUserInteraction = CvssV4Data.ModifiedUserInteractionType.fromValue(value); + } + CvssV4Data.ModifiedCiaType modifiedVulnConfidentialityImpact = null; + value = rsV.getString(53); + if (value != null) { + modifiedVulnConfidentialityImpact = CvssV4Data.ModifiedCiaType.fromValue(value); + } + CvssV4Data.ModifiedCiaType modifiedVulnIntegrityImpact = null; + value = rsV.getString(54); + if (value != null) { + modifiedVulnIntegrityImpact = CvssV4Data.ModifiedCiaType.fromValue(value); + } + CvssV4Data.ModifiedCiaType modifiedVulnAvailabilityImpact = null; + value = rsV.getString(55); + if (value != null) { + modifiedVulnAvailabilityImpact = CvssV4Data.ModifiedCiaType.fromValue(value); + } + CvssV4Data.ModifiedSubCType modifiedSubConfidentialityImpact = null; + value = rsV.getString(56); + if (value != null) { + modifiedSubConfidentialityImpact = CvssV4Data.ModifiedSubCType.fromValue(value); + } + CvssV4Data.ModifiedSubIaType modifiedSubIntegrityImpact = null; + value = rsV.getString(57); + if (value != null) { + modifiedSubIntegrityImpact = CvssV4Data.ModifiedSubIaType.fromValue(value); + } + CvssV4Data.ModifiedSubIaType modifiedSubAvailabilityImpact = null; + value = rsV.getString(58); + if (value != null) { + modifiedSubAvailabilityImpact = CvssV4Data.ModifiedSubIaType.fromValue(value); + } + CvssV4Data.SafetyType safety = null; + value = rsV.getString(59); + if (value != null) { + safety = CvssV4Data.SafetyType.fromValue(value); + } + CvssV4Data.AutomatableType automatable = null; + value = rsV.getString(60); + if (value != null) { + automatable = CvssV4Data.AutomatableType.fromValue(value); + } + CvssV4Data.RecoveryType recovery = null; + value = rsV.getString(61); + if (value != null) { + recovery = CvssV4Data.RecoveryType.fromValue(value); + } + CvssV4Data.ValueDensityType valueDensity = null; + value = rsV.getString(62); + if (value != null) { + valueDensity = CvssV4Data.ValueDensityType.fromValue(value); + } + CvssV4Data.VulnerabilityResponseEffortType vulnerabilityResponseEffort = null; + value = rsV.getString(63); + if (value != null) { + vulnerabilityResponseEffort = CvssV4Data.VulnerabilityResponseEffortType.fromValue(value); + } + CvssV4Data.ProviderUrgencyType providerUrgency = null; + value = rsV.getString(64); + if (value != null) { + providerUrgency = CvssV4Data.ProviderUrgencyType.fromValue(value); + } + Double baseScore = null; + if (rsV.getObject(65) != null) { + baseScore = rsV.getDouble(65); + } + CvssV4Data.SeverityType baseSeverity = null; + value = rsV.getString(66); + if (value != null) { + baseSeverity = CvssV4Data.SeverityType.fromValue(value); + } + Double threatScore = null; + if (rsV.getObject(67) != null) { + threatScore = rsV.getDouble(67); + } + CvssV4Data.SeverityType threatSeverity = null; + value = rsV.getString(68); + if (value != null) { + threatSeverity = CvssV4Data.SeverityType.fromValue(value); + } + Double environmentalScore = null; + if (rsV.getObject(69) != null) { + environmentalScore = rsV.getDouble(69); + } + CvssV4Data.SeverityType environmentalSeverity = null; + value = rsV.getString(70); + if (value != null) { + environmentalSeverity = CvssV4Data.SeverityType.fromValue(value); + } + //initializing data twice to get the vector string. I really should have designed the object better... + CvssV4Data data = new CvssV4Data(version, vectorString, attackVector, attackComplexity, attackRequirements, privilegesRequired, + userInteraction, vulnConfidentialityImpact, vulnIntegrityImpact, vulnAvailabilityImpact, subConfidentialityImpact, + subIntegrityImpact, subAvailabilityImpact, exploitMaturity, confidentialityRequirement, integrityRequirement, + availabilityRequirement, modifiedAttackVector, modifiedAttackComplexity, modifiedAttackRequirements, + modifiedPrivilegesRequired, modifiedUserInteraction, modifiedVulnConfidentialityImpact, modifiedVulnIntegrityImpact, + modifiedVulnAvailabilityImpact, modifiedSubConfidentialityImpact, modifiedSubIntegrityImpact, + modifiedSubAvailabilityImpact, safety, automatable, recovery, valueDensity, vulnerabilityResponseEffort, + providerUrgency, baseScore, baseSeverity, threatScore, threatSeverity, environmentalScore, environmentalSeverity); + vectorString = data.toString(); + data = new CvssV4Data(version, vectorString, attackVector, attackComplexity, attackRequirements, privilegesRequired, + userInteraction, vulnConfidentialityImpact, vulnIntegrityImpact, vulnAvailabilityImpact, subConfidentialityImpact, + subIntegrityImpact, subAvailabilityImpact, exploitMaturity, confidentialityRequirement, integrityRequirement, + availabilityRequirement, modifiedAttackVector, modifiedAttackComplexity, modifiedAttackRequirements, + modifiedPrivilegesRequired, modifiedUserInteraction, modifiedVulnConfidentialityImpact, modifiedVulnIntegrityImpact, + modifiedVulnAvailabilityImpact, modifiedSubConfidentialityImpact, modifiedSubIntegrityImpact, + modifiedSubAvailabilityImpact, safety, automatable, recovery, valueDensity, vulnerabilityResponseEffort, + providerUrgency, baseScore, baseSeverity, threatScore, threatSeverity, environmentalScore, environmentalSeverity); + + final String source = rsV.getString(71); + CvssV4.Type cvssType = null; + value = rsV.getString(72); + if (value != null) { + cvssType = CvssV4.Type.fromValue(value); + } + final CvssV4 cvssv4 = new CvssV4(source, cvssType, data); + vuln.setCvssV4(cvssv4); + } } else { LOGGER.debug(cve + " does not exist in the database"); return null; } } - try (PreparedStatement psCWE = getPreparedStatement(conn, SELECT_VULNERABILITY_CWE, cveId); - ResultSet rsC = psCWE.executeQuery()) { + try (PreparedStatement psCWE = getPreparedStatement(conn, SELECT_VULNERABILITY_CWE, cveId); ResultSet rsC = psCWE.executeQuery()) { while (rsC.next()) { vuln.addCwe(rsC.getString(1)); } } - try (PreparedStatement psR = getPreparedStatement(conn, SELECT_REFERENCES, cveId); - ResultSet rsR = psR.executeQuery()) { + try (PreparedStatement psR = getPreparedStatement(conn, SELECT_REFERENCES, cveId); ResultSet rsR = psR.executeQuery()) { while (rsR.next()) { vuln.addReference(rsR.getString(1), rsR.getString(2), rsR.getString(3)); } } - try (PreparedStatement psS = getPreparedStatement(conn, SELECT_SOFTWARE, cveId); - ResultSet rsS = psS.executeQuery()) { + try (PreparedStatement psS = getPreparedStatement(conn, SELECT_SOFTWARE, cveId); ResultSet rsS = psS.executeQuery()) { //1 part, 2 vendor, 3 product, 4 version, 5 update_version, 6 edition, 7 lang, //8 sw_edition, 9 target_sw, 10 target_hw, 11 other, 12 versionEndExcluding, //13 versionEndIncluding, 14 versionStartExcluding, 15 versionStartIncluding, 16 vulnerable @@ -810,13 +1083,13 @@ public Vulnerability getVulnerability(String cve, Connection conn) throws Databa */ public void updateVulnerability(DefCveItem cve, String baseEcosystem) { clearCache(); - final String cveId = cve.getCve().getCVEDataMeta().getId(); + final String cveId = cve.getCve().getId(); try { - final String description = cveItemConverter.extractDescription(cve); - if (cveItemConverter.isRejected(description)) { + if (cve.getCve().getVulnStatus() != null && cve.getCve().getVulnStatus().toUpperCase().startsWith("REJECT")) { deleteVulnerability(cveId); } else { if (cveItemConverter.testCveCpeStartWithFilter(cve)) { + final String description = cveItemConverter.extractDescription(cve); final int vulnerabilityId = updateOrInsertVulnerability(cve, description); updateVulnerabilityInsertCwe(vulnerabilityId, cve); updateVulnerabilityInsertReferences(vulnerabilityId, cve); @@ -825,15 +1098,14 @@ public void updateVulnerability(DefCveItem cve, String baseEcosystem) { updateVulnerabilityInsertSoftware(vulnerabilityId, cveId, software, baseEcosystem); } } - } catch (SQLException ex) { - final String msg = String.format("Error updating '%s'", cveId); + final String msg = String.format("Error updating '%s'; %s", cveId, ex.getMessage()); LOGGER.debug(msg, ex); - throw new DatabaseException(msg, ex); + throw new DatabaseException(msg); } catch (CpeValidationException ex) { - final String msg = String.format("Error parsing CPE entry from '%s'", cveId); + final String msg = String.format("Error parsing CPE entry from '%s'; %s", cveId, ex.getMessage()); LOGGER.debug(msg, ex); - throw new DatabaseException(msg, ex); + throw new DatabaseException(msg); } } @@ -858,8 +1130,7 @@ private void loadCpeEcosystemCache() { private void saveCpeEcosystemCache() { final Map, String> map = CpeEcosystemCache.getChanged(); if (map != null && !map.isEmpty()) { - try (Connection conn = databaseManager.getConnection(); - PreparedStatement ps = getPreparedStatement(conn, MERGE_CPE_ECOSYSTEM)) { + try (Connection conn = databaseManager.getConnection(); PreparedStatement ps = getPreparedStatement(conn, MERGE_CPE_ECOSYSTEM)) { for (Map.Entry, String> entry : map.entrySet()) { ps.setString(1, entry.getKey().getLeft()); ps.setString(2, entry.getKey().getRight()); @@ -894,8 +1165,7 @@ private int updateOrInsertVulnerability(DefCveItem cve, String description) { loadCpeEcosystemCache(); } final int vulnerabilityId; - try (Connection conn = databaseManager.getConnection(); - PreparedStatement callUpdate = getPreparedStatement(conn, UPDATE_VULNERABILITY)) { + try (Connection conn = databaseManager.getConnection(); PreparedStatement callUpdate = getPreparedStatement(conn, UPDATE_VULNERABILITY)) { // String 1.cve, String 2.description, String 3.v2Severity, Float 4.v2ExploitabilityScore, // Float 5.v2ImpactScore, Boolean 6.v2AcInsufInfo, Boolean 7.v2ObtainAllPrivilege, // Boolean 8.v2ObtainUserPrivilege, Boolean 9.v2ObtainOtherPrivilege, Boolean 10.v2UserInteractionRequired, @@ -906,88 +1176,213 @@ private int updateOrInsertVulnerability(DefCveItem cve, String description) { // String 23.v3PrivilegesRequired, String 24.v3UserInteraction, String 25.v3Scope, // String 26.v3ConfidentialityImpact, String 27.v3IntegrityImpact, String 28.v3AvailabilityImpact, // Float 29.v3BaseScore, String 30.v3BaseSeverity, String 31.v3Version - callUpdate.setString(1, cve.getCve().getCVEDataMeta().getId()); +// . String 32.v4version, String 33.v4attackVector, String 34.v4attackComplexity, String 35.v4attackRequirements, +// String 36.v4privilegesRequired, String 37.v4userInteraction, String 38.v4vulnConfidentialityImpact, +// String 39.v4vulnIntegrityImpact, String 40.v4vulnAvailabilityImpact, String 41.v4subConfidentialityImpact, +// String 42.v4subIntegrityImpact, String 43.v4subAvailabilityImpact, String 44.v4exploitMaturity, +// String 45.v4confidentialityRequirement, String 46.v4integrityRequirement, String 47.v4availabilityRequirement, +// String 48.v4modifiedAttackVector, String 49.v4modifiedAttackComplexity, String 50.v4modifiedAttackRequirements, +// String 51.v4modifiedPrivilegesRequired, String 52.v4modifiedUserInteraction, String 53.v4modifiedVulnConfidentialityImpact, +// String 54.v4modifiedVulnIntegrityImpact, String 55.v4modifiedVulnAvailabilityImpact, String 56.v4modifiedSubConfidentialityImpact, +// String 57.v4modifiedSubIntegrityImpact, String 58.v4modifiedSubAvailabilityImpact, String 59.v4safety, +// String 60.v4automatable, String 61.v4recovery, String 62.v4valueDensity, String 63.v4vulnerabilityResponseEffort, +// String 64.v4providerUrgency, Float 65.v4baseScore, String 66.v4baseSeverity, Float 67.v4threatScore, +// String 68.v4threatSeverity, Float 69.v4environmentalScore, String 70.v4environmentalSeverity +// . String 71.v4Source, String 72.v4type + callUpdate.setString(1, cve.getCve().getId()); callUpdate.setString(2, description); - if (cve.getImpact().getBaseMetricV2() != null) { - final BaseMetricV2 cvssv2 = cve.getImpact().getBaseMetricV2(); - Map props = cvssv2.getAdditionalProperties(); - callUpdate.setString(3, cvssv2.getSeverity()); - setFloatValue(callUpdate, 4, props, "exploitabilityScore"); - setFloatValue(callUpdate, 5, props, "impactScore"); - setBooleanValue(callUpdate, 6, props, "acInsufInfo"); - setBooleanValue(callUpdate, 7, props, "obtainAllPrivilege"); - setBooleanValue(callUpdate, 8, props, "obtainUserPrivilege"); - setBooleanValue(callUpdate, 9, props, "obtainOtherPrivilege"); - setBooleanValue(callUpdate, 10, props, "userInteractionRequired"); - callUpdate.setFloat(11, cvssv2.getCvssV2().getBaseScore().floatValue()); - callUpdate.setString(12, cvssv2.getCvssV2().getAccessVector().value()); - callUpdate.setString(13, cvssv2.getCvssV2().getAccessComplexity().value()); - callUpdate.setString(14, cvssv2.getCvssV2().getAuthentication().value()); - callUpdate.setString(15, cvssv2.getCvssV2().getConfidentialityImpact().value()); - callUpdate.setString(16, cvssv2.getCvssV2().getIntegrityImpact().value()); - callUpdate.setString(17, cvssv2.getCvssV2().getAvailabilityImpact().value()); - props = cvssv2.getCvssV2().getAdditionalProperties(); - setStringValue(callUpdate, 18, props, "version"); + Optional optCvssv2 = null; + if (cve.getCve().getMetrics() != null && cve.getCve().getMetrics().getCvssMetricV2() != null) { + optCvssv2 = cve.getCve().getMetrics().getCvssMetricV2().stream().sorted(Comparator.comparing(CvssV2::getType)).findFirst(); + } + if (optCvssv2 != null && optCvssv2.isPresent()) { + final CvssV2 cvssv2 = optCvssv2.get(); + setUpdateColumn(callUpdate, 3, cvssv2.getBaseSeverity()); + setUpdateColumn(callUpdate, 4, cvssv2.getExploitabilityScore()); + setUpdateColumn(callUpdate, 5, cvssv2.getImpactScore()); + setUpdateColumn(callUpdate, 6, cvssv2.getAcInsufInfo()); + setUpdateColumn(callUpdate, 7, cvssv2.getObtainAllPrivilege()); + setUpdateColumn(callUpdate, 8, cvssv2.getObtainUserPrivilege()); + setUpdateColumn(callUpdate, 9, cvssv2.getObtainOtherPrivilege()); + setUpdateColumn(callUpdate, 10, cvssv2.getUserInteractionRequired()); + setUpdateColumn(callUpdate, 11, cvssv2.getCvssData().getBaseScore()); + setUpdateColumn(callUpdate, 12, cvssv2.getCvssData().getAccessVector()); + setUpdateColumn(callUpdate, 13, cvssv2.getCvssData().getAccessComplexity()); + setUpdateColumn(callUpdate, 14, cvssv2.getCvssData().getAuthentication()); + setUpdateColumn(callUpdate, 15, cvssv2.getCvssData().getConfidentialityImpact()); + setUpdateColumn(callUpdate, 16, cvssv2.getCvssData().getIntegrityImpact()); + setUpdateColumn(callUpdate, 17, cvssv2.getCvssData().getAvailabilityImpact()); + setUpdateColumn(callUpdate, 18, cvssv2.getCvssData().getVersion()); + } else { + callUpdate.setNull(3, java.sql.Types.VARCHAR); + callUpdate.setNull(4, java.sql.Types.DOUBLE); + callUpdate.setNull(5, java.sql.Types.DOUBLE); + callUpdate.setNull(6, java.sql.Types.VARCHAR); + //TODO this is may also be an issue for MS SQL, if an issue is created we'll just need + // to create an isMsSQL flag. See todo below in setUpdateColum + if (isOracle) { + callUpdate.setNull(7, java.sql.Types.BIT); + callUpdate.setNull(8, java.sql.Types.BIT); + callUpdate.setNull(9, java.sql.Types.BIT); + callUpdate.setNull(10, java.sql.Types.BIT); + } else { + callUpdate.setNull(7, java.sql.Types.BOOLEAN); + callUpdate.setNull(8, java.sql.Types.BOOLEAN); + callUpdate.setNull(9, java.sql.Types.BOOLEAN); + callUpdate.setNull(10, java.sql.Types.BOOLEAN); + } + callUpdate.setNull(11, java.sql.Types.DOUBLE); + callUpdate.setNull(12, java.sql.Types.VARCHAR); + callUpdate.setNull(13, java.sql.Types.VARCHAR); + callUpdate.setNull(14, java.sql.Types.VARCHAR); + callUpdate.setNull(15, java.sql.Types.VARCHAR); + callUpdate.setNull(16, java.sql.Types.VARCHAR); + callUpdate.setNull(17, java.sql.Types.VARCHAR); + callUpdate.setNull(18, java.sql.Types.VARCHAR); + } + Optional optCvssv30 = Optional.empty(); + if (cve.getCve().getMetrics() != null && cve.getCve().getMetrics().getCvssMetricV30() != null) { + optCvssv30 = cve.getCve().getMetrics().getCvssMetricV30().stream().sorted(Comparator.comparing(CvssV3::getType)).findFirst(); + } + Optional optCvssv31 = Optional.empty(); + if (cve.getCve().getMetrics() != null && cve.getCve().getMetrics().getCvssMetricV31() != null) { + optCvssv31 = cve.getCve().getMetrics().getCvssMetricV31().stream().sorted(Comparator.comparing(CvssV3::getType)).findFirst(); + } + + CvssV3 cvssv3 = null; + if (optCvssv31.isPresent()) { + cvssv3 = optCvssv31.get(); + } else if (optCvssv30.isPresent()) { + cvssv3 = optCvssv30.get(); + } + if (cvssv3 != null) { + setUpdateColumn(callUpdate, 19, cvssv3.getExploitabilityScore()); + setUpdateColumn(callUpdate, 20, cvssv3.getImpactScore()); + setUpdateColumn(callUpdate, 21, cvssv3.getCvssData().getAttackVector()); + setUpdateColumn(callUpdate, 22, cvssv3.getCvssData().getAttackComplexity()); + setUpdateColumn(callUpdate, 23, cvssv3.getCvssData().getPrivilegesRequired()); + setUpdateColumn(callUpdate, 24, cvssv3.getCvssData().getUserInteraction()); + setUpdateColumn(callUpdate, 25, cvssv3.getCvssData().getScope()); + setUpdateColumn(callUpdate, 26, cvssv3.getCvssData().getConfidentialityImpact()); + setUpdateColumn(callUpdate, 27, cvssv3.getCvssData().getIntegrityImpact()); + setUpdateColumn(callUpdate, 28, cvssv3.getCvssData().getAvailabilityImpact()); + setUpdateColumn(callUpdate, 29, cvssv3.getCvssData().getBaseScore()); + setUpdateColumn(callUpdate, 30, cvssv3.getCvssData().getBaseSeverity()); + setUpdateColumn(callUpdate, 31, cvssv3.getCvssData().getVersion()); } else { - callUpdate.setNull(3, java.sql.Types.NULL); - callUpdate.setNull(4, java.sql.Types.NULL); - callUpdate.setNull(5, java.sql.Types.NULL); - callUpdate.setNull(6, java.sql.Types.NULL); - callUpdate.setNull(7, java.sql.Types.NULL); - callUpdate.setNull(8, java.sql.Types.NULL); - callUpdate.setNull(9, java.sql.Types.NULL); - callUpdate.setNull(10, java.sql.Types.NULL); - callUpdate.setNull(11, java.sql.Types.NULL); - callUpdate.setNull(12, java.sql.Types.NULL); - callUpdate.setNull(13, java.sql.Types.NULL); - callUpdate.setNull(14, java.sql.Types.NULL); - callUpdate.setNull(15, java.sql.Types.NULL); - callUpdate.setNull(16, java.sql.Types.NULL); - callUpdate.setNull(17, java.sql.Types.NULL); - callUpdate.setNull(18, java.sql.Types.NULL); + callUpdate.setNull(19, java.sql.Types.DOUBLE); + callUpdate.setNull(20, java.sql.Types.DOUBLE); + callUpdate.setNull(21, java.sql.Types.VARCHAR); + callUpdate.setNull(22, java.sql.Types.VARCHAR); + callUpdate.setNull(23, java.sql.Types.VARCHAR); + callUpdate.setNull(24, java.sql.Types.VARCHAR); + callUpdate.setNull(25, java.sql.Types.VARCHAR); + callUpdate.setNull(26, java.sql.Types.VARCHAR); + callUpdate.setNull(27, java.sql.Types.VARCHAR); + callUpdate.setNull(28, java.sql.Types.VARCHAR); + callUpdate.setNull(29, java.sql.Types.DOUBLE); + callUpdate.setNull(30, java.sql.Types.VARCHAR); + callUpdate.setNull(31, java.sql.Types.VARCHAR); } - if (cve.getImpact().getBaseMetricV3() != null) { - final BaseMetricV3 cvssv3 = cve.getImpact().getBaseMetricV3(); - Map props = cvssv3.getAdditionalProperties(); - setFloatValue(callUpdate, 19, props, "exploitabilityScore"); - setFloatValue(callUpdate, 20, props, "impactScore"); - - callUpdate.setString(21, cvssv3.getCvssV3().getAttackVector().value()); - callUpdate.setString(22, cvssv3.getCvssV3().getAttackComplexity().value()); - callUpdate.setString(23, cvssv3.getCvssV3().getPrivilegesRequired().value()); - callUpdate.setString(24, cvssv3.getCvssV3().getUserInteraction().value()); - callUpdate.setString(25, cvssv3.getCvssV3().getScope().value()); - callUpdate.setString(26, cvssv3.getCvssV3().getConfidentialityImpact().value()); - callUpdate.setString(27, cvssv3.getCvssV3().getIntegrityImpact().value()); - callUpdate.setString(28, cvssv3.getCvssV3().getAvailabilityImpact().value()); - callUpdate.setFloat(29, cvssv3.getCvssV3().getBaseScore().floatValue()); - callUpdate.setString(30, cvssv3.getCvssV3().getBaseSeverity().value()); - - props = cvssv3.getCvssV3().getAdditionalProperties(); - setStringValue(callUpdate, 31, props, "version"); + + Optional optCvssv4 = null; + if (cve.getCve().getMetrics() != null && cve.getCve().getMetrics().getCvssMetricV40() != null) { + optCvssv4 = cve.getCve().getMetrics().getCvssMetricV40().stream().sorted(Comparator.comparing(CvssV4::getType)).findFirst(); + } + if (optCvssv4 != null && optCvssv4.isPresent()) { + final CvssV4 cvssv4 = optCvssv4.get(); + setUpdateColumn(callUpdate, 32, cvssv4.getCvssData().getVersion()); + setUpdateColumn(callUpdate, 33, cvssv4.getCvssData().getAttackVector()); + setUpdateColumn(callUpdate, 34, cvssv4.getCvssData().getAttackComplexity()); + setUpdateColumn(callUpdate, 35, cvssv4.getCvssData().getAttackRequirements()); + setUpdateColumn(callUpdate, 36, cvssv4.getCvssData().getPrivilegesRequired()); + setUpdateColumn(callUpdate, 37, cvssv4.getCvssData().getUserInteraction()); + setUpdateColumn(callUpdate, 38, cvssv4.getCvssData().getVulnConfidentialityImpact()); + setUpdateColumn(callUpdate, 39, cvssv4.getCvssData().getVulnIntegrityImpact()); + setUpdateColumn(callUpdate, 40, cvssv4.getCvssData().getVulnAvailabilityImpact()); + setUpdateColumn(callUpdate, 41, cvssv4.getCvssData().getSubConfidentialityImpact()); + setUpdateColumn(callUpdate, 42, cvssv4.getCvssData().getSubIntegrityImpact()); + setUpdateColumn(callUpdate, 43, cvssv4.getCvssData().getSubAvailabilityImpact()); + setUpdateColumn(callUpdate, 44, cvssv4.getCvssData().getExploitMaturity()); + setUpdateColumn(callUpdate, 45, cvssv4.getCvssData().getConfidentialityRequirement()); + setUpdateColumn(callUpdate, 46, cvssv4.getCvssData().getIntegrityRequirement()); + setUpdateColumn(callUpdate, 47, cvssv4.getCvssData().getAvailabilityRequirement()); + setUpdateColumn(callUpdate, 48, cvssv4.getCvssData().getModifiedAttackVector()); + setUpdateColumn(callUpdate, 49, cvssv4.getCvssData().getModifiedAttackComplexity()); + setUpdateColumn(callUpdate, 50, cvssv4.getCvssData().getModifiedAttackRequirements()); + setUpdateColumn(callUpdate, 51, cvssv4.getCvssData().getModifiedPrivilegesRequired()); + setUpdateColumn(callUpdate, 52, cvssv4.getCvssData().getModifiedUserInteraction()); + setUpdateColumn(callUpdate, 53, cvssv4.getCvssData().getModifiedVulnConfidentialityImpact()); + setUpdateColumn(callUpdate, 54, cvssv4.getCvssData().getModifiedVulnIntegrityImpact()); + setUpdateColumn(callUpdate, 55, cvssv4.getCvssData().getModifiedVulnAvailabilityImpact()); + setUpdateColumn(callUpdate, 56, cvssv4.getCvssData().getModifiedSubConfidentialityImpact()); + setUpdateColumn(callUpdate, 57, cvssv4.getCvssData().getModifiedSubIntegrityImpact()); + setUpdateColumn(callUpdate, 58, cvssv4.getCvssData().getModifiedSubAvailabilityImpact()); + setUpdateColumn(callUpdate, 59, cvssv4.getCvssData().getSafety()); + setUpdateColumn(callUpdate, 60, cvssv4.getCvssData().getAutomatable()); + setUpdateColumn(callUpdate, 61, cvssv4.getCvssData().getRecovery()); + setUpdateColumn(callUpdate, 62, cvssv4.getCvssData().getValueDensity()); + setUpdateColumn(callUpdate, 63, cvssv4.getCvssData().getVulnerabilityResponseEffort()); + setUpdateColumn(callUpdate, 64, cvssv4.getCvssData().getProviderUrgency()); + setUpdateColumn(callUpdate, 65, cvssv4.getCvssData().getBaseScore()); + setUpdateColumn(callUpdate, 66, cvssv4.getCvssData().getBaseSeverity()); + setUpdateColumn(callUpdate, 67, cvssv4.getCvssData().getThreatScore()); + setUpdateColumn(callUpdate, 68, cvssv4.getCvssData().getThreatSeverity()); + setUpdateColumn(callUpdate, 69, cvssv4.getCvssData().getEnvironmentalScore()); + setUpdateColumn(callUpdate, 70, cvssv4.getCvssData().getEnvironmentalSeverity()); + setUpdateColumn(callUpdate, 71, cvssv4.getSource()); + setUpdateColumn(callUpdate, 72, cvssv4.getType()); } else { - callUpdate.setNull(19, java.sql.Types.NULL); - callUpdate.setNull(20, java.sql.Types.NULL); - callUpdate.setNull(21, java.sql.Types.NULL); - callUpdate.setNull(22, java.sql.Types.NULL); - callUpdate.setNull(23, java.sql.Types.NULL); - callUpdate.setNull(24, java.sql.Types.NULL); - callUpdate.setNull(25, java.sql.Types.NULL); - callUpdate.setNull(26, java.sql.Types.NULL); - callUpdate.setNull(27, java.sql.Types.NULL); - callUpdate.setNull(28, java.sql.Types.NULL); - callUpdate.setNull(29, java.sql.Types.NULL); - callUpdate.setNull(30, java.sql.Types.NULL); - callUpdate.setNull(31, java.sql.Types.NULL); + callUpdate.setNull(32, java.sql.Types.VARCHAR); + callUpdate.setNull(33, java.sql.Types.VARCHAR); + callUpdate.setNull(34, java.sql.Types.VARCHAR); + callUpdate.setNull(35, java.sql.Types.VARCHAR); + callUpdate.setNull(36, java.sql.Types.VARCHAR); + callUpdate.setNull(37, java.sql.Types.VARCHAR); + callUpdate.setNull(38, java.sql.Types.VARCHAR); + callUpdate.setNull(39, java.sql.Types.VARCHAR); + callUpdate.setNull(40, java.sql.Types.VARCHAR); + callUpdate.setNull(41, java.sql.Types.VARCHAR); + callUpdate.setNull(42, java.sql.Types.VARCHAR); + callUpdate.setNull(43, java.sql.Types.VARCHAR); + callUpdate.setNull(44, java.sql.Types.VARCHAR); + callUpdate.setNull(45, java.sql.Types.VARCHAR); + callUpdate.setNull(46, java.sql.Types.VARCHAR); + callUpdate.setNull(47, java.sql.Types.VARCHAR); + callUpdate.setNull(48, java.sql.Types.VARCHAR); + callUpdate.setNull(49, java.sql.Types.VARCHAR); + callUpdate.setNull(50, java.sql.Types.VARCHAR); + callUpdate.setNull(51, java.sql.Types.VARCHAR); + callUpdate.setNull(52, java.sql.Types.VARCHAR); + callUpdate.setNull(53, java.sql.Types.VARCHAR); + callUpdate.setNull(54, java.sql.Types.VARCHAR); + callUpdate.setNull(55, java.sql.Types.VARCHAR); + callUpdate.setNull(56, java.sql.Types.VARCHAR); + callUpdate.setNull(57, java.sql.Types.VARCHAR); + callUpdate.setNull(58, java.sql.Types.VARCHAR); + callUpdate.setNull(59, java.sql.Types.VARCHAR); + callUpdate.setNull(60, java.sql.Types.VARCHAR); + callUpdate.setNull(61, java.sql.Types.VARCHAR); + callUpdate.setNull(62, java.sql.Types.VARCHAR); + callUpdate.setNull(63, java.sql.Types.VARCHAR); + callUpdate.setNull(64, java.sql.Types.VARCHAR); + callUpdate.setNull(65, java.sql.Types.DOUBLE); + callUpdate.setNull(66, java.sql.Types.VARCHAR); + callUpdate.setNull(67, java.sql.Types.DOUBLE); + callUpdate.setNull(68, java.sql.Types.VARCHAR); + callUpdate.setNull(69, java.sql.Types.DOUBLE); + callUpdate.setNull(70, java.sql.Types.VARCHAR); + callUpdate.setNull(71, java.sql.Types.VARCHAR); + callUpdate.setNull(72, java.sql.Types.VARCHAR); } if (isOracle) { try { final CallableStatement cs = (CallableStatement) callUpdate; - cs.registerOutParameter(32, JDBCType.INTEGER); + cs.registerOutParameter(73, JDBCType.INTEGER); cs.executeUpdate(); - vulnerabilityId = cs.getInt(32); + vulnerabilityId = cs.getInt(73); } catch (SQLException ex) { - final String msg = String.format("Unable to retrieve id for new vulnerability for '%s'", cve.getCve().getCVEDataMeta().getId()); + final String msg = String.format("Unable to retrieve id for new vulnerability for '%s'", cve.getCve().getId()); throw new DatabaseException(msg, ex); } } else { @@ -995,7 +1390,7 @@ private int updateOrInsertVulnerability(DefCveItem cve, String description) { rs.next(); vulnerabilityId = rs.getInt(1); } catch (SQLException ex) { - final String msg = String.format("Unable to retrieve id for new vulnerability for '%s'", cve.getCve().getCVEDataMeta().getId()); + final String msg = String.format("Unable to retrieve id for new vulnerability for '%s'", cve.getCve().getId()); throw new DatabaseException(msg, ex); } } @@ -1013,22 +1408,24 @@ private int updateOrInsertVulnerability(DefCveItem cve, String description) { * @throws SQLException thrown if there is an error inserting the data */ private void updateVulnerabilityInsertCwe(int vulnerabilityId, DefCveItem cve) throws SQLException { - try (Connection conn = databaseManager.getConnection(); - PreparedStatement insertCWE = getPreparedStatement(conn, INSERT_CWE, vulnerabilityId)) { - for (ProblemtypeDatum datum : cve.getCve().getProblemtype().getProblemtypeData()) { - for (LangString desc : datum.getDescription()) { - if ("en".equals(desc.getLang())) { - insertCWE.setString(2, desc.getValue()); - if (isBatchInsertEnabled()) { - insertCWE.addBatch(); - } else { - insertCWE.execute(); + if (cve.getCve() != null && cve.getCve().getWeaknesses() != null) { + try (Connection conn = databaseManager.getConnection(); + PreparedStatement insertCWE = getPreparedStatement(conn, INSERT_CWE, vulnerabilityId)) { + for (Weakness weakness : cve.getCve().getWeaknesses()) { + for (LangString desc : weakness.getDescription()) { + if ("en".equals(desc.getLang())) { + insertCWE.setString(2, desc.getValue()); + if (isBatchInsertEnabled()) { + insertCWE.addBatch(); + } else { + insertCWE.execute(); + } } } } - } - if (isBatchInsertEnabled()) { - insertCWE.executeBatch(); + if (isBatchInsertEnabled()) { + insertCWE.executeBatch(); + } } } } @@ -1112,8 +1509,7 @@ public void updateKnownExploitedVulnerabilities( private void updateVulnerabilityInsertSoftware(int vulnerabilityId, String cveId, List software, String baseEcosystem) throws DatabaseException, SQLException { - try (Connection conn = databaseManager.getConnection(); - PreparedStatement insertSoftware = getPreparedStatement(conn, INSERT_SOFTWARE)) { + try (Connection conn = databaseManager.getConnection(); PreparedStatement insertSoftware = getPreparedStatement(conn, INSERT_SOFTWARE)) { for (VulnerableSoftware parsedCpe : software) { insertSoftware.setInt(1, vulnerabilityId); insertSoftware.setString(2, parsedCpe.getPart().getAbbreviation()); @@ -1167,14 +1563,29 @@ private void updateVulnerabilityInsertSoftware(int vulnerabilityId, String cveId * @throws SQLException thrown if there is an error inserting the data */ private void updateVulnerabilityInsertReferences(int vulnerabilityId, DefCveItem cve) throws SQLException { - try (Connection conn = databaseManager.getConnection(); - PreparedStatement insertReference = getPreparedStatement(conn, INSERT_REFERENCE)) { + try (Connection conn = databaseManager.getConnection(); PreparedStatement insertReference = getPreparedStatement(conn, INSERT_REFERENCE)) { if (cve.getCve().getReferences() != null) { - for (Reference r : cve.getCve().getReferences().getReferenceData()) { + for (Reference r : cve.getCve().getReferences()) { insertReference.setInt(1, vulnerabilityId); - insertReference.setString(2, r.getName()); - insertReference.setString(3, r.getUrl()); - insertReference.setString(4, r.getRefsource()); + String name = null; + if (r.getTags() != null) { + name = r.getTags().stream().sorted().collect(Collectors.joining(",")).toUpperCase().replaceAll("\\s", "_"); + } + if (name != null) { + insertReference.setString(2, name); + } else { + insertReference.setNull(2, java.sql.Types.VARCHAR); + } + if (r.getUrl() != null && !r.getUrl().isEmpty()) { + insertReference.setString(3, r.getUrl()); + } else { + insertReference.setNull(3, java.sql.Types.VARCHAR); + } + if (r.getSource() != null && !r.getSource().isEmpty()) { + insertReference.setString(4, r.getSource()); + } else { + insertReference.setNull(4, java.sql.Types.VARCHAR); + } if (isBatchInsertEnabled()) { insertReference.addBatch(); } else { @@ -1198,20 +1609,24 @@ private void updateVulnerabilityInsertReferences(int vulnerabilityId, DefCveItem */ private List parseCpes(DefCveItem cve) throws CpeValidationException { final List software = new ArrayList<>(); - final List cpeEntries = cve.getConfigurations().getNodes().stream() - .collect(NodeFlatteningCollector.getInstance()) - .collect(CpeMatchStreamCollector.getInstance()) - .filter(predicate -> predicate.getCpe23Uri() != null) - .filter(predicate -> predicate.getCpe23Uri().startsWith(cpeStartsWithFilter)) + + final List cpeEntries = cve.getCve().getConfigurations().stream() + .filter(config -> config.getNodes() != null) + .map(Config::getNodes) + .flatMap(List::stream) + .map(Node::getCpeMatch) + .flatMap(List::stream) + .filter(predicate -> predicate.getCriteria() != null) + .filter(predicate -> predicate.getCriteria().startsWith(cpeStartsWithFilter)) //this single CPE entry causes nearly 100% FP - so filtering it at the source. - .filter(entry -> !("CVE-2009-0754".equals(cve.getCve().getCVEDataMeta().getId()) - && "cpe:2.3:a:apache:apache:*:*:*:*:*:*:*:*".equals(entry.getCpe23Uri()))) + .filter(entry -> !("CVE-2009-0754".equals(cve.getCve().getId()) + && "cpe:2.3:a:apache:apache:*:*:*:*:*:*:*:*".equals(entry.getCriteria()))) .collect(Collectors.toList()); final VulnerableSoftwareBuilder builder = new VulnerableSoftwareBuilder(); try { cpeEntries.forEach(entry -> { - builder.cpe(parseCpe(entry, cve.getCve().getCVEDataMeta().getId())) + builder.cpe(parseCpe(entry, cve.getCve().getId())) .versionEndExcluding(entry.getVersionEndExcluding()) .versionStartExcluding(entry.getVersionStartExcluding()) .versionEndIncluding(entry.getVersionEndIncluding()) @@ -1240,22 +1655,14 @@ private List parseCpes(DefCveItem cve) throws CpeValidationE * @throws DatabaseException thrown if there is an error converting the * CpeMatch into a CPE object */ - private Cpe parseCpe(DefCpeMatch cpe, String cveId) throws DatabaseException { - Cpe parsedCpe; + private Cpe parseCpe(CpeMatch cpe, String cveId) throws DatabaseException { + final Cpe parsedCpe; try { //the replace is a hack as the NVD does not properly escape backslashes in their JSON - parsedCpe = CpeParser.parse(cpe.getCpe23Uri(), true); + parsedCpe = CpeParser.parse(cpe.getCriteria(), true); } catch (CpeParsingException ex) { - LOGGER.debug("NVD (" + cveId + ") contain an invalid 2.3 CPE: " + cpe.getCpe23Uri()); - if (cpe.getCpe22Uri() != null && !cpe.getCpe22Uri().isEmpty()) { - try { - parsedCpe = CpeParser.parse(cpe.getCpe22Uri(), true); - } catch (CpeParsingException ex2) { - throw new DatabaseException("Unable to parse CPE: " + cpe.getCpe23Uri(), ex); - } - } else { - throw new DatabaseException("Unable to parse CPE: " + cpe.getCpe23Uri(), ex); - } + LOGGER.debug("NVD (" + cveId + ") contain an invalid 2.3 CPE: " + cpe.getCriteria()); + throw new DatabaseException("Unable to parse CPE: " + cpe.getCriteria(), ex); } return parsedCpe; } @@ -1336,8 +1743,8 @@ public boolean dataExists() { } LOGGER.error("Unable to access the local database.\n\nEnsure that '{}' is a writable directory. " + "If the problem persist try deleting the files in '{}' and running {} again. If the problem continues, please " - + "create a log file (see documentation at https://jeremylong.github.io/DependencyCheck/) and open a ticket at " - + "https://github.com/jeremylong/DependencyCheck/issues and include the log file.\n\n", + + "create a log file (see documentation at https://dependency-check.github.io/DependencyCheck/) and open a ticket at " + + "https://github.com/dependency-check/DependencyCheck/issues and include the log file.\n\n", dd, dd, settings.getString(Settings.KEYS.APPLICATION_NAME)); LOGGER.debug("", ex); } @@ -1399,8 +1806,7 @@ public void persistEcosystemCache() { public void defrag() { if (isH2) { final long start = System.currentTimeMillis(); - try (Connection conn = databaseManager.getConnection(); - CallableStatement psCompaxt = conn.prepareCall("SHUTDOWN DEFRAG")) { + try (Connection conn = databaseManager.getConnection(); CallableStatement psCompaxt = conn.prepareCall("SHUTDOWN DEFRAG")) { LOGGER.info("Begin database defrag"); psCompaxt.execute(); final long millis = System.currentTimeMillis() - start; @@ -1447,8 +1853,7 @@ VulnerableSoftware getMatchingSoftware(Cpe cpe, Set vulnerab */ public void deleteUnusedCpe() { clearCache(); - try (Connection conn = databaseManager.getConnection(); - PreparedStatement ps = getPreparedStatement(conn, DELETE_UNUSED_DICT_CPE)) { + try (Connection conn = databaseManager.getConnection(); PreparedStatement ps = getPreparedStatement(conn, DELETE_UNUSED_DICT_CPE)) { ps.executeUpdate(); } catch (SQLException ex) { LOGGER.error("Unable to delete CPE dictionary entries", ex); @@ -1468,8 +1873,7 @@ public void deleteUnusedCpe() { */ public void addCpe(String cpe, String vendor, String product) { clearCache(); - try (Connection conn = databaseManager.getConnection(); - PreparedStatement ps = getPreparedStatement(conn, ADD_DICT_CPE)) { + try (Connection conn = databaseManager.getConnection(); PreparedStatement ps = getPreparedStatement(conn, ADD_DICT_CPE)) { ps.setString(1, cpe); ps.setString(2, vendor); ps.setString(3, product); @@ -1528,6 +1932,340 @@ private void addNullableStringParameter(PreparedStatement ps, int pos, String va } } + private void setUpdateColumn(PreparedStatement ps, int i, Double value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.DOUBLE); + } else { + ps.setDouble(i, value); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV2Data.AuthenticationType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV2Data.CiaType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV2Data.Version value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV2Data.AccessComplexityType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV2Data.AccessVectorType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, String value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV4.Type value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, Boolean value) throws SQLException { + if (value == null) { + //TODO this is may also be an issue for MS SQL, if an issue is created we'll just need + // to create an isMsSQL flag. See todo above in updateOrInsertVulnerability. + if (isOracle) { + ps.setNull(i, java.sql.Types.BIT); + } else { + ps.setNull(i, java.sql.Types.BOOLEAN); + } + } else { + ps.setBoolean(i, value); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV3Data.AttackVectorType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV3Data.AttackComplexityType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV3Data.PrivilegesRequiredType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV3Data.UserInteractionType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV3Data.ScopeType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV3Data.SeverityType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV3Data.CiaType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV3Data.Version value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.Version value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.AttackVectorType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.AttackComplexityType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.AttackRequirementsType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.PrivilegesRequiredType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.UserInteractionType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.CiaType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.ExploitMaturityType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.CiaRequirementType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.ModifiedAttackVectorType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.ModifiedAttackComplexityType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.ModifiedAttackRequirementsType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.ModifiedPrivilegesRequiredType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.ModifiedUserInteractionType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.ModifiedCiaType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.ModifiedSubCType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.ModifiedSubIaType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.SafetyType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.AutomatableType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.RecoveryType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.ValueDensityType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.VulnerabilityResponseEffortType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.ProviderUrgencyType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + + private void setUpdateColumn(PreparedStatement ps, int i, CvssV4Data.SeverityType value) throws SQLException { + if (value == null) { + ps.setNull(i, java.sql.Types.VARCHAR); + } else { + ps.setString(i, value.value()); + } + } + /** * Sets the float parameter on a prepared statement from a properties map. * @@ -1542,10 +2280,10 @@ private void setFloatValue(PreparedStatement ps, int i, Map prop try { ps.setFloat(i, Float.parseFloat(props.get(key).toString())); } catch (NumberFormatException nfe) { - ps.setNull(i, java.sql.Types.NULL); + ps.setNull(i, java.sql.Types.FLOAT); } } else { - ps.setNull(i, java.sql.Types.NULL); + ps.setNull(i, java.sql.Types.FLOAT); } } @@ -1562,7 +2300,7 @@ private void setStringValue(PreparedStatement ps, int i, Map pro if (props != null && props.containsKey(key)) { ps.setString(i, props.get(key).toString()); } else { - ps.setNull(i, java.sql.Types.NULL); + ps.setNull(i, java.sql.Types.VARCHAR); } } @@ -1579,7 +2317,7 @@ private void setBooleanValue(PreparedStatement ps, int i, Map pr if (props != null && props.containsKey(key)) { ps.setBoolean(i, Boolean.parseBoolean(props.get(key).toString())); } else { - ps.setNull(i, java.sql.Types.NULL); + ps.setNull(i, java.sql.Types.BOOLEAN); } } diff --git a/core/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveItemOperator.java b/core/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveItemOperator.java index 87866186e72..9d22ec4093b 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveItemOperator.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/nvdcve/CveItemOperator.java @@ -17,13 +17,16 @@ */ package org.owasp.dependencycheck.data.nvdcve; +import io.github.jeremylong.openvulnerability.client.nvd.Config; + +import java.util.Objects; import java.util.stream.Collectors; import org.owasp.dependencycheck.data.nvd.ecosystem.Ecosystem; -import org.owasp.dependencycheck.data.nvd.json.CpeMatchStreamCollector; -import org.owasp.dependencycheck.data.nvd.json.DefCveItem; -import org.owasp.dependencycheck.data.nvd.json.LangString; -import org.owasp.dependencycheck.data.nvd.json.NodeFlatteningCollector; +import io.github.jeremylong.openvulnerability.client.nvd.DefCveItem; +import io.github.jeremylong.openvulnerability.client.nvd.LangString; +import io.github.jeremylong.openvulnerability.client.nvd.Node; +import java.util.List; import org.owasp.dependencycheck.dependency.VulnerableSoftware; /** @@ -57,7 +60,7 @@ public CveItemOperator(String cpeStartsWithFilter) { * @return the English descriptions from the CVE object */ public String extractDescription(DefCveItem cve) { - return cve.getCve().getDescription().getDescriptionData().stream().filter((desc) + return cve.getCve().getDescriptions().stream().filter((desc) -> "en".equals(desc.getLang())).map(LangString::getValue).collect(Collectors.joining(" ")); } @@ -215,12 +218,20 @@ public boolean isRejected(String description) { * @return true if the CVE affects CPEs identified by the * configured CPE Starts with filter */ - protected boolean testCveCpeStartWithFilter(final DefCveItem cve) { - //cycle through to see if this is a CPE we care about (use the CPE filters - return cve.getConfigurations().getNodes().stream() - .collect(NodeFlatteningCollector.getInstance()) - .collect(CpeMatchStreamCollector.getInstance()) - .filter(cpe -> cpe.getCpe23Uri() != null) - .anyMatch(cpe -> cpe.getCpe23Uri().startsWith(cpeStartsWithFilter)); + boolean testCveCpeStartWithFilter(final DefCveItem cve) { + if (cve.getCve().getConfigurations() != null) { + //cycle through to see if this is a CPE we care about (use the CPE filters + return cve.getCve().getConfigurations().stream() + .filter(config -> config.getNodes() != null) + .map(Config::getNodes) + .flatMap(List::stream) + .filter(Objects::nonNull) + .map(Node::getCpeMatch) + .filter(Objects::nonNull) + .flatMap(List::stream) + .filter(cpe -> cpe != null && cpe.getCriteria() != null) + .anyMatch(cpe -> cpe.getCriteria().startsWith(cpeStartsWithFilter)); + } + return false; } } diff --git a/core/src/main/java/org/owasp/dependencycheck/data/nvdcve/DatabaseManager.java b/core/src/main/java/org/owasp/dependencycheck/data/nvdcve/DatabaseManager.java index f2ad3472e4f..b1553ebf988 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/nvdcve/DatabaseManager.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/nvdcve/DatabaseManager.java @@ -70,7 +70,7 @@ public final class DatabaseManager { /** * The URL that discusses upgrading non-H2 databases. */ - public static final String UPGRADE_HELP_URL = "https://jeremylong.github.io/DependencyCheck/data/upgrade.html"; + public static final String UPGRADE_HELP_URL = "https://dependency-check.github.io/DependencyCheck/data/upgrade.html"; /** * The database driver used to connect to the database. */ @@ -197,6 +197,10 @@ private void initialize() throws DatabaseException { LOGGER.debug("Unable to connect to the database", ex); throw new DatabaseException("Unable to connect to the database", ex); } + } else if (isH2 && ex.getMessage().contains("file version or invalid file header")) { + LOGGER.error("Incompatible or corrupt database found. To resolve this issue please remove the existing " + + "database by running purge"); + throw new DatabaseException("Incompatible or corrupt database found; run the purge command to resolve the issue"); } else { LOGGER.debug("Unable to connect to the database", ex); throw new DatabaseException("Unable to connect to the database", ex); diff --git a/core/src/main/java/org/owasp/dependencycheck/data/nvdcve/DatabaseProperties.java b/core/src/main/java/org/owasp/dependencycheck/data/nvdcve/DatabaseProperties.java index f1ef704d3f1..698e0bcd749 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/nvdcve/DatabaseProperties.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/nvdcve/DatabaseProperties.java @@ -17,8 +17,6 @@ */ package org.owasp.dependencycheck.data.nvdcve; -import java.time.Instant; -import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.Map; @@ -27,8 +25,7 @@ import java.util.TreeMap; import javax.annotation.concurrent.ThreadSafe; -import org.owasp.dependencycheck.data.update.nvd.NvdCveInfo; -import org.owasp.dependencycheck.data.update.exception.UpdateException; +import org.owasp.dependencycheck.utils.DateUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -46,26 +43,21 @@ public class DatabaseProperties { */ private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseProperties.class); /** - * Modified key word, used as a key to store information about the modified - * file (i.e. the containing the last 8 days of updates).. + * The last modified request data for the NVD API. */ - public static final String MODIFIED = "Modified"; + public static final String NVD_API_LAST_MODIFIED = "nvd.api.last.modified"; /** - * The properties file key for the last checked field - used to store the - * last check time of the Modified NVD CVE xml file. + * The date the NVD API was last checked for an update. */ - public static final String LAST_CHECKED = "NVD CVE Checked"; + public static final String NVD_API_LAST_CHECKED = "nvd.api.last.checked"; /** - * The properties file key for the last updated field - used to store the - * last updated time of the Modified NVD CVE xml file. + * The date the NVD cache was last checked for an update. */ - public static final String LAST_UPDATED = "NVD CVE Modified"; + public static final String NVD_CACHE_LAST_CHECKED = "nvd.cache.last.checked"; /** - * Stores the last updated time for each of the NVD CVE files. These - * timestamps should be updated if we process the modified file within 7 - * days of the last update. + * The date the NVD cache data was last modified/updated. */ - public static final String LAST_UPDATED_BASE = "NVD CVE "; + public static final String NVD_CACHE_LAST_MODIFIED = "nvd.cache.last.modified"; /** * The key for the last time the CPE data was updated. */ @@ -74,7 +66,6 @@ public class DatabaseProperties { * The key for the database schema version. */ public static final String VERSION = "version"; - /** * The key for the last check time for the Known Exploited Vulnerabilities. */ @@ -83,7 +74,6 @@ public class DatabaseProperties { * The key for the version the Known Exploited Vulnerabilities. */ public static final String KEV_VERSION = "kev.version"; - /** * A collection of properties about the data. */ @@ -112,27 +102,13 @@ public synchronized boolean isEmpty() { return properties == null || properties.isEmpty(); } - /** - * Saves the last updated information to the properties file. - * - * @param updatedValue the updated NVD CVE entry - * @throws UpdateException is thrown if there is an update exception - */ - public synchronized void save(NvdCveInfo updatedValue) throws UpdateException { - if (updatedValue == null) { - return; - } - save(LAST_UPDATED_BASE + updatedValue.getId(), String.valueOf(updatedValue.getTimestamp())); - } - /** * Saves the key value pair to the properties store. * * @param key the property key * @param value the property value - * @throws UpdateException is thrown if there is an update exception */ - public synchronized void save(String key, String value) throws UpdateException { + public synchronized void save(String key, String value) { properties.put(key, value); cveDB.saveProperty(key, value); } @@ -181,21 +157,100 @@ public synchronized Map getMetaData() { for (Entry entry : properties.entrySet()) { final String key = (String) entry.getKey(); if (!"version".equals(key)) { - if ("NVD CVE Modified".equals(key) || "NVD CVE Checked".equals(key) || "VersionCheckOn".equals(key)) { - try { - final long epoch = Long.parseLong((String) entry.getValue()); - final ZonedDateTime dateTime = Instant.ofEpochSecond(epoch).atZone(ZoneId.systemDefault()); - final String formatted = DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(dateTime); - map.put(key, formatted); - } catch (Throwable ex) { //deliberately being broad in this catch clause - LOGGER.debug("Unable to parse timestamp from DB", ex); - map.put(key, (String) entry.getValue()); - } - } else if (!key.startsWith("NVD CVE ")) { - map.put(key, (String) entry.getValue()); + if (DatabaseProperties.NVD_API_LAST_CHECKED.equals(key)) { + map.put("NVD API Last Checked", entry.getValue().toString()); + + } else if (DatabaseProperties.NVD_API_LAST_MODIFIED.equals(key)) { + map.put("NVD API Last Modified", entry.getValue().toString()); + + } else if (DatabaseProperties.NVD_CACHE_LAST_CHECKED.equals(key)) { + map.put("NVD Cache Last Checked", entry.getValue().toString()); + + } else if (DatabaseProperties.NVD_CACHE_LAST_MODIFIED.equals(key)) { + map.put("NVD Cache Last Modified", entry.getValue().toString()); } } } return map; } + + /** + * Retrieves a zoned date time. + * + * @param key the property key + * @return the zoned date time + */ + public ZonedDateTime getTimestamp(String key) { + return DatabaseProperties.getTimestamp(properties, key); + } + + /** + * Stores a timestamp. + * + * @param key the property key + * @param timestamp the zoned date time + */ + public void save(String key, ZonedDateTime timestamp) { + final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssX"); + save(key, dtf.format(timestamp)); + } + + /** + * Stores a timestamp in the properties file. + * + * @param properties the properties to store the timestamp + * @param key the property key + * @param timestamp the zoned date time + */ + public static void setTimestamp(Properties properties, String key, ZonedDateTime timestamp) { + final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssX"); + properties.put(key, dtf.format(timestamp)); + } + + /** + * Retrieves a zoned date time. + * + * @param properties the properties file containing the date time + * @param key the property key + * @return the zoned date time + */ + public static ZonedDateTime getTimestamp(Properties properties, String key) { + final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssX"); + final String val = properties.getProperty(key); + if (val != null) { + final String value = properties.getProperty(key); + return ZonedDateTime.parse(value, dtf); + } + return null; + } + + /** + * Retrieves a zoned date time. + * + * @param properties the properties file containing the date time + * @param key the property key + * @return the zoned date time + */ + public static ZonedDateTime getIsoTimestamp(Properties properties, String key) { + //final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssX"); + final DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE_TIME; + final String val = properties.getProperty(key); + if (val != null) { + final String value = properties.getProperty(key); + return ZonedDateTime.parse(value, dtf); + } + return null; + } + + /** + * Returns the database property value in seconds. + * + * @param key the key to the property + * @return the property value in seconds + */ + public long getPropertyInSeconds(String key) { + final String value = getProperty(key, "0"); + return DateUtil.getEpochValueInSeconds(value); + } + } diff --git a/core/src/main/java/org/owasp/dependencycheck/data/nvdcve/H2Functions.java b/core/src/main/java/org/owasp/dependencycheck/data/nvdcve/H2Functions.java index 4032248b9b6..edb46a4efe2 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/nvdcve/H2Functions.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/nvdcve/H2Functions.java @@ -178,6 +178,47 @@ public static void insertSoftware(final Connection conn, int vulnerabilityId, St * @param v3BaseScore the CVSS v3 base score * @param v3BaseSeverity the CVSS v3 base severity * @param v3Version the CVSS v3 version + * @param v4version CVSS v4 data + * @param v4attackVector CVSS v4 data + * @param v4attackComplexity CVSS v4 data + * @param v4attackRequirements CVSS v4 data + * @param v4privilegesRequired CVSS v4 data + * @param v4userInteraction CVSS v4 data + * @param v4vulnConfidentialityImpact CVSS v4 data + * @param v4vulnIntegrityImpact CVSS v4 data + * @param v4vulnAvailabilityImpact CVSS v4 data + * @param v4subConfidentialityImpact CVSS v4 data + * @param v4subIntegrityImpact CVSS v4 data + * @param v4subAvailabilityImpact CVSS v4 data + * @param v4exploitMaturity CVSS v4 data + * @param v4confidentialityRequirement CVSS v4 data + * @param v4integrityRequirement CVSS v4 data + * @param v4availabilityRequirement CVSS v4 data + * @param v4modifiedAttackVector CVSS v4 data + * @param v4modifiedAttackComplexity CVSS v4 data + * @param v4modifiedAttackRequirements CVSS v4 data + * @param v4modifiedPrivilegesRequired CVSS v4 data + * @param v4modifiedUserInteraction CVSS v4 data + * @param v4modifiedVulnConfidentialityImpact CVSS v4 data + * @param v4modifiedVulnIntegrityImpact CVSS v4 data + * @param v4modifiedVulnAvailabilityImpact CVSS v4 data + * @param v4modifiedSubConfidentialityImpact CVSS v4 data + * @param v4modifiedSubIntegrityImpact CVSS v4 data + * @param v4modifiedSubAvailabilityImpact CVSS v4 data + * @param v4safety CVSS v4 data + * @param v4automatable CVSS v4 data + * @param v4recovery CVSS v4 data + * @param v4valueDensity CVSS v4 data + * @param v4vulnerabilityResponseEffort CVSS v4 data + * @param v4providerUrgency CVSS v4 data + * @param v4baseScore CVSS v4 data + * @param v4baseSeverity CVSS v4 data + * @param v4threatScore CVSS v4 data + * @param v4threatSeverity CVSS v4 data + * @param v4environmentalScore CVSS v4 data + * @param v4environmentalSeverity CVSS v4 data + * @param v4source CVSS v4 data + * @param v4type CVSS v4 data * @return a result set containing the vulnerability id * @throws SQLException thrown if there is an error updating or inserting * the vulnerability @@ -192,7 +233,20 @@ public static ResultSet updateVulnerability(final Connection conn, String cve, Float v3ImpactScore, String v3AttackVector, String v3AttackComplexity, String v3PrivilegesRequired, String v3UserInteraction, String v3Scope, String v3ConfidentialityImpact, String v3IntegrityImpact, String v3AvailabilityImpact, - Float v3BaseScore, String v3BaseSeverity, String v3Version) throws SQLException { + Float v3BaseScore, String v3BaseSeverity, String v3Version, String v4version, + String v4attackVector, String v4attackComplexity, String v4attackRequirements, + String v4privilegesRequired, String v4userInteraction, String v4vulnConfidentialityImpact, + String v4vulnIntegrityImpact, String v4vulnAvailabilityImpact, String v4subConfidentialityImpact, + String v4subIntegrityImpact, String v4subAvailabilityImpact, String v4exploitMaturity, + String v4confidentialityRequirement, String v4integrityRequirement, String v4availabilityRequirement, + String v4modifiedAttackVector, String v4modifiedAttackComplexity, String v4modifiedAttackRequirements, + String v4modifiedPrivilegesRequired, String v4modifiedUserInteraction, String v4modifiedVulnConfidentialityImpact, + String v4modifiedVulnIntegrityImpact, String v4modifiedVulnAvailabilityImpact, String v4modifiedSubConfidentialityImpact, + String v4modifiedSubIntegrityImpact, String v4modifiedSubAvailabilityImpact, String v4safety, + String v4automatable, String v4recovery, String v4valueDensity, String v4vulnerabilityResponseEffort, + String v4providerUrgency, Float v4baseScore, String v4baseSeverity, Float v4threatScore, + String v4threatSeverity, Float v4environmentalScore, String v4environmentalSeverity, + String v4source, String v4type) throws SQLException { final SimpleResultSet ret = new SimpleResultSet(); ret.addColumn("id", Types.INTEGER, 10, 0); @@ -240,7 +294,22 @@ public static ResultSet updateVulnerability(final Connection conn, String cve, + "v3ImpactScore=?, v3AttackVector=?, v3AttackComplexity=?, " + "v3PrivilegesRequired=?, v3UserInteraction=?, v3Scope=?, " + "v3ConfidentialityImpact=?, v3IntegrityImpact=?, v3AvailabilityImpact=?, " - + "v3BaseScore=?, v3BaseSeverity=?, v3Version=? " + + "v3BaseScore=?, v3BaseSeverity=?, v3Version=?, v4version=?, v4attackVector=?, " + + "v4attackComplexity=?, v4attackRequirements=?, v4privilegesRequired=?, " + + "v4userInteraction=?, v4vulnConfidentialityImpact=?, v4vulnIntegrityImpact=?, " + + "v4vulnAvailabilityImpact=?, v4subConfidentialityImpact=?, v4subIntegrityImpact=?, " + + "v4subAvailabilityImpact=?, v4exploitMaturity=?, " + + "v4confidentialityRequirement=?, v4integrityRequirement=?, " + + "v4availabilityRequirement=?, v4modifiedAttackVector=?, " + + "v4modifiedAttackComplexity=?, v4modifiedAttackRequirements=?, " + + "v4modifiedPrivilegesRequired=?, v4modifiedUserInteraction=?, " + + "v4modifiedVulnConfidentialityImpact=?, v4modifiedVulnIntegrityImpact=?, " + + "v4modifiedVulnAvailabilityImpact=?, v4modifiedSubConfidentialityImpact=?, " + + "v4modifiedSubIntegrityImpact=?, v4modifiedSubAvailabilityImpact=?, " + + "v4safety=?, v4automatable=?, v4recovery=?, v4valueDensity=?, " + + "v4vulnerabilityResponseEffort=?, v4providerUrgency=?, v4baseScore=?, " + + "v4baseSeverity=?, v4threatScore=?, v4threatSeverity=?, v4environmentalScore=?, " + + "v4environmentalSeverity=?, v4source=?, v4type=?" + "WHERE id=?"); } else { //just do insert @@ -255,8 +324,22 @@ public static ResultSet updateVulnerability(final Connection conn, String cve, + "v3ImpactScore, v3AttackVector, v3AttackComplexity, " + "v3PrivilegesRequired, v3UserInteraction, v3Scope, " + "v3ConfidentialityImpact, v3IntegrityImpact, v3AvailabilityImpact, " - + "v3BaseScore, v3BaseSeverity, v3Version, cve) VALUES (?, ?, ?, ?, ?, ?, " - + "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + + "v3BaseScore, v3BaseSeverity, v3Version, v4version, v4attackVector, " + + "v4attackComplexity, v4attackRequirements, v4privilegesRequired, " + + "v4userInteraction, v4vulnConfidentialityImpact, v4vulnIntegrityImpact, " + + "v4vulnAvailabilityImpact, v4subConfidentialityImpact, v4subIntegrityImpact, " + + "v4subAvailabilityImpact, v4exploitMaturity,v4confidentialityRequirement, " + + "v4integrityRequirement, v4availabilityRequirement,v4modifiedAttackVector, " + + "v4modifiedAttackComplexity, v4modifiedAttackRequirements,v4modifiedPrivilegesRequired, " + + "v4modifiedUserInteraction, v4modifiedVulnConfidentialityImpact,v4modifiedVulnIntegrityImpact, " + + "v4modifiedVulnAvailabilityImpact, v4modifiedSubConfidentialityImpact,v4modifiedSubIntegrityImpact, " + + "v4modifiedSubAvailabilityImpact, v4safety, v4automatable, v4recovery, v4valueDensity, " + + "v4vulnerabilityResponseEffort, v4providerUrgency, v4baseScore, v4baseSeverity, " + + "v4threatScore,v4threatSeverity, v4environmentalScore, v4environmentalSeverity, " + + "v4source, v4type, cve) VALUES (?, ?, ?, ?, ?, ?, " + + "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, " + + "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, " + + "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", returnedColumns); } @@ -292,11 +375,55 @@ public static ResultSet updateVulnerability(final Connection conn, String cve, setStringOrNull(merge, 29, v3BaseSeverity); setStringOrNull(merge, 30, v3Version); + setStringOrNull(merge, 31, v4version); + setStringOrNull(merge, 32, v4attackVector); + setStringOrNull(merge, 33, v4attackComplexity); + setStringOrNull(merge, 34, v4attackRequirements); + setStringOrNull(merge, 35, v4privilegesRequired); + setStringOrNull(merge, 36, v4userInteraction); + setStringOrNull(merge, 37, v4vulnConfidentialityImpact); + setStringOrNull(merge, 38, v4vulnIntegrityImpact); + setStringOrNull(merge, 39, v4vulnAvailabilityImpact); + setStringOrNull(merge, 40, v4subConfidentialityImpact); + setStringOrNull(merge, 41, v4subIntegrityImpact); + setStringOrNull(merge, 42, v4subAvailabilityImpact); + setStringOrNull(merge, 43, v4exploitMaturity); + setStringOrNull(merge, 44, v4confidentialityRequirement); + setStringOrNull(merge, 45, v4integrityRequirement); + setStringOrNull(merge, 46, v4availabilityRequirement); + setStringOrNull(merge, 47, v4modifiedAttackVector); + setStringOrNull(merge, 48, v4modifiedAttackComplexity); + setStringOrNull(merge, 49, v4modifiedAttackRequirements); + setStringOrNull(merge, 50, v4modifiedPrivilegesRequired); + setStringOrNull(merge, 51, v4modifiedUserInteraction); + setStringOrNull(merge, 52, v4modifiedVulnConfidentialityImpact); + setStringOrNull(merge, 53, v4modifiedVulnIntegrityImpact); + setStringOrNull(merge, 54, v4modifiedVulnAvailabilityImpact); + setStringOrNull(merge, 55, v4modifiedSubConfidentialityImpact); + setStringOrNull(merge, 56, v4modifiedSubIntegrityImpact); + setStringOrNull(merge, 57, v4modifiedSubAvailabilityImpact); + setStringOrNull(merge, 58, v4safety); + setStringOrNull(merge, 59, v4automatable); + setStringOrNull(merge, 60, v4recovery); + setStringOrNull(merge, 61, v4valueDensity); + setStringOrNull(merge, 62, v4vulnerabilityResponseEffort); + setStringOrNull(merge, 63, v4providerUrgency); + setFloatOrNull(merge, 64, v4baseScore); + setStringOrNull(merge, 65, v4baseSeverity); + setFloatOrNull(merge, 66, v4threatScore); + setStringOrNull(merge, 67, v4threatSeverity); + setFloatOrNull(merge, 68, v4environmentalScore); + setStringOrNull(merge, 69, v4environmentalSeverity); + setStringOrNull(merge, 70, v4source); + setStringOrNull(merge, 71, v4type); + + //cve must be the last entry if (vulnerabilityId == 0) { - merge.setString(31, cve); + merge.setString(72, cve); } else { - merge.setInt(31, vulnerabilityId); + merge.setInt(72, vulnerabilityId); } + final int count = merge.executeUpdate(); if (vulnerabilityId == 0) { try (ResultSet rs = merge.getGeneratedKeys()) { @@ -329,7 +456,8 @@ public static ResultSet updateVulnerability(final Connection conn, String cve, * @param requiredAction the action required * @param dueDate the due date * @param notes notes - * @throws SQLException + * @throws SQLException thrown if there is a database error merging the + * Known Exploited information to the database */ public static void mergeKnownExploited(final Connection conn, String cveId, String vendorProject, String product, String vulnerabilityName, diff --git a/core/src/main/java/org/owasp/dependencycheck/data/ossindex/ODCConnectionTransport.java b/core/src/main/java/org/owasp/dependencycheck/data/ossindex/ODCConnectionTransport.java index 64701c8ef34..0e766b78625 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/ossindex/ODCConnectionTransport.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/ossindex/ODCConnectionTransport.java @@ -18,13 +18,21 @@ package org.owasp.dependencycheck.data.ossindex; import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.URL; -import org.owasp.dependencycheck.utils.Settings; -import org.owasp.dependencycheck.utils.URLConnectionFactory; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpHeaders; +import org.apache.hc.core5.http.message.BasicHeader; +import org.owasp.dependencycheck.utils.Downloader; +import org.owasp.dependencycheck.utils.ResourceNotFoundException; +import org.owasp.dependencycheck.utils.TooManyRequestsException; import org.sonatype.ossindex.service.client.OssindexClientConfiguration; import org.sonatype.ossindex.service.client.transport.BasicAuthHelper; -import org.sonatype.ossindex.service.client.transport.HttpUrlConnectionTransport; +import org.sonatype.ossindex.service.client.transport.Transport; import org.sonatype.ossindex.service.client.transport.UserAgentSupplier; /** @@ -33,20 +41,12 @@ * * @author Jeremy Long */ -public class ODCConnectionTransport extends HttpUrlConnectionTransport { +public class ODCConnectionTransport implements Transport { - /** - * The authorization header. - */ - private static final String AUTHORIZATION = "Authorization"; /** * The OSS Index client configuration. */ private final OssindexClientConfiguration configuration; - /** - * The URL Connection factory. - */ - private final URLConnectionFactory connectionFactory; /** * The user agent to send in the HTTP connection. */ @@ -55,27 +55,40 @@ public class ODCConnectionTransport extends HttpUrlConnectionTransport { /** * Constructs a new transport object to connect to the OSS Index. * - * @param settings the ODC settings * @param config the OSS client configuration * @param userAgent the user agent to send to OSS Index */ - public ODCConnectionTransport(Settings settings, OssindexClientConfiguration config, UserAgentSupplier userAgent) { - super(userAgent); + public ODCConnectionTransport(OssindexClientConfiguration config, UserAgentSupplier userAgent) { this.userAgent = userAgent; this.configuration = config; - connectionFactory = new URLConnectionFactory(settings); } @Override - protected HttpURLConnection connect(final URL url) throws IOException { - final HttpURLConnection connection = connectionFactory.createHttpURLConnection(url); - connection.setRequestProperty("User-Agent", userAgent.get()); + public void init(OssindexClientConfiguration configuration) { + // no initialisation needed + } - final String authorization = BasicAuthHelper.authorizationHeader(configuration.getAuthConfiguration()); - if (authorization != null) { - connection.setRequestProperty(AUTHORIZATION, authorization); + @Override + public String post(URI url, String payloadType, String payload, String acceptType) throws TransportException, IOException { + try { + final List
headers = new ArrayList<>(3); + headers.add(new BasicHeader(HttpHeaders.ACCEPT, acceptType)); + headers.add(new BasicHeader(HttpHeaders.USER_AGENT, userAgent.get())); + // TODO consider to promote pre-emptive authentication by default to the Downloader and also load the OSSIndex credentials there. + final String authorization = BasicAuthHelper.authorizationHeader(configuration.getAuthConfiguration()); + if (authorization != null) { + headers.add(new BasicHeader(HttpHeaders.AUTHORIZATION, authorization)); + } + return Downloader.getInstance().postBasedFetchContent(url, payload, ContentType.create(payloadType, StandardCharsets.UTF_8), headers); + } catch (TooManyRequestsException e) { + throw new TransportException("Too many requests for " + url.toString() + " HTTP status 429", e); + } catch (ResourceNotFoundException e) { + throw new TransportException("Not found for " + url.toString() + "HTTP status 404", e); } - return connection; } + @Override + public void close() throws Exception { + // no resource closure needed; fully delegated to HTTPClient + } } diff --git a/core/src/main/java/org/owasp/dependencycheck/data/ossindex/OssindexClientFactory.java b/core/src/main/java/org/owasp/dependencycheck/data/ossindex/OssindexClientFactory.java index 78026f58ebb..6502be6e9dd 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/ossindex/OssindexClientFactory.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/ossindex/OssindexClientFactory.java @@ -85,12 +85,6 @@ public static OssindexClient create(final Settings settings) { final int batchSize = settings.getInt(Settings.KEYS.ANALYZER_OSSINDEX_BATCH_SIZE, OssindexClientConfiguration.DEFAULT_BATCH_SIZE); config.setBatchSize(batchSize); - // proxy likely does not need to be configured here as we are using the - // URLConnectionFactory#createHttpURLConnection() which automatically configures - // the proxy on the connection. -// ProxyConfiguration proxy = new ProxyConfiguration(); -// settings.getString(Settings.KEYS.PROXY_PASSWORD); -// config.setProxyConfiguration(proxy); if (settings.getBoolean(Settings.KEYS.ANALYZER_OSSINDEX_USE_CACHE, true)) { final DirectoryCache.Configuration cache = new DirectoryCache.Configuration(); final File data; @@ -101,7 +95,7 @@ public static OssindexClient create(final Settings settings) { cache.setBaseDir(cacheDir.toPath()); cache.setExpireAfter(Duration.standardHours(24)); config.setCacheConfiguration(cache); - LOGGER.debug("OSS Index Cache: " + cache); + LOGGER.debug("OSS Index Cache: {}", cache); } else { LOGGER.warn("Unable to use a cache for the OSS Index"); } @@ -115,7 +109,7 @@ public static OssindexClient create(final Settings settings) { settings.getString(Settings.KEYS.APPLICATION_VERSION, "unknown") ); - final Transport transport = new ODCConnectionTransport(settings, config, userAgent); + final Transport transport = new ODCConnectionTransport(config, userAgent); final Marshaller marshaller = new GsonMarshaller(); diff --git a/core/src/main/java/org/owasp/dependencycheck/data/update/EngineVersionCheck.java b/core/src/main/java/org/owasp/dependencycheck/data/update/EngineVersionCheck.java index c81d8c7a740..ae8fd3c1d9f 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/update/EngineVersionCheck.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/update/EngineVersionCheck.java @@ -18,13 +18,12 @@ package org.owasp.dependencycheck.data.update; import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.nio.charset.StandardCharsets; +import java.util.Arrays; import javax.annotation.concurrent.ThreadSafe; -import org.apache.commons.io.IOUtils; + import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.data.nvdcve.CveDB; import org.owasp.dependencycheck.data.nvdcve.DatabaseException; @@ -32,9 +31,10 @@ import org.owasp.dependencycheck.data.update.exception.UpdateException; import org.owasp.dependencycheck.utils.DateUtil; import org.owasp.dependencycheck.utils.DependencyVersion; +import org.owasp.dependencycheck.utils.Downloader; +import org.owasp.dependencycheck.utils.ResourceNotFoundException; import org.owasp.dependencycheck.utils.Settings; -import org.owasp.dependencycheck.utils.URLConnectionFactory; -import org.owasp.dependencycheck.utils.URLConnectionFailureException; +import org.owasp.dependencycheck.utils.TooManyRequestsException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -123,14 +123,14 @@ public boolean update(Engine engine) throws UpdateException { final CveDB db = engine.getDatabase(); final boolean autoupdate = settings.getBoolean(Settings.KEYS.AUTO_UPDATE, true); final boolean enabled = settings.getBoolean(Settings.KEYS.UPDATE_VERSION_CHECK_ENABLED, true); - final String original = settings.getString(Settings.KEYS.CVE_ORIGINAL_JSON); - final String current = settings.getString(Settings.KEYS.CVE_MODIFIED_JSON); + final String datafeed = settings.getString(Settings.KEYS.NVD_API_DATAFEED_URL); /* * Only update if auto-update is enabled, the engine check is - * enabled, and the NVD CVE URLs have not been modified (i.e. the - * user has not configured them to point to an internal source). + * enabled, and the NVD DataFeed is being used (i.e. the user + * is likely on a private network). This check is not really needed + * so we are okay skipping it. */ - if (enabled && autoupdate && original != null && original.equals(current)) { + if (enabled && autoupdate && datafeed != null) { LOGGER.debug("Begin Engine Version Check"); final DatabaseProperties properties = db.getDatabaseProperties(); @@ -169,13 +169,21 @@ public boolean update(Engine engine) throws UpdateException { * github documentation site or accessing the local database. */ protected boolean shouldUpdate(final long lastChecked, final long now, final DatabaseProperties properties, - String currentVersion) throws UpdateException { + String currentVersion) throws UpdateException { //check every 30 days if we know there is an update, otherwise check every 7 days final int checkRange = 30; if (!DateUtil.withinDateRange(lastChecked, now, checkRange)) { LOGGER.debug("Checking web for new version."); - final String currentRelease = getCurrentReleaseVersion(); - if (currentRelease != null) { + final String publishedData = getCurrentReleaseVersion(); + if (publishedData != null) { + final String[] parts = publishedData.split("\n"); + if (parts.length > 1) { + final String message = String.join("\n", Arrays.copyOfRange(parts, 1, parts.length)).trim(); + LOGGER.warn("\n\n*********************************************************\n" + + message + + "\n*********************************************************\n"); + } + final String currentRelease = parts[0].trim(); final DependencyVersion v = new DependencyVersion(currentRelease); if (v.getVersionParts() != null && v.getVersionParts().size() >= 3) { updateToVersion = v.toString(); @@ -208,30 +216,20 @@ protected boolean shouldUpdate(final long lastChecked, final long now, final Dat * @return the current released version number */ protected String getCurrentReleaseVersion() { - HttpURLConnection conn = null; try { - final String str = settings.getString(Settings.KEYS.ENGINE_VERSION_CHECK_URL, "https://jeremylong.github.io/DependencyCheck/current.txt"); + final String str = settings.getString(Settings.KEYS.ENGINE_VERSION_CHECK_URL, "https://dependency-check.github.io/DependencyCheck/current.txt"); final URL url = new URL(str); - final URLConnectionFactory factory = new URLConnectionFactory(settings); - conn = factory.createHttpURLConnection(url); - conn.connect(); - if (conn.getResponseCode() != 200) { - return null; - } - try (InputStream is = conn.getInputStream()) { - final String releaseVersion = new String(IOUtils.toByteArray(is), StandardCharsets.UTF_8); - return releaseVersion.trim(); - } + String releaseVersion = null; + releaseVersion = Downloader.getInstance().fetchContent(url, StandardCharsets.UTF_8); + return releaseVersion.trim(); + } catch (TooManyRequestsException ex) { + LOGGER.debug("Unable to retrieve current release version of dependency-check - downloader failed on HTTP 429 Too many requests"); + } catch (ResourceNotFoundException ex) { + LOGGER.debug("Unable to retrieve current release version of dependency-check - downloader failed on HTTP 404 ResourceNotFound"); } catch (MalformedURLException ex) { LOGGER.debug("Unable to retrieve current release version of dependency-check - malformed url?"); - } catch (URLConnectionFailureException ex) { - LOGGER.debug("Unable to retrieve current release version of dependency-check - connection failed"); } catch (IOException ex) { LOGGER.debug("Unable to retrieve current release version of dependency-check - i/o exception"); - } finally { - if (conn != null) { - conn.disconnect(); - } } return null; } diff --git a/core/src/main/java/org/owasp/dependencycheck/data/update/HostedSuppressionsDataSource.java b/core/src/main/java/org/owasp/dependencycheck/data/update/HostedSuppressionsDataSource.java index afa0630eb53..09d7627b7b2 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/update/HostedSuppressionsDataSource.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/update/HostedSuppressionsDataSource.java @@ -34,7 +34,7 @@ import java.net.URL; import java.nio.file.Files; -public class HostedSuppressionsDataSource implements CachedWebDataSource { +public class HostedSuppressionsDataSource extends LocalDataSource { /** * Static logger. @@ -45,17 +45,17 @@ public class HostedSuppressionsDataSource implements CachedWebDataSource { * The configured settings. */ private Settings settings; - /** * The default URL to the Hosted Suppressions file. */ - public static final String DEFAULT_SUPPRESSIONS_URL = "https://jeremylong.github.io/DependencyCheck/suppressions/publishedSuppressions.xml"; + public static final String DEFAULT_SUPPRESSIONS_URL = "https://dependency-check.github.io/DependencyCheck/suppressions/publishedSuppressions.xml"; /** * Downloads the current Hosted suppressions file. * * @param engine a reference to the ODC Engine - * @return returns false as no updates are made to the database, just web resources cached locally + * @return returns false as no updates are made to the database, just web + * resources cached locally * @throws UpdateException thrown if the update encountered fatal errors */ @Override @@ -76,11 +76,12 @@ public boolean update(Engine engine) throws UpdateException { if (proceed) { LOGGER.debug("Begin Hosted Suppressions file update"); fetchHostedSuppressions(settings, url, repoFile); + saveLastUpdated(repoFile, System.currentTimeMillis() / 1000); } } catch (UpdateException ex) { // only emit a warning, DependencyCheck will continue without taking the latest hosted suppressions into account. LOGGER.warn("Failed to update hosted suppressions file, results may contain false positives already resolved by the " - + "DependencyCheck project", ex); + + "DependencyCheck project", ex); } catch (MalformedURLException ex) { throw new UpdateException(String.format("Invalid URL for Hosted Suppressions file (%s)", configuredUrl), ex); } catch (IOException ex) { @@ -93,8 +94,8 @@ public boolean update(Engine engine) throws UpdateException { * Determines if the we should update the Hosted Suppressions file. * * @param repo the Hosted Suppressions file. - * @return true if an update to the Hosted Suppressions file should - * be performed; otherwise false + * @return true if an update to the Hosted Suppressions file + * should be performed; otherwise false * @throws NumberFormatException thrown if an invalid value is contained in * the database properties */ @@ -102,7 +103,7 @@ protected boolean shouldUpdate(File repo) throws NumberFormatException { boolean proceed = true; if (repo != null && repo.isFile()) { final int validForHours = settings.getInt(Settings.KEYS.HOSTED_SUPPRESSIONS_VALID_FOR_HOURS, 2); - final long lastUpdatedOn = repo.lastModified(); + final long lastUpdatedOn = getLastUpdated(repo); final long now = System.currentTimeMillis(); LOGGER.debug("Last updated: {}", lastUpdatedOn); LOGGER.debug("Now: {}", now); @@ -120,7 +121,8 @@ protected boolean shouldUpdate(File repo) throws NumberFormatException { * * @param settings a reference to the dependency-check settings * @param repoUrl the URL to the hosted suppressions file to use - * @param repoFile the local file where the hosted suppressions file is to be placed + * @param repoFile the local file where the hosted suppressions file is to + * be placed * @throws UpdateException thrown if there is an exception during * initialization */ @@ -130,8 +132,7 @@ private void fetchHostedSuppressions(Settings settings, URL repoUrl, File repoFi if (LOGGER.isDebugEnabled()) { LOGGER.debug("Hosted Suppressions URL: {}", repoUrl.toExternalForm()); } - final Downloader downloader = new Downloader(settings); - downloader.fetchFile(repoUrl, repoFile); + Downloader.getInstance().fetchFile(repoUrl, repoFile); } catch (IOException | TooManyRequestsException | ResourceNotFoundException | WriteLockException ex) { throw new UpdateException("Failed to update the hosted suppressions file", ex); } @@ -144,7 +145,7 @@ public boolean purge(Engine engine) { boolean result = true; try { final URL repoUrl = new URL(settings.getString(Settings.KEYS.HOSTED_SUPPRESSIONS_URL, - DEFAULT_SUPPRESSIONS_URL)); + DEFAULT_SUPPRESSIONS_URL)); final String filename = new File(repoUrl.getPath()).getName(); final File repo = new File(settings.getDataDirectory(), filename); if (repo.exists()) { diff --git a/core/src/main/java/org/owasp/dependencycheck/data/update/KnownExploitedDataSource.java b/core/src/main/java/org/owasp/dependencycheck/data/update/KnownExploitedDataSource.java index 459af715d94..2bae99b04a3 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/update/KnownExploitedDataSource.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/update/KnownExploitedDataSource.java @@ -19,8 +19,13 @@ import java.io.IOException; import java.io.InputStream; +import java.net.URISyntaxException; import java.net.URL; import java.sql.SQLException; + +import org.apache.hc.client5.http.impl.classic.AbstractHttpClientResponseHandler; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.io.HttpClientResponseHandler; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.data.knownexploited.json.KnownExploitedVulnerabilitiesSchema; import org.owasp.dependencycheck.data.nvdcve.CveDB; @@ -29,8 +34,7 @@ import org.owasp.dependencycheck.data.update.cisa.KnownExploitedVulnerabilityParser; import org.owasp.dependencycheck.data.update.exception.CorruptedDatastreamException; import org.owasp.dependencycheck.data.update.exception.UpdateException; -import org.owasp.dependencycheck.utils.DateUtil; -import org.owasp.dependencycheck.utils.HttpResourceConnection; +import org.owasp.dependencycheck.utils.Downloader; import org.owasp.dependencycheck.utils.ResourceNotFoundException; import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.TooManyRequestsException; @@ -38,7 +42,6 @@ import org.slf4j.LoggerFactory; /** - * * @author jeremy */ public class KnownExploitedDataSource implements CachedWebDataSource { @@ -75,21 +78,31 @@ public boolean update(Engine engine) throws UpdateException { try { final URL url = new URL(settings.getString(Settings.KEYS.KEV_URL, DEFAULT_URL)); LOGGER.info("Updating CISA Known Exploited Vulnerability list: " + url.toString()); - //TODO - add all the proxy config, likely use the same as configured for NVD - final HttpResourceConnection conn = new HttpResourceConnection(settings); - try (InputStream in = conn.fetch(url)) { - final KnownExploitedVulnerabilityParser parser = new KnownExploitedVulnerabilityParser(); - final KnownExploitedVulnerabilitiesSchema data = parser.parse(in); - final String currentVersion = dbProperties.getProperty(DatabaseProperties.KEV_VERSION, ""); - if (!currentVersion.equals(data.getCatalogVersion())) { - cveDB.updateKnownExploitedVulnerabilities(data.getVulnerabilities()); - } - //all dates in the db are now stored in seconds as opposed to previously milliseconds. - dbProperties.save(DatabaseProperties.KEV_LAST_CHECKED, Long.toString(System.currentTimeMillis() / 1000)); - return true; + + final HttpClientResponseHandler kevParsingResponseHandler = + new AbstractHttpClientResponseHandler<>() { + @Override + public KnownExploitedVulnerabilitiesSchema handleEntity(HttpEntity entity) throws IOException { + try (InputStream in = entity.getContent()) { + final KnownExploitedVulnerabilityParser parser = new KnownExploitedVulnerabilityParser(); + final KnownExploitedVulnerabilitiesSchema data = parser.parse(in); + return data; + } catch (CorruptedDatastreamException | UpdateException e) { + throw new IOException("Error processing response", e); + } + } + }; + + final KnownExploitedVulnerabilitiesSchema data = Downloader.getInstance().fetchAndHandle(url, kevParsingResponseHandler); + final String currentVersion = dbProperties.getProperty(DatabaseProperties.KEV_VERSION, ""); + if (!currentVersion.equals(data.getCatalogVersion())) { + cveDB.updateKnownExploitedVulnerabilities(data.getVulnerabilities()); } - } catch (TooManyRequestsException | ResourceNotFoundException | IOException - | CorruptedDatastreamException | DatabaseException | SQLException ex) { + //all dates in the db are now stored in seconds as opposed to previously milliseconds. + dbProperties.save(DatabaseProperties.KEV_LAST_CHECKED, Long.toString(System.currentTimeMillis() / 1000)); + return true; + } catch (TooManyRequestsException | ResourceNotFoundException | IOException | DatabaseException + | SQLException | URISyntaxException ex) { throw new UpdateException(ex); } } @@ -98,7 +111,7 @@ public boolean update(Engine engine) throws UpdateException { @Override public boolean purge(Engine engine) { - //do nothing - covered by the NvdCveUpdater data source. + //do nothing - covered by the NvdApiDataSource. return true; } @@ -120,7 +133,7 @@ private boolean shouldUpdate() throws UpdateException { if (cveDB.dataExists() && 0 < validForHours) { // ms Valid = valid (hours) x 60 min/hour x 60 sec/min x 1000 ms/sec final long validForSeconds = validForHours * 60L * 60L; - final long lastChecked = getPropertyInSeconds(DatabaseProperties.KEV_LAST_CHECKED); + final long lastChecked = dbProperties.getPropertyInSeconds(DatabaseProperties.KEV_LAST_CHECKED); final long now = System.currentTimeMillis() / 1000; proceed = (now - lastChecked) > validForSeconds; if (!proceed) { @@ -130,15 +143,4 @@ private boolean shouldUpdate() throws UpdateException { return proceed; } - /** - * Returns the database property value in seconds. - * - * @param key the key to the property - * @return the property value in seconds - */ - private long getPropertyInSeconds(String key) { - final String value = dbProperties.getProperty(key, "0"); - return DateUtil.getEpochValueInSeconds(value); - } - } diff --git a/core/src/main/java/org/owasp/dependencycheck/data/update/LocalDataSource.java b/core/src/main/java/org/owasp/dependencycheck/data/update/LocalDataSource.java new file mode 100644 index 00000000000..88d51840668 --- /dev/null +++ b/core/src/main/java/org/owasp/dependencycheck/data/update/LocalDataSource.java @@ -0,0 +1,83 @@ +/* + * This file is part of dependency-check-core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2024 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.data.update; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Properties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * @author Jeremy Long + */ +public abstract class LocalDataSource implements CachedWebDataSource { + + /** + * Static logger. + */ + private static final Logger LOGGER = LoggerFactory.getLogger(LocalDataSource.class); + + /** + * Saves the timestamp in a properties file next to the provided repo file + * + * @param repo the local file data source + * @param timestamp the epoch timestamp to store + */ + protected void saveLastUpdated(File repo, long timestamp) { + final File timestampFile = new File(repo + ".properties"); + try (OutputStream out = new FileOutputStream(timestampFile)) { + final Properties prop = new Properties(); + prop.setProperty("LAST_UPDATED", String.valueOf(timestamp)); + prop.store(out, null); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + + /** + * Retrieves the last updated date from the local file system (in a file + * next to the repo file). + * + * @param repo the local file data source + * @return the epoch timestamp of the last updated date/time + */ + protected long getLastUpdated(File repo) { + long lastUpdatedOn = 0; + final File timestampFile = new File(repo + ".properties"); + if (timestampFile.isFile()) { + try (InputStream is = new FileInputStream(timestampFile)) { + final Properties props = new Properties(); + props.load(is); + lastUpdatedOn = Integer.parseInt(props.getProperty("LAST_UPDATED", "0")); + } catch (IOException | NumberFormatException ex) { + LOGGER.debug("error reading timestamp file", ex); + } + if (lastUpdatedOn <= 0) { + //fall back on conversion from file last modified to storing in the db. + lastUpdatedOn = repo.lastModified(); + } + } + return lastUpdatedOn; + } +} diff --git a/core/src/main/java/org/owasp/dependencycheck/data/update/NvdApiDataSource.java b/core/src/main/java/org/owasp/dependencycheck/data/update/NvdApiDataSource.java new file mode 100644 index 00000000000..43f530cc562 --- /dev/null +++ b/core/src/main/java/org/owasp/dependencycheck/data/update/NvdApiDataSource.java @@ -0,0 +1,685 @@ +/* + * This file is part of dependency-check-core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2023 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.data.update; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import io.github.jeremylong.openvulnerability.client.nvd.DefCveItem; +import io.github.jeremylong.openvulnerability.client.nvd.NvdApiException; +import io.github.jeremylong.openvulnerability.client.nvd.NvdCveClient; +import io.github.jeremylong.openvulnerability.client.nvd.NvdCveClientBuilder; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.StringReader; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.text.MessageFormat; +import java.time.Duration; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.zip.GZIPOutputStream; +import org.owasp.dependencycheck.Engine; +import org.owasp.dependencycheck.data.nvdcve.CveDB; +import org.owasp.dependencycheck.data.nvdcve.DatabaseException; +import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties; +import org.owasp.dependencycheck.data.update.exception.UpdateException; +import org.owasp.dependencycheck.data.update.nvd.api.DownloadTask; +import org.owasp.dependencycheck.data.update.nvd.api.NvdApiProcessor; +import org.owasp.dependencycheck.utils.DateUtil; +import org.owasp.dependencycheck.utils.DownloadFailedException; +import org.owasp.dependencycheck.utils.Downloader; +import org.owasp.dependencycheck.utils.InvalidSettingException; +import org.owasp.dependencycheck.utils.ResourceNotFoundException; +import org.owasp.dependencycheck.utils.Settings; +import org.owasp.dependencycheck.utils.TooManyRequestsException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * @author Jeremy Long + */ +public class NvdApiDataSource implements CachedWebDataSource { + + /** + * The logger. + */ + private static final Logger LOGGER = LoggerFactory.getLogger(NvdApiDataSource.class); + /** + * The thread pool size to use for CPU-intense tasks. + */ + private static final int PROCESSING_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors(); + /** + * The configured settings. + */ + private Settings settings; + /** + * Reference to the DAO. + */ + private CveDB cveDb = null; + /** + * The properties obtained from the database. + */ + private DatabaseProperties dbProperties = null; + /** + * The key for the NVD API cache properties file's last modified date. + */ + private static final String NVD_API_CACHE_MODIFIED_DATE = "lastModifiedDate"; + /** + * The number of results per page from the NVD API. The default is 2000; we + * are setting the value to be explicit. + */ + private static final int RESULTS_PER_PAGE = 2000; + + @Override + public boolean update(Engine engine) throws UpdateException { + this.settings = engine.getSettings(); + this.cveDb = engine.getDatabase(); + if (isUpdateConfiguredFalse()) { + return false; + } + dbProperties = cveDb.getDatabaseProperties(); + + final String nvdDataFeedUrl = settings.getString(Settings.KEYS.NVD_API_DATAFEED_URL); + if (nvdDataFeedUrl != null) { + return processDatafeed(nvdDataFeedUrl); + } + return processApi(); + } + + protected UrlData extractUrlData(String nvdDataFeedUrl) { + String url; + String pattern = null; + if (nvdDataFeedUrl.endsWith(".json.gz")) { + final int lio = nvdDataFeedUrl.lastIndexOf("/"); + pattern = nvdDataFeedUrl.substring(lio + 1); + url = nvdDataFeedUrl.substring(0, lio); + } else { + url = nvdDataFeedUrl; + } + if (!url.endsWith("/")) { + url += "/"; + } + return new UrlData(url, pattern); + } + + private boolean processDatafeed(String nvdDataFeedUrl) throws UpdateException { + boolean updatesMade = false; + try { + dbProperties = cveDb.getDatabaseProperties(); + if (checkUpdate()) { + final UrlData data = extractUrlData(nvdDataFeedUrl); + final String url = data.getUrl(); + String pattern = data.getPattern(); + final Properties cacheProperties = getRemoteCacheProperties(url, pattern); + if (pattern == null) { + final String prefix = cacheProperties.getProperty("prefix", "nvdcve-"); + pattern = prefix + "{0}.json.gz"; + } + + final ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")); + final Map updateable = getUpdatesNeeded(url, pattern, cacheProperties, now); + if (!updateable.isEmpty()) { + final int max = settings.getInt(Settings.KEYS.MAX_DOWNLOAD_THREAD_POOL_SIZE, 1); + final int downloadPoolSize = Math.min(Runtime.getRuntime().availableProcessors(), max); + // going over 2 threads does not appear to improve performance + final int maxExec = PROCESSING_THREAD_POOL_SIZE; + final int execPoolSize = Math.min(maxExec, 2); + + ExecutorService processingExecutorService = null; + ExecutorService downloadExecutorService = null; + try { + downloadExecutorService = Executors.newFixedThreadPool(downloadPoolSize); + processingExecutorService = Executors.newFixedThreadPool(execPoolSize); + + DownloadTask runLast = null; + final Set>> downloadFutures = new HashSet<>(updateable.size()); + runLast = startDownloads(updateable, processingExecutorService, runLast, downloadFutures, downloadExecutorService); + + //complete downloads + final Set> processFutures = new HashSet<>(updateable.size()); + for (Future> future : downloadFutures) { + processDownload(future, processFutures); + } + //process the data + processFuture(processFutures); + processFutures.clear(); + + //download and process the modified as the last entry + if (runLast != null) { + final Future> modified = downloadExecutorService.submit(runLast); + processDownload(modified, processFutures); + processFuture(processFutures); + } + + } finally { + if (processingExecutorService != null) { + processingExecutorService.shutdownNow(); + } + if (downloadExecutorService != null) { + downloadExecutorService.shutdownNow(); + } + } + updatesMade = true; + } + storeLastModifiedDates(now, cacheProperties, updateable); + if (updatesMade) { + cveDb.persistEcosystemCache(); + } + final int updateCount = cveDb.updateEcosystemCache(); + LOGGER.debug("Corrected the ecosystem for {} ecoSystemCache entries", updateCount); + if (updatesMade || updateCount > 0) { + cveDb.cleanupDatabase(); + } + } + } catch (UpdateException ex) { + if (ex.getCause() != null && ex.getCause() instanceof DownloadFailedException) { + final String jre = System.getProperty("java.version"); + if (jre == null || jre.startsWith("1.4") || jre.startsWith("1.5") || jre.startsWith("1.6") || jre.startsWith("1.7")) { + LOGGER.error("An old JRE is being used ({} {}), and likely does not have the correct root certificates or algorithms " + + "to connect to the NVD - consider upgrading your JRE.", System.getProperty("java.vendor"), jre); + } + } + throw ex; + } catch (DatabaseException ex) { + throw new UpdateException("Database Exception, unable to update the data to use the most current data.", ex); + } + return updatesMade; + } + + private void storeLastModifiedDates(final ZonedDateTime now, final Properties cacheProperties, + final Map updateable) throws UpdateException { + + final ZonedDateTime lastModifiedRequest = DatabaseProperties.getTimestamp(cacheProperties, + NVD_API_CACHE_MODIFIED_DATE + ".modified"); + dbProperties.save(DatabaseProperties.NVD_CACHE_LAST_CHECKED, now); + dbProperties.save(DatabaseProperties.NVD_CACHE_LAST_MODIFIED, lastModifiedRequest); + //allow users to initially load from a cache but then use the API - this may happen with the GH Action + dbProperties.save(DatabaseProperties.NVD_API_LAST_CHECKED, now); + dbProperties.save(DatabaseProperties.NVD_API_LAST_MODIFIED, lastModifiedRequest); + + for (String entry : updateable.keySet()) { + final ZonedDateTime date = DatabaseProperties.getTimestamp(cacheProperties, NVD_API_CACHE_MODIFIED_DATE + "." + entry); + dbProperties.save(DatabaseProperties.NVD_CACHE_LAST_MODIFIED + "." + entry, date); + } + } + + private DownloadTask startDownloads(final Map updateable, ExecutorService processingExecutorService, DownloadTask runLast, + final Set>> downloadFutures, ExecutorService downloadExecutorService) throws UpdateException { + DownloadTask lastCall = runLast; + for (Map.Entry cve : updateable.entrySet()) { + final DownloadTask call = new DownloadTask(cve.getValue(), processingExecutorService, cveDb, settings); + if (call.isModified()) { + lastCall = call; + } else { + final boolean added = downloadFutures.add(downloadExecutorService.submit(call)); + if (!added) { + throw new UpdateException("Unable to add the download task for " + cve); + } + } + } + return lastCall; + } + + private void processFuture(final Set> processFutures) throws UpdateException { + //complete processing + for (Future future : processFutures) { + try { + final NvdApiProcessor task = future.get(); + } catch (InterruptedException ex) { + LOGGER.debug("Thread was interrupted during processing", ex); + Thread.currentThread().interrupt(); + throw new UpdateException(ex); + } catch (ExecutionException ex) { + LOGGER.debug("Execution Exception during process", ex); + throw new UpdateException(ex); + } + } + } + + private void processDownload(Future> future, final Set> processFutures) throws UpdateException { + final Future task; + try { + task = future.get(); + if (task != null) { + processFutures.add(task); + } + } catch (InterruptedException ex) { + LOGGER.debug("Thread was interrupted during download", ex); + Thread.currentThread().interrupt(); + throw new UpdateException("The download was interrupted", ex); + } catch (ExecutionException ex) { + LOGGER.debug("Thread was interrupted during download execution", ex); + throw new UpdateException("The execution of the download was interrupted", ex); + } + } + + private boolean processApi() throws UpdateException { + final ZonedDateTime lastChecked = dbProperties.getTimestamp(DatabaseProperties.NVD_API_LAST_CHECKED); + final int validForHours = settings.getInt(Settings.KEYS.NVD_API_VALID_FOR_HOURS, 0); + if (cveDb.dataExists() && lastChecked != null && validForHours > 0) { + // ms Valid = valid (hours) x 60 min/hour x 60 sec/min x 1000 ms/sec + final long validForSeconds = validForHours * 60L * 60L; + final ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")); + final Duration duration = Duration.between(lastChecked, now); + final long difference = duration.getSeconds(); + if (difference < validForSeconds) { + LOGGER.info("Skipping the NVD API Update as it was completed within the last {} minutes", validForSeconds / 60); + return false; + } + } + + ZonedDateTime lastModifiedRequest = dbProperties.getTimestamp(DatabaseProperties.NVD_API_LAST_MODIFIED); + final NvdCveClientBuilder builder = NvdCveClientBuilder.aNvdCveApi(); + final String endpoint = settings.getString(Settings.KEYS.NVD_API_ENDPOINT); + if (endpoint != null) { + builder.withEndpoint(endpoint); + } + if (lastModifiedRequest != null) { + // make it UTC as required by NvdCveClientBuilder#withLastModifiedFilter + lastModifiedRequest = lastModifiedRequest.withZoneSameInstant(ZoneId.of("UTC")); + final ZonedDateTime end = lastModifiedRequest.plusDays(120); + builder.withLastModifiedFilter(lastModifiedRequest, end); + } + final String key = settings.getString(Settings.KEYS.NVD_API_KEY); + if (key != null) { + //using a higher delay as the system may not be able to process these faster. + builder.withApiKey(key) + .withDelay(5000) + .withThreadCount(4); + } else { + LOGGER.warn("An NVD API Key was not provided - it is highly recommended to use " + + "an NVD API key as the update can take a VERY long time without an API Key"); + builder.withDelay(10000); + } + + final int resultsPerPage = Math.min(settings.getInt(Settings.KEYS.NVD_API_RESULTS_PER_PAGE, RESULTS_PER_PAGE), RESULTS_PER_PAGE); + + builder.withResultsPerPage(resultsPerPage); + //removed due to the virtualMatch filter causing overhead with the NVD API + //final String virtualMatch = settings.getString(Settings.KEYS.CVE_CPE_STARTS_WITH_FILTER); + //if (virtualMatch != null) { + // builder.withVirtualMatchString(virtualMatch); + //} + + final int retryCount = settings.getInt(Settings.KEYS.NVD_API_MAX_RETRY_COUNT, 10); + builder.withMaxRetryCount(retryCount); + long delay = 0; + try { + delay = settings.getLong(Settings.KEYS.NVD_API_DELAY); + } catch (InvalidSettingException ex) { + LOGGER.warn("Invalid setting `NVD_API_DELAY`? ({}), using default delay", settings.getString(Settings.KEYS.NVD_API_DELAY)); + } + if (delay > 0) { + builder.withDelay(delay); + } + + ExecutorService processingExecutorService = null; + try { + processingExecutorService = Executors.newFixedThreadPool(PROCESSING_THREAD_POOL_SIZE); + final List> submitted = new ArrayList<>(); + int max = -1; + int ctr = 0; + try (NvdCveClient api = builder.build()) { + while (api.hasNext()) { + final Collection items = api.next(); + max = api.getTotalAvailable(); + if (ctr == 0) { + LOGGER.info(String.format("NVD API has %,d records in this update", max)); + } + if (items != null && !items.isEmpty()) { + final ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.registerModule(new JavaTimeModule()); + final File outputFile = settings.getTempFile("nvd-data-", ".jsonarray.gz"); + try (FileOutputStream fos = new FileOutputStream(outputFile); GZIPOutputStream out = new GZIPOutputStream(fos);) { + objectMapper.writeValue(out, items); + final Future f = processingExecutorService.submit(new NvdApiProcessor(cveDb, outputFile)); + submitted.add(f); + } + ctr += 1; + if ((ctr % 5) == 0) { + //TODO get results per page from the API as it could adjust automatically + final double percent = (double) (ctr * resultsPerPage) / max * 100; + if (percent < 100) { + LOGGER.info(String.format("Downloaded %,d/%,d (%.0f%%)", ctr * resultsPerPage, max, percent)); + } + } + } + final ZonedDateTime last = api.getLastUpdated(); + if (last != null && (lastModifiedRequest == null || lastModifiedRequest.compareTo(last) < 0)) { + lastModifiedRequest = last; + } + } + + } catch (Exception e) { + if (e instanceof NvdApiException && (e.getMessage().equals("NVD Returned Status Code: 404") + || e.getMessage().equals("NVD Returned Status Code: 403"))) { + final String msg; + if (key != null) { + msg = "Error updating the NVD Data; the NVD returned a 403 or 404 error\n\nPlease ensure your API Key is valid; " + + "see https://github.com/jeremylong/open-vulnerability-cli/blob/main/README.md#api-key-is-used-and-a-403-or-404-error-occurs\n\n" + + "If your NVD API Key is valid try increasing the NVD API Delay.\n\n" + + "If this is occurring in a CI environment"; + } else { + msg = "Error updating the NVD Data; the NVD returned a 403 or 404 error\n\nConsider using an NVD API Key; " + + "see https://github.com/dependency-check/DependencyCheck?tab=readme-ov-file#nvd-api-key-highly-recommended"; + } + throw new UpdateException(msg); + } else { + throw new UpdateException("Error updating the NVD Data", e); + } + } + LOGGER.info(String.format("Downloaded %,d/%,d (%.0f%%)", max, max, 100f)); + max = submitted.size(); + final boolean updated = max > 0; + ctr = 0; + for (Future f : submitted) { + try { + final NvdApiProcessor proc = f.get(); + ctr += 1; + final double percent = (double) ctr / max * 100; + LOGGER.info(String.format("Completed processing batch %d/%d (%.0f%%) in %,dms", ctr, max, percent, proc.getDurationMillis())); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + throw new RuntimeException(ex); + } catch (ExecutionException ex) { + LOGGER.error("Exception processing NVD API Results", ex); + throw new RuntimeException(ex); + } + } + if (lastModifiedRequest != null) { + dbProperties.save(DatabaseProperties.NVD_API_LAST_CHECKED, ZonedDateTime.now()); + dbProperties.save(DatabaseProperties.NVD_API_LAST_MODIFIED, lastModifiedRequest); + } + return updated; + } finally { + if (processingExecutorService != null) { + processingExecutorService.shutdownNow(); + } + } + } + + /** + * Checks if the system is configured NOT to update. + * + * @return false if the system is configured to perform an update; otherwise + * true + */ + private boolean isUpdateConfiguredFalse() { + if (!settings.getBoolean(Settings.KEYS.UPDATE_NVDCVE_ENABLED, true)) { + return true; + } + boolean autoUpdate = true; + try { + autoUpdate = settings.getBoolean(Settings.KEYS.AUTO_UPDATE); + } catch (InvalidSettingException ex) { + LOGGER.debug("Invalid setting for auto-update; using true."); + } + return !autoUpdate; + } + + @Override + public boolean purge(Engine engine) { + boolean result = true; + try { + final File dataDir = engine.getSettings().getDataDirectory(); + final File db = new File(dataDir, engine.getSettings().getString(Settings.KEYS.DB_FILE_NAME, "odc.mv.db")); + if (db.exists()) { + if (db.delete()) { + LOGGER.info("Database file purged; local copy of the NVD has been removed"); + } else { + LOGGER.error("Unable to delete '{}'; please delete the file manually", db.getAbsolutePath()); + result = false; + } + } else { + LOGGER.info("Unable to purge database; the database file does not exist: {}", db.getAbsolutePath()); + result = false; + } + final File traceFile = new File(dataDir, "odc.trace.db"); + if (traceFile.exists() && !traceFile.delete()) { + LOGGER.error("Unable to delete '{}'; please delete the file manually", traceFile.getAbsolutePath()); + result = false; + } + final File lockFile = new File(dataDir, "odc.update.lock"); + if (lockFile.exists() && !lockFile.delete()) { + LOGGER.error("Unable to delete '{}'; please delete the file manually", lockFile.getAbsolutePath()); + result = false; + } + } catch (IOException ex) { + final String msg = "Unable to delete the database"; + LOGGER.error(msg, ex); + result = false; + } + return result; + } + + /** + * Checks if the NVD API Cache JSON files were last checked recently. As an + * optimization, we can avoid repetitive checks against the NVD cache. + * + * @return true to proceed with the check, or false to skip + * @throws UpdateException thrown when there is an issue checking for + * updates + */ + private boolean checkUpdate() throws UpdateException { + boolean proceed = true; + // If the valid setting has not been specified, then we proceed to check... + final int validForHours = settings.getInt(Settings.KEYS.NVD_API_VALID_FOR_HOURS, 0); + if (dataExists() && 0 < validForHours) { + // ms Valid = valid (hours) x 60 min/hour x 60 sec/min x 1000 ms/sec + final long validForSeconds = validForHours * 60L * 60L; + final ZonedDateTime lastChecked = dbProperties.getTimestamp(DatabaseProperties.NVD_CACHE_LAST_CHECKED); + if (lastChecked != null) { + final ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")); + final Duration duration = Duration.between(lastChecked, now); + final long difference = duration.getSeconds(); + proceed = difference > validForSeconds; + if (!proceed) { + LOGGER.info("Skipping NVD API Cache check since last check was within {} hours.", validForHours); + LOGGER.debug("Last NVD API was at {}, and now {} is within {} s.", lastChecked, now, validForSeconds); + } + } else { + LOGGER.warn("NVD cache last checked not present; updating the entire database. This could occur if you are " + + "switching back and forth from using the API vs a datafeed or if you are using a database created prior to ODC 9.x"); + } + } + return proceed; + } + + /** + * Checks the CVE Index to ensure data exists and analysis can continue. + * + * @return true if the database contains data + */ + private boolean dataExists() { + return cveDb.dataExists(); + } + + /** + * Determines if the index needs to be updated. This is done by fetching the + * NVD CVE meta data and checking the last update date. If the data needs to + * be refreshed this method will return the NvdCveUrl for the files that + * need to be updated. + * + * @param url the URL of the NVD API cache + * @param filePattern the string format pattern for the cached files (e.g. + * "nvdcve-{0}.json.gz") + * @param cacheProperties the properties from the remote NVD API cache + * @param now the start time of the update process + * @return the map of key to URLs - where the key is the year or `modified` + * @throws UpdateException Is thrown if there is an issue with the last + * updated properties file + */ + protected final Map getUpdatesNeeded(String url, String filePattern, + Properties cacheProperties, ZonedDateTime now) throws UpdateException { + LOGGER.debug("starting getUpdatesNeeded() ..."); + final Map updates = new HashMap<>(); + if (dbProperties != null && !dbProperties.isEmpty()) { + final int startYear = settings.getInt(Settings.KEYS.NVD_API_DATAFEED_START_YEAR, 2002); + // for establishing the current year use the timezone where the new year starts first + // as from that moment on CNAs might start assigning CVEs with the new year depending + // on the CNA's timezone + final int endYear = now.withZoneSameInstant(ZoneId.of("UTC+14:00")).getYear(); + boolean needsFullUpdate = false; + for (int y = startYear; y <= endYear; y++) { + final ZonedDateTime val = dbProperties.getTimestamp(DatabaseProperties.NVD_CACHE_LAST_MODIFIED + "." + y); + if (val == null) { + needsFullUpdate = true; + break; + } + } + final ZonedDateTime lastUpdated = dbProperties.getTimestamp(DatabaseProperties.NVD_CACHE_LAST_MODIFIED); + final int days = settings.getInt(Settings.KEYS.NVD_API_DATAFEED_VALID_FOR_DAYS, 7); + + if (!needsFullUpdate && lastUpdated.equals(DatabaseProperties.getTimestamp(cacheProperties, NVD_API_CACHE_MODIFIED_DATE))) { + return updates; + } else { + updates.put("modified", url + MessageFormat.format(filePattern, "modified")); + if (needsFullUpdate) { + for (int i = startYear; i <= endYear; i++) { + if (cacheProperties.containsKey(NVD_API_CACHE_MODIFIED_DATE + "." + i)) { + updates.put(String.valueOf(i), url + MessageFormat.format(filePattern, String.valueOf(i))); + } + } + } else if (!DateUtil.withinDateRange(lastUpdated, now, days)) { + for (int i = startYear; i <= endYear; i++) { + if (cacheProperties.containsKey(NVD_API_CACHE_MODIFIED_DATE + "." + i)) { + final ZonedDateTime lastModifiedCache = DatabaseProperties.getTimestamp(cacheProperties, + NVD_API_CACHE_MODIFIED_DATE + "." + i); + final ZonedDateTime lastModifiedDB = dbProperties.getTimestamp(DatabaseProperties.NVD_CACHE_LAST_MODIFIED + "." + i); + if (lastModifiedDB == null || lastModifiedCache.compareTo(lastModifiedDB) > 0) { + updates.put(String.valueOf(i), url + MessageFormat.format(filePattern, String.valueOf(i))); + } + } + } + } + } + } + if (updates.size() > 3) { + LOGGER.info("NVD API Cache requires several updates; this could take a couple of minutes."); + } + return updates; + } + + /** + * Downloads the metadata properties of the NVD API cache. + * + * @param url the base URL to the NVD API cache + * @param pattern the pattern of the datafile name for the NVD API cache + * @return the cache properties + * @throws UpdateException thrown if the properties file could not be + * downloaded + */ + protected final Properties getRemoteCacheProperties(String url, String pattern) throws UpdateException { + final Properties properties = new Properties(); + try { + final URL u = new URI(url + "cache.properties").toURL(); + final String content = Downloader.getInstance().fetchContent(u, StandardCharsets.UTF_8); + properties.load(new StringReader(content)); + + } catch (URISyntaxException ex) { + throw new UpdateException("Invalid NVD Cache URL", ex); + } catch (DownloadFailedException | ResourceNotFoundException ex) { + final String metaPattern; + if (pattern == null) { + metaPattern = "nvdcve-{0}.meta"; + } else { + metaPattern = pattern.replace(".json.gz", ".meta"); + } + try { + URL metaUrl = new URI(url + MessageFormat.format(metaPattern, "modified")).toURL(); + String content = Downloader.getInstance().fetchContent(metaUrl, StandardCharsets.UTF_8); + final Properties props = new Properties(); + props.load(new StringReader(content)); + ZonedDateTime lmd = DatabaseProperties.getIsoTimestamp(props, "lastModifiedDate"); + DatabaseProperties.setTimestamp(properties, "lastModifiedDate.modified", lmd); + DatabaseProperties.setTimestamp(properties, "lastModifiedDate", lmd); + final int startYear = settings.getInt(Settings.KEYS.NVD_API_DATAFEED_START_YEAR, 2002); + final ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC")); + final int endYear = now.withZoneSameInstant(ZoneId.of("UTC+14:00")).getYear(); + for (int y = startYear; y <= endYear; y++) { + metaUrl = new URI(url + MessageFormat.format(metaPattern, String.valueOf(y))).toURL(); + content = Downloader.getInstance().fetchContent(metaUrl, StandardCharsets.UTF_8); + props.clear(); + props.load(new StringReader(content)); + lmd = DatabaseProperties.getIsoTimestamp(props, "lastModifiedDate"); + DatabaseProperties.setTimestamp(properties, "lastModifiedDate." + String.valueOf(y), lmd); + } + } catch (URISyntaxException | TooManyRequestsException | ResourceNotFoundException | IOException ex1) { + throw new UpdateException("Unable to download the data feed META files", ex); + } + } catch (TooManyRequestsException ex) { + throw new UpdateException("Unable to download the NVD API cache.properties", ex); + } catch (IOException ex) { + throw new UpdateException("Invalid NVD Cache Properties file contents", ex); + } + return properties; + } + + protected static class UrlData { + + /** + * The URL to download resources from. + */ + private final String url; + + /** + * The pattern to construct the file names for resources from. + */ + private final String pattern; + + public UrlData(String url, String pattern) { + this.url = url; + this.pattern = pattern; + } + + /** + * Get the value of pattern + * + * @return the value of pattern + */ + public String getPattern() { + return pattern; + } + + /** + * Get the value of url + * + * @return the value of url + */ + public String getUrl() { + return url; + } + + } +} diff --git a/core/src/main/java/org/owasp/dependencycheck/data/update/NvdCveUpdater.java b/core/src/main/java/org/owasp/dependencycheck/data/update/NvdCveUpdater.java deleted file mode 100644 index cbd2939b423..00000000000 --- a/core/src/main/java/org/owasp/dependencycheck/data/update/NvdCveUpdater.java +++ /dev/null @@ -1,585 +0,0 @@ -/* - * This file is part of dependency-check-core. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright (c) 2012 Jeremy Long. All Rights Reserved. - */ -package org.owasp.dependencycheck.data.update; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.net.MalformedURLException; -import java.time.ZoneOffset; -import java.time.ZonedDateTime; -import java.util.HashSet; -import java.util.Set; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.stream.Collectors; -import javax.annotation.concurrent.ThreadSafe; -import org.apache.commons.io.FileUtils; - -import org.owasp.dependencycheck.Engine; -import org.owasp.dependencycheck.data.nvd.json.MetaProperties; -import org.owasp.dependencycheck.data.nvdcve.CveDB; -import org.owasp.dependencycheck.data.nvdcve.DatabaseException; -import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties; - -import static org.owasp.dependencycheck.data.nvdcve.DatabaseProperties.MODIFIED; - -import org.owasp.dependencycheck.data.update.exception.InvalidDataException; -import org.owasp.dependencycheck.data.update.exception.UpdateException; -import org.owasp.dependencycheck.data.update.nvd.DownloadTask; -import org.owasp.dependencycheck.data.update.nvd.NvdCache; -import org.owasp.dependencycheck.data.update.nvd.NvdCveInfo; -import org.owasp.dependencycheck.data.update.nvd.ProcessTask; -import org.owasp.dependencycheck.utils.DateUtil; -import org.owasp.dependencycheck.utils.DownloadFailedException; -import org.owasp.dependencycheck.utils.Downloader; -import org.owasp.dependencycheck.utils.InvalidSettingException; -import org.owasp.dependencycheck.utils.ResourceNotFoundException; -import org.owasp.dependencycheck.utils.Settings; -import org.owasp.dependencycheck.utils.TooManyRequestsException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Class responsible for updating the NVD CVE data. - * - * @author Jeremy Long - */ -@ThreadSafe -public class NvdCveUpdater implements CachedWebDataSource { - - /** - * The logger. - */ - private static final Logger LOGGER = LoggerFactory.getLogger(NvdCveUpdater.class); - /** - * The thread pool size to use for CPU-intense tasks. - */ - private static final int PROCESSING_THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors(); - /** - * The thread pool size to use when downloading files. - */ - private static final int DOWNLOAD_THREAD_POOL_SIZE = Math.round(1.5f * Runtime.getRuntime().availableProcessors()); - /** - * ExecutorService for CPU-intense processing tasks. - */ - private ExecutorService processingExecutorService = null; - /** - * ExecutorService for tasks that involve blocking activities and are not - * very CPU-intense, e.g. downloading files. - */ - private ExecutorService downloadExecutorService = null; - /** - * The configured settings. - */ - private Settings settings; - /** - * Reference to the DAO. - */ - private CveDB cveDb = null; - /** - * The properties obtained from the database. - */ - private DatabaseProperties dbProperties = null; - - /** - * Downloads the latest NVD CVE XML file from the web and imports it into - * the current CVE Database. A lock on a file is obtained in an attempt to - * prevent more then one thread/JVM from updating the database at the same - * time. This method may sleep upto 5 minutes. - * - * @param engine a reference to the dependency-check engine - * @return whether or not an update was made to the CveDB - * @throws UpdateException is thrown if there is an error updating the - * database - */ - @Override - public synchronized boolean update(Engine engine) throws UpdateException { - this.settings = engine.getSettings(); - this.cveDb = engine.getDatabase(); - if (isUpdateConfiguredFalse()) { - return false; - } - boolean updatesMade = false; - try { - dbProperties = cveDb.getDatabaseProperties(); - if (checkUpdate()) { - final List updateable = getUpdatesNeeded(); - if (!updateable.isEmpty()) { - initializeExecutorServices(); - performUpdate(updateable); - updatesMade = true; - } - //all dates in the db are now stored in seconds as opposed to previously milliseconds. - dbProperties.save(DatabaseProperties.LAST_CHECKED, Long.toString(System.currentTimeMillis() / 1000)); - if (updatesMade) { - cveDb.persistEcosystemCache(); - } - final int updateCount = cveDb.updateEcosystemCache(); - LOGGER.debug("Corrected the ecosystem for {} ecoSystemCache entries", updateCount); - if (updatesMade || updateCount > 0) { - cveDb.cleanupDatabase(); - } - } - } catch (UpdateException ex) { - if (ex.getCause() != null && ex.getCause() instanceof DownloadFailedException) { - final String jre = System.getProperty("java.version"); - if (jre == null || jre.startsWith("1.4") || jre.startsWith("1.5") || jre.startsWith("1.6") || jre.startsWith("1.7")) { - LOGGER.error("An old JRE is being used ({} {}), and likely does not have the correct root certificates or algorithms " - + "to connect to the NVD - consider upgrading your JRE.", System.getProperty("java.vendor"), jre); - } - } - throw ex; - } catch (DatabaseException ex) { - throw new UpdateException("Database Exception, unable to update the data to use the most current data.", ex); - } finally { - shutdownExecutorServices(); - } - return updatesMade; - } - - /** - * Checks if the system is configured NOT to update. - * - * @return false if the system is configured to perform an update; otherwise - * true - */ - private boolean isUpdateConfiguredFalse() { - if (!settings.getBoolean(Settings.KEYS.UPDATE_NVDCVE_ENABLED, true)) { - return true; - } - boolean autoUpdate = true; - try { - autoUpdate = settings.getBoolean(Settings.KEYS.AUTO_UPDATE); - } catch (InvalidSettingException ex) { - LOGGER.debug("Invalid setting for auto-update; using true."); - } - return !autoUpdate; - } - - /** - * Initialize the executor services for download and processing of the NVD - * CVE XML data. - */ - protected void initializeExecutorServices() { - final int downloadPoolSize; - final int max = settings.getInt(Settings.KEYS.MAX_DOWNLOAD_THREAD_POOL_SIZE, 1); - downloadPoolSize = Math.min(DOWNLOAD_THREAD_POOL_SIZE, max); - downloadExecutorService = Executors.newFixedThreadPool(downloadPoolSize); - processingExecutorService = Executors.newFixedThreadPool(PROCESSING_THREAD_POOL_SIZE); - LOGGER.debug("#download threads: {}", downloadPoolSize); - LOGGER.debug("#processing threads: {}", PROCESSING_THREAD_POOL_SIZE); - } - - /** - * Shutdown and cleanup of resources used by the executor services. - */ - private void shutdownExecutorServices() { - if (processingExecutorService != null) { - processingExecutorService.shutdownNow(); - } - if (downloadExecutorService != null) { - downloadExecutorService.shutdownNow(); - } - } - - /** - * Checks if the NVD CVE XML files were last checked recently. As an - * optimization, we can avoid repetitive checks against the NVD. Setting - * CVE_CHECK_VALID_FOR_HOURS determines the duration since last check before - * checking again. A database property stores the timestamp of the last - * check. - * - * @return true to proceed with the check, or false to skip - * @throws UpdateException thrown when there is an issue checking for - * updates - */ - private boolean checkUpdate() throws UpdateException { - boolean proceed = true; - // If the valid setting has not been specified, then we proceed to check... - final int validForHours = settings.getInt(Settings.KEYS.CVE_CHECK_VALID_FOR_HOURS, 0); - if (dataExists() && 0 < validForHours) { - // ms Valid = valid (hours) x 60 min/hour x 60 sec/min x 1000 ms/sec - final long validForSeconds = validForHours * 60L * 60L; - final long lastChecked = getPropertyInSeconds(DatabaseProperties.LAST_CHECKED); - final long now = System.currentTimeMillis() / 1000; - proceed = (now - lastChecked) > validForSeconds; - if (!proceed) { - LOGGER.info("Skipping NVD check since last check was within {} hours.", validForHours); - LOGGER.debug("Last NVD was at {}, and now {} is within {} s.", lastChecked, now, validForSeconds); - } - } - return proceed; - } - - /** - * Checks the CVE Index to ensure data exists and analysis can continue. - * - * @return true if the database contains data - */ - private boolean dataExists() { - return cveDb.dataExists(); - } - - /** - * Downloads the latest NVD CVE XML file from the web and imports it into - * the current CVE Database. - * - * @param updateable a collection of NVD CVE data file references that need - * to be downloaded and processed to update the database - * @throws UpdateException is thrown if there is an error updating the - * database - */ - @SuppressWarnings("FutureReturnValueIgnored") - private void performUpdate(List updateable) throws UpdateException { - if (updateable.isEmpty()) { - return; - } - if (updateable.size() > 3) { - LOGGER.info("NVD CVE requires several updates; this could take a couple of minutes."); - } - - DownloadTask runLast = null; - final Set>> downloadFutures = new HashSet<>(updateable.size()); - for (NvdCveInfo cve : updateable) { - final DownloadTask call = new DownloadTask(cve, processingExecutorService, cveDb, settings); - if (call.isModified()) { - runLast = call; - } else { - final boolean added = downloadFutures.add(downloadExecutorService.submit(call)); - if (!added) { - throw new UpdateException("Unable to add the download task for " + cve.getId()); - } - } - } - - //next, move the future future processTasks to just future processTasks and check for errors. - final Set> processFutures = new HashSet<>(updateable.size()); - for (Future> future : downloadFutures) { - final Future task; - try { - task = future.get(); - if (task != null) { - processFutures.add(task); - } - } catch (InterruptedException ex) { - LOGGER.debug("Thread was interrupted during download", ex); - Thread.currentThread().interrupt(); - throw new UpdateException("The download was interrupted", ex); - } catch (ExecutionException ex) { - LOGGER.debug("Thread was interrupted during download execution", ex); - throw new UpdateException("The execution of the download was interrupted", ex); - } - } - - for (Future future : processFutures) { - try { - final ProcessTask task = future.get(); - if (task.getException() != null) { - throw task.getException(); - } - } catch (InterruptedException ex) { - LOGGER.debug("Thread was interrupted during processing", ex); - Thread.currentThread().interrupt(); - throw new UpdateException(ex); - } catch (ExecutionException ex) { - LOGGER.debug("Execution Exception during process", ex); - throw new UpdateException(ex); - } - } - - if (runLast != null) { - final Future> modified = downloadExecutorService.submit(runLast); - final Future task; - try { - task = modified.get(); - if (task != null) { - final ProcessTask last = task.get(); - if (last.getException() != null) { - throw last.getException(); - } - } - } catch (InterruptedException ex) { - LOGGER.debug("Thread was interrupted during download", ex); - Thread.currentThread().interrupt(); - throw new UpdateException("The download was interrupted", ex); - } catch (ExecutionException ex) { - LOGGER.debug("Thread was interrupted during download execution", ex); - throw new UpdateException("The execution of the download was interrupted", ex); - } - } - - } - - /** - * Downloads the NVD CVE Meta file properties. - * - * @param url the URL to the NVD CVE JSON file - * @return the meta file properties - * @throws UpdateException thrown if the meta file could not be downloaded - */ - protected final MetaProperties getMetaFile(String url) throws UpdateException { - try { - final long waitTime = settings.getInt(Settings.KEYS.CVE_DOWNLOAD_WAIT_TIME, 4000); - MetaProperties retVal = doMetaDownload(url, false); - - final int downloadAttempts = 4; - for (int x = 2; retVal == null && x <= downloadAttempts; x++) { - Thread.sleep(waitTime * (x / 2)); - retVal = doMetaDownload(url, x == downloadAttempts); - } - return retVal; - } catch (InterruptedException ex) { - Thread.interrupted(); - throw new UpdateException("Download interupted", ex); - } - } - - /** - * Downloads the NVD CVE Meta file properties. - * - * @param url the URL to the NVD CVE JSON file - * @param throwErrors if true and an error occurs, the error - * will be thrown; otherwise the error will be suppressed - * @return the meta file properties - * @throws UpdateException thrown if the meta file could not be downloaded - */ - private MetaProperties doMetaDownload(String url, boolean throwErrors) throws UpdateException { - final String metaUrl = url.substring(0, url.length() - 7) + "meta"; - final NvdCache cache = new NvdCache(settings); - try { - final URL u = new URL(metaUrl); - final File tmp = settings.getTempFile("nvd", "meta"); - if (cache.notInCache(u, tmp)) { - final Downloader d = new Downloader(settings); - final String content = d.fetchContent(u, true, Settings.KEYS.CVE_USER, Settings.KEYS.CVE_PASSWORD); - try (FileOutputStream fos = new FileOutputStream(tmp); - OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8); - BufferedWriter writer = new BufferedWriter(osw)) { - writer.write(content); - } - cache.storeInCache(u, tmp); - FileUtils.deleteQuietly(tmp); - return new MetaProperties(content); - } else { - final String content; - try (FileInputStream fis = new FileInputStream(tmp); - InputStreamReader isr = new InputStreamReader(fis, StandardCharsets.UTF_8); - BufferedReader reader = new BufferedReader(isr)) { - content = reader.lines().collect(Collectors.joining("\n")); - } - FileUtils.deleteQuietly(tmp); - return new MetaProperties(content); - } - } catch (MalformedURLException ex) { - if (throwErrors) { - throw new UpdateException("Meta file url is invalid: " + metaUrl, ex); - } - } catch (InvalidDataException ex) { - if (throwErrors) { - throw new UpdateException("Meta file content is invalid: " + metaUrl, ex); - } - } catch (DownloadFailedException ex) { - if (throwErrors) { - throw new UpdateException("Unable to download meta file: " + metaUrl, ex); - } - } catch (TooManyRequestsException ex) { - if (throwErrors) { - throw new UpdateException("Unable to download meta file: " + metaUrl + "; received 429 -- too many requests", ex); - } - } catch (ResourceNotFoundException ex) { - if (throwErrors) { - throw new UpdateException("Unable to download meta file: " + metaUrl + "; received 404 -- resource not found", ex); - } - } catch (IOException ex) { - if (throwErrors) { - throw new RuntimeException(ex); - } - } - return null; - } - - /** - * Determines if the index needs to be updated. This is done by fetching the - * NVD CVE meta data and checking the last update date. If the data needs to - * be refreshed this method will return the NvdCveUrl for the files that - * need to be updated. - * - * @return the collection of files that need to be updated - * @throws UpdateException Is thrown if there is an issue with the last - * updated properties file - */ - protected final List getUpdatesNeeded() throws UpdateException { - LOGGER.debug("starting getUpdatesNeeded() ..."); - final List updates = new ArrayList<>(); - if (dbProperties != null && !dbProperties.isEmpty()) { - try { - final int startYear = settings.getInt(Settings.KEYS.CVE_START_YEAR, 2002); - // for establishing the current year use the timezone where the new year starts first - // as from that moment on CNAs might start assigning CVEs with the new year depending - // on the CNA's timezone - final ZonedDateTime today = ZonedDateTime.now().withZoneSameInstant(ZoneOffset.ofHours(14)); - final int endYear = today.getYear(); - final int dayOfEndYear = today.getDayOfYear(); - boolean needsFullUpdate = false; - for (int y = startYear; y <= endYear; y++) { - final long val = Long.parseLong(dbProperties.getProperty(DatabaseProperties.LAST_UPDATED_BASE + y, "0")); - if (val == 0) { - needsFullUpdate = true; - break; - } - } - final long lastUpdated = getPropertyInSeconds(DatabaseProperties.LAST_UPDATED); - final long now = System.currentTimeMillis() / 1000; - final int days = settings.getInt(Settings.KEYS.CVE_MODIFIED_VALID_FOR_DAYS, 7); - - String url = settings.getString(Settings.KEYS.CVE_MODIFIED_JSON); - final MetaProperties modified = getMetaFile(url); - - if (!needsFullUpdate && lastUpdated == modified.getLastModifiedDate()) { - return updates; - } else { - final String baseUrl = settings.getString(Settings.KEYS.CVE_BASE_JSON); - final NvdCveInfo item = new NvdCveInfo(MODIFIED, url, modified.getLastModifiedDate()); - updates.add(item); - if (needsFullUpdate) { - // no need to download each one, just use the modified timestamp - for (int i = startYear; i < endYear; i++) { - url = String.format(baseUrl, i); - final NvdCveInfo entry = new NvdCveInfo(Integer.toString(i), url, modified.getLastModifiedDate()); - updates.add(entry); - } - // for endyear check metadata availability to determine inclusion when still in grace period - if (dayOfEndYear < settings.getInt(Settings.KEYS.NVD_NEW_YEAR_GRACE_PERIOD, 10)) { - try { - url = String.format(baseUrl, endYear); - final MetaProperties meta = getMetaFile(url); - } catch (UpdateException ue) { - if (ue.getCause() instanceof ResourceNotFoundException) { - LOGGER.warn("NVD Data for {} has not been published yet.", endYear); - } else { - throw ue; - } - } - } else { - url = String.format(baseUrl, endYear); - final NvdCveInfo entry = new NvdCveInfo(Integer.toString(endYear), url, modified.getLastModifiedDate()); - updates.add(entry); - } - } else if (!DateUtil.withinDateRange(lastUpdated, now, days)) { - final long waitTime = settings.getInt(Settings.KEYS.CVE_DOWNLOAD_WAIT_TIME, 4000); - for (int i = startYear; i <= endYear; i++) { - try { - url = String.format(baseUrl, i); - Thread.sleep(waitTime); - final MetaProperties meta = getMetaFile(url); - final long currentTimestamp = getPropertyInSeconds(DatabaseProperties.LAST_UPDATED_BASE + i); - - if (currentTimestamp < meta.getLastModifiedDate()) { - final NvdCveInfo entry = new NvdCveInfo(Integer.toString(i), url, meta.getLastModifiedDate()); - updates.add(entry); - } - } catch (UpdateException ex) { - final int grace = settings.getInt(Settings.KEYS.NVD_NEW_YEAR_GRACE_PERIOD, 10); - if (ex.getCause() instanceof ResourceNotFoundException - && i == endYear && dayOfEndYear < grace) { - LOGGER.warn("NVD Data for {} has not been published yet.", endYear); - } else { - throw ex; - } - } catch (InterruptedException ex) { - Thread.interrupted(); - throw new UpdateException("The download of the meta file was interupted: " + url, ex); - } - } - } - } - } catch (NumberFormatException ex) { - LOGGER.warn("An invalid schema version or timestamp exists in the data.properties file."); - LOGGER.debug("", ex); - } - } - return updates; - } - - /** - * Returns the database property value in seconds. - * - * @param key the key to the property - * @return the property value in seconds - */ - private long getPropertyInSeconds(String key) { - final String value = dbProperties.getProperty(key, "0"); - return DateUtil.getEpochValueInSeconds(value); - } - - /** - * Sets the settings object; this is used during testing. - * - * @param settings the configured settings - */ - protected synchronized void setSettings(Settings settings) { - this.settings = settings; - } - - @Override - public boolean purge(Engine engine) { - boolean result = true; - try { - final File dataDir = engine.getSettings().getDataDirectory(); - final File db = new File(dataDir, engine.getSettings().getString(Settings.KEYS.DB_FILE_NAME, "odc.mv.db")); - if (db.exists()) { - if (db.delete()) { - LOGGER.info("Database file purged; local copy of the NVD has been removed"); - } else { - LOGGER.error("Unable to delete '{}'; please delete the file manually", db.getAbsolutePath()); - result = false; - } - } else { - LOGGER.info("Unable to purge database; the database file does not exist: {}", db.getAbsolutePath()); - result = false; - } - final File traceFile = new File(dataDir, "odc.trace.db"); - if (traceFile.exists() && !traceFile.delete()) { - LOGGER.error("Unable to delete '{}'; please delete the file manually", traceFile.getAbsolutePath()); - result = false; - } - final File lockFile = new File(dataDir, "odc.update.lock"); - if (lockFile.exists() && !lockFile.delete()) { - LOGGER.error("Unable to delete '{}'; please delete the file manually", lockFile.getAbsolutePath()); - result = false; - } - } catch (IOException ex) { - final String msg = "Unable to delete the database"; - LOGGER.error(msg, ex); - result = false; - } - return result; - } -} diff --git a/core/src/main/java/org/owasp/dependencycheck/data/update/RetireJSDataSource.java b/core/src/main/java/org/owasp/dependencycheck/data/update/RetireJSDataSource.java index 59f4b7a39fa..7dcbf994b0d 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/update/RetireJSDataSource.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/update/RetireJSDataSource.java @@ -40,7 +40,7 @@ * @author Jeremy Long */ @ThreadSafe -public class RetireJSDataSource implements CachedWebDataSource { +public class RetireJSDataSource extends LocalDataSource { /** * Static logger. @@ -87,6 +87,7 @@ public boolean update(Engine engine) throws UpdateException { if (proceed) { LOGGER.debug("Begin RetireJS Update"); initializeRetireJsRepo(settings, url, repoFile); + saveLastUpdated(repoFile, System.currentTimeMillis() / 1000); } } catch (MalformedURLException ex) { throw new UpdateException(String.format("Invalid URL for RetireJS repository (%s)", configuredUrl), ex); @@ -109,7 +110,7 @@ protected boolean shouldUpdate(File repo) throws NumberFormatException { boolean proceed = true; if (repo != null && repo.isFile()) { final int validForHours = settings.getInt(Settings.KEYS.ANALYZER_RETIREJS_REPO_VALID_FOR_HOURS, 0); - final long lastUpdatedOn = repo.lastModified(); + final long lastUpdatedOn = getLastUpdated(repo); final long now = System.currentTimeMillis(); LOGGER.debug("Last updated: {}", lastUpdatedOn); LOGGER.debug("Now: {}", now); @@ -122,6 +123,7 @@ protected boolean shouldUpdate(File repo) throws NumberFormatException { return proceed; } + /** * Initializes the local RetireJS repository * @@ -135,8 +137,7 @@ protected boolean shouldUpdate(File repo) throws NumberFormatException { private void initializeRetireJsRepo(Settings settings, URL repoUrl, File repoFile) throws UpdateException { try (WriteLock lock = new WriteLock(settings, true, repoFile.getName() + ".lock")) { LOGGER.debug("RetireJS Repo URL: {}", repoUrl.toExternalForm()); - final Downloader downloader = new Downloader(settings); - downloader.fetchFile(repoUrl, repoFile, Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_USER, Settings.KEYS.ANALYZER_RETIREJS_REPO_JS_PASSWORD); + Downloader.getInstance().fetchFile(repoUrl, repoFile); } catch (IOException | TooManyRequestsException | ResourceNotFoundException | WriteLockException ex) { throw new UpdateException("Failed to initialize the RetireJS repo", ex); } diff --git a/core/src/main/java/org/owasp/dependencycheck/data/update/cisa/KnownExploitedVulnerabilityParser.java b/core/src/main/java/org/owasp/dependencycheck/data/update/cisa/KnownExploitedVulnerabilityParser.java index c4c28f5a0bb..1d7ee983f16 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/update/cisa/KnownExploitedVulnerabilityParser.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/update/cisa/KnownExploitedVulnerabilityParser.java @@ -19,10 +19,8 @@ import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.Module; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectReader; -import com.fasterxml.jackson.module.afterburner.AfterburnerModule; import com.fasterxml.jackson.module.blackbird.BlackbirdModule; import java.io.EOFException; import java.io.IOException; @@ -33,7 +31,6 @@ import org.owasp.dependencycheck.data.knownexploited.json.KnownExploitedVulnerabilitiesSchema; import org.owasp.dependencycheck.data.update.exception.CorruptedDatastreamException; import org.owasp.dependencycheck.data.update.exception.UpdateException; -import org.owasp.dependencycheck.utils.Utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -61,13 +58,7 @@ public class KnownExploitedVulnerabilityParser { public KnownExploitedVulnerabilitiesSchema parse(InputStream in) throws UpdateException, CorruptedDatastreamException { final ObjectMapper objectMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - final Module module; - if (Utils.getJavaVersion() <= 8) { - module = new AfterburnerModule(); - } else { - module = new BlackbirdModule(); - } - objectMapper.registerModule(module); + objectMapper.registerModule(new BlackbirdModule()); final ObjectReader objectReader = objectMapper.readerFor(KnownExploitedVulnerabilitiesSchema.class); diff --git a/core/src/main/java/org/owasp/dependencycheck/data/update/cpe/CpeEcosystemCache.java b/core/src/main/java/org/owasp/dependencycheck/data/update/cpe/CpeEcosystemCache.java index 671b7bd009b..71d61cf2185 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/update/cpe/CpeEcosystemCache.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/update/cpe/CpeEcosystemCache.java @@ -20,7 +20,7 @@ import java.util.HashMap; import java.util.Map; import org.apache.commons.lang3.StringUtils; -import org.owasp.dependencycheck.data.update.nvd.NvdCveParser; + import org.owasp.dependencycheck.utils.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -50,7 +50,7 @@ private CpeEcosystemCache() { /** * The logger. */ - private static final Logger LOGGER = LoggerFactory.getLogger(NvdCveParser.class); + private static final Logger LOGGER = LoggerFactory.getLogger(CpeEcosystemCache.class); //CSOFF: EmptyBlock /** diff --git a/core/src/main/java/org/owasp/dependencycheck/data/update/exception/CorruptedDatastreamException.java b/core/src/main/java/org/owasp/dependencycheck/data/update/exception/CorruptedDatastreamException.java index 2794adb98bf..3ce88bf2f26 100644 --- a/core/src/main/java/org/owasp/dependencycheck/data/update/exception/CorruptedDatastreamException.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/update/exception/CorruptedDatastreamException.java @@ -27,6 +27,8 @@ @ThreadSafe public class CorruptedDatastreamException extends Exception { + private static final long serialVersionUID = 1L; + /** * Create a new CorruptedDatastreamException. */ diff --git a/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/DownloadTask.java b/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/DownloadTask.java deleted file mode 100644 index a0d8f0bf9ce..00000000000 --- a/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/DownloadTask.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * This file is part of dependency-check-core. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright (c) 2013 Jeremy Long. All Rights Reserved. - */ -package org.owasp.dependencycheck.data.update.nvd; - -import java.io.File; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; -import javax.annotation.concurrent.ThreadSafe; -import org.apache.commons.lang3.StringUtils; -import org.owasp.dependencycheck.data.nvdcve.CveDB; -import org.owasp.dependencycheck.data.update.exception.UpdateException; -import org.owasp.dependencycheck.utils.DownloadFailedException; -import org.owasp.dependencycheck.utils.Downloader; -import org.owasp.dependencycheck.utils.ResourceNotFoundException; -import org.owasp.dependencycheck.utils.Settings; -import org.owasp.dependencycheck.utils.TooManyRequestsException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * A callable object to download two files. - * - * @author Jeremy Long - */ -@ThreadSafe -public class DownloadTask implements Callable> { - - /** - * The Logger. - */ - private static final Logger LOGGER = LoggerFactory.getLogger(DownloadTask.class); - /** - * The CVE DB to use when processing the files. - */ - private final CveDB cveDB; - /** - * The processor service to pass the results of the download to. - */ - private final ExecutorService processorService; - /** - * The NVD CVE Meta Data. - */ - private NvdCveInfo nvdCveInfo; - /** - * A reference to the global settings object. - */ - private final Settings settings; - /** - * a file. - */ - private final File file; - - /** - * Simple constructor for the callable download task. - * - * @param nvdCveInfo the NVD CVE info - * @param processor the processor service to submit the downloaded files to - * @param cveDB the CVE DB to use to store the vulnerability data - * @param settings a reference to the global settings object; this is - * necessary so that when the thread is started the dependencies have a - * correct reference to the global settings. - * @throws UpdateException thrown if temporary files could not be created - */ - public DownloadTask(NvdCveInfo nvdCveInfo, ExecutorService processor, CveDB cveDB, Settings settings) throws UpdateException { - this.nvdCveInfo = nvdCveInfo; - this.processorService = processor; - this.cveDB = cveDB; - this.settings = settings; - - try { - this.file = File.createTempFile("cve" + nvdCveInfo.getId() + '_', ".json.gz", settings.getTempDirectory()); - } catch (IOException ex) { - throw new UpdateException("Unable to create temporary files", ex); - } - } - - /** - * Get the value of nvdCveInfo. - * - * @return the value of nvdCveInfo - */ - public NvdCveInfo getNvdCveInfo() { - return nvdCveInfo; - } - - /** - * Set the value of nvdCveInfo. - * - * @param nvdCveInfo new value of nvdCveInfo - */ - public void setNvdCveInfo(NvdCveInfo nvdCveInfo) { - this.nvdCveInfo = nvdCveInfo; - } - - /** - * Get the value of file. - * - * @return the value of file - */ - public File getFile() { - return file; - } - - @SuppressWarnings("BusyWait") - @Override - public Future call() throws Exception { - final long waitTime = settings.getInt(Settings.KEYS.CVE_DOWNLOAD_WAIT_TIME, 4000); - long startDownload = 0; - final NvdCache cache = new NvdCache(settings); - try { - final URL url1 = new URL(nvdCveInfo.getUrl()); - if (cache.notInCache(url1, file)) { - Thread.sleep(waitTime); - LOGGER.info("Download Started for NVD CVE - {}", nvdCveInfo.getId()); - startDownload = System.currentTimeMillis(); - final int downloadAttempts = 5; - for (int x = 2; x <= downloadAttempts && !attemptDownload(url1, x == downloadAttempts); x++) { - LOGGER.info("Download Attempt {} for NVD CVE - {}", x, nvdCveInfo.getId()); - Thread.sleep(waitTime * (x / 2)); - } - if (file.isFile() && file.length() > 0) { - LOGGER.info("Download Complete for NVD CVE - {} ({} ms)", nvdCveInfo.getId(), - System.currentTimeMillis() - startDownload); - cache.storeInCache(url1, file); - } else { - throw new DownloadFailedException("Unable to download NVD CVE " + nvdCveInfo.getId()); - } - } - if (this.processorService == null) { - return null; - } - final ProcessTask task = new ProcessTask(cveDB, this, settings); - final Future val = this.processorService.submit(task); - return val; - - } catch (Throwable ex) { - LOGGER.error("Error downloading NVD CVE - {} Reason: {}", nvdCveInfo.getId(), ex.getMessage()); - throw ex; - } finally { - settings.cleanup(false); - } - } - - private boolean attemptDownload(final URL url1, boolean showLog) throws TooManyRequestsException, ResourceNotFoundException { - try { - final Downloader downloader = new Downloader(settings); - downloader.fetchFile(url1, file, Settings.KEYS.CVE_USER, Settings.KEYS.CVE_PASSWORD); - } catch (DownloadFailedException ex) { - if (showLog) { - LOGGER.error("Download Failed for NVD CVE - {}\nSome CVEs may not be reported. Reason: {}", - nvdCveInfo.getId(), ex.getMessage()); - if (settings.getString(Settings.KEYS.PROXY_SERVER) == null) { - LOGGER.error("If you are behind a proxy you may need to configure dependency-check to use the proxy."); - } - LOGGER.debug("", ex); - } - return false; - } - return true; - } - - /** - * Attempts to delete the files that were downloaded. - */ - public void cleanup() { - if (file != null && file.exists() && !file.delete()) { - LOGGER.debug("Failed to delete first temporary file {}", file); - file.deleteOnExit(); - } - } - - /** - * Attempts to delete the files that were downloaded. - */ - public void evictCorruptFileFromCache() { - final NvdCache cache = new NvdCache(settings); - try { - final URL url1 = new URL(nvdCveInfo.getUrl()); - cache.evictFromCache(url1); - } catch (MalformedURLException e) { - LOGGER.debug("Ignoring Cache-eviction request for an invalid URL"); - } - } - - /** - * Returns true if the process task is for the modified json file from the - * NVD. - * - * @return true if the process task is for the modified data; - * otherwise false - */ - public boolean isModified() { - return StringUtils.containsIgnoreCase(file.toString(), "modified"); - } -} diff --git a/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/NvdCache.java b/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/NvdCache.java deleted file mode 100644 index 2471e7ce0f3..00000000000 --- a/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/NvdCache.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * This file is part of dependency-check-core. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright (c) 2021 Jeremy Long. All Rights Reserved. - */ -package org.owasp.dependencycheck.data.update.nvd; - -import java.io.File; -import java.io.IOException; -import java.net.URL; -import java.nio.file.Files; -import java.time.Instant; -import org.apache.commons.io.FileUtils; -import org.owasp.dependencycheck.utils.Settings; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Simple four hour cache for files. - * - * @author Jeremy Long - */ -public class NvdCache { - - /** - * The Logger. - */ - private static final Logger LOGGER = LoggerFactory.getLogger(DownloadTask.class); - /** - * The settings. - */ - private final Settings settings; - - /** - * Creates a new cache for the NVD files. - * - * @param settings ODC settings - */ - public NvdCache(Settings settings) { - this.settings = settings; - } - - /** - * Checks if the file is in the cache and within four hours. If found and - * viable, the cached data will be copied to the given file. - * - * @param url the URL of the file cached - * @param file the path of the file to restore from the cache - * @return true if the URL file is not in the cache; otherwise - * false - */ - public boolean notInCache(URL url, File file) { - try { - //valid for up to four hours. - final long validEpoch = Instant.now().toEpochMilli() - 14400000; - final File tmp = new File(url.getPath()); - final String filename = tmp.getName(); - final File cache = new File(settings.getDataDirectory(), "nvdcache"); - if (!cache.isDirectory()) { - return true; - } - final File nvdFile = new File(cache, filename); - if (nvdFile.isFile() && nvdFile.lastModified() > validEpoch) { - LOGGER.debug("Copying {} from cache", url); - FileUtils.copyFile(nvdFile, file); - return false; - } - return true; - } catch (IOException ex) { - LOGGER.debug("Error checking for nvd file in cache", ex); - return true; - } - } - - /** - * Stores a file in the cache. - * - * @param url the URL of the file to cache - * @param file the file to cache - */ - public void storeInCache(URL url, File file) { - if (file.isFile()) { - try { - final File tmp = new File(url.getPath()); - final String filename = tmp.getName(); - final File cache = new File(settings.getDataDirectory(), "nvdcache"); - if (!cache.isDirectory() && !cache.mkdir()) { - return; - } - final File nvdFile = new File(cache, filename); - FileUtils.copyFile(file, nvdFile); - if (!nvdFile.setLastModified(Instant.now().toEpochMilli())) { - LOGGER.debug("Unable to set last modified date on {}", nvdFile); - } - } catch (IOException ex) { - LOGGER.debug("Error storing nvd file in cache", ex); - } - } - } - - /** - * Evict a file corresponding to a URL from the cache. - *
- * Used to clear files from the cache that are found to be a corrupted download. - * - * @param url - * the origin URL of the file that is to be evicted from the cache - */ - public void evictFromCache(URL url) { - try { - final File tmp = new File(url.getPath()); - final String filename = tmp.getName(); - final File cache = new File(settings.getDataDirectory(), "nvdcache"); - if (!cache.isDirectory()) { - return; - } - LOGGER.error("Removing file from cache for {} as a corrupted download is detected", url); - final File nvdFile = new File(cache, filename); - Files.delete(nvdFile.toPath()); - } catch (IOException ex) { - LOGGER.warn("Error evicting corrupt nvd file from cache", ex); - } - } -} diff --git a/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/NvdCveInfo.java b/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/NvdCveInfo.java deleted file mode 100644 index 57009240d7a..00000000000 --- a/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/NvdCveInfo.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * This file is part of dependency-check-core. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright (c) 2013 Jeremy Long. All Rights Reserved. - */ -package org.owasp.dependencycheck.data.update.nvd; - -import javax.annotation.concurrent.ThreadSafe; - -/** - * A pojo that contains the Url and timestamp of the current NvdCve JSON files. - * - * @author Jeremy Long - */ -@ThreadSafe -public class NvdCveInfo { - - /** - * The identifier for the CVE data file. - */ - private final String id; - /** - * The URL to download the file. - */ - private final String url; - /** - * The timestamp of the file - epoch time. - */ - private final long timestamp; - - /** - * Construct a new NVD CVE Info object. - * - * @param id the id - * @param url the url - * @param timestamp the timestamp - */ - public NvdCveInfo(String id, String url, long timestamp) { - this.id = id; - this.url = url; - this.timestamp = timestamp; - } - - /** - * Get the value of id. - * - * @return the value of id - */ - public String getId() { - return id; - } - - /** - * Get the value of URL. - * - * @return the value of URL - */ - public String getUrl() { - return url; - } - - /** - * Get the value of timestamp - epoch time. - * - * @return the value of timestamp - epoch time - */ - public long getTimestamp() { - return timestamp; - } -} diff --git a/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/NvdCveParser.java b/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/NvdCveParser.java deleted file mode 100644 index a1451eaf919..00000000000 --- a/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/NvdCveParser.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * This file is part of dependency-check-core. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright (c) 2018 Steve Springett. All Rights Reserved. - */ -package org.owasp.dependencycheck.data.update.nvd; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonToken; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.Module; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectReader; -import com.fasterxml.jackson.databind.json.JsonMapper; -import com.fasterxml.jackson.module.blackbird.BlackbirdModule; -import com.fasterxml.jackson.module.afterburner.AfterburnerModule; - -import java.io.EOFException; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import static java.nio.charset.StandardCharsets.UTF_8; -import java.util.zip.GZIPInputStream; -import java.util.zip.ZipException; - -import org.owasp.dependencycheck.data.nvdcve.CveDB; -import org.owasp.dependencycheck.data.update.exception.CorruptedDatastreamException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.owasp.dependencycheck.data.nvd.json.DefCveItem; -import org.owasp.dependencycheck.data.nvd.ecosystem.CveEcosystemMapper; -import org.owasp.dependencycheck.data.update.exception.UpdateException; -import org.owasp.dependencycheck.utils.Settings; -import org.owasp.dependencycheck.utils.Utils; - -/** - * Parser and processor of NVD CVE JSON data feeds. - * - * @author Jeremy Long - */ -public final class NvdCveParser { - - /** - * The logger. - */ - private static final Logger LOGGER = LoggerFactory.getLogger(NvdCveParser.class); - /** - * A reference to the CVE DB. - */ - private final CveDB cveDB; - /** - * A reference to the ODC settings. - */ - private final Settings settings; - - /** - * Creates a new NVD CVE JSON Parser. - * - * @param settings the dependency-check settings - * @param db a reference to the database - */ - public NvdCveParser(Settings settings, CveDB db) { - this.settings = settings; - this.cveDB = db; - } - - /** - * Parses the NVD JSON file and inserts/updates data into the database. - * - * @param file the NVD JSON file to parse - * @throws UpdateException thrown if the file could not be read - * @throws CorruptedDatastreamException thrown if the file was found to be a - * corrupted download (ZipException or premature EOF) - */ - public void parse(File file) throws UpdateException, CorruptedDatastreamException { - LOGGER.debug("Parsing " + file.getName()); - - final Module module; - if (Utils.getJavaVersion() <= 8) { - module = new AfterburnerModule(); - } else { - module = new BlackbirdModule(); - } - final ObjectMapper objectMapper = JsonMapper.builder() - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - .addModule(module) - .build(); - - final ObjectReader objectReader = objectMapper.readerFor(DefCveItem.class); - - try (InputStream fin = new FileInputStream(file); - InputStream in = new GZIPInputStream(fin); - InputStreamReader isr = new InputStreamReader(in, UTF_8); - JsonParser parser = objectReader.getFactory().createParser(isr)) { - - final CveEcosystemMapper mapper = new CveEcosystemMapper(); - init(parser); - while (parser.nextToken() == JsonToken.START_OBJECT) { - final DefCveItem cve = objectReader.readValue(parser); - cveDB.updateVulnerability(cve, mapper.getEcosystem(cve)); - } - } catch (FileNotFoundException ex) { - LOGGER.error(ex.getMessage()); - throw new UpdateException("Unable to find the NVD CVE file, `" + file + "`, to parse", ex); - } catch (ZipException | EOFException ex) { - throw new CorruptedDatastreamException("Error parsing NVD CVE file", ex); - } catch (IOException ex) { - LOGGER.error("Error reading NVD JSON data: {}", file); - LOGGER.debug("Error extracting the NVD JSON data from: " + file, ex); - throw new UpdateException("Unable to find the NVD CVE file to parse", ex); - } - } - - void init(JsonParser parser) throws IOException { - JsonToken nextToken = parser.nextToken(); - if (nextToken != JsonToken.START_OBJECT) { - throw new IOException("Expected " + JsonToken.START_OBJECT + ", got " + nextToken); - } - - do { - nextToken = parser.nextToken(); - if (nextToken == null) { - break; - } - - if (nextToken.isStructStart()) { - if (nextToken == JsonToken.START_ARRAY) { - break; - } else { - parser.skipChildren(); - } - } - } while (true); - } -} diff --git a/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/ProcessTask.java b/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/ProcessTask.java deleted file mode 100644 index a3f2e70f1d4..00000000000 --- a/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/ProcessTask.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * This file is part of dependency-check-core. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright (c) 2013 Jeremy Long. All Rights Reserved. - */ -package org.owasp.dependencycheck.data.update.nvd; - -import java.io.File; -import java.io.IOException; -import java.sql.SQLException; -import java.util.concurrent.Callable; -import javax.annotation.concurrent.ThreadSafe; -import javax.xml.parsers.ParserConfigurationException; -import org.owasp.dependencycheck.data.nvdcve.CveDB; -import org.owasp.dependencycheck.data.nvdcve.DatabaseException; -import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties; -import org.owasp.dependencycheck.data.update.exception.CorruptedDatastreamException; -import org.owasp.dependencycheck.data.update.exception.UpdateException; -import org.owasp.dependencycheck.utils.Settings; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * A callable task that will process a given set of NVD CVE xml files and update - * the Cve Database accordingly. - * - * @author Jeremy Long - */ -@ThreadSafe -public class ProcessTask implements Callable { - - /** - * The logger. - */ - private static final Logger LOGGER = LoggerFactory.getLogger(ProcessTask.class); - /** - * A field to store any update exceptions that occur during the "call". - */ - private UpdateException exception = null; - /** - * A reference to the CveDB. - */ - private final CveDB cveDB; - /** - * A reference to the callable download task. - */ - private final DownloadTask downloadTask; - /** - * A reference to the properties. - */ - private final DatabaseProperties properties; - /** - * A reference to the global settings object. - */ - private final Settings settings; - - /** - * Get the value of exception. - * - * @return the value of exception - */ - public UpdateException getException() { - return exception; - } - - /** - * Set the value of exception. - * - * @param exception new value of exception - */ - public void setException(UpdateException exception) { - this.exception = exception; - } - - /** - * Constructs a new ProcessTask used to process an NVD CVE update. - * - * @param cveDB the data store object - * @param downloadTask the download task that contains the URL references to - * download - * @param settings a reference to the global settings object; this is - * necessary so that when the thread is started the dependencies have a - * correct reference to the global settings. - */ - public ProcessTask(final CveDB cveDB, final DownloadTask downloadTask, Settings settings) { - this.cveDB = cveDB; - this.downloadTask = downloadTask; - this.properties = cveDB.getDatabaseProperties(); - this.settings = settings; - } - - /** - * Implements the callable interface. - * - * @return this object - * @throws Exception thrown if there is an exception; note that any - * UpdateExceptions are simply added to the tasks exception collection - */ - @Override - public ProcessTask call() throws Exception { - try { - processFiles(); - } catch (UpdateException ex) { - this.exception = ex; - } finally { - settings.cleanup(false); - } - return this; - } - - /** - * Imports the NVD CVE JSON File into the database. - * - * @param file the file containing the NVD CVE JSON - * @throws ParserConfigurationException is thrown if there is a parser - * configuration exception - * @throws IOException is thrown if there is a IO Exception - * @throws SQLException is thrown if there is a SQL exception - * @throws DatabaseException is thrown if there is a database exception - * @throws ClassNotFoundException thrown if the h2 database driver cannot be - * loaded - * @throws UpdateException thrown if the file could not be found - * @throws CorruptedDatastreamException thrown if the file was found to be a corrupted download - */ - protected void importJSON(File file) throws ParserConfigurationException, IOException, SQLException, DatabaseException, - ClassNotFoundException, UpdateException, CorruptedDatastreamException { - - final NvdCveParser parser = new NvdCveParser(settings, cveDB); - parser.parse(file); - } - - /** - * Processes the NVD CVE XML file and imports the data into the DB. - * - * @throws UpdateException thrown if there is an error loading the data into - * the database - */ - private void processFiles() throws UpdateException { - LOGGER.info("Processing Started for NVD CVE - {}", downloadTask.getNvdCveInfo().getId()); - final long startProcessing = System.currentTimeMillis(); - try { - importJSON(downloadTask.getFile()); - properties.save(downloadTask.getNvdCveInfo()); - } catch (ParserConfigurationException | SQLException | DatabaseException | ClassNotFoundException | IOException ex) { - throw new UpdateException(ex); - } catch (CorruptedDatastreamException ex) { - downloadTask.evictCorruptFileFromCache(); - throw new UpdateException(ex); - } finally { - downloadTask.cleanup(); - } - LOGGER.info("Processing Complete for NVD CVE - {} ({} ms)", downloadTask.getNvdCveInfo().getId(), - System.currentTimeMillis() - startProcessing); - } -} diff --git a/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/api/CveApiJson20CveItemSource.java b/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/api/CveApiJson20CveItemSource.java new file mode 100644 index 00000000000..cfe7d5d5b60 --- /dev/null +++ b/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/api/CveApiJson20CveItemSource.java @@ -0,0 +1,101 @@ +/* + * This file is part of dependency-check-core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2013 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.data.update.nvd.api; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import io.github.jeremylong.openvulnerability.client.nvd.DefCveItem; +import org.apache.commons.io.IOUtils; + +import java.io.IOException; +import java.io.InputStream; + +public class CveApiJson20CveItemSource implements CveItemSource { + + /** + * The object mapper. + */ + private final ObjectMapper mapper; + /** + * The input stream. + */ + private final InputStream inputStream; + /** + * The JSON Parser + */ + private final JsonParser jsonParser; + /** + * The current item. + */ + private DefCveItem currentItem; + /** + * The next item. + */ + private DefCveItem nextItem; + + /** + * Constructs a CVE Item Source record. + * + * @param inputStream the input source to read from + * @throws IOException thrown if there is an issue reading from the input + * stream + */ + public CveApiJson20CveItemSource(InputStream inputStream) throws IOException { + mapper = new ObjectMapper(); + mapper.registerModule(new JavaTimeModule()); + this.inputStream = inputStream; + jsonParser = mapper.getFactory().createParser(inputStream); + + JsonToken token = null; + do { + token = jsonParser.nextToken(); + if (token == JsonToken.FIELD_NAME) { + final String fieldName = jsonParser.currentName(); + if ("vulnerabilities".equals(fieldName) && (jsonParser.nextToken() == JsonToken.START_ARRAY)) { + nextItem = readItem(jsonParser); + } + } + } while (token != null && nextItem == null); + } + + @Override + public void close() throws Exception { + IOUtils.closeQuietly(jsonParser, inputStream); + } + + @Override + public boolean hasNext() { + return nextItem != null; + } + + @Override + public DefCveItem next() throws IOException { + currentItem = nextItem; + nextItem = readItem(jsonParser); + return currentItem; + } + + private DefCveItem readItem(JsonParser jsonParser) throws IOException { + if (jsonParser.nextToken() == JsonToken.START_OBJECT) { + return mapper.readValue(jsonParser, DefCveItem.class); + } + return null; + } +} diff --git a/core/src/test/java/org/owasp/dependencycheck/data/update/NvdCveUpdaterIT.java b/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/api/CveItemSource.java similarity index 50% rename from core/src/test/java/org/owasp/dependencycheck/data/update/NvdCveUpdaterIT.java rename to core/src/main/java/org/owasp/dependencycheck/data/update/nvd/api/CveItemSource.java index 90b41674369..674178b2819 100644 --- a/core/src/test/java/org/owasp/dependencycheck/data/update/NvdCveUpdaterIT.java +++ b/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/api/CveItemSource.java @@ -15,29 +15,27 @@ * * Copyright (c) 2013 Jeremy Long. All Rights Reserved. */ -package org.owasp.dependencycheck.data.update; +package org.owasp.dependencycheck.data.update.nvd.api; -import java.util.List; -import org.junit.Test; -import org.owasp.dependencycheck.BaseDBTestCase; -import static org.junit.Assert.assertNotNull; -import org.owasp.dependencycheck.data.update.nvd.NvdCveInfo; +import io.github.jeremylong.openvulnerability.client.nvd.DefCveItem; -/** - * - * @author Jeremy Long - */ -public class NvdCveUpdaterIT extends BaseDBTestCase { +import java.io.IOException; + +public interface CveItemSource extends AutoCloseable { + + /** + * Returns whether there is another item. + * + * @return true if there is another item; otherwise + * false. + */ + boolean hasNext(); /** - * Test of updatesNeeded method. + * Returns the next item. + * + * @return the next item + * @throws IOException thrown if there is an error reading from the source */ - @Test - public void testUpdatesNeeded() throws Exception { - NvdCveUpdater instance = new NvdCveUpdater(); - instance.setSettings(getSettings()); - instance.initializeExecutorServices(); - List result = instance.getUpdatesNeeded(); - assertNotNull(result); - } + T next() throws IOException; } diff --git a/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/api/DownloadTask.java b/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/api/DownloadTask.java new file mode 100644 index 00000000000..25f791b1304 --- /dev/null +++ b/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/api/DownloadTask.java @@ -0,0 +1,114 @@ +/* + * This file is part of dependency-check-core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2013 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.data.update.nvd.api; + +import java.io.File; +import java.net.URL; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import javax.annotation.concurrent.ThreadSafe; +import org.apache.commons.lang3.StringUtils; +import org.owasp.dependencycheck.data.nvdcve.CveDB; +import org.owasp.dependencycheck.utils.Downloader; +import org.owasp.dependencycheck.utils.Settings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A callable object to download the NVD API cache files and start the + * NvdApiProcessor. + * + * @author Jeremy Long + */ +@ThreadSafe +public class DownloadTask implements Callable> { + + /** + * The Logger. + */ + private static final Logger LOGGER = LoggerFactory.getLogger(DownloadTask.class); + /** + * The CVE DB to use when processing the files. + */ + private final CveDB cveDB; + /** + * The processor service to pass the results of the download to. + */ + private final ExecutorService processorService; + /** + * The NVD API Cache file URL. + */ + private final String url; + /** + * A reference to the global settings object. + */ + private final Settings settings; + + /** + * Simple constructor for the callable download task. + * + * @param url the file to download + * @param processor the processor service to submit the downloaded files to + * @param cveDB the CVE DB to use to store the vulnerability data + * @param settings a reference to the global settings object; this is + * necessary so that when the thread is started the dependencies have a + * correct reference to the global settings. + */ + public DownloadTask(String url, ExecutorService processor, CveDB cveDB, Settings settings) { + this.url = url; + this.processorService = processor; + this.cveDB = cveDB; + this.settings = settings; + } + + @SuppressWarnings("BusyWait") + @Override + public Future call() throws Exception { + try { + final URL u = new URL(url); + LOGGER.info("Download Started for NVD Cache - {}", url); + final long startDownload = System.currentTimeMillis(); + final File outputFile = settings.getTempFile("nvd-datafeed-", "json.gz"); + Downloader.getInstance().fetchFile(u, outputFile, true, Settings.KEYS.NVD_API_DATAFEED_USER, Settings.KEYS.NVD_API_DATAFEED_PASSWORD, + Settings.KEYS.NVD_API_DATAFEED_BEARER_TOKEN); + if (this.processorService == null) { + return null; + } + final NvdApiProcessor task = new NvdApiProcessor(cveDB, outputFile, startDownload); + final Future val = this.processorService.submit(task); + return val; + } catch (Throwable ex) { + LOGGER.error("Error downloading NVD CVE - {} Reason: {}", url, ex.getMessage()); + throw ex; + } finally { + settings.cleanup(false); + } + } + + /** + * Returns true if the process task is for the modified json file from the + * NVD API Cache. + * + * @return true if the process task is for the modified data; + * otherwise false + */ + public boolean isModified() { + return StringUtils.containsIgnoreCase(url, "modified"); + } +} diff --git a/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/api/JsonArrayCveItemSource.java b/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/api/JsonArrayCveItemSource.java new file mode 100644 index 00000000000..caf2c99fca6 --- /dev/null +++ b/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/api/JsonArrayCveItemSource.java @@ -0,0 +1,106 @@ +/* + * This file is part of dependency-check-core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2013 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.data.update.nvd.api; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import io.github.jeremylong.openvulnerability.client.nvd.DefCveItem; + +import java.io.IOException; +import java.io.InputStream; + +public class JsonArrayCveItemSource implements CveItemSource { + + /** + * The object mapper. + */ + private final ObjectMapper mapper; + /** + * The input stream. + */ + private final InputStream inputStream; + /** + * The JSON parser. + */ + private final JsonParser jsonParser; + /** + * The current item. + */ + private DefCveItem currentItem; + /** + * The next item. + */ + private DefCveItem nextItem; + + /** + * Constructs a new Item Source. + * + * @param inputStream the input stream to read from + * @throws IOException thrown if there is a problem reading from the input + * stream + */ + public JsonArrayCveItemSource(InputStream inputStream) throws IOException { + mapper = new ObjectMapper(); + mapper.registerModule(new JavaTimeModule()); + this.inputStream = inputStream; + jsonParser = mapper.getFactory().createParser(inputStream); + + if (jsonParser.nextToken() == JsonToken.START_ARRAY) { + nextItem = readItem(jsonParser); + } + } + + @Override + public void close() throws Exception { + if (jsonParser != null) { + try { + jsonParser.close(); + } catch (IOException ex) { + //ignore + } + } + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException ex) { + //ignore + } + } + } + + @Override + public boolean hasNext() { + return nextItem != null; + } + + @Override + public DefCveItem next() throws IOException { + currentItem = nextItem; + nextItem = readItem(jsonParser); + return currentItem; + } + + private DefCveItem readItem(JsonParser jsonParser) throws IOException { + if (jsonParser.nextToken() == JsonToken.START_OBJECT) { + return mapper.readValue(jsonParser, DefCveItem.class); + } + return null; + } +} diff --git a/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/api/NvdApiProcessor.java b/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/api/NvdApiProcessor.java new file mode 100644 index 00000000000..6dde51bbd87 --- /dev/null +++ b/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/api/NvdApiProcessor.java @@ -0,0 +1,134 @@ +/* + * This file is part of dependency-check-core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2023 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.data.update.nvd.api; + +import io.github.jeremylong.openvulnerability.client.nvd.DefCveItem; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.util.concurrent.Callable; +import java.util.zip.GZIPInputStream; + +import org.owasp.dependencycheck.data.nvd.ecosystem.CveEcosystemMapper; +import org.owasp.dependencycheck.data.nvdcve.CveDB; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Stores a collection of NVD CVE Data from the NVD API into the database. + * + * @author Jeremy Long + */ +public class NvdApiProcessor implements Callable { + + /** + * The Logger for use throughout the class. + */ + private static final Logger LOGGER = LoggerFactory.getLogger(NvdApiProcessor.class); + /** + * A reference to the database. + */ + private final CveDB cveDB; + /** + * The file containing the data to inject. + */ + private File jsonFile; + /** + * Reference to the CVE Ecosystem Mapper object. + */ + private final CveEcosystemMapper mapper = new CveEcosystemMapper(); + /** + * The start time. + */ + private final long startTime; + /** + * The end time. + */ + private long endTime = 0; + + /** + * Create a new processor to put the NVD data into the database. + * + * @param cveDB a reference to the database. + * @param jsonFile the JSON data file to inject. + * @param startTime the start time of the update process. + */ + public NvdApiProcessor(final CveDB cveDB, File jsonFile, long startTime) { + this.cveDB = cveDB; + this.jsonFile = jsonFile; + this.startTime = startTime; + } + + /** + * Create a new processor to put the NVD data into the database. + * + * @param cveDB a reference to the database + * @param jsonFile the JSON data file to inject. + */ + public NvdApiProcessor(final CveDB cveDB, File jsonFile) { + this(cveDB, jsonFile, System.currentTimeMillis()); + } + + @Override + public NvdApiProcessor call() throws Exception { + if (jsonFile.getName().endsWith(".jsonarray.gz")) { + try (InputStream fis = Files.newInputStream(jsonFile.toPath()); + InputStream is = new BufferedInputStream(new GZIPInputStream(fis)); + CveItemSource itemSource = new JsonArrayCveItemSource(is)) { + updateCveDb(itemSource); + } + } else if (jsonFile.getName().endsWith(".gz")) { + try (InputStream fis = Files.newInputStream(jsonFile.toPath()); + InputStream is = new BufferedInputStream(new GZIPInputStream(fis)); + CveItemSource itemSource = new CveApiJson20CveItemSource(is)) { + updateCveDb(itemSource); + } + } else { + try (InputStream fis = Files.newInputStream(jsonFile.toPath()); + InputStream is = new BufferedInputStream(fis); + CveItemSource itemSource = new JsonArrayCveItemSource(is)) { + updateCveDb(itemSource); + } + } + endTime = System.currentTimeMillis(); + return this; + } + + private void updateCveDb(CveItemSource itemSource) throws IOException { + while (itemSource.hasNext()) { + final DefCveItem entry = itemSource.next(); + try { + cveDB.updateVulnerability(entry, mapper.getEcosystem(entry)); + } catch (Exception ex) { + LOGGER.error("Failed to process " + entry.getCve().getId(), ex); + } + } + } + + /** + * Calculates how long the update process took. + * + * @return the number of milliseconds that the update process took + */ + public long getDurationMillis() { + return endTime - startTime; + } +} diff --git a/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/api/package-info.java b/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/api/package-info.java new file mode 100644 index 00000000000..b2d1baeaac8 --- /dev/null +++ b/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/api/package-info.java @@ -0,0 +1,4 @@ +/** + * Contains classes used to download, parse, and load the NVD API CVE data from NIST into the local database.

+ */ +package org.owasp.dependencycheck.data.update.nvd.api; diff --git a/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/package-info.java b/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/package-info.java deleted file mode 100644 index 6b29278aca0..00000000000 --- a/core/src/main/java/org/owasp/dependencycheck/data/update/nvd/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Contains classes used to download, parse, and load the NVD CVE data from NIST into the local database.

- */ -package org.owasp.dependencycheck.data.update.nvd; diff --git a/core/src/main/java/org/owasp/dependencycheck/dependency/CvssV2.java b/core/src/main/java/org/owasp/dependencycheck/dependency/CvssV2.java deleted file mode 100644 index e82bcaf864a..00000000000 --- a/core/src/main/java/org/owasp/dependencycheck/dependency/CvssV2.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * This file is part of dependency-check-core. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright (c) 2018 Jeremy Long. All Rights Reserved. - */ -package org.owasp.dependencycheck.dependency; - -import java.io.Serializable; - -/** - * CVSS V2 scoring information. - * - * @author Jeremy Long - */ -public class CvssV2 implements Serializable { - - /** - * Serial version UID. - */ - private static final long serialVersionUID = -2203955879356702367L; - - /** - * CVSS Score. - */ - private final float score; - /** - * CVSS Access Vector. - */ - private final String accessVector; - /** - * CVSS Access Complexity. - */ - private final String accessComplexity; - /** - * CVSS Authentication. - */ - private final String authentication; - /** - * CVSS Confidentiality Impact. - */ - private final String confidentialityImpact; - /** - * CVSS Integrity Impact. - */ - private final String integrityImpact; - /** - * CVSS Availability Impact. - */ - private final String availabilityImpact; - /** - * CVSS version. - */ - private final String version; - - /** - * CVSSv2 Base Metric severity. - */ - private final String severity; - /** - * CVSSv2 Base Metric exploitability score. - */ - private final Float exploitabilityScore; - /** - * CVSSv2 Base Metric impact score. - */ - private final Float impactScore; - /** - * CVSSv2 Base Metric acInsufInfo. - */ - private final Boolean acInsufInfo; - /** - * CVSSv2 Base Metric obtain all privilege. - */ - private final Boolean obtainAllPrivilege; - /** - * CVSSv2 Base Metric obtain user privilege. - */ - private final Boolean obtainUserPrivilege; - /** - * CVSSv2 Base Metric obtain other privilege. - */ - private final Boolean obtainOtherPrivilege; - /** - * CVSSv2 Base Metric user interaction required. - */ - private final Boolean userInteractionRequired; - - /** - * Constructs a new CVSS V2 object. - * - * @param score the score - * @param accessVector the access vector - * @param accessComplexity the access complexity - * @param authentication the authentication - * @param confidentialityImpact the confidentiality impact - * @param integrityImpact the integrity impact - * @param availabilityImpact the availability impact - * @param severity the severity - */ - //CSOFF: ParameterNumber - public CvssV2(float score, String accessVector, String accessComplexity, String authentication, - String confidentialityImpact, String integrityImpact, String availabilityImpact, String severity) { - this(score, accessVector, accessComplexity, authentication, confidentialityImpact, - integrityImpact, availabilityImpact, severity, null, null, null, null, null, null, null, null); - } - - /** - * Constructs a new CVSS V2 object. - * - * @param score the score - * @param accessVector the access vector - * @param accessComplexity the access complexity - * @param authentication the authentication - * @param confidentialityImpact the confidentiality impact - * @param integrityImpact the integrity impact - * @param availabilityImpact the availability impact - * @param severity the severity - * @param exploitabilityScore the exploitability score - * @param impactScore the impact score - * @param acInsufInfo the acInsufInfo - * @param obtainAllPrivilege whether or not the vulnerability allows one to obtain all privileges - * @param obtainUserPrivilege whether or not the vulnerability allows one to obtain user privileges - * @param obtainOtherPrivilege whether or not the vulnerability allows one to obtain other privileges - * @param userInteractionRequired whether or not user interaction is required - * @param version the CVSS version - */ - //CSOFF: ParameterNumber - public CvssV2(float score, String accessVector, String accessComplexity, String authentication, - String confidentialityImpact, String integrityImpact, String availabilityImpact, String severity, - Float exploitabilityScore, Float impactScore, Boolean acInsufInfo, Boolean obtainAllPrivilege, - Boolean obtainUserPrivilege, Boolean obtainOtherPrivilege, Boolean userInteractionRequired, String version) { - this.score = score; - this.accessVector = accessVector; - this.accessComplexity = accessComplexity; - this.authentication = authentication; - this.confidentialityImpact = confidentialityImpact; - this.integrityImpact = integrityImpact; - this.availabilityImpact = availabilityImpact; - - this.severity = severity; - this.exploitabilityScore = exploitabilityScore; - this.impactScore = impactScore; - this.acInsufInfo = acInsufInfo; - this.obtainAllPrivilege = obtainAllPrivilege; - this.obtainUserPrivilege = obtainUserPrivilege; - this.obtainOtherPrivilege = obtainOtherPrivilege; - this.userInteractionRequired = userInteractionRequired; - this.version = version; - } - //CSON: ParameterNumber - - /** - * Get the value of score. - * - * @return the value of score - */ - public float getScore() { - return score; - } - - /** - * Get the value of accessVector. - * - * @return the value of accessVector - */ - public String getAccessVector() { - return accessVector; - } - - /** - * Get the value of accessComplexity. - * - * @return the value of accessComplexity - */ - public String getAccessComplexity() { - return accessComplexity; - } - - /** - * Get the value of authentication. - * - * @return the value of authentication - */ - public String getAuthentication() { - return authentication; - } - - /** - * Get the value of confidentialityImpact. - * - * @return the value of confidentialityImpact - */ - public String getConfidentialityImpact() { - return confidentialityImpact; - } - - /** - * Get the value of integrityImpact. - * - * @return the value of integrityImpact - */ - public String getIntegrityImpact() { - return integrityImpact; - } - - /** - * Get the value of availabilityImpact. - * - * @return the value of availabilityImpact - */ - public String getAvailabilityImpact() { - return availabilityImpact; - } - - /** - * Get the value of version. - * - * @return the value of version - */ - public String getVersion() { - return version; - } - - /** - * Returns the severity for the vulnerability. - * - * @return the severity - */ - public String getSeverity() { - return severity; - } - - /** - * Returns the exploitabilityScore for the vulnerability. - * - * @return the exploitabilityScore - */ - public Float getExploitabilityScore() { - return exploitabilityScore; - } - - /** - * Returns the impactScore for the vulnerability. - * - * @return the impactScore - */ - public Float getImpactScore() { - return impactScore; - } - - /** - * Returns the acInsufInfo for the vulnerability. - * - * @return the acInsufInfo - */ - public Boolean isAcInsufInfo() { - return acInsufInfo; - } - - /** - * Returns the obtainAllPrivilege for the vulnerability. - * - * @return the obtainAllPrivilege - */ - public Boolean isObtainAllPrivilege() { - return obtainAllPrivilege; - } - - /** - * Returns the obtainUserPrivilege for the vulnerability. - * - * @return the obtainUserPrivilege - */ - public Boolean isObtainUserPrivilege() { - return obtainUserPrivilege; - } - - /** - * Returns the obtainOtherPrivilege for the vulnerability. - * - * @return the obtainOtherPrivilege - */ - public Boolean isObtainOtherPrivilege() { - return obtainOtherPrivilege; - } - - /** - * Returns the userInteractionRequired for the vulnerability. - * - * @return the userInteractionRequired - */ - public Boolean isUserInteractionRequired() { - return userInteractionRequired; - } - - @Override - public String toString() { - return String.format("/AV:%s/AC:%s/Au:%s/C:%s/I:%s/A:%s", - accessVector == null ? "" : accessVector.substring(0, 1), - accessComplexity == null ? "" : accessComplexity.substring(0, 1), - authentication == null ? "" : authentication.substring(0, 1), - confidentialityImpact == null ? "" : confidentialityImpact.substring(0, 1), - integrityImpact == null ? "" : integrityImpact.substring(0, 1), - availabilityImpact == null ? "" : availabilityImpact.substring(0, 1)); - } -} diff --git a/core/src/main/java/org/owasp/dependencycheck/dependency/CvssV3.java b/core/src/main/java/org/owasp/dependencycheck/dependency/CvssV3.java deleted file mode 100644 index bf6c0814c2e..00000000000 --- a/core/src/main/java/org/owasp/dependencycheck/dependency/CvssV3.java +++ /dev/null @@ -1,330 +0,0 @@ -/* - * This file is part of dependency-check-core. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright (c) 2018 Jeremy Long. All Rights Reserved. - */ -package org.owasp.dependencycheck.dependency; - -import org.sonatype.ossindex.service.api.cvss.Cvss3Severity; - -import java.io.Serializable; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; - -/** - * CVSS V3 scoring information. - * - * @author Jeremy Long - */ -public class CvssV3 implements Serializable { - - /** - * Serial version UID. - */ - private static final long serialVersionUID = -315810090425928920L; - - /** - * The CVSS v3 Base Metrics (that are required by the spec for any CVSS v3 Vector String) - */ - private static final List BASE_METRICS = Arrays.asList("AV", "AC", "PR", "UI", "S", "C", "I", "A"); - - /** - * CVSS Availability Impact. - */ - private final String attackVector; - /** - * CVSS Availability Impact. - */ - private final String attackComplexity; - /** - * CVSS Availability Impact. - */ - private final String privilegesRequired; - /** - * CVSS Availability Impact. - */ - private final String userInteraction; - /** - * CVSS Availability Impact. - */ - private final String scope; - /** - * CVSS Availability Impact. - */ - private final String confidentialityImpact; - /** - * CVSS Availability Impact. - */ - private final String integrityImpact; - /** - * CVSS Availability Impact. - */ - private final String availabilityImpact; - /** - * CVSS Base Score. - */ - private final float baseScore; - /** - * CVSS Base Severity. - */ - private final String baseSeverity; - /** - * CVSSv3 Base Metric exploitability score. - */ - private final Float exploitabilityScore; - /** - * CVSSv3 Base Metric impact score. - */ - private final Float impactScore; - /** - * CVSS version. - */ - private final String version; - - /** - * Constructs a new CVSS V3 object. - * - * @param attackVector the attack vector value - * @param attackComplexity the attack complexity value - * @param privilegesRequired the privileges required value - * @param userInteraction the user interaction value - * @param scope the scope value - * @param confidentialityImpact the confidentiality impact value - * @param integrityImpact the integrity impact value - * @param availabilityImpact the availability impact value - * @param baseScore the base score - * @param baseSeverity the base severity - */ - //CSOFF: ParameterNumber - public CvssV3(String attackVector, String attackComplexity, String privilegesRequired, - String userInteraction, String scope, String confidentialityImpact, String integrityImpact, - String availabilityImpact, float baseScore, String baseSeverity) { - this(attackVector, attackComplexity, privilegesRequired, userInteraction, scope, confidentialityImpact, - integrityImpact, availabilityImpact, baseScore, baseSeverity, null, null, null); - } - - /** - * Constructs a new CVSS V3 object. - * - * @param attackVector the attack vector value - * @param attackComplexity the attack complexity value - * @param privilegesRequired the privileges required value - * @param userInteraction the user interaction value - * @param scope the scope value - * @param confidentialityImpact the confidentiality impact value - * @param integrityImpact the integrity impact value - * @param availabilityImpact the availability impact value - * @param baseScore the base score - * @param baseSeverity the base severity - * @param exploitabilityScore the exploitability score - * @param impactScore the impact score - * @param version the CVSS version - */ - public CvssV3(String attackVector, String attackComplexity, String privilegesRequired, - String userInteraction, String scope, String confidentialityImpact, String integrityImpact, - String availabilityImpact, float baseScore, String baseSeverity, Float exploitabilityScore, Float impactScore, String version) { - this.attackVector = attackVector; - this.attackComplexity = attackComplexity; - this.privilegesRequired = privilegesRequired; - this.userInteraction = userInteraction; - this.scope = scope; - this.confidentialityImpact = confidentialityImpact; - this.integrityImpact = integrityImpact; - this.availabilityImpact = availabilityImpact; - this.baseScore = baseScore; - this.baseSeverity = baseSeverity; - this.exploitabilityScore = exploitabilityScore; - this.impactScore = impactScore; - this.version = version; - } - //CSON: ParameterNumber - - /** - * Constructs a new CVSS V3 object from a CVSS v3.x Vector String representation and - * a CVSS V3 Base score. - * - * @param vectorString a CVSS v3 Vector String - * @param baseScore the CVSS v3 base score - * @throws IllegalArgumentException when the provided vectorString is not a valid - * CVSS v3.x vector string. - */ - public CvssV3(String vectorString, float baseScore) { - if (!vectorString.startsWith("CVSS:3")) { - throw new IllegalArgumentException("Not a valid CVSSv3 vector string: " + vectorString); - } - this.version = vectorString.substring(5, vectorString.indexOf('/')); - final String[] metricStrings = vectorString.substring(vectorString.indexOf('/') + 1).split("/"); - final HashMap metrics = new HashMap<>(); - for (int i = 0; i < metricStrings.length; i++) { - final String[] metricKeyVal = metricStrings[i].split(":"); - if (metricKeyVal.length != 2) { - throw new IllegalArgumentException( - String.format("Not a valid CVSSv3 vector string '%s', invalid metric component '%s'", - vectorString, metricStrings[i])); - } - metrics.put(metricKeyVal[0], metricKeyVal[1]); - } - if (!metrics.keySet().containsAll(BASE_METRICS)) { - throw new IllegalArgumentException( - String.format("Not a valid CVSSv3 vector string '%s'; missing one or more required Base Metrics;", - vectorString)); - } - this.attackVector = metrics.get("AV"); - this.attackComplexity = metrics.get("AC"); - this.privilegesRequired = metrics.get("PR"); - this.userInteraction = metrics.get("UI"); - this.scope = metrics.get("S"); - this.confidentialityImpact = metrics.get("C"); - this.integrityImpact = metrics.get("I"); - this.availabilityImpact = metrics.get("A"); - this.baseScore = baseScore; - this.baseSeverity = Cvss3Severity.of(baseScore).name(); - this.exploitabilityScore = null; - this.impactScore = null; - } - - /** - * Get the value of attackVector. - * - * @return the value of attackVector - */ - public String getAttackVector() { - return attackVector; - } - - /** - * Get the value of attackComplexity. - * - * @return the value of attackComplexity - */ - public String getAttackComplexity() { - return attackComplexity; - } - - /** - * Get the value of privilegesRequired. - * - * @return the value of privilegesRequired - */ - public String getPrivilegesRequired() { - return privilegesRequired; - } - - /** - * Get the value of userInteraction. - * - * @return the value of userInteraction - */ - public String getUserInteraction() { - return userInteraction; - } - - /** - * Get the value of scope. - * - * @return the value of scope - */ - public String getScope() { - return scope; - } - - /** - * Get the value of confidentialityImpact. - * - * @return the value of confidentialityImpact - */ - public String getConfidentialityImpact() { - return confidentialityImpact; - } - - /** - * Get the value of integrityImpact. - * - * @return the value of integrityImpact - */ - public String getIntegrityImpact() { - return integrityImpact; - } - - /** - * Get the value of availabilityImpact. - * - * @return the value of availabilityImpact - */ - public String getAvailabilityImpact() { - return availabilityImpact; - } - - /** - * Get the value of baseScore. - * - * @return the value of baseScore - */ - public float getBaseScore() { - return baseScore; - } - - /** - * Get the value of baseSeverity. - * - * @return the value of baseSeverity - */ - public String getBaseSeverity() { - return baseSeverity; - } - - /** - * Get the value of version. - * - * @return the value of version - */ - public String getVersion() { - return version; - } - - /** - * Returns the exploitabilityScore for the vulnerability. - * - * @return the exploitabilityScore - */ - public Float getexploitabilityScore() { - return exploitabilityScore; - } - - /** - * Returns the impactScore for the vulnerability. - * - * @return the impactScore - */ - public Float getimpactScore() { - return impactScore; - } - - @Override - public String toString() { - return String.format("CVSS:%s/AV:%s/AC:%s/PR:%s/UI:%s/S:%s/C:%s/I:%s/A:%s", - version == null ? "" : version, - attackVector == null ? "" : attackVector.substring(0, 1), - attackComplexity == null ? "" : attackComplexity.substring(0, 1), - privilegesRequired == null ? "" : privilegesRequired.substring(0, 1), - userInteraction == null ? "" : userInteraction.substring(0, 1), - scope == null ? "" : scope.substring(0, 1), - confidentialityImpact == null ? "" : confidentialityImpact.substring(0, 1), - integrityImpact == null ? "" : integrityImpact.substring(0, 1), - availabilityImpact == null ? "" : availabilityImpact.substring(0, 1)); - } - -} diff --git a/core/src/main/java/org/owasp/dependencycheck/dependency/Dependency.java b/core/src/main/java/org/owasp/dependencycheck/dependency/Dependency.java index 92a1402ebd2..ad33bd8a585 100644 --- a/core/src/main/java/org/owasp/dependencycheck/dependency/Dependency.java +++ b/core/src/main/java/org/owasp/dependencycheck/dependency/Dependency.java @@ -625,7 +625,7 @@ public synchronized Set getVulnerabilities(boolean sorted) { if (sorted) { vulnerabilitySet = new TreeSet<>(vulnerabilities); } else { - vulnerabilitySet = vulnerabilities; + vulnerabilitySet = new HashSet<>(vulnerabilities); } return Collections.unmodifiableSet(vulnerabilitySet); } @@ -867,7 +867,7 @@ public synchronized void addAllProjectReferences(Set projectReferences) public synchronized void addRelatedDependency(Dependency dependency) { if (this == dependency) { LOGGER.warn("Attempted to add a circular reference - please post the log file to issue #172 here " - + "https://github.com/jeremylong/DependencyCheck/issues/172"); + + "https://github.com/dependency-check/DependencyCheck/issues/172"); LOGGER.debug("this: {}", this); LOGGER.debug("dependency: {}", dependency); } else if (NAME_COMPARATOR.compare(this, dependency) == 0) { diff --git a/core/src/main/java/org/owasp/dependencycheck/dependency/Evidence.java b/core/src/main/java/org/owasp/dependencycheck/dependency/Evidence.java index 82eb1ae1fbc..a726d613850 100644 --- a/core/src/main/java/org/owasp/dependencycheck/dependency/Evidence.java +++ b/core/src/main/java/org/owasp/dependencycheck/dependency/Evidence.java @@ -59,6 +59,11 @@ public class Evidence implements Serializable, Comparable { */ private Confidence confidence; + /** + * Whether the evidence originates from a hint. + */ + private boolean fromHint; + /** * Creates a new Evidence object. */ @@ -74,10 +79,24 @@ public Evidence() { * @param confidence the confidence of the evidence. */ public Evidence(String source, String name, String value, Confidence confidence) { + this(source, name, value, confidence, false); + } + + /** + * Creates a new Evidence objects. + * + * @param source the source of the evidence. + * @param name the name of the evidence. + * @param value the value of the evidence. + * @param confidence the confidence of the evidence. + * @param fromHint whether the evidence was introduced by a hint. + */ + public Evidence(String source, String name, String value, Confidence confidence, boolean fromHint) { this.source = source; this.name = name; this.value = value; this.confidence = confidence; + this.fromHint = fromHint; } /** @@ -152,6 +171,24 @@ public void setConfidence(Confidence confidence) { this.confidence = confidence; } + /** + * Get the value of fromHint. + * + * @return the value of fromHint + */ + public boolean isFromHint() { + return fromHint; + } + + /** + * Set the value of fromHint. + * + * @param fromHint new value of fromHint + */ + public void setFromHint(boolean fromHint) { + this.fromHint = fromHint; + } + /** * Implements the hashCode for Evidence. * @@ -187,6 +224,7 @@ public boolean equals(Object obj) { .append(this.name == null ? null : this.name.toLowerCase(), o.name == null ? null : o.name.toLowerCase()) .append(this.value == null ? null : this.value.toLowerCase(), o.value == null ? null : o.value.toLowerCase()) .append(this.confidence, o.getConfidence()) + .append(this.fromHint, o.isFromHint()) .build(); } @@ -196,7 +234,6 @@ public boolean equals(Object obj) { * @param o the evidence being compared * @return an integer indicating the ordering of the two objects */ - @SuppressWarnings("deprecation") @Override public int compareTo(@NotNull Evidence o) { return new CompareToBuilder() @@ -204,6 +241,7 @@ public int compareTo(@NotNull Evidence o) { .append(this.name == null ? null : this.name.toLowerCase(), o.name == null ? null : o.name.toLowerCase()) .append(this.value == null ? null : this.value.toLowerCase(), o.value == null ? null : o.value.toLowerCase()) .append(this.confidence, o.getConfidence()) + .append(this.fromHint, o.isFromHint()) .toComparison(); } @@ -214,6 +252,7 @@ public int compareTo(@NotNull Evidence o) { */ @Override public String toString() { - return "Evidence{" + "name=" + name + ", source=" + source + ", value=" + value + ", confidence=" + confidence + '}'; + return "Evidence{" + "name=" + name + ", source=" + source + ", value=" + value + ", confidence=" + confidence + + ", fromHint=" + fromHint + '}'; } } diff --git a/core/src/main/java/org/owasp/dependencycheck/dependency/Vulnerability.java b/core/src/main/java/org/owasp/dependencycheck/dependency/Vulnerability.java index c9e1c8a71fc..395dd3d38bd 100644 --- a/core/src/main/java/org/owasp/dependencycheck/dependency/Vulnerability.java +++ b/core/src/main/java/org/owasp/dependencycheck/dependency/Vulnerability.java @@ -17,12 +17,15 @@ */ package org.owasp.dependencycheck.dependency; +import io.github.jeremylong.openvulnerability.client.nvd.CvssV2; +import io.github.jeremylong.openvulnerability.client.nvd.CvssV3; +import io.github.jeremylong.openvulnerability.client.nvd.CvssV4; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import javax.annotation.concurrent.NotThreadSafe; import org.apache.commons.lang3.builder.CompareToBuilder; @@ -89,11 +92,20 @@ public enum Source { /** * References for this vulnerability. */ - private final Set references = Collections.synchronizedSet(new HashSet<>()); + private final Set references = ConcurrentHashMap.newKeySet(); /** * A set of vulnerable software. */ - private final Set vulnerableSoftware = new HashSet<>(); + private final Set vulnerableSoftware = ConcurrentHashMap.newKeySet(); + /** + * Immutable views for getters. + */ + private final Set referencesView = Collections.unmodifiableSet(references); + /** + * Immutable views for getters. + */ + private final Set vulnerableSoftwareView = Collections.unmodifiableSet(vulnerableSoftware); + /** * The CWE(s) for the vulnerability. */ @@ -115,6 +127,11 @@ public enum Source { */ private CvssV3 cvssV3; + /** + * The CVSS V4 scoring information. + */ + private CvssV4 cvssV4; + /** * The Vulnerable Software that caused this vulnerability to be flagged. */ @@ -188,7 +205,7 @@ public void setDescription(String description) { * @return the value of references */ public Set getReferences() { - return references; + return referencesView; } /** @@ -247,6 +264,7 @@ public void addReference(String referenceSource, String referenceName, String re public void setKnownExploitedVulnerability(org.owasp.dependencycheck.data.knownexploited.json.Vulnerability kev) { this.knownExploitedVulnerability = kev; } + /** * Get the value of knownExploitedVulnerability. * @@ -255,13 +273,14 @@ public void setKnownExploitedVulnerability(org.owasp.dependencycheck.data.knowne public org.owasp.dependencycheck.data.knownexploited.json.Vulnerability getKnownExploitedVulnerability() { return knownExploitedVulnerability; } + /** * Get the value of vulnerableSoftware. * * @return the value of vulnerableSoftware */ public Set getVulnerableSoftware() { - return vulnerableSoftware; + return vulnerableSoftwareView; } /** @@ -273,13 +292,20 @@ public Set getVulnerableSoftware() { */ @SuppressWarnings("unchecked") public List getVulnerableSoftware(boolean sorted) { - synchronized (vulnerableSoftware) { - final List sortedVulnerableSoftware = new ArrayList<>(this.vulnerableSoftware); - if (sorted) { - Collections.sort(sortedVulnerableSoftware); - } - return sortedVulnerableSoftware; + final List sortedVulnerableSoftware = new ArrayList<>(this.vulnerableSoftware); + if (sorted) { + Collections.sort(sortedVulnerableSoftware); } + return sortedVulnerableSoftware; + } + + /** + * Removes the specified vulnerableSoftware from the collection. + * + * @param vulnerableSoftware a collection of vulnerable software to be removed + */ + public void removeVulnerableSoftware(Set vulnerableSoftware) { + this.vulnerableSoftware.removeAll(vulnerableSoftware); } /** @@ -336,6 +362,24 @@ public void setCvssV3(CvssV3 cvssV3) { this.cvssV3 = cvssV3; } + /** + * Get the CVSS V3 scoring information. + * + * @return the CVSS V3 scoring information + */ + public CvssV4 getCvssV4() { + return cvssV4; + } + + /** + * Sets the CVSS V4 scoring information. + * + * @param cvssV4 the CVSS V4 scoring information + */ + public void setCvssV4(CvssV4 cvssV4) { + this.cvssV4 = cvssV4; + } + /** * Get the set of CWEs. * @@ -451,8 +495,7 @@ public String toString() { * on both sides. If any of the vulnerabilities does not have a CVSSv3 score * the sort order may be off, but it will be consistent. *
- * The ranking (high to low) of severity can be informally represented as - * {@code <CVSSv3 critical> >> <Unscored recognized critical> >> + * The ranking (high to low) of severity can be informally represented as {@code <CVSSv3 critical> >> <Unscored recognized critical> >> * <Unscored unrecognized (assumed Critical)> >> <Score-based comparison for high-or-lower scoring severities with * recognized unscored severities taking the lower bound of the comparable CVSSv3 range> * } @@ -481,7 +524,7 @@ public int compareTo(@NotNull Vulnerability o) { * be reported as the highest severity after sorting on descending severity. *
* For vulnerabilities not scored with a CVSS score we estimate a score from - * the severity text. For textual severities assumed or sementically + * the severity text. For textual severities assumed or semantically * confirmed to be of a critical nature we assign a value in between the * highest CVSSv2 HIGH and the lowest CVSSv3 CRITICAL severity level. * @@ -490,12 +533,15 @@ public int compareTo(@NotNull Vulnerability o) { * @return A float value that allows for best-effort sorting on * vulnerability severity */ - private float bestEffortSeverityLevelForSorting() { + private Double bestEffortSeverityLevelForSorting() { + if (this.cvssV4 != null) { + return SeverityUtil.sortAdjustedCVSSv3BaseScore(this.cvssV4.getCvssData().getBaseScore()); + } if (this.cvssV3 != null) { - return SeverityUtil.sortAdjustedCVSSv3BaseScore(this.cvssV3.getBaseScore()); + return SeverityUtil.sortAdjustedCVSSv3BaseScore(this.cvssV3.getCvssData().getBaseScore()); } if (this.cvssV2 != null) { - return this.cvssV2.getScore(); + return this.cvssV2.getCvssData().getBaseScore(); } return SeverityUtil.estimatedSortAdjustedCVSSv3(this.unscoredSeverity); } @@ -508,11 +554,14 @@ private float bestEffortSeverityLevelForSorting() { * unscored severities that critical is assumed. */ public String getHighestSeverityText() { + if (this.cvssV4 != null) { + return this.cvssV4.getCvssData().getBaseSeverity().value().toUpperCase(); + } if (this.cvssV3 != null) { - return this.cvssV3.getBaseSeverity().toUpperCase(); + return this.cvssV3.getCvssData().getBaseSeverity().value().toUpperCase(); } if (this.cvssV2 != null) { - return this.cvssV2.getSeverity().toUpperCase(); + return this.cvssV2.getCvssData().getBaseSeverity().toUpperCase(); } return SeverityUtil.unscoredToSeveritytext(this.unscoredSeverity).toUpperCase(); } diff --git a/core/src/main/java/org/owasp/dependencycheck/dependency/VulnerableSoftware.java b/core/src/main/java/org/owasp/dependencycheck/dependency/VulnerableSoftware.java index 5982c80450d..31763bf21e9 100644 --- a/core/src/main/java/org/owasp/dependencycheck/dependency/VulnerableSoftware.java +++ b/core/src/main/java/org/owasp/dependencycheck/dependency/VulnerableSoftware.java @@ -28,6 +28,7 @@ import org.apache.commons.lang3.builder.HashCodeBuilder; import org.jetbrains.annotations.NotNull; import org.owasp.dependencycheck.analyzer.exception.UnexpectedAnalysisException; +import org.owasp.dependencycheck.dependency.naming.CpeIdentifier; import org.owasp.dependencycheck.utils.DependencyVersion; import us.springett.parsers.cpe.Cpe; import us.springett.parsers.cpe.ICpe; @@ -123,16 +124,25 @@ public VulnerableSoftware(Part part, String vendor, String product, String versi } //CSON: ParameterNumber + /** + * Normalizes null and empty strings to null for consistent comparison. + * @param s the string to normalize + * @return null if s is null or empty, otherwise s + */ + private static String normalizeForComparison(String s) { + return (s == null || s.isEmpty()) ? null : s; + } + @Override - public int compareTo(@NotNull Object o) { + public int compareTo(@NotNull ICpe o) { if (o instanceof VulnerableSoftware) { final VulnerableSoftware other = (VulnerableSoftware) o; return new CompareToBuilder() .appendSuper(super.compareTo(other)) - .append(versionStartIncluding, other.versionStartIncluding) - .append(versionStartExcluding, other.versionStartExcluding) - .append(versionEndIncluding, other.versionEndIncluding) - .append(versionEndExcluding, other.versionEndExcluding) + .append(normalizeForComparison(versionStartIncluding), normalizeForComparison(other.versionStartIncluding)) + .append(normalizeForComparison(versionStartExcluding), normalizeForComparison(other.versionStartExcluding)) + .append(normalizeForComparison(versionEndIncluding), normalizeForComparison(other.versionEndIncluding)) + .append(normalizeForComparison(versionEndExcluding), normalizeForComparison(other.versionEndExcluding)) .append(this.vulnerable, other.vulnerable) .build(); } else if (o instanceof Cpe) { @@ -517,4 +527,8 @@ public String toString() { } return sb.toString(); } + + public String toNvdSearchUrl() { + return CpeIdentifier.nvdSearchUrlFor(this); + } } diff --git a/core/src/main/java/org/owasp/dependencycheck/dependency/naming/CpeIdentifier.java b/core/src/main/java/org/owasp/dependencycheck/dependency/naming/CpeIdentifier.java index 7ed914d87a5..0f6dc48006b 100644 --- a/core/src/main/java/org/owasp/dependencycheck/dependency/naming/CpeIdentifier.java +++ b/core/src/main/java/org/owasp/dependencycheck/dependency/naming/CpeIdentifier.java @@ -20,6 +20,7 @@ import org.apache.commons.lang3.builder.CompareToBuilder; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.apache.hc.core5.net.PercentCodec; import org.jetbrains.annotations.NotNull; import org.owasp.dependencycheck.dependency.Confidence; import us.springett.parsers.cpe.Cpe; @@ -27,6 +28,8 @@ import us.springett.parsers.cpe.exceptions.CpeValidationException; import us.springett.parsers.cpe.values.Part; +import static java.nio.charset.StandardCharsets.UTF_8; + /** * A CPE Identifier for a dependency object. * @@ -203,4 +206,41 @@ public int compareTo(@NotNull Identifier o) { .append(this.confidence, o.getConfidence()) .toComparison(); } + + /** + * Produces an NVD search URL for a given CPE to find all applicable vulnerabilities, including all populated parts + * of the given CPE. + *

+ * The opened link should be sorted in descending order (sortDirection=2) by publish date (sortOrder=3). + */ + public static String nvdSearchUrlFor(Cpe cpe) { + // Use PercentCodec to force `*` to be encoded for CPE strings inside the URL. Technically '*' is not a reserved + // character in the fragment of URLs, but not all browsers handle this consistently, so better to encode aggressively. + // URlEncoder does not distinguish between parts of URLs appropriately, as well as not forcing encoding of these. + return String.format("https://nvd.nist.gov/vuln/search#/nvd/home?sortOrder=3&sortDirection=2&cpeFilterMode=applicability&resultType=records&cpeName=%s", + PercentCodec.encode(cpe.toCpe23FS(), UTF_8)); + } + + /** + * Produces an NVD search URL for a given application vendor/product/version combination to find all applicable vulnerabilities. + *

+ * The opened link should be sorted in descending order (sortDirection=2) by publish date (sortOrder=3). + */ + public static String nvdSearchUrlFor(String vendor, String product, String version) throws CpeValidationException { + return nvdSearchUrlFor(new CpeBuilder().part(Part.APPLICATION).vendor(vendor).product(product).version(version).build()); + } + + /** + * Produces an NVD search URL for a given CPE to find all applicable vulnerabilities, including only the part, vendor, + * and product of the given CPE (if populated). Discards all other parts/discriminators of the CPE in the generated search. + *

+ * The opened link should be sorted in descending order (sortDirection=2) by publish date (sortOrder=3). + */ + public static String nvdProductSearchUrlFor(Cpe cpe) { + try { + return nvdSearchUrlFor(new CpeBuilder().part(cpe.getPart()).vendor(cpe.getVendor()).product(cpe.getProduct()).build()); + } catch (CpeValidationException e) { + throw new RuntimeException(e); + } + } } diff --git a/core/src/main/java/org/owasp/dependencycheck/processing/BundlerAuditProcessor.java b/core/src/main/java/org/owasp/dependencycheck/processing/BundlerAuditProcessor.java index 973a5711df4..eef7b5f62d1 100644 --- a/core/src/main/java/org/owasp/dependencycheck/processing/BundlerAuditProcessor.java +++ b/core/src/main/java/org/owasp/dependencycheck/processing/BundlerAuditProcessor.java @@ -20,27 +20,12 @@ import com.github.packageurl.MalformedPackageURLException; import com.github.packageurl.PackageURL; import com.github.packageurl.PackageURLBuilder; -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Map; -import org.apache.commons.io.FileUtils; +import io.github.jeremylong.openvulnerability.client.nvd.CvssV2; +import io.github.jeremylong.openvulnerability.client.nvd.CvssV2Data; import org.owasp.dependencycheck.Engine; -import static org.owasp.dependencycheck.analyzer.RubyBundleAuditAnalyzer.ADVISORY; -import static org.owasp.dependencycheck.analyzer.RubyBundleAuditAnalyzer.CRITICALITY; -import static org.owasp.dependencycheck.analyzer.RubyBundleAuditAnalyzer.CVE; -import static org.owasp.dependencycheck.analyzer.RubyBundleAuditAnalyzer.DEPENDENCY_ECOSYSTEM; -import static org.owasp.dependencycheck.analyzer.RubyBundleAuditAnalyzer.NAME; -import static org.owasp.dependencycheck.analyzer.RubyBundleAuditAnalyzer.VERSION; import org.owasp.dependencycheck.data.nvdcve.CveDB; import org.owasp.dependencycheck.data.nvdcve.DatabaseException; import org.owasp.dependencycheck.dependency.Confidence; -import org.owasp.dependencycheck.dependency.CvssV2; import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.EvidenceType; import org.owasp.dependencycheck.dependency.Reference; @@ -56,6 +41,22 @@ import us.springett.parsers.cpe.exceptions.CpeValidationException; import us.springett.parsers.cpe.values.Part; +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +import static org.owasp.dependencycheck.analyzer.RubyBundleAuditAnalyzer.ADVISORY; +import static org.owasp.dependencycheck.analyzer.RubyBundleAuditAnalyzer.CRITICALITY; +import static org.owasp.dependencycheck.analyzer.RubyBundleAuditAnalyzer.CVE; +import static org.owasp.dependencycheck.analyzer.RubyBundleAuditAnalyzer.DEPENDENCY_ECOSYSTEM; +import static org.owasp.dependencycheck.analyzer.RubyBundleAuditAnalyzer.NAME; +import static org.owasp.dependencycheck.analyzer.RubyBundleAuditAnalyzer.VERSION; + /** * Processor for the output of bundler-audit. * @@ -124,8 +125,7 @@ public void run() { final Map map = new HashMap<>(); boolean appendToDescription = false; - try (InputStreamReader ir = new InputStreamReader(getInput(), StandardCharsets.UTF_8); - BufferedReader br = new BufferedReader(ir)) { + try (InputStreamReader ir = new InputStreamReader(getInput(), StandardCharsets.UTF_8); BufferedReader br = new BufferedReader(ir)) { String nextLine; while ((nextLine = br.readLine()) != null) { @@ -133,7 +133,7 @@ public void run() { appendToDescription = false; gem = nextLine.substring(NAME.length()); if (!map.containsKey(gem)) { - map.put(gem, createDependencyForGem(engine, parentName, fileName, filePath, gem)); + map.put(gem, createDependencyForGem(engine, gemDependency.getActualFile(), parentName, fileName, filePath, gem)); } dependency = map.get(gem); LOGGER.debug("bundle-audit ({}): {}", parentName, nextLine); @@ -201,7 +201,7 @@ private void addReferenceToVulnerability(String parentName, Vulnerability vulner ref.setName(vulnerability.getName()); ref.setSource("bundle-audit"); ref.setUrl(url); - vulnerability.getReferences().add(ref); + vulnerability.addReference(ref); } LOGGER.debug("bundle-audit ({}): {}", parentName, nextLine); } @@ -216,7 +216,7 @@ private void addReferenceToVulnerability(String parentName, Vulnerability vulner private void addCriticalityToVulnerability(String parentName, Vulnerability vulnerability, String nextLine) { if (null != vulnerability) { final String criticality = nextLine.substring(CRITICALITY.length()).trim(); - float score = -1.0f; + Double score = -1.0; Vulnerability v = null; final CveDB cvedb = engine.getDatabase(); if (cvedb != null) { @@ -235,13 +235,18 @@ private void addCriticalityToVulnerability(String parentName, Vulnerability vuln } } else { if ("High".equalsIgnoreCase(criticality)) { - score = 8.5f; + score = 8.5; } else if ("Medium".equalsIgnoreCase(criticality)) { - score = 5.5f; + score = 5.5; } else if ("Low".equalsIgnoreCase(criticality)) { - score = 2.0f; + score = 2.0; } - vulnerability.setCvssV2(new CvssV2(score, "-", "-", "-", "-", "-", "-", criticality)); + LOGGER.debug("bundle-audit vulnerability missing CVSS data: {}", vulnerability.getName()); + final CvssV2Data cvssData = new CvssV2Data(CvssV2Data.Version._2_0, null, null, null, null, null, null, null, score, criticality.toUpperCase(), + null, null, null, null, null, null, null, null, null, null); + final CvssV2 cvssV2 = new CvssV2(null, null, cvssData, criticality.toUpperCase(), null, null, null, null, null, null, null); + vulnerability.setCvssV2(cvssV2); + vulnerability.setUnscoredSeverity(null); } } LOGGER.debug("bundle-audit ({}): {}", parentName, nextLine); @@ -289,7 +294,7 @@ private Vulnerability createVulnerability(String parentName, Dependency dependen .version(version).build(); vulnerability.addVulnerableSoftware(vs); vulnerability.setMatchedVulnerableSoftware(vs); - vulnerability.setCvssV2(new CvssV2(-1, "-", "-", "-", "-", "-", "-", "unknown")); + vulnerability.setUnscoredSeverity("UNKNOWN"); } LOGGER.debug("bundle-audit ({}): {}", parentName, nextLine); return vulnerability; @@ -299,6 +304,7 @@ private Vulnerability createVulnerability(String parentName, Dependency dependen * Creates the dependency based off of the gem. * * @param engine the engine used for scanning + * @param gemFile the gem file * @param parentName the gem parent * @param fileName the file name * @param filePath the file path @@ -306,19 +312,14 @@ private Vulnerability createVulnerability(String parentName, Dependency dependen * @return the dependency to add * @throws IOException thrown if a temporary gem file could not be written */ - private Dependency createDependencyForGem(Engine engine, String parentName, String fileName, String filePath, String gem) throws IOException { - final File gemFile; - try { - gemFile = File.createTempFile(gem, "_Gemfile.lock", engine.getSettings().getTempDirectory()); - } catch (IOException ioe) { - throw new IOException("Unable to create temporary gem file"); - } + private Dependency createDependencyForGem(Engine engine, File gemFile, String parentName, String fileName, + String filePath, String gem) throws IOException { final String displayFileName = String.format("%s%c%s:%s", parentName, File.separatorChar, fileName, gem); - - FileUtils.write(gemFile, displayFileName, Charset.defaultCharset()); // unique contents to avoid dependency bundling - final Dependency dependency = new Dependency(gemFile); + final Dependency dependency = new Dependency(gemFile, true); + dependency.setSha1sum(Checksum.getSHA1Checksum(displayFileName)); dependency.setEcosystem(DEPENDENCY_ECOSYSTEM); dependency.addEvidence(EvidenceType.PRODUCT, "bundler-audit", "Name", gem, Confidence.HIGHEST); + dependency.addEvidence(EvidenceType.VENDOR, "bundler-audit", "Name", gem, Confidence.HIGH); //TODO add package URL - note, this may require parsing the gemfile.lock and getting the version for each entry dependency.setDisplayFileName(displayFileName); diff --git a/core/src/main/java/org/owasp/dependencycheck/processing/MixAuditProcessor.java b/core/src/main/java/org/owasp/dependencycheck/processing/MixAuditProcessor.java index c4661c36894..342a529d7d0 100644 --- a/core/src/main/java/org/owasp/dependencycheck/processing/MixAuditProcessor.java +++ b/core/src/main/java/org/owasp/dependencycheck/processing/MixAuditProcessor.java @@ -31,7 +31,7 @@ import org.owasp.dependencycheck.data.elixir.MixAuditJsonParser; import org.owasp.dependencycheck.data.elixir.MixAuditResult; import org.owasp.dependencycheck.dependency.Confidence; -import org.owasp.dependencycheck.dependency.CvssV2; + import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.dependency.EvidenceType; import org.owasp.dependencycheck.dependency.Vulnerability; @@ -166,6 +166,7 @@ private Dependency createDependency(Dependency parentDependency, String packageN dep.addEvidence(EvidenceType.VERSION, "mix_audit", "Version", version, Confidence.HIGHEST); dep.addEvidence(EvidenceType.PRODUCT, "mix_audit", "Package", packageName, Confidence.HIGHEST); + dep.addEvidence(EvidenceType.VENDOR, "mix_audit", "Package", packageName, Confidence.HIGH); try { final PackageURL purl = PackageURLBuilder.aPackageURL().withType("hex").withName(packageName) @@ -197,7 +198,7 @@ private Vulnerability createVulnerability(MixAuditResult result) throws CpeValid vulnerability.addVulnerableSoftware(vs); vulnerability.setMatchedVulnerableSoftware(vs); - vulnerability.setCvssV2(new CvssV2(-1, "-", "-", "-", "-", "-", "-", "unknown")); + vulnerability.setUnscoredSeverity("UNKOWN"); vulnerability.setDescription(result.getDescription()); vulnerability.setName(result.getCve()); diff --git a/core/src/main/java/org/owasp/dependencycheck/reporting/ReportGenerator.java b/core/src/main/java/org/owasp/dependencycheck/reporting/ReportGenerator.java index 041c3c07367..1292954a2b8 100644 --- a/core/src/main/java/org/owasp/dependencycheck/reporting/ReportGenerator.java +++ b/core/src/main/java/org/owasp/dependencycheck/reporting/ReportGenerator.java @@ -17,41 +17,16 @@ */ package org.owasp.dependencycheck.reporting; -import java.time.ZonedDateTime; -import java.util.List; - +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.UnsupportedEncodingException; -import java.nio.charset.StandardCharsets; -import java.time.format.DateTimeFormatter; -import javax.annotation.concurrent.NotThreadSafe; -import javax.xml.XMLConstants; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerConfigurationException; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.sax.SAXSource; -import javax.xml.transform.sax.SAXTransformerFactory; -import javax.xml.transform.stream.StreamResult; - import org.apache.commons.io.FilenameUtils; import org.apache.commons.text.WordUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.context.Context; - import org.owasp.dependencycheck.analyzer.Analyzer; import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties; import org.owasp.dependencycheck.dependency.Dependency; @@ -68,9 +43,32 @@ import org.xml.sax.SAXException; import org.xml.sax.XMLReader; -import com.fasterxml.jackson.core.JsonFactory; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.JsonParser; +import javax.annotation.concurrent.NotThreadSafe; +import javax.xml.XMLConstants; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.sax.SAXTransformerFactory; +import javax.xml.transform.stream.StreamResult; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; /** * The ReportGenerator is used to, as the name implies, generate reports. @@ -118,13 +116,21 @@ public enum Format { */ SARIF, /** - * Generate HTML report without script or non-vulnerable libraries for Jenkins. + * Generate HTML report without script or non-vulnerable libraries for + * Jenkins. */ JENKINS, /** * Generate JUNIT report. */ - JUNIT + JUNIT, + /** + * Generate Report in GitLab dependency check format. + * + * @see format definition + * @see additional explanations on the format + */ + GITLAB } /** @@ -142,6 +148,7 @@ public enum Format { //CSOFF: ParameterNumber //CSOFF: LineLength + /** * Constructs a new ReportGenerator. * @@ -156,7 +163,7 @@ public enum Format { */ @Deprecated public ReportGenerator(String applicationName, List dependencies, List analyzers, - DatabaseProperties properties, Settings settings) { + DatabaseProperties properties, Settings settings) { this(applicationName, dependencies, analyzers, properties, settings, null); } @@ -174,7 +181,7 @@ public ReportGenerator(String applicationName, List dependencies, Li * @since 5.1.0 */ public ReportGenerator(String applicationName, List dependencies, List analyzers, - DatabaseProperties properties, Settings settings, ExceptionCollection exceptions) { + DatabaseProperties properties, Settings settings, ExceptionCollection exceptions) { this(applicationName, null, null, null, dependencies, analyzers, properties, settings, exceptions); } @@ -195,8 +202,8 @@ public ReportGenerator(String applicationName, List dependencies, Li */ @Deprecated public ReportGenerator(String applicationName, String groupID, String artifactID, String version, - List dependencies, List analyzers, DatabaseProperties properties, - Settings settings) { + List dependencies, List analyzers, DatabaseProperties properties, + Settings settings) { this(applicationName, groupID, artifactID, version, dependencies, analyzers, properties, settings, null); } @@ -217,8 +224,8 @@ public ReportGenerator(String applicationName, String groupID, String artifactID * @since 5.1.0 */ public ReportGenerator(String applicationName, String groupID, String artifactID, String version, - List dependencies, List analyzers, DatabaseProperties properties, - Settings settings, ExceptionCollection exceptions) { + List dependencies, List analyzers, DatabaseProperties properties, + Settings settings, ExceptionCollection exceptions) { this.settings = settings; velocityEngine = createVelocityEngine(); velocityEngine.init(); @@ -244,13 +251,14 @@ public ReportGenerator(String applicationName, String groupID, String artifactID */ @SuppressWarnings("JavaTimeDefaultTimeZone") private VelocityContext createContext(String applicationName, List dependencies, - List analyzers, DatabaseProperties properties, String groupID, - String artifactID, String version, ExceptionCollection exceptions) { + List analyzers, DatabaseProperties properties, String groupID, + String artifactID, String version, ExceptionCollection exceptions) { final ZonedDateTime dt = ZonedDateTime.now(); final String scanDate = DateTimeFormatter.RFC_1123_DATE_TIME.format(dt); final String scanDateXML = DateTimeFormatter.ISO_INSTANT.format(dt); final String scanDateJunit = DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(dt); + final String scanDateGitLab = DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(dt.withNano(0)); final VelocityContext ctxt = new VelocityContext(); ctxt.put("applicationName", applicationName); @@ -261,10 +269,12 @@ private VelocityContext createContext(String applicationName, List d ctxt.put("scanDate", scanDate); ctxt.put("scanDateXML", scanDateXML); ctxt.put("scanDateJunit", scanDateJunit); + ctxt.put("scanDateGitLab", scanDateGitLab); ctxt.put("enc", new EscapeTool()); ctxt.put("rpt", new ReportTool()); ctxt.put("checksum", Checksum.class); ctxt.put("WordUtils", new WordUtils()); + ctxt.put("StringUtils", new StringUtils()); ctxt.put("VENDOR", EvidenceType.VENDOR); ctxt.put("PRODUCT", EvidenceType.PRODUCT); ctxt.put("VERSION", EvidenceType.VERSION); @@ -300,9 +310,9 @@ private VelocityEngine createVelocityEngine() { * Writes the dependency-check report to the given output location. * * @param outputLocation the path where the reports should be written - * @param format the format the report should be written in (XML, HTML, - * JSON, CSV, ALL) or even the path to a custom velocity template (either - * fully qualified or the template name on the class path). + * @param format the format the report should be written in (a valid member + * of {@link Format}) or even the path to a custom velocity template + * (either fully qualified or the template name on the class path). * @throws ReportException is thrown if there is an error creating out the * reports */ @@ -319,9 +329,10 @@ public void write(String outputLocation, String format) throws ReportException { } else { File out = getReportFile(outputLocation, null); if (out.isDirectory()) { - out = new File(out, FilenameUtils.getBaseName(format)); - LOGGER.warn("Writing non-standard VSL output to a directory using template name as file name."); + out = new File(out, FilenameUtils.getBaseName(format)); + LOGGER.warn("Writing non-standard VSL output to a directory using template name as file name."); } + LOGGER.info("Writing custom report to: {}", out.getAbsolutePath()); processTemplate(format, out); } @@ -331,7 +342,8 @@ public void write(String outputLocation, String format) throws ReportException { * Writes the dependency-check report(s). * * @param outputLocation the path where the reports should be written - * @param format the format the report should be written in (XML, HTML, ALL) + * @param format the format the report should be written in (see + * {@link Format}) * @throws ReportException is thrown if there is an error creating out the * reports */ @@ -345,6 +357,7 @@ public void write(String outputLocation, Format format) throws ReportException { } else { final File out = getReportFile(outputLocation, format); final String templateName = format.toString().toLowerCase() + "Report"; + LOGGER.info("Writing {} report to: {}", format, out.getAbsolutePath()); processTemplate(templateName, out); if (settings.getBoolean(Settings.KEYS.PRETTY_PRINT, false)) { if (format == Format.JSON || format == Format.SARIF) { @@ -394,6 +407,9 @@ public static File getReportFile(String outputLocation, Format format) { if (format == Format.SARIF && !pathToCheck.endsWith(".sarif")) { return new File(outFile, "dependency-check-report.sarif"); } + if (format == Format.GITLAB && !pathToCheck.endsWith(".json")) { + return new File(outFile, "dependency-check-gitlab.json"); + } return outFile; } @@ -410,7 +426,6 @@ public static File getReportFile(String outputLocation, Format format) { @SuppressFBWarnings(justification = "try with resources will clean up the output stream", value = {"OBL_UNSATISFIED_OBLIGATION"}) protected void processTemplate(String template, File file) throws ReportException { ensureParentDirectoryExists(file); - LOGGER.info("Writing report to: " + file.getAbsolutePath()); try (OutputStream output = new FileOutputStream(file)) { processTemplate(template, output); } catch (IOException ex) { @@ -453,7 +468,7 @@ protected void processTemplate(String templateName, OutputStream outputStream) t } try (InputStreamReader reader = new InputStreamReader(input, StandardCharsets.UTF_8); - OutputStreamWriter writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)) { + OutputStreamWriter writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)) { if (!velocityEngine.evaluate(context, writer, logTag, reader)) { throw new ReportException("Failed to convert the template into html."); } @@ -526,7 +541,7 @@ private void pretifyXml(String path) throws ReportException { if (out.isFile() && in.isFile() && in.delete()) { try { Thread.sleep(1000); - org.apache.commons.io.FileUtils.moveFile(out, in); + Files.move(out.toPath(), in.toPath()); } catch (IOException ex) { LOGGER.error("Unable to generate pretty report, caused by: {}", ex.getMessage()); } catch (InterruptedException ex) { @@ -550,8 +565,7 @@ private void pretifyJson(String pathToJson) throws ReportException { final JsonFactory factory = new JsonFactory(); - try (InputStream is = new FileInputStream(in); - OutputStream os = new FileOutputStream(out)) { + try (InputStream is = new FileInputStream(in); OutputStream os = new FileOutputStream(out)) { final JsonParser parser = factory.createParser(is); final JsonGenerator generator = factory.createGenerator(os); @@ -569,7 +583,7 @@ private void pretifyJson(String pathToJson) throws ReportException { if (out.isFile() && in.isFile() && in.delete()) { try { Thread.sleep(1000); - org.apache.commons.io.FileUtils.moveFile(out, in); + Files.move(out.toPath(), in.toPath()); } catch (IOException ex) { LOGGER.error("Unable to generate pretty report, caused by: {}", ex.getMessage()); } catch (InterruptedException ex) { diff --git a/core/src/main/java/org/owasp/dependencycheck/reporting/ReportTool.java b/core/src/main/java/org/owasp/dependencycheck/reporting/ReportTool.java index cc553298e91..32615f7e347 100644 --- a/core/src/main/java/org/owasp/dependencycheck/reporting/ReportTool.java +++ b/core/src/main/java/org/owasp/dependencycheck/reporting/ReportTool.java @@ -79,7 +79,7 @@ public String identifierToSuppressionId(Identifier id) { * @param severity the text representation of a score * @return the estimated score */ - public float estimateSeverity(String severity) { + public Double estimateSeverity(String severity) { return SeverityUtil.estimateCvssV2(severity); } @@ -99,7 +99,8 @@ public Collection convertToSarifRules(List dependencies) buildDescription(v.getDescription(), v.getKnownExploitedVulnerability()), v.getSource().name(), v.getCvssV2(), - v.getCvssV3()); + v.getCvssV3(), + v.getCvssV4()); rules.put(v.getName(), r); } } @@ -110,33 +111,40 @@ public Collection convertToSarifRules(List dependencies) private String determineScore(Vulnerability vuln) { if (vuln.getUnscoredSeverity() != null) { if ("0.0".equals(vuln.getUnscoredSeverity())) { - return "Unknown"; + return "unknown"; } else { return normalizeSeverity(vuln.getUnscoredSeverity().toLowerCase()); } - } else if (vuln.getCvssV3() != null && vuln.getCvssV3().getBaseSeverity() != null) { - return normalizeSeverity(vuln.getCvssV3().getBaseSeverity().toLowerCase()); - } else if (vuln.getCvssV2() != null && vuln.getCvssV2().getSeverity() != null) { - return normalizeSeverity(vuln.getCvssV2().getSeverity()); + } else if (vuln.getCvssV4() != null && vuln.getCvssV4().getCvssData().getBaseSeverity() != null) { + return normalizeSeverity(vuln.getCvssV4().getCvssData().getBaseSeverity().value().toLowerCase()); + } else if (vuln.getCvssV3() != null && vuln.getCvssV3().getCvssData().getBaseSeverity() != null) { + return normalizeSeverity(vuln.getCvssV3().getCvssData().getBaseSeverity().value().toLowerCase()); + } else if (vuln.getCvssV2() != null && vuln.getCvssV2().getCvssData().getBaseSeverity() != null) { + return normalizeSeverity(vuln.getCvssV2().getCvssData().getBaseSeverity()); } - return "Unknown"; + return "unknown"; } - private String normalizeSeverity(String sev) { - switch (sev) { + /** + * Map severity names from various sources to a standard set of severity names. + * @param sev the severity name + * @return the standardized severity name (critical, high, medium, low, unknown) + */ + public String normalizeSeverity(String sev) { + switch (sev.toLowerCase()) { case "critical": - return "Critical"; + return "critical"; case "high": - return "High"; + return "high"; case "medium": case "moderate": - return "Medium"; + return "medium"; case "low": case "informational": case "info": - return "Low"; + return "low"; default: - return "Unknown"; + return "unknown"; } } diff --git a/core/src/main/java/org/owasp/dependencycheck/reporting/SarifRule.java b/core/src/main/java/org/owasp/dependencycheck/reporting/SarifRule.java index 781f5158ce9..50ddbbb7eb3 100644 --- a/core/src/main/java/org/owasp/dependencycheck/reporting/SarifRule.java +++ b/core/src/main/java/org/owasp/dependencycheck/reporting/SarifRule.java @@ -17,8 +17,9 @@ */ package org.owasp.dependencycheck.reporting; -import org.owasp.dependencycheck.dependency.CvssV2; -import org.owasp.dependencycheck.dependency.CvssV3; +import io.github.jeremylong.openvulnerability.client.nvd.CvssV2; +import io.github.jeremylong.openvulnerability.client.nvd.CvssV3; +import io.github.jeremylong.openvulnerability.client.nvd.CvssV4; /** * @@ -61,7 +62,7 @@ public class SarifRule { /** * CVSS V2 field. */ - private String cvssv2ConfidentialImpact; + private String cvssv2ConfidentialityImpact; /** * CVSS V2 field. */ @@ -138,6 +139,14 @@ public class SarifRule { * CVSS V3 field. */ private String cvssv3Version; + /** + * CVSS V4 field. + */ + private String cvssv4BaseScore; + /** + * CVSS V4 Vector. + */ + private String cvssv4Vector; /** * The source of the rule. */ @@ -152,49 +161,92 @@ public class SarifRule { * @param source the source * @param cvssV2 the CVSS v2 score * @param cvssV3 the CVSS v3 score + * @param cvssV4 the CVSS v4 score */ public SarifRule(String name, String shortDescription, String fullDescription, - String source, CvssV2 cvssV2, CvssV3 cvssV3) { + String source, CvssV2 cvssV2, CvssV3 cvssV3, CvssV4 cvssV4) { this.id = name; this.name = name; this.shortDescription = shortDescription; this.fullDescription = fullDescription; this.source = source; if (cvssV2 != null) { - this.cvssv2Score = Float.toString(cvssV2.getScore()); - this.cvssv2AccessVector = cvssV2.getAccessVector(); - this.cvssv2AccessComplexity = cvssV2.getAccessComplexity(); - this.cvssv2Authentication = cvssV2.getAuthentication(); - this.cvssv2ConfidentialImpact = cvssV2.getConfidentialityImpact(); - this.cvssv2IntegrityImpact = cvssV2.getIntegrityImpact(); - this.cvssv2AvailabilityImpact = cvssV2.getAvailabilityImpact(); - this.cvssv2Severity = cvssV2.getSeverity(); - this.cvssv2Version = cvssV2.getVersion(); + if (cvssV2.getCvssData().getBaseScore() != null) { + this.cvssv2Score = cvssV2.getCvssData().getBaseScore().toString(); + } + if (cvssV2.getCvssData().getAccessVector() != null) { + this.cvssv2AccessVector = cvssV2.getCvssData().getAccessVector().name(); + } + if (cvssV2.getCvssData().getAccessComplexity() != null) { + this.cvssv2AccessComplexity = cvssV2.getCvssData().getAccessComplexity().name(); + } + if (cvssV2.getCvssData().getAuthentication() != null) { + this.cvssv2Authentication = cvssV2.getCvssData().getAuthentication().name(); + } + if (cvssV2.getCvssData().getConfidentialityImpact() != null) { + this.cvssv2ConfidentialityImpact = cvssV2.getCvssData().getConfidentialityImpact().name(); + } + if (cvssV2.getCvssData().getIntegrityImpact() != null) { + this.cvssv2IntegrityImpact = cvssV2.getCvssData().getIntegrityImpact().name(); + } + if (cvssV2.getCvssData().getAvailabilityImpact() != null) { + this.cvssv2AvailabilityImpact = cvssV2.getCvssData().getAvailabilityImpact().name(); + } + this.cvssv2Severity = cvssV2.getCvssData().getBaseSeverity(); + if (cvssV2.getCvssData().getVersion() != null) { + this.cvssv2Version = cvssV2.getCvssData().getVersion().name(); + } if (cvssV2.getExploitabilityScore() != null) { - this.cvssv2ExploitabilityScore = Float.toString(cvssV2.getExploitabilityScore()); + this.cvssv2ExploitabilityScore = cvssV2.getExploitabilityScore().toString(); } if (cvssV2.getImpactScore() != null) { - this.cvssv2ImpactScore = Float.toString(cvssV2.getImpactScore()); + this.cvssv2ImpactScore = cvssV2.getImpactScore().toString(); } } if (cvssV3 != null) { - this.cvssv3BaseScore = Float.toString(cvssV3.getBaseScore()); - this.cvssv3AttackVector = cvssV3.getAttackVector(); - this.cvssv3AttackComplexity = cvssV3.getAttackComplexity(); - this.cvssv3PrivilegesRequired = cvssV3.getPrivilegesRequired(); - this.cvssv3UserInteraction = cvssV3.getUserInteraction(); - this.cvssv3Scope = cvssV3.getScope(); - this.cvssv3ConfidentialityImpact = cvssV3.getConfidentialityImpact(); - this.cvssv3IntegrityImpact = cvssV3.getIntegrityImpact(); - this.cvssv3AvailabilityImpact = cvssV3.getAvailabilityImpact(); - this.cvssv3BaseSeverity = cvssV3.getBaseSeverity(); - if (cvssV3.getexploitabilityScore() != null) { - this.cvssv3ExploitabilityScore = Float.toString(cvssV3.getexploitabilityScore()); + if (cvssV3.getCvssData().getBaseScore() != null) { + this.cvssv3BaseScore = cvssV3.getCvssData().getBaseScore().toString(); + } + if (cvssV3.getCvssData().getAttackVector() != null) { + this.cvssv3AttackVector = cvssV3.getCvssData().getAttackVector().name(); + } + if (cvssV3.getCvssData().getAttackComplexity() != null) { + this.cvssv3AttackComplexity = cvssV3.getCvssData().getAttackComplexity().name(); + } + if (cvssV3.getCvssData().getPrivilegesRequired() != null) { + this.cvssv3PrivilegesRequired = cvssV3.getCvssData().getPrivilegesRequired().name(); + } + if (cvssV3.getCvssData().getUserInteraction() != null) { + this.cvssv3UserInteraction = cvssV3.getCvssData().getUserInteraction().name(); + } + if (cvssV3.getCvssData().getScope() != null) { + this.cvssv3Scope = cvssV3.getCvssData().getScope().name(); + } + if (cvssV3.getCvssData().getConfidentialityImpact() != null) { + this.cvssv3ConfidentialityImpact = cvssV3.getCvssData().getConfidentialityImpact().name(); + } + if (cvssV3.getCvssData().getIntegrityImpact() != null) { + this.cvssv3IntegrityImpact = cvssV3.getCvssData().getIntegrityImpact().name(); + } + if (cvssV3.getCvssData().getAvailabilityImpact() != null) { + this.cvssv3AvailabilityImpact = cvssV3.getCvssData().getAvailabilityImpact().name(); } - if (cvssV3.getimpactScore() != null) { - this.cvssv3ImpactScore = Float.toString(cvssV3.getimpactScore()); + if (cvssV3.getCvssData().getBaseSeverity() != null) { + this.cvssv3BaseSeverity = cvssV3.getCvssData().getBaseSeverity().name(); } - this.cvssv3Version = cvssV3.getVersion(); + if (cvssV3.getExploitabilityScore() != null) { + this.cvssv3ExploitabilityScore = cvssV3.getExploitabilityScore().toString(); + } + if (cvssV3.getImpactScore() != null) { + this.cvssv3ImpactScore = cvssV3.getImpactScore().toString(); + } + this.cvssv3Version = cvssV3.getCvssData().getVersion().name(); + } + if (cvssV4 != null && cvssV4.getCvssData() != null) { + if (cvssV4.getCvssData().getBaseScore() != null) { + this.cvssv4BaseScore = cvssV4.getCvssData().getBaseScore().toString(); + } + this.cvssv4Vector = cvssV4.toString(); } } @@ -560,21 +612,21 @@ public void setCvssv2IntegrityImpact(String cvssv2IntegrityImpact) { } /** - * Get the value of CVSS2 Confidential Impact. + * Get the value of CVSS2 Confidentiality Impact. * - * @return the value of CVSS2 Confidential Impact + * @return the value of CVSS2 Confidentiality Impact */ - public String getCvssv2ConfidentialImpact() { - return cvssv2ConfidentialImpact; + public String getCvssv2ConfidentialityImpact() { + return cvssv2ConfidentialityImpact; } /** - * Set the value of CVSS2 Confidential Impact. + * Set the value of CVSS2 Confidentiality Impact. * - * @param cvssv2ConfidentialImpact new value of CVSS2 Confidential Impact + * @param cvssv2ConfidentialityImpact new value of CVSS2 Confidentiality Impact */ - public void setCvssv2ConfidentialImpact(String cvssv2ConfidentialImpact) { - this.cvssv2ConfidentialImpact = cvssv2ConfidentialImpact; + public void setCvssv2ConfidentialityImpact(String cvssv2ConfidentialityImpact) { + this.cvssv2ConfidentialityImpact = cvssv2ConfidentialityImpact; } /** @@ -721,4 +773,36 @@ public void setId(String id) { this.id = id; } + /** + * Get the value of CVSS4 Base Score. + * + * @return the value of CVSS4 Base Score + */ + public String getCvssv4BaseScore() { + return cvssv4BaseScore; + } + + /** + * Set the value of CVSS4 Base Score. + * @param cvssv4BaseScore new value of CVSS4 Base Score + */ + public void setCvssv4BaseScore(String cvssv4BaseScore) { + this.cvssv4BaseScore = cvssv4BaseScore; + } + + /** + * Get the Cvssv4 Vector. + * @return the Cvssv4 Vector + */ + public String getCvssv4Vector() { + return cvssv4Vector; + } + + /** + * Set the Cvssv4 Vector. + * @param cvssv4Vector new value of Cvssv4 Vector + */ + public void setCvssv4Vector(String cvssv4Vector) { + this.cvssv4Vector = cvssv4Vector; + } } diff --git a/core/src/main/java/org/owasp/dependencycheck/utils/CvssUtil.java b/core/src/main/java/org/owasp/dependencycheck/utils/CvssUtil.java new file mode 100644 index 00000000000..411f27bb4fc --- /dev/null +++ b/core/src/main/java/org/owasp/dependencycheck/utils/CvssUtil.java @@ -0,0 +1,355 @@ +/* + * This file is part of dependency-check-core. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2023 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.utils; + +import io.github.jeremylong.openvulnerability.client.nvd.CvssV2; +import io.github.jeremylong.openvulnerability.client.nvd.CvssV2Data; +import io.github.jeremylong.openvulnerability.client.nvd.CvssV3; +import io.github.jeremylong.openvulnerability.client.nvd.CvssV3Data; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import io.github.jeremylong.openvulnerability.client.nvd.CvssV4; +import io.github.jeremylong.openvulnerability.client.nvd.CvssV4Data; +import org.sonatype.ossindex.service.api.cvss.Cvss3Severity; + +/** + * Utility class to create CVSS Objects. + * + * @author Jeremy Long + */ +public final class CvssUtil { + + private CvssUtil() { + //empty constructor for utility class. + } + + /** + * The CVSS v3 Base Metrics (that are required by the spec for any CVSS v3 + * Vector String) + */ + private static final List BASE_METRICS_V3 = Arrays.asList("AV", "AC", "PR", "UI", "S", "C", "I", "A"); + + /** + * The CVSS V2 Metrics required for the vector string to be complete. + */ + private static final List BASE_METRICS_V2 = Arrays.asList("AV", "AC", "Au", "C", "I", "A"); + /** + * ZERO. + */ + private static final Double ZERO = 0.0; + /** + * ONE. + */ + private static final Double ONE = 1.0; + /** + * FOUR. + */ + private static final Double FOUR = 4.0; + /** + * SEVEN. + */ + private static final Double SEVEN = 7.0; + /** + * NINE. + */ + private static final Double NINE = 9.0; + /** + * TEN. + */ + private static final Double TEN = 10.0; + /** + * UNKNOWN. + */ + private static final String UNKNOWN = "UNKNOWN"; + /** + * HIGH. + */ + private static final String HIGH = "HIGH"; + /** + * MEDIUM. + */ + private static final String MEDIUM = "MEDIUM"; + /** + * LOW. + */ + private static final String LOW = "LOW"; + + /** + * Convert a CVSSv2 vector String into a CvssV3 Object. + * + * @param vectorString the vector string + * @param baseScore the base score + * @return the CVSSv2 object + */ + public static CvssV2 vectorToCvssV2(String vectorString, Double baseScore) { + if (vectorString.startsWith("CVSS:")) { + throw new IllegalArgumentException("Not a valid CVSSv2 vector string: " + vectorString); + } + final String[] metricStrings = vectorString.substring(vectorString.indexOf('/') + 1).split("/"); + final HashMap metrics = new HashMap<>(); + for (int i = 0; i < metricStrings.length; i++) { + final String[] metricKeyVal = metricStrings[i].split(":"); + if (metricKeyVal.length != 2) { + throw new IllegalArgumentException( + String.format("Not a valid CVSSv2 vector string '%s', invalid metric component '%s'", + vectorString, metricStrings[i])); + } + metrics.put(metricKeyVal[0], metricKeyVal[1]); + } + if (!metrics.keySet().containsAll(BASE_METRICS_V2)) { + throw new IllegalArgumentException( + String.format("Not a valid CVSSv2 vector string '%s'; missing one or more required Metrics;", + vectorString)); + } + + //"AV:L/AC:L/Au:N/C:N/I:N/A:C" + final CvssV2Data.AccessVectorType accessVector = CvssV2Data.AccessVectorType.fromValue(metrics.get("AV")); + final CvssV2Data.AccessComplexityType attackComplexity = CvssV2Data.AccessComplexityType.fromValue(metrics.get("AC")); + final CvssV2Data.AuthenticationType authentication = CvssV2Data.AuthenticationType.fromValue(metrics.get("Au")); + final CvssV2Data.CiaType confidentialityImpact = CvssV2Data.CiaType.fromValue(metrics.get("C")); + final CvssV2Data.CiaType integrityImpact = CvssV2Data.CiaType.fromValue(metrics.get("I")); + final CvssV2Data.CiaType availabilityImpact = CvssV2Data.CiaType.fromValue(metrics.get("A")); + + final String baseSeverity = cvssV2ScoreToSeverity(baseScore); + final CvssV2Data data = new CvssV2Data(CvssV2Data.Version._2_0, vectorString, accessVector, attackComplexity, + authentication, confidentialityImpact, integrityImpact, availabilityImpact, baseScore, baseSeverity, + null, null, null, null, null, null, null, null, null, null); + final CvssV2 cvss = new CvssV2(null, null, data, baseSeverity, null, null, null, null, null, null, null); + return cvss; + + } + + /** + * Determines the severity from the score. + * + * @param score the score + * @return the severity + */ + public static String cvssV2ScoreToSeverity(Double score) { + if (score != null) { + if (ZERO.compareTo(score) <= 0 && FOUR.compareTo(score) > 0) { + return LOW; + } else if (FOUR.compareTo(score) <= 0 && SEVEN.compareTo(score) > 0) { + return MEDIUM; + } else if (SEVEN.compareTo(score) <= 0 && TEN.compareTo(score) >= 0) { + return HIGH; + } + } + return UNKNOWN; + } + + /** + * Determines the severity from the score. + * + * @param score the score + * @return the severity + */ + public static CvssV3Data.SeverityType cvssV3ScoreToSeverity(Double score) { + if (score != null) { + if (ZERO.compareTo(score) == 0) { + return CvssV3Data.SeverityType.NONE; + } else if (ZERO.compareTo(score) <= 0 && FOUR.compareTo(score) > 0) { + return CvssV3Data.SeverityType.LOW; + } else if (FOUR.compareTo(score) <= 0 && SEVEN.compareTo(score) > 0) { + return CvssV3Data.SeverityType.MEDIUM; + } else if (SEVEN.compareTo(score) <= 0 && NINE.compareTo(score) > 0) { + return CvssV3Data.SeverityType.HIGH; + } else if (NINE.compareTo(score) <= 0 && TEN.compareTo(score) >= 0) { + return CvssV3Data.SeverityType.CRITICAL; + } + } + return null; + } + + /** + * Convert a CVSSv3 vector String into a CvssV3 Object. + * + * @param vectorString the vector string + * @param baseScore the base score + * @return the CVSSv3 object + */ + public static CvssV3 vectorToCvssV3(String vectorString, Double baseScore) { + if (!vectorString.startsWith("CVSS:3")) { + throw new IllegalArgumentException("Not a valid CVSSv3 vector string: " + vectorString); + } + final String versionString = vectorString.substring(5, vectorString.indexOf('/')); + final String[] metricStrings = vectorString.substring(vectorString.indexOf('/') + 1).split("/"); + final HashMap metrics = new HashMap<>(); + for (int i = 0; i < metricStrings.length; i++) { + final String[] metricKeyVal = metricStrings[i].split(":"); + if (metricKeyVal.length != 2) { + throw new IllegalArgumentException( + String.format("Not a valid CVSSv3 vector string '%s', invalid metric component '%s'", + vectorString, metricStrings[i])); + } + metrics.put(metricKeyVal[0], metricKeyVal[1]); + } + if (!metrics.keySet().containsAll(BASE_METRICS_V3)) { + throw new IllegalArgumentException( + String.format("Not a valid CVSSv3 vector string '%s'; missing one or more required Base Metrics;", + vectorString)); + } + + final CvssV3Data.Version version = CvssV3Data.Version.fromValue(versionString); + //"CVSS:3.1\/AV:L\/AC:L\/PR:L\/UI:N\/S:U\/C:N\/I:N\/A:H" + final CvssV3Data.AttackVectorType attackVector = CvssV3Data.AttackVectorType.fromValue(metrics.get("AV")); + final CvssV3Data.AttackComplexityType attackComplexity = CvssV3Data.AttackComplexityType.fromValue(metrics.get("AC")); + final CvssV3Data.PrivilegesRequiredType privilegesRequired = CvssV3Data.PrivilegesRequiredType.fromValue(metrics.get("PR")); + final CvssV3Data.UserInteractionType userInteraction = CvssV3Data.UserInteractionType.fromValue(metrics.get("UI")); + final CvssV3Data.ScopeType scope = CvssV3Data.ScopeType.fromValue(metrics.get("S")); + final CvssV3Data.CiaType confidentialityImpact = CvssV3Data.CiaType.fromValue(metrics.get("C")); + final CvssV3Data.CiaType integrityImpact = CvssV3Data.CiaType.fromValue(metrics.get("I")); + final CvssV3Data.CiaType availabilityImpact = CvssV3Data.CiaType.fromValue(metrics.get("A")); + + final String baseSeverityString = Cvss3Severity.of(baseScore.floatValue()).name(); + final CvssV3Data.SeverityType baseSeverity = CvssV3Data.SeverityType.fromValue(baseSeverityString); + final CvssV3Data data = new CvssV3Data(version, vectorString, attackVector, attackComplexity, + privilegesRequired, userInteraction, scope, confidentialityImpact, integrityImpact, availabilityImpact, baseScore, + baseSeverity, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null); + final CvssV3 cvss = new CvssV3(null, null, data, null, null); + return cvss; + } + + public static CvssV4Data.SeverityType cvssV4ScoreToSeverity(double baseScore) { + if (baseScore == 0.0) { + return CvssV4Data.SeverityType.NONE; + } else if (baseScore > 0.0 && baseScore < 4.0) { + return CvssV4Data.SeverityType.LOW; + } else if (baseScore >= 4.0 && baseScore < 7.0) { + return CvssV4Data.SeverityType.MEDIUM; + } else if (baseScore >= 7.0 && baseScore < 9.0) { + return CvssV4Data.SeverityType.HIGH; + } else if (baseScore >= 9.0 && baseScore <= 10.0) { + return CvssV4Data.SeverityType.CRITICAL; + } else { + throw new IllegalArgumentException("Invalid CVSS base score: " + baseScore); + } + } + + /** + * Convert a CVSSv4 vector String into a CvssV4 Object. + * + * @param source the source of the CVSS data + * @param type the type of CVSS data (primary or secondary) + * @param baseScore the base score + * @param vectorString the vector string + * @return the CVSSv4 object + */ + public static CvssV4 vectorToCvssV4(String source, CvssV4.Type type, Double baseScore, String vectorString) { + // Remove "CVSS:" prefix and split by "/" + String[] parts = vectorString.replaceFirst("^CVSS:", "").split("/"); + Map values = new HashMap<>(); + for (String part : parts) { + String[] kv = part.split(":"); + if (kv.length == 2) { + values.put(kv[0], kv[1]); + } + } + + CvssV4Data.Version version = CvssV4Data.Version.fromValue(values.getOrDefault("4.0", "4.0")); + + CvssV4Data.AttackVectorType attackVector = values.containsKey("AV") ? CvssV4Data.AttackVectorType.fromValue(values.get("AV")) : null; + CvssV4Data.AttackComplexityType attackComplexity = values.containsKey("AC") ? CvssV4Data.AttackComplexityType.fromValue(values.get("AC")) : null; + CvssV4Data.AttackRequirementsType attackRequirements = values.containsKey("AT") ? CvssV4Data.AttackRequirementsType.fromValue(values.get("AT")) : null; + CvssV4Data.PrivilegesRequiredType privilegesRequired = values.containsKey("PR") ? CvssV4Data.PrivilegesRequiredType.fromValue(values.get("PR")) : null; + CvssV4Data.UserInteractionType userInteraction = values.containsKey("UI") ? CvssV4Data.UserInteractionType.fromValue(values.get("UI")) : null; + CvssV4Data.CiaType vulnConfidentialityImpact = values.containsKey("VC") ? CvssV4Data.CiaType.fromValue(values.get("VC")) : null; + CvssV4Data.CiaType vulnIntegrityImpact = values.containsKey("VI") ? CvssV4Data.CiaType.fromValue(values.get("VI")) : null; + CvssV4Data.CiaType vulnAvailabilityImpact = values.containsKey("VA") ? CvssV4Data.CiaType.fromValue(values.get("VA")) : null; + CvssV4Data.CiaType subConfidentialityImpact = values.containsKey("SC") ? CvssV4Data.CiaType.fromValue(values.get("SC")) : null; + CvssV4Data.CiaType subIntegrityImpact = values.containsKey("SI") ? CvssV4Data.CiaType.fromValue(values.get("SI")) : null; + CvssV4Data.CiaType subAvailabilityImpact = values.containsKey("SA") ? CvssV4Data.CiaType.fromValue(values.get("SA")) : null; + CvssV4Data.ExploitMaturityType exploitMaturity = values.containsKey("E") ? CvssV4Data.ExploitMaturityType.fromValue(values.get("E")) : CvssV4Data.ExploitMaturityType.NOT_DEFINED; + CvssV4Data.CiaRequirementType confidentialityRequirement = values.containsKey("CR") ? CvssV4Data.CiaRequirementType.fromValue(values.get("CR")) : CvssV4Data.CiaRequirementType.NOT_DEFINED; + CvssV4Data.CiaRequirementType integrityRequirement = values.containsKey("IR") ? CvssV4Data.CiaRequirementType.fromValue(values.get("IR")) : CvssV4Data.CiaRequirementType.NOT_DEFINED; + CvssV4Data.CiaRequirementType availabilityRequirement = values.containsKey("AR") ? CvssV4Data.CiaRequirementType.fromValue(values.get("AR")) : CvssV4Data.CiaRequirementType.NOT_DEFINED; + CvssV4Data.ModifiedAttackVectorType modifiedAttackVector = values.containsKey("MAV") ? CvssV4Data.ModifiedAttackVectorType.fromValue(values.get("MAV")) : CvssV4Data.ModifiedAttackVectorType.NOT_DEFINED; + CvssV4Data.ModifiedAttackComplexityType modifiedAttackComplexity = values.containsKey("MAC") ? CvssV4Data.ModifiedAttackComplexityType.fromValue(values.get("MAC")) : CvssV4Data.ModifiedAttackComplexityType.NOT_DEFINED; + CvssV4Data.ModifiedAttackRequirementsType modifiedAttackRequirements = values.containsKey("MAT") ? CvssV4Data.ModifiedAttackRequirementsType.fromValue(values.get("MAT")) : CvssV4Data.ModifiedAttackRequirementsType.NOT_DEFINED; + CvssV4Data.ModifiedPrivilegesRequiredType modifiedPrivilegesRequired = values.containsKey("MPR") ? CvssV4Data.ModifiedPrivilegesRequiredType.fromValue(values.get("MPR")) : CvssV4Data.ModifiedPrivilegesRequiredType.NOT_DEFINED; + CvssV4Data.ModifiedUserInteractionType modifiedUserInteraction = values.containsKey("MUI") ? CvssV4Data.ModifiedUserInteractionType.fromValue(values.get("MUI")) : CvssV4Data.ModifiedUserInteractionType.NOT_DEFINED; + CvssV4Data.ModifiedCiaType modifiedVulnConfidentialityImpact = values.containsKey("MVC") ? CvssV4Data.ModifiedCiaType.fromValue(values.get("MVC")) : CvssV4Data.ModifiedCiaType.NOT_DEFINED; + CvssV4Data.ModifiedCiaType modifiedVulnIntegrityImpact = values.containsKey("MVI") ? CvssV4Data.ModifiedCiaType.fromValue(values.get("MVI")) : CvssV4Data.ModifiedCiaType.NOT_DEFINED; + CvssV4Data.ModifiedCiaType modifiedVulnAvailabilityImpact = values.containsKey("MVA") ? CvssV4Data.ModifiedCiaType.fromValue(values.get("MVA")) : CvssV4Data.ModifiedCiaType.NOT_DEFINED; + CvssV4Data.ModifiedSubCType modifiedSubConfidentialityImpact = values.containsKey("MSC") ? CvssV4Data.ModifiedSubCType.fromValue(values.get("MSC")) : CvssV4Data.ModifiedSubCType.NOT_DEFINED; + CvssV4Data.ModifiedSubIaType modifiedSubIntegrityImpact = values.containsKey("MSI") ? CvssV4Data.ModifiedSubIaType.fromValue(values.get("MSI")) : CvssV4Data.ModifiedSubIaType.NOT_DEFINED; + CvssV4Data.ModifiedSubIaType modifiedSubAvailabilityImpact = values.containsKey("MSA") ? CvssV4Data.ModifiedSubIaType.fromValue(values.get("MSA")) : CvssV4Data.ModifiedSubIaType.NOT_DEFINED; + CvssV4Data.SafetyType safety = values.containsKey("S") ? CvssV4Data.SafetyType.fromValue(values.get("S")) : CvssV4Data.SafetyType.NOT_DEFINED; + CvssV4Data.AutomatableType automatable = values.containsKey("AU") ? CvssV4Data.AutomatableType.fromValue(values.get("AU")) : CvssV4Data.AutomatableType.NOT_DEFINED; + CvssV4Data.RecoveryType recovery = values.containsKey("R") ? CvssV4Data.RecoveryType.fromValue(values.get("R")) : CvssV4Data.RecoveryType.NOT_DEFINED; + CvssV4Data.ValueDensityType valueDensity = values.containsKey("V") ? CvssV4Data.ValueDensityType.fromValue(values.get("V")) : CvssV4Data.ValueDensityType.NOT_DEFINED; + CvssV4Data.VulnerabilityResponseEffortType vulnerabilityResponseEffort = values.containsKey("RE") ? CvssV4Data.VulnerabilityResponseEffortType.fromValue(values.get("RE")) : CvssV4Data.VulnerabilityResponseEffortType.NOT_DEFINED; + CvssV4Data.ProviderUrgencyType providerUrgency = values.containsKey("U") ? CvssV4Data.ProviderUrgencyType.fromValue(values.get("U")) : CvssV4Data.ProviderUrgencyType.NOT_DEFINED; + + CvssV4Data.SeverityType baseSeverity = cvssV4ScoreToSeverity(baseScore); + // Scores and severities are not present in the vector string, set to null/defaults + Double threatScore = null; + CvssV4Data.SeverityType threatSeverity = null; + Double environmentalScore = null; + CvssV4Data.SeverityType environmentalSeverity = null; + + CvssV4Data cvssData = new CvssV4Data( + version, + vectorString, + attackVector, + attackComplexity, + attackRequirements, + privilegesRequired, + userInteraction, + vulnConfidentialityImpact, + vulnIntegrityImpact, + vulnAvailabilityImpact, + subConfidentialityImpact, + subIntegrityImpact, + subAvailabilityImpact, + exploitMaturity, + confidentialityRequirement, + integrityRequirement, + availabilityRequirement, + modifiedAttackVector, + modifiedAttackComplexity, + modifiedAttackRequirements, + modifiedPrivilegesRequired, + modifiedUserInteraction, + modifiedVulnConfidentialityImpact, + modifiedVulnIntegrityImpact, + modifiedVulnAvailabilityImpact, + modifiedSubConfidentialityImpact, + modifiedSubIntegrityImpact, + modifiedSubAvailabilityImpact, + safety, + automatable, + recovery, + valueDensity, + vulnerabilityResponseEffort, + providerUrgency, + baseScore, + baseSeverity, + threatScore, + threatSeverity, + environmentalScore, + environmentalSeverity + ); + + return new CvssV4(source, type, cvssData); + } +} diff --git a/core/src/main/java/org/owasp/dependencycheck/utils/DateUtil.java b/core/src/main/java/org/owasp/dependencycheck/utils/DateUtil.java index b385892fa2c..36e3d775856 100644 --- a/core/src/main/java/org/owasp/dependencycheck/utils/DateUtil.java +++ b/core/src/main/java/org/owasp/dependencycheck/utils/DateUtil.java @@ -17,6 +17,7 @@ */ package org.owasp.dependencycheck.utils; +import java.time.ZonedDateTime; import org.owasp.dependencycheck.exception.ParseException; import java.util.Calendar; @@ -80,6 +81,19 @@ public static boolean withinDateRange(long date, long compareTo, int dayRange) { return (compareTo - date) < msRange; } + /** + * Determines if the date is within the given day range. + * + * @param date the date + * @param compareTo the date to compare against + * @param dayRange the number of days allowed + * @return if the date is within the dayRange of compareTo + */ + public static boolean withinDateRange(ZonedDateTime date, ZonedDateTime compareTo, int dayRange) { + final ZonedDateTime rangeEnd = date.plusDays(dayRange); + return compareTo.isAfter(date) && compareTo.isBefore(rangeEnd); + } + /** * Returns the string value converted to an epoch seconds. Note, in some * cases the value provided may be in milliseconds. diff --git a/core/src/main/java/org/owasp/dependencycheck/utils/DependencyVersion.java b/core/src/main/java/org/owasp/dependencycheck/utils/DependencyVersion.java index bbe242b3099..7f14f4e3f43 100644 --- a/core/src/main/java/org/owasp/dependencycheck/utils/DependencyVersion.java +++ b/core/src/main/java/org/owasp/dependencycheck/utils/DependencyVersion.java @@ -78,7 +78,7 @@ public final void parseVersion(String version) { versionParts = new ArrayList<>(); if (version != null) { final Pattern rx = Pattern - .compile("(\\d+[a-z]{1,3}$|[a-z]{1,3}[_-]?\\d+|\\d+|(rc|release|snapshot|beta|alpha)$)", + .compile("(\\d{1,100}[a-z]{1,3}$|[a-z]{1,3}[_-]?\\d{1,100}|\\d{1,100}|(rc|release|snapshot|beta|alpha)$)", Pattern.CASE_INSENSITIVE); final Matcher matcher = rx.matcher(version.toLowerCase()); while (matcher.find()) { diff --git a/core/src/main/java/org/owasp/dependencycheck/utils/ExtractionUtil.java b/core/src/main/java/org/owasp/dependencycheck/utils/ExtractionUtil.java index 29c785f9406..36eedb4b7a0 100644 --- a/core/src/main/java/org/owasp/dependencycheck/utils/ExtractionUtil.java +++ b/core/src/main/java/org/owasp/dependencycheck/utils/ExtractionUtil.java @@ -17,6 +17,17 @@ */ package org.owasp.dependencycheck.utils; +import org.apache.commons.compress.archivers.ArchiveEntry; +import org.apache.commons.compress.archivers.ArchiveInputStream; +import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream; +import org.apache.commons.io.IOUtils; +import org.owasp.dependencycheck.Engine; +import org.owasp.dependencycheck.analyzer.exception.AnalysisException; +import org.owasp.dependencycheck.analyzer.exception.ArchiveExtractionException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.concurrent.ThreadSafe; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; @@ -28,17 +39,6 @@ import java.util.zip.GZIPInputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; -import javax.annotation.concurrent.ThreadSafe; - -import org.apache.commons.compress.archivers.ArchiveEntry; -import org.apache.commons.compress.archivers.ArchiveInputStream; -import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream; -import org.apache.commons.io.IOUtils; -import org.owasp.dependencycheck.Engine; -import org.owasp.dependencycheck.analyzer.exception.AnalysisException; -import org.owasp.dependencycheck.analyzer.exception.ArchiveExtractionException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Set of utilities to extract files from archives. @@ -350,7 +350,7 @@ public static void extractGzip(File file) throws FileNotFoundException, IOExcept FileOutputStream out = new FileOutputStream(newFile)) { IOUtils.copy(cin, out); } finally { - if (gzip.isFile() && !org.apache.commons.io.FileUtils.deleteQuietly(gzip)) { + if (gzip.isFile() && !FileUtils.delete(gzip)) { LOGGER.debug("Failed to delete temporary file when extracting 'gz' {}", gzip); gzip.deleteOnExit(); } @@ -382,7 +382,7 @@ public static void extractZip(File file) throws FileNotFoundException, IOExcepti cin.getNextEntry(); IOUtils.copy(cin, out); } finally { - if (zip.isFile() && !org.apache.commons.io.FileUtils.deleteQuietly(zip)) { + if (zip.isFile() && !FileUtils.delete(zip)) { LOGGER.debug("Failed to delete temporary file when extracting 'zip' {}", zip); zip.deleteOnExit(); } diff --git a/core/src/main/java/org/owasp/dependencycheck/utils/PEParser.java b/core/src/main/java/org/owasp/dependencycheck/utils/PEParser.java index 4c6522fa706..b9fc1da1401 100644 --- a/core/src/main/java/org/owasp/dependencycheck/utils/PEParser.java +++ b/core/src/main/java/org/owasp/dependencycheck/utils/PEParser.java @@ -9,7 +9,7 @@ ****************************************************************************** */ /** **************************************************************************** * This is a copy of https://github.com/kichik/pecoff4j/blob/2137804a7c1f1aa5f4272a9623bad452f7aab0ad/java/src/org/boris/pecoff4j/io/PEParser.java#L1 - * Added a logger and more forgiving error handling while reading files per https://github.com/jeremylong/DependencyCheck/issues/2601 + * Added a logger and more forgiving error handling while reading files per https://github.com/dependency-check/DependencyCheck/issues/2601 ***************************************************************************** */ package org.owasp.dependencycheck.utils; diff --git a/core/src/main/java/org/owasp/dependencycheck/utils/PyPACoreMetadataParser.java b/core/src/main/java/org/owasp/dependencycheck/utils/PyPACoreMetadataParser.java index fcfe28a9b57..e33b59fc4e6 100644 --- a/core/src/main/java/org/owasp/dependencycheck/utils/PyPACoreMetadataParser.java +++ b/core/src/main/java/org/owasp/dependencycheck/utils/PyPACoreMetadataParser.java @@ -64,6 +64,7 @@ private PyPACoreMetadataParser() { * The Wheel metadata of a Python package as a File * * @return The metadata properties read from the file + * @throws AnalysisException thrown if there is an analysis exception */ public static Properties getProperties(File file) throws AnalysisException { try (BufferedReader utf8Reader = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8)) { diff --git a/core/src/main/java/org/owasp/dependencycheck/utils/SeverityUtil.java b/core/src/main/java/org/owasp/dependencycheck/utils/SeverityUtil.java index ed3283bfe37..1da28475628 100644 --- a/core/src/main/java/org/owasp/dependencycheck/utils/SeverityUtil.java +++ b/core/src/main/java/org/owasp/dependencycheck/utils/SeverityUtil.java @@ -27,6 +27,22 @@ */ public final class SeverityUtil { + /** + * The cutoff for high severity. + */ + private static final Double HIGH = 10.0; + /** + * The cutoff for medium severity. + */ + private static final Double MEDIUM = 6.9; + /** + * The cutoff for low severity. + */ + private static final Double LOW = 3.9; + /** + * The cutoff for none severity. + */ + private static final Double NONE = 0.0; /** * The logger. */ @@ -47,31 +63,33 @@ private SeverityUtil() { * @param severity the severity text (e.g. "medium") * @return a score from 0 to 10 */ - public static float estimateCvssV2(String severity) { + public static Double estimateCvssV2(String severity) { switch (severity == null ? "none" : severity.toLowerCase()) { case "critical": case "high": - return 10.0f; + return HIGH; case "moderate": case "medium": - return 6.9f; + return MEDIUM; case "info": + case "none": case "informational": - return 0.0f; + return NONE; case "low": case "unknown": - case "none": default: - return 3.9f; + return LOW; } } /** - * Converts a textual severity to the text that should be used to signal - * it in a report. + * Converts a textual severity to the text that should be used to signal it + * in a report. + * * @param severity The textual unscored severity - * @return The severity when properly recognized, otherwise the severity extended with a remark that it was not recognized and - * assumed to represent a critical severity. + * @return The severity when properly recognized, otherwise the severity + * extended with a remark that it was not recognized and assumed to + * represent a critical severity. */ public static String unscoredToSeveritytext(final String severity) { switch (Severity.forUnscored(severity)) { @@ -94,108 +112,120 @@ public static String unscoredToSeveritytext(final String severity) { } /** - * Creates an estimated sort-adjusted CVSSv3 score for an unscored textual severity. - * For recognized severities below critical it returns a value at the lower bound of the CVSSv3 baseScore for that severity. - * For recognized critical severities it returns a score in-between the upper bound of the HIGH CVSSv2 score and the lowest - * sort-adjusted CVSSv3 critical score, so that unscored critical vulnerabilties are ordered in between CRITICAL scored CVSSv3 - * rated vulnerabilities and HIGH-scored CVSSv2 rated vulnerabilities. - * For unrecognized severities it returns a score in-between the top HIGH CVSSv2 score and the estimatedSortAdjustedCVSSv3 - * score for an unscored severity recognized as critical, so that recognized critical will win over unrecognized severities - * while unrecognized severities are assumed to be of a critical nature. + * Creates an estimated sort-adjusted CVSSv3 score for an unscored textual + * severity. For recognized severities below critical it returns a value at + * the lower bound of the CVSSv3 baseScore for that severity. For recognized + * critical severities it returns a score in-between the upper bound of the + * HIGH CVSSv2 score and the lowest sort-adjusted CVSSv3 critical score, so + * that unscored critical vulnerabilties are ordered in between CRITICAL + * scored CVSSv3 rated vulnerabilities and HIGH-scored CVSSv2 rated + * vulnerabilities. For unrecognized severities it returns a score + * in-between the top HIGH CVSSv2 score and the estimatedSortAdjustedCVSSv3 + * score for an unscored severity recognized as critical, so that recognized + * critical will win over unrecognized severities while unrecognized + * severities are assumed to be of a critical nature. * * @param severity The textual severity, may be null - * @return A float that can be used to numerically sort vulnerabilities in approximated severity (highest float represents - * highest severity). - * @see #sortAdjustedCVSSv3BaseScore(float) + * @return A float that can be used to numerically sort vulnerabilities in + * approximated severity (highest float represents highest severity). + * @see #sortAdjustedCVSSv3BaseScore(Double) */ - public static float estimatedSortAdjustedCVSSv3(final String severity) { + public static Double estimatedSortAdjustedCVSSv3(final String severity) { switch (Severity.forUnscored(severity)) { case CRITICAL: - return 10.2f; + return 10.2; case HIGH: - return 7.0f; + return 7.0; case MEDIUM: - return 4.0f; + return 4.0; case LOW: - return 0.1f; + return 0.1; case INFO: - return 0.0f; + return 0.0; case ASSUMED_CRITICAL: default: SeverityUtil.LOGGER.debug("Unrecognized unscored textual severity: {}, assuming critical score as worst-case " - + "estimate for sorting", - severity); - return 10.1f; + + "estimate for sorting", + severity); + return 10.1; } } /** - * Compute an adjusted CVSSv3 baseScore that ensures that CRITICAL CVSSv3 scores will win over HIGH CVSSv2 and CRITICAL - * unscored severities to allow for a best-effort sorting that enables the report to list a reliable 'highest severity' - * in the report. + * Compute an adjusted CVSSv3 baseScore that ensures that CRITICAL CVSSv3 + * scores will win over HIGH CVSSv2 and CRITICAL unscored severities to + * allow for a best-effort sorting that enables the report to list a + * reliable 'highest severity' in the report. * * @param cvssV3BaseScore The cvssV3 baseScore severity of a vulnerability - * @return The cvssV3 baseScore, adjusted if necessary in order to guarantee that CVSSv3 CRITICAL scores will rate higher than - * CVSSv2 HIGH, unscored critical severities and unscored unrecognized severities (which are assumed for sorting to be of a - * critical nature) + * @return The cvssV3 baseScore, adjusted if necessary in order to guarantee + * that CVSSv3 CRITICAL scores will rate higher than CVSSv2 HIGH, unscored + * critical severities and unscored unrecognized severities (which are + * assumed for sorting to be of a critical nature) * @see #estimatedSortAdjustedCVSSv3(String) */ - public static float sortAdjustedCVSSv3BaseScore(final float cvssV3BaseScore) { - if (cvssV3BaseScore >= 9.0f) { - return cvssV3BaseScore + 1.3f; + public static Double sortAdjustedCVSSv3BaseScore(final Double cvssV3BaseScore) { + if (cvssV3BaseScore.floatValue() >= 9.0f) { + return cvssV3BaseScore + 1.3; } return cvssV3BaseScore; } /** - * An enum to translate unscored severity texts to a severity level of a defined set of severities. - * Allows for re-use of the text-to-severity mapping in multiple helper methods. + * An enum to translate unscored severity texts to a severity level of a + * defined set of severities. Allows for re-use of the text-to-severity + * mapping in multiple helper methods. */ private enum Severity { /** - * A severity level for textual values that should be regarded as accompanying a critical severity vulnerability + * A severity level for textual values that should be regarded as + * accompanying a critical severity vulnerability */ CRITICAL, /** - * A severity level for textual values that are not recognized and therefor assumed to be accompanying a critical severity - * vulnerability + * A severity level for textual values that are not recognized and + * therefor assumed to be accompanying a critical severity vulnerability */ ASSUMED_CRITICAL, /** - * A severity level for textual values that should be regarded as accompanying a high severity vulnerability + * A severity level for textual values that should be regarded as + * accompanying a high severity vulnerability */ HIGH, /** - * A severity level for textual values that should be regarded as accompanying a medium severity vulnerability + * A severity level for textual values that should be regarded as + * accompanying a medium severity vulnerability */ MEDIUM, /** - * A severity level for textual values that should be regarded as accompanying a low severity vulnerability + * A severity level for textual values that should be regarded as + * accompanying a low severity vulnerability */ LOW, /** - * A severity level for textual values that should be regarded as accompanying a vulnerability of informational nature + * A severity level for textual values that should be regarded as + * accompanying a vulnerability of informational nature */ INFO; public static Severity forUnscored(String value) { switch (value == null ? "none" : value.toLowerCase()) { - case "critical": - return CRITICAL; - case "high": - return HIGH; - case "moderate": - case "medium": - return MEDIUM; - case "info": - case "informational": - return INFO; - case "low": - case "unknown": - case "none": - return LOW; - default: - return ASSUMED_CRITICAL; + case "critical": + return CRITICAL; + case "high": + return HIGH; + case "moderate": + case "medium": + return MEDIUM; + case "info": + case "informational": + return INFO; + case "low": + case "unknown": + case "none": + return LOW; + default: + return ASSUMED_CRITICAL; } } } diff --git a/core/src/main/java/org/owasp/dependencycheck/utils/Utils.java b/core/src/main/java/org/owasp/dependencycheck/utils/Utils.java deleted file mode 100644 index a3a92643429..00000000000 --- a/core/src/main/java/org/owasp/dependencycheck/utils/Utils.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This file is part of dependency-check-core. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright (c) 2022 Jeremy Long. All Rights Reserved. - */ -package org.owasp.dependencycheck.utils; - -/** - * - * @author Jeremy Long - */ -public final class Utils { - - /** - * Empty constructor for utility class. - */ - private Utils() { - } - - /** - * Returns the Java major version as a whole number. - * - * @return the Java major version as a whole number - */ - public static int getJavaVersion() { - String version = System.getProperty("java.specification.version"); - if (version.startsWith("1.")) { - version = version.substring(2, 3); - } else { - final int dot = version.indexOf("."); - if (dot != -1) { - version = version.substring(0, dot); - } - } - return Integer.parseInt(version); - } -} diff --git a/core/src/main/java/org/owasp/dependencycheck/xml/hints/HintParser.java b/core/src/main/java/org/owasp/dependencycheck/xml/hints/HintParser.java index 2cc320fd664..6c54b8f4146 100644 --- a/core/src/main/java/org/owasp/dependencycheck/xml/hints/HintParser.java +++ b/core/src/main/java/org/owasp/dependencycheck/xml/hints/HintParser.java @@ -148,7 +148,7 @@ public void parseHints(InputStream inputStream) throws HintParseException, SAXEx InputStream schemaStream12 = FileUtils.getResourceAsStream(HINT_SCHEMA_1_2); InputStream schemaStream11 = FileUtils.getResourceAsStream(HINT_SCHEMA_1_1)) { - final BOMInputStream bomStream = new BOMInputStream(inputStream); + final BOMInputStream bomStream = BOMInputStream.builder().setInputStream(inputStream).get(); final ByteOrderMark bom = bomStream.getBOM(); final String defaultEncoding = StandardCharsets.UTF_8.name(); final String charsetName = bom == null ? defaultEncoding : bom.getCharsetName(); diff --git a/core/src/main/java/org/owasp/dependencycheck/xml/hints/HintRule.java b/core/src/main/java/org/owasp/dependencycheck/xml/hints/HintRule.java index a1ec3009b13..399196ea698 100644 --- a/core/src/main/java/org/owasp/dependencycheck/xml/hints/HintRule.java +++ b/core/src/main/java/org/owasp/dependencycheck/xml/hints/HintRule.java @@ -147,7 +147,7 @@ public List getGivenVendor() { * @param confidence the confidence of the evidence */ public void addAddProduct(String source, String name, String value, Confidence confidence) { - addProduct.add(new Evidence(source, name, value, confidence)); + addProduct.add(new Evidence(source, name, value, confidence, true)); } /** @@ -168,7 +168,7 @@ public List getAddProduct() { * @param confidence the confidence of the evidence */ public void addAddVersion(String source, String name, String value, Confidence confidence) { - addVersion.add(new Evidence(source, name, value, confidence)); + addVersion.add(new Evidence(source, name, value, confidence, true)); } /** @@ -189,7 +189,7 @@ public List getAddVersion() { * @param confidence the confidence of the evidence */ public void addAddVendor(String source, String name, String value, Confidence confidence) { - addVendor.add(new Evidence(source, name, value, confidence)); + addVendor.add(new Evidence(source, name, value, confidence, true)); } /** diff --git a/core/src/main/java/org/owasp/dependencycheck/xml/pom/Model.java b/core/src/main/java/org/owasp/dependencycheck/xml/pom/Model.java index e9b62c1b6be..b5c8fa757a9 100644 --- a/core/src/main/java/org/owasp/dependencycheck/xml/pom/Model.java +++ b/core/src/main/java/org/owasp/dependencycheck/xml/pom/Model.java @@ -350,7 +350,7 @@ public void processProperties(Properties properties) { /** * Replaces the group/artifact/version obtained from the `pom.xml` which may * contain variable references with the interpolated values of the - * pom.properties * content (when present). Validates that at least the documented properties * for the G/A/V coordinates are all present. If not it will leave the model * unmodified as the property-source was apparently not a valid diff --git a/core/src/main/java/org/owasp/dependencycheck/xml/pom/PomHandler.java b/core/src/main/java/org/owasp/dependencycheck/xml/pom/PomHandler.java index 32f0b9e2381..6dd415b1a7c 100644 --- a/core/src/main/java/org/owasp/dependencycheck/xml/pom/PomHandler.java +++ b/core/src/main/java/org/owasp/dependencycheck/xml/pom/PomHandler.java @@ -174,7 +174,7 @@ public void endElement(String uri, String localName, String qName) throws SAXExc model.setArtifactId(currentText.toString()); break; case VERSION: - model.setVersion(currentText.toString()); + model.setVersion(currentText.toString().trim()); break; case NAME: model.setName(currentText.toString()); diff --git a/core/src/main/java/org/owasp/dependencycheck/xml/pom/PomParser.java b/core/src/main/java/org/owasp/dependencycheck/xml/pom/PomParser.java index 92c808f6334..e27fc335e0a 100644 --- a/core/src/main/java/org/owasp/dependencycheck/xml/pom/PomParser.java +++ b/core/src/main/java/org/owasp/dependencycheck/xml/pom/PomParser.java @@ -111,7 +111,8 @@ public Model parse(InputStream inputStream) throws PomParseException { final XMLReader xmlReader = saxParser.getXMLReader(); xmlReader.setContentHandler(handler); - final BOMInputStream bomStream = new BOMInputStream(new XmlInputStream(new PomProjectInputStream(inputStream))); + final BOMInputStream bomStream = BOMInputStream.builder() + .setInputStream(new XmlInputStream(new PomProjectInputStream(inputStream))).get(); final ByteOrderMark bom = bomStream.getBOM(); final String defaultEncoding = StandardCharsets.UTF_8.name(); final String charsetName = bom == null ? defaultEncoding : bom.getCharsetName(); @@ -141,7 +142,7 @@ public Model parseWithoutDocTypeCleanup(InputStream inputStream) throws PomParse final XMLReader xmlReader = saxParser.getXMLReader(); xmlReader.setContentHandler(handler); - final BOMInputStream bomStream = new BOMInputStream(new XmlInputStream(inputStream)); + final BOMInputStream bomStream = BOMInputStream.builder().setInputStream(new XmlInputStream(inputStream)).get(); final ByteOrderMark bom = bomStream.getBOM(); final String defaultEncoding = StandardCharsets.UTF_8.name(); final String charsetName = bom == null ? defaultEncoding : bom.getCharsetName(); diff --git a/core/src/main/java/org/owasp/dependencycheck/xml/suppression/SuppressionHandler.java b/core/src/main/java/org/owasp/dependencycheck/xml/suppression/SuppressionHandler.java index 3ea7aebbf3c..50f4df32a9f 100644 --- a/core/src/main/java/org/owasp/dependencycheck/xml/suppression/SuppressionHandler.java +++ b/core/src/main/java/org/owasp/dependencycheck/xml/suppression/SuppressionHandler.java @@ -191,10 +191,10 @@ public void endElement(String uri, String localName, String qName) throws SAXExc rule.addVulnerabilityName(processPropertyType()); break; case NOTES: - rule.addNotes(currentText.toString().trim()); + rule.setNotes(currentText.toString().trim()); break; case CVSS_BELOW: - final float cvss = Float.parseFloat(currentText.toString().trim()); + final Double cvss = Double.valueOf(currentText.toString().trim()); rule.addCvssBelow(cvss); break; default: diff --git a/core/src/main/java/org/owasp/dependencycheck/xml/suppression/SuppressionParser.java b/core/src/main/java/org/owasp/dependencycheck/xml/suppression/SuppressionParser.java index d56c32c07bf..edafaa044b2 100644 --- a/core/src/main/java/org/owasp/dependencycheck/xml/suppression/SuppressionParser.java +++ b/core/src/main/java/org/owasp/dependencycheck/xml/suppression/SuppressionParser.java @@ -106,7 +106,7 @@ public List parseSuppressionRules(InputStream inputStream) InputStream schemaStream11 = FileUtils.getResourceAsStream(SUPPRESSION_SCHEMA_1_1); InputStream schemaStream10 = FileUtils.getResourceAsStream(SUPPRESSION_SCHEMA_1_0)) { - final BOMInputStream bomStream = new BOMInputStream(inputStream); + final BOMInputStream bomStream = BOMInputStream.builder().setInputStream(inputStream).get(); final ByteOrderMark bom = bomStream.getBOM(); final String defaultEncoding = StandardCharsets.UTF_8.name(); final String charsetName = bom == null ? defaultEncoding : bom.getCharsetName(); diff --git a/core/src/main/java/org/owasp/dependencycheck/xml/suppression/SuppressionRule.java b/core/src/main/java/org/owasp/dependencycheck/xml/suppression/SuppressionRule.java index 3fd508ab05e..de007453a97 100644 --- a/core/src/main/java/org/owasp/dependencycheck/xml/suppression/SuppressionRule.java +++ b/core/src/main/java/org/owasp/dependencycheck/xml/suppression/SuppressionRule.java @@ -62,7 +62,7 @@ public class SuppressionRule { /** * The list of cvssBelow scores. */ - private List cvssBelow = new ArrayList<>(); + private List cvssBelow = new ArrayList<>(); /** * The list of CWE entries to suppress. */ @@ -230,7 +230,7 @@ public boolean hasCpe() { * * @return the value of cvssBelow */ - public List getCvssBelow() { + public List getCvssBelow() { return cvssBelow; } @@ -239,7 +239,7 @@ public List getCvssBelow() { * * @param cvssBelow new value of cvssBelow */ - public void setCvssBelow(List cvssBelow) { + public void setCvssBelow(List cvssBelow) { this.cvssBelow = cvssBelow; } @@ -248,14 +248,14 @@ public void setCvssBelow(List cvssBelow) { * * @param cvss the CVSS to add */ - public void addCvssBelow(Float cvss) { + public void addCvssBelow(Double cvss) { this.cvssBelow.add(cvss); } /** - * Returns whether or not this suppression rule has CVSS suppressions. + * Returns whether or not this suppression rule has CVSS suppression criteria. * - * @return whether or not this suppression rule has CVSS suppressions + * @return whether or not this suppression rule has CVSS suppression criteria. */ public boolean hasCvssBelow() { return !cvssBelow.isEmpty(); @@ -273,28 +273,19 @@ public String getNotes() { /** * Set the value of notes. * - * @param notes new value of cve + * @param notes new value of notes */ public void setNotes(String notes) { this.notes = notes; } - /** - * Adds the notes to the cve list. - * - * @param notes the cve to add - */ - public void addNotes(String notes) { - this.notes = notes; - } - /** * Returns whether this suppression rule has notes entries. * * @return whether this suppression rule has notes entries */ public boolean hasNotes() { - return !cve.isEmpty(); + return !notes.isEmpty(); } /** @@ -534,13 +525,19 @@ public void process(Dependency dependency) { } } if (!remove) { - for (float cvss : this.cvssBelow) { - if (v.getCvssV2() != null && v.getCvssV2().getScore() < cvss) { + for (Double cvss : this.cvssBelow) { + //TODO validate this comparison + if (v.getCvssV2() != null && v.getCvssV2().getCvssData().getBaseScore().compareTo(cvss) < 0) { + remove = true; + removeVulns.add(v); + break; + } + if (v.getCvssV3() != null && v.getCvssV3().getCvssData().getBaseScore().compareTo(cvss) < 0) { remove = true; removeVulns.add(v); break; } - if (v.getCvssV3() != null && v.getCvssV3().getBaseScore() < cvss) { + if (v.getCvssV4() != null && v.getCvssV4().getCvssData().getBaseScore().compareTo(cvss) < 0) { remove = true; removeVulns.add(v); break; diff --git a/core/src/main/resources/GrokAssembly.zip b/core/src/main/resources/GrokAssembly.zip index 606d701bc69..2f6edd65b85 100644 Binary files a/core/src/main/resources/GrokAssembly.zip and b/core/src/main/resources/GrokAssembly.zip differ diff --git a/core/src/main/resources/META-INF/licenses/jquery/MIT-LICENSE.txt b/core/src/main/resources/META-INF/licenses/jquery/MIT-LICENSE.txt index 6bc1c3584fc..f642c3f7a77 100644 --- a/core/src/main/resources/META-INF/licenses/jquery/MIT-LICENSE.txt +++ b/core/src/main/resources/META-INF/licenses/jquery/MIT-LICENSE.txt @@ -1,1026 +1,20 @@ - - - - - - - - - jquery/MIT-LICENSE.txt at master · jquery/jquery - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - - - -
-
- - - - - -
- - - - -
- - -
-
- - - - - - - - - - - - - - -
- - -
- - - - - - - - - - - - -
-
- - - - - - - - -
-
- -
-
-
- - - -
    - - -
  • -
    - -
    - - - - Watch - - - -
    -
    -
    - Notification status - -
    - -
    - -
    - -
    - -

    Not watching

    - You only receive notifications for discussions in which you participate or are @mentioned. - - - Watch - -
    -
    - -
    - -
    - -

    Watching

    - You receive notifications for all discussions in this repository. - - - Unwatch - -
    -
    - -
    - -
    - -

    Ignoring

    - You do not receive any notifications for discussions in this repository. - - - Stop ignoring - -
    -
    - -
    - -
    -
    -
    - - -
  • - -
  • - - - Unstar - - - - Star - - -
  • - -
  • - - - Fork - - -
  • - - -
- -

- public - - - / - jquery -

-
- - - - -
- - - - - - -
- - -
- - - branch: - master - - -
- -
-
- Switch branches/tags - -
- -
-
- -
-
- -
-
- -
- -
- -
- - 1.8-stable -
-
- - 1.9-stable -
-
- - 1.x-master -
-
- - #13388 -
- -
- - ajax-unit -
-
- - master -
-
- -
Nothing to show
-
- - -
-
- -
- - 2.0.0-beta3 -
-
- - 2.0.0b2 -
-
- - 2.0.0b1 -
-
- - 2.0.0 -
-
- - 1.9.1 -
-
- - 1.9.0rc1 -
-
- - 1.9.0b1 -
-
- - 1.9.0 -
-
- - 1.8rc1 -
-
- - 1.8b2 -
-
- - 1.8b1 -
-
- - 1.8.3+1 -
-
- - 1.8.3 -
-
- - 1.8.2 -
-
- - 1.8.1 -
-
- - 1.8.0 -
-
- - 1.7rc2 -
-
- - 1.7rc1 -
-
- - 1.7b2 -
-
- - 1.7b1 -
-
- - 1.7.2rc1 -
-
- - 1.7.2b1 -
-
- - 1.7.2 -
-
- - 1.7.1rc1 -
-
- - 1.7.1 -
-
- - 1.7 -
-
- - 1.6rc1 -
-
- - 1.6b1 -
-
- - 1.6.4rc1 -
-
- - 1.6.4 -
-
- - 1.6.3rc1 -
-
- - 1.6.3 -
-
- - 1.6.2rc1 -
-
- - 1.6.2 -
-
- - 1.6.1rc1 -
-
- - 1.6.1 -
-
- - 1.6 -
-
- - 1.5rc1 -
-
- - 1.5b1 -
-
- - 1.5.2rc1 -
-
- - 1.5.2 -
-
- - 1.5.1rc1 -
-
- - 1.5.1 -
-
- - 1.5 -
-
- - 1.4rc1 -
-
- - 1.4a2 -
-
- - 1.4a1 -
-
- - 1.4.4rc3 -
-
- - 1.4.4rc2 -
-
- - 1.4.4rc1 -
-
- - 1.4.4 -
-
- - 1.4.3rc2 -
-
- - 1.4.3rc1 -
-
- - 1.4.3 -
-
- - 1.4.2 -
-
- - 1.4.1 -
-
- - 1.4 -
-
- - 1.3rc1 -
-
- - 1.3b2 -
-
- - 1.3b1 -
-
- - 1.3.2 -
-
- - 1.3.1rc1 -
-
- - 1.3.1 -
-
- - 1.3 -
-
- - 1.2.6 -
-
- - 1.2.5 -
-
- - 1.2.4b -
-
- - 1.2.4a -
-
- - 1.2.4 -
-
- - 1.2.3b -
-
- - 1.2.3a -
-
- - 1.2.3 -
-
- - 1.2.2b2 -
-
- - 1.2.2b -
-
- - 1.2.2 -
-
- - 1.2.1 -
-
- - 1.2 -
-
- - 1.1b -
-
- - 1.1a -
-
- - 1.1.4 -
-
- - 1.1.3a -
-
- - 1.1.3.1 -
-
- - 1.1.3 -
-
- - 1.1.2 -
-
- - 1.1.1 -
-
- - 1.1 -
-
- - 1.0a -
-
- - 1.0.4 -
-
- - 1.0.3 -
-
- - 1.0.2 -
-
- - 1.0.1 -
-
- - 1.0 -
-
- -
Nothing to show
- -
- -
-
-
- -
- - - -
- - - - - - - -
-
- -
- - - - - - - -
-
- - - - - - - - - -
- - - - - -
-

3 contributors

- - - - - -
- -
- - -
- -
-
- -
-
-
-
- - file - 22 lines (18 sloc) - 1.099 kb -
-
-
- Edit - Raw - Blame - History -
-
- -
-
-
Filtering examples
termresults in
bobbob
bob-catbob cat
- - - - -
- 1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 - - -
Copyright 2013 jQuery Foundation and other contributors
http://jquery.com/

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.
-
- - - - - - -

- - - - - - - - - - -
- - - - - - - - - -
-
-
- -
-
-
-
-
-
- -
- - - -
- - Something went wrong with that request. Please try again. - -
- - - - - - - - +Copyright OpenJS Foundation and other contributors, https://openjsf.org/ + +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/core/src/main/resources/META-INF/services/org.owasp.dependencycheck.analyzer.Analyzer b/core/src/main/resources/META-INF/services/org.owasp.dependencycheck.analyzer.Analyzer index c40992ece46..3b56712f747 100644 --- a/core/src/main/resources/META-INF/services/org.owasp.dependencycheck.analyzer.Analyzer +++ b/core/src/main/resources/META-INF/services/org.owasp.dependencycheck.analyzer.Analyzer @@ -39,6 +39,7 @@ org.owasp.dependencycheck.analyzer.RubyBundleAuditAnalyzer org.owasp.dependencycheck.analyzer.ElixirMixAuditAnalyzer org.owasp.dependencycheck.analyzer.ComposerLockAnalyzer org.owasp.dependencycheck.analyzer.CocoaPodsAnalyzer +org.owasp.dependencycheck.analyzer.CarthageAnalyzer org.owasp.dependencycheck.analyzer.SwiftPackageManagerAnalyzer org.owasp.dependencycheck.analyzer.SwiftPackageResolvedAnalyzer org.owasp.dependencycheck.analyzer.VersionFilterAnalyzer @@ -48,4 +49,5 @@ org.owasp.dependencycheck.analyzer.PinnedMavenInstallAnalyzer org.owasp.dependencycheck.analyzer.KnownExploitedVulnerabilityAnalyzer org.owasp.dependencycheck.analyzer.DartAnalyzer org.owasp.dependencycheck.analyzer.UnusedSuppressionRuleAnalyzer +org.owasp.dependencycheck.analyzer.LibmanAnalyzer diff --git a/core/src/main/resources/META-INF/services/org.owasp.dependencycheck.data.update.CachedWebDataSource b/core/src/main/resources/META-INF/services/org.owasp.dependencycheck.data.update.CachedWebDataSource index 8e10a07f8c9..06b30b96fc5 100644 --- a/core/src/main/resources/META-INF/services/org.owasp.dependencycheck.data.update.CachedWebDataSource +++ b/core/src/main/resources/META-INF/services/org.owasp.dependencycheck.data.update.CachedWebDataSource @@ -1,4 +1,4 @@ -org.owasp.dependencycheck.data.update.NvdCveUpdater +org.owasp.dependencycheck.data.update.NvdApiDataSource org.owasp.dependencycheck.data.update.EngineVersionCheck org.owasp.dependencycheck.data.update.RetireJSDataSource org.owasp.dependencycheck.data.update.HostedSuppressionsDataSource diff --git a/core/src/main/resources/data/dbStatements.properties b/core/src/main/resources/data/dbStatements.properties index 17782e10d31..c7f06782970 100644 --- a/core/src/main/resources/data/dbStatements.properties +++ b/core/src/main/resources/data/dbStatements.properties @@ -21,7 +21,7 @@ COUNT_CPE=SELECT COUNT(*) records FROM cpeEntry INSERT_CWE=INSERT INTO cweEntry (cveid, cwe) VALUES (?, ?) INSERT_REFERENCE=INSERT INTO reference (cveid, name, url, source) VALUES (?, ?, ?, ?) INSERT_SOFTWARE=CALL insert_software(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) -UPDATE_VULNERABILITY=CALL update_vulnerability(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) +UPDATE_VULNERABILITY=CALL update_vulnerability(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) SELECT_CPE_ECOSYSTEM=SELECT DISTINCT vendor, product, ecosystem FROM cpeEcosystemCache SELECT_CVE_FROM_SOFTWARE=SELECT cve, part, vendor, product, version, update_version, edition, lang, sw_edition, target_sw, target_hw, other, versionEndExcluding, versionEndIncluding, versionStartExcluding, versionStartIncluding, vulnerable FROM software INNER JOIN vulnerability ON vulnerability.id = software.cveid INNER JOIN cpeEntry ON cpeEntry.id = software.cpeEntryId WHERE vendor = ? AND product = ? ORDER BY cve, vendor, product, version, update_version @@ -30,7 +30,7 @@ SELECT_REFERENCES=SELECT source, name, url FROM reference WHERE cveid = ? SELECT_VENDOR_PRODUCT_LIST=SELECT vendor, product FROM cpeEntry GROUP BY vendor, product SELECT_VENDOR_PRODUCT_LIST_FOR_NODE=SELECT vendor, product FROM cpeEntry WHERE ecosystem like 'npm' or ecosystem like 'node.js' or target_sw like 'node.js' GROUP BY vendor, product SELECT_SOFTWARE=SELECT part, vendor, product, version, update_version, edition, lang, sw_edition, target_sw, target_hw, other, versionEndExcluding, versionEndIncluding, versionStartExcluding, versionStartIncluding, vulnerable FROM software INNER JOIN cpeEntry ON software.cpeEntryId = cpeEntry.id WHERE cveid = ? -SELECT_VULNERABILITY=SELECT id, description, v2Severity, v2ExploitabilityScore, v2ImpactScore, v2AcInsufInfo, v2ObtainAllPrivilege, v2ObtainUserPrivilege, v2ObtainOtherPrivilege, v2UserInteractionRequired, v2Score, v2AccessVector, v2AccessComplexity, v2Authentication, v2ConfidentialityImpact, v2IntegrityImpact, v2AvailabilityImpact, v2Version, v3ExploitabilityScore, v3ImpactScore, v3AttackVector, v3AttackComplexity, v3PrivilegesRequired, v3UserInteraction, v3Scope, v3ConfidentialityImpact, v3IntegrityImpact, v3AvailabilityImpact, v3BaseScore, v3BaseSeverity, v3Version FROM vulnerability WHERE cve = ? +SELECT_VULNERABILITY=SELECT id, description, v2Severity, v2ExploitabilityScore, v2ImpactScore, v2AcInsufInfo, v2ObtainAllPrivilege, v2ObtainUserPrivilege, v2ObtainOtherPrivilege, v2UserInteractionRequired, v2Score, v2AccessVector, v2AccessComplexity, v2Authentication, v2ConfidentialityImpact, v2IntegrityImpact, v2AvailabilityImpact, v2Version, v3ExploitabilityScore, v3ImpactScore, v3AttackVector, v3AttackComplexity, v3PrivilegesRequired, v3UserInteraction, v3Scope, v3ConfidentialityImpact, v3IntegrityImpact, v3AvailabilityImpact, v3BaseScore, v3BaseSeverity, v3Version, v4version, v4attackVector, v4attackComplexity, v4attackRequirements, v4privilegesRequired, v4userInteraction, v4vulnConfidentialityImpact, v4vulnIntegrityImpact, v4vulnAvailabilityImpact, v4subConfidentialityImpact, v4subIntegrityImpact, v4subAvailabilityImpact, v4exploitMaturity, v4confidentialityRequirement, v4integrityRequirement, v4availabilityRequirement, v4modifiedAttackVector, v4modifiedAttackComplexity, v4modifiedAttackRequirements, v4modifiedPrivilegesRequired, v4modifiedUserInteraction, v4modifiedVulnConfidentialityImpact, v4modifiedVulnIntegrityImpact, v4modifiedVulnAvailabilityImpact, v4modifiedSubConfidentialityImpact, v4modifiedSubIntegrityImpact, v4modifiedSubAvailabilityImpact, v4safety, v4automatable, v4recovery, v4valueDensity, v4vulnerabilityResponseEffort, v4providerUrgency, v4baseScore, v4baseSeverity, v4threatScore, v4threatSeverity, v4environmentalScore, v4environmentalSeverity, v4source, v4type FROM vulnerability WHERE cve = ? SELECT_VULNERABILITY_CWE=SELECT cwe FROM cweEntry WHERE cveid = ? SELECT_PROPERTIES=SELECT * FROM properties SELECT_PROPERTY=SELECT * FROM properties WHERE id = ? diff --git a/core/src/main/resources/data/dbStatements_h2.properties b/core/src/main/resources/data/dbStatements_h2.properties index ed8fae70bb8..7aeaa17897c 100644 --- a/core/src/main/resources/data/dbStatements_h2.properties +++ b/core/src/main/resources/data/dbStatements_h2.properties @@ -16,6 +16,6 @@ MERGE_PROPERTY=MERGE INTO properties (id, `value`) KEY(id) VALUES(?, ?) MERGE_CPE_ECOSYSTEM=MERGE INTO cpeEcosystemCache (vendor, product, ecosystem) KEY(vendor, product) VALUES(?, ?, ?) CLEANUP_ORPHANS=DELETE FROM cpeEntry WHERE id IN (SELECT id FROM cpeEntry LEFT JOIN software ON cpeEntry.id = software.CPEEntryId WHERE software.CPEEntryId IS NULL) -UPDATE_VULNERABILITY=SELECT * FROM update_vulnerability(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) +UPDATE_VULNERABILITY=SELECT * FROM update_vulnerability(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) SELECT_SCHEMA_VERSION=SELECT `value` FROM properties WHERE id = 'version' diff --git a/core/src/main/resources/data/dbStatements_microsoft sql server.properties b/core/src/main/resources/data/dbStatements_microsoft sql server.properties index a5eb15b9c7b..4a05e6da786 100644 --- a/core/src/main/resources/data/dbStatements_microsoft sql server.properties +++ b/core/src/main/resources/data/dbStatements_microsoft sql server.properties @@ -13,7 +13,7 @@ # limitations under the License. INSERT_SOFTWARE=EXEC insert_software ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? -UPDATE_VULNERABILITY=EXEC update_vulnerability ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? +UPDATE_VULNERABILITY=EXEC update_vulnerability ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? UPDATE_ECOSYSTEM=UPDATE cpeEntry SET ecosystem=cpeEcosystemCache.ecosystem FROM cpeEntry INNER JOIN cpeEcosystemCache ON cpeEcosystemCache.vendor=cpeEntry.vendor AND cpeEcosystemCache.product=cpeEntry.product WHERE cpeEntry.ecosystem IS NULL AND cpeEcosystemCache.ecosystem<>'MULTIPLE'; UPDATE_ECOSYSTEM2=UPDATE cpeEntry SET ecosystem=null FROM cpeEntry INNER JOIN cpeEcosystemCache ON cpeEcosystemCache.vendor=cpeEntry.vendor AND cpeEcosystemCache.product=cpeEntry.product WHERE cpeEcosystemCache.ecosystem='MULTIPLE' AND cpeEntry.ecosystem IS NOT NULL; diff --git a/core/src/main/resources/data/dbStatements_oracle.properties b/core/src/main/resources/data/dbStatements_oracle.properties index ee7ed4b9e70..ea99b352934 100644 --- a/core/src/main/resources/data/dbStatements_oracle.properties +++ b/core/src/main/resources/data/dbStatements_oracle.properties @@ -19,5 +19,6 @@ CLEANUP_ORPHANS=DELETE FROM cpeEntry WHERE id not in (SELECT CPEEntryId FROM sof UPDATE_ECOSYSTEM=UPDATE v_update_ecosystems SET entryEco=cachedEco WHERE entryEco IS NULL AND cachedEco <>'MULTIPLE' UPDATE_ECOSYSTEM2=UPDATE v_update_ecosystems SET entryEco = NULL WHERE cachedEco = 'MULTIPLE' AND entryEco IS NOT NULL -UPDATE_VULNERABILITY={ call update_vulnerability( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) } -MERGE_KNOWN_EXPLOITED={ CALL merge_knownexploited(?,?,?,?,?,?,?,?,?) } \ No newline at end of file +# The oracle call has one more `?` then other databases due to the `out` parameter +UPDATE_VULNERABILITY={ call update_vulnerability(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) } +MERGE_KNOWN_EXPLOITED={ CALL merge_knownexploited(?,?,?,?,?,?,?,?,?) } diff --git a/core/src/main/resources/data/dbStatements_postgresql.properties b/core/src/main/resources/data/dbStatements_postgresql.properties index 04c982502c6..2f9c3c0c31c 100644 --- a/core/src/main/resources/data/dbStatements_postgresql.properties +++ b/core/src/main/resources/data/dbStatements_postgresql.properties @@ -15,7 +15,7 @@ MERGE_PROPERTY=SELECT save_property(?, ?); CLEANUP_ORPHANS=DELETE FROM cpeEntry WHERE NOT EXISTS (SELECT * FROM software WHERE cpeEntry.id = software.CPEEntryId); INSERT_SOFTWARE=SELECT insert_software(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) -UPDATE_VULNERABILITY=SELECT update_vulnerability(?::VARCHAR(20), ?::VARCHAR(8000), ?::VARCHAR(20), ?::DECIMAL(3,1), ?::DECIMAL(3,1), ?::BOOLEAN, ?::BOOLEAN, ?:: BOOLEAN, ?::BOOLEAN, ?::BOOLEAN, ?::DECIMAL(3,1), ?::VARCHAR(20), ?::VARCHAR(20), ?::VARCHAR(20), ?::VARCHAR(20), ?::VARCHAR(20), ?::VARCHAR(20), ?::VARCHAR(5),?::DECIMAL(3,1), ?::DECIMAL(3,1), ?::VARCHAR(20), ?::VARCHAR(20), ?::VARCHAR(20), ?::VARCHAR(20), ?::VARCHAR(20), ?::VARCHAR(20), ?::VARCHAR(20), ?::VARCHAR(20), ?::DECIMAL(3,1), ?::VARCHAR(20), ?::VARCHAR(5)); +UPDATE_VULNERABILITY=SELECT update_vulnerability(?::VARCHAR(20), ?::VARCHAR(8000), ?::VARCHAR(20), ?::DECIMAL(3,1), ?::DECIMAL(3,1), ?::BOOLEAN, ?::BOOLEAN, ?:: BOOLEAN, ?::BOOLEAN, ?::BOOLEAN, ?::DECIMAL(3,1), ?::VARCHAR(20), ?::VARCHAR(20), ?::VARCHAR(20), ?::VARCHAR(20), ?::VARCHAR(20), ?::VARCHAR(20), ?::VARCHAR(5),?::DECIMAL(3,1), ?::DECIMAL(3,1), ?::VARCHAR(20), ?::VARCHAR(20), ?::VARCHAR(20), ?::VARCHAR(20), ?::VARCHAR(20), ?::VARCHAR(20), ?::VARCHAR(20), ?::VARCHAR(20), ?::DECIMAL(3,1), ?::VARCHAR(20), ?::VARCHAR(5), ?::VARCHAR(5), ?::VARCHAR(15), ?::VARCHAR(15), ?::VARCHAR(15), ?::VARCHAR(15), ?::VARCHAR(15), ?::VARCHAR(15), ?::VARCHAR(15), ?::VARCHAR(15), ?::VARCHAR(15), ?::VARCHAR(15), ?::VARCHAR(15), ?::VARCHAR(20), ?::VARCHAR(15), ?::VARCHAR(15), ?::VARCHAR(15), ?::VARCHAR(15), ?::VARCHAR(15), ?::VARCHAR(15), ?::VARCHAR(15), ?::VARCHAR(15), ?::VARCHAR(15), ?::VARCHAR(15), ?::VARCHAR(15), ?::VARCHAR(15), ?::VARCHAR(15), ?::VARCHAR(15), ?::VARCHAR(15), ?::VARCHAR(15), ?::VARCHAR(15), ?::VARCHAR(15), ?::VARCHAR(15), ?::VARCHAR(15), ?::DECIMAL(3,1), ?::VARCHAR(15), ?::DECIMAL(3,1), ?::VARCHAR(15), ?::DECIMAL(3,1), ?::VARCHAR(15), ?::VARCHAR(50), ?::VARCHAR(15)); MERGE_CPE_ECOSYSTEM=SELECT merge_ecosystem(?, ?, ?); MERGE_KNOWN_EXPLOITED=CALL merge_knownexploited(?,?,?,?,?,?,?,?,?); diff --git a/core/src/main/resources/data/initialize.sql b/core/src/main/resources/data/initialize.sql index 580aaee4fdd..b2c5ee29baf 100644 --- a/core/src/main/resources/data/initialize.sql +++ b/core/src/main/resources/data/initialize.sql @@ -20,7 +20,20 @@ CREATE TABLE vulnerability (id int auto_increment PRIMARY KEY, cve VARCHAR(20) U v3ImpactScore DECIMAL(3,1), v3AttackVector VARCHAR(20), v3AttackComplexity VARCHAR(20), v3PrivilegesRequired VARCHAR(20), v3UserInteraction VARCHAR(20), v3Scope VARCHAR(20), v3ConfidentialityImpact VARCHAR(20), v3IntegrityImpact VARCHAR(20), v3AvailabilityImpact VARCHAR(20), - v3BaseScore DECIMAL(3,1), v3BaseSeverity VARCHAR(20), v3Version VARCHAR(5)); + v3BaseScore DECIMAL(3,1), v3BaseSeverity VARCHAR(20), v3Version VARCHAR(5), + v4version VARCHAR(5), v4attackVector VARCHAR(15), v4attackComplexity VARCHAR(15), + v4attackRequirements VARCHAR(15), v4privilegesRequired VARCHAR(15), v4userInteraction VARCHAR(15), + v4vulnConfidentialityImpact VARCHAR(15), v4vulnIntegrityImpact VARCHAR(15), v4vulnAvailabilityImpact VARCHAR(15), + v4subConfidentialityImpact VARCHAR(15), v4subIntegrityImpact VARCHAR(15), + v4subAvailabilityImpact VARCHAR(15), v4exploitMaturity VARCHAR(20), v4confidentialityRequirement VARCHAR(15), + v4integrityRequirement VARCHAR(15), v4availabilityRequirement VARCHAR(15), v4modifiedAttackVector VARCHAR(15), + v4modifiedAttackComplexity VARCHAR(15), v4modifiedAttackRequirements VARCHAR(15), v4modifiedPrivilegesRequired VARCHAR(15), + v4modifiedUserInteraction VARCHAR(15), v4modifiedVulnConfidentialityImpact VARCHAR(15), v4modifiedVulnIntegrityImpact VARCHAR(15), + v4modifiedVulnAvailabilityImpact VARCHAR(15), v4modifiedSubConfidentialityImpact VARCHAR(15), v4modifiedSubIntegrityImpact VARCHAR(15), + v4modifiedSubAvailabilityImpact VARCHAR(15), v4safety VARCHAR(15), v4automatable VARCHAR(15), v4recovery VARCHAR(15), + v4valueDensity VARCHAR(15), v4vulnerabilityResponseEffort VARCHAR(15), v4providerUrgency VARCHAR(15), + v4baseScore DECIMAL(3,1), v4baseSeverity VARCHAR(15), v4threatScore DECIMAL(3,1), v4threatSeverity VARCHAR(15), + v4environmentalScore DECIMAL(3,1), v4environmentalSeverity VARCHAR(15), v4source VARCHAR(50), v4type VARCHAR(15)); CREATE TABLE reference (cveid INT, name VARCHAR(1000), url VARCHAR(1000), source VARCHAR(255), CONSTRAINT fkReference FOREIGN KEY (cveid) REFERENCES vulnerability(id) ON DELETE CASCADE); @@ -68,4 +81,4 @@ CREATE ALIAS insert_software FOR "org.owasp.dependencycheck.data.nvdcve.H2Functi CREATE ALIAS merge_knownexploited FOR "org.owasp.dependencycheck.data.nvdcve.H2Functions.mergeKnownExploited"; CREATE TABLE properties (id varchar(50) PRIMARY KEY, `value` varchar(500)); -INSERT INTO properties(id, `value`) VALUES ('version', '5.4'); \ No newline at end of file +INSERT INTO properties(id, `value`) VALUES ('version', '5.5'); \ No newline at end of file diff --git a/core/src/main/resources/data/initialize_mssql.sql b/core/src/main/resources/data/initialize_mssql.sql index 10d27e78cd2..2a79d913910 100644 --- a/core/src/main/resources/data/initialize_mssql.sql +++ b/core/src/main/resources/data/initialize_mssql.sql @@ -39,7 +39,20 @@ CREATE TABLE vulnerability (id int identity(1,1) PRIMARY KEY, cve VARCHAR(20) UN v3ImpactScore DECIMAL(3,1), v3AttackVector VARCHAR(20), v3AttackComplexity VARCHAR(20), v3PrivilegesRequired VARCHAR(20), v3UserInteraction VARCHAR(20), v3Scope VARCHAR(20), v3ConfidentialityImpact VARCHAR(20), v3IntegrityImpact VARCHAR(20), v3AvailabilityImpact VARCHAR(20), - v3BaseScore DECIMAL(3,1), v3BaseSeverity VARCHAR(20), v3Version VARCHAR(5)); + v3BaseScore DECIMAL(3,1), v3BaseSeverity VARCHAR(20), v3Version VARCHAR(5), + v4version VARCHAR(5), v4attackVector VARCHAR(15), v4attackComplexity VARCHAR(15), + v4attackRequirements VARCHAR(15), v4privilegesRequired VARCHAR(15), v4userInteraction VARCHAR(15), + v4vulnConfidentialityImpact VARCHAR(15), v4vulnIntegrityImpact VARCHAR(15), v4vulnAvailabilityImpact VARCHAR(15), + v4subConfidentialityImpact VARCHAR(15), v4subIntegrityImpact VARCHAR(15), + v4subAvailabilityImpact VARCHAR(15), v4exploitMaturity VARCHAR(20), v4confidentialityRequirement VARCHAR(15), + v4integrityRequirement VARCHAR(15), v4availabilityRequirement VARCHAR(15), v4modifiedAttackVector VARCHAR(15), + v4modifiedAttackComplexity VARCHAR(15), v4modifiedAttackRequirements VARCHAR(15), v4modifiedPrivilegesRequired VARCHAR(15), + v4modifiedUserInteraction VARCHAR(15), v4modifiedVulnConfidentialityImpact VARCHAR(15), v4modifiedVulnIntegrityImpact VARCHAR(15), + v4modifiedVulnAvailabilityImpact VARCHAR(15), v4modifiedSubConfidentialityImpact VARCHAR(15), v4modifiedSubIntegrityImpact VARCHAR(15), + v4modifiedSubAvailabilityImpact VARCHAR(15), v4safety VARCHAR(15), v4automatable VARCHAR(15), v4recovery VARCHAR(15), + v4valueDensity VARCHAR(15), v4vulnerabilityResponseEffort VARCHAR(15), v4providerUrgency VARCHAR(15), + v4baseScore DECIMAL(3,1), v4baseSeverity VARCHAR(15), v4threatScore DECIMAL(3,1), v4threatSeverity VARCHAR(15), + v4environmentalScore DECIMAL(3,1), v4environmentalSeverity VARCHAR(15), v4source VARCHAR(50), v4type VARCHAR(15)); CREATE TABLE reference (cveid INT, name VARCHAR(1000), url VARCHAR(1000), source VARCHAR(255), CONSTRAINT FK_Reference FOREIGN KEY (cveid) REFERENCES vulnerability(id) ON DELETE CASCADE); @@ -75,7 +88,7 @@ CREATE TABLE knownExploited (cveID varchar(20) PRIMARY KEY, notes VARCHAR(2000)); CREATE INDEX idxCwe ON cweEntry(cveid); -CREATE INDEX idxVulnerability ON vulnerability(cve); +--CREATE INDEX idxVulnerability ON vulnerability(cve); CREATE INDEX idxReference ON reference(cveid); CREATE INDEX idxSoftwareCve ON software(cveid); CREATE INDEX idxSoftwareCpe ON software(cpeEntryId); @@ -120,7 +133,20 @@ CREATE PROCEDURE update_vulnerability ( @v3AttackComplexity VARCHAR(20), @v3PrivilegesRequired VARCHAR(20), @v3UserInteraction VARCHAR(20), @v3Scope VARCHAR(20), @v3ConfidentialityImpact VARCHAR(20), @v3IntegrityImpact VARCHAR(20), @v3AvailabilityImpact VARCHAR(20), @v3BaseScore DECIMAL(3,1), @v3BaseSeverity VARCHAR(20), - @v3Version VARCHAR(5)) AS + @v3Version VARCHAR(5), @v4version VARCHAR(5), @v4attackVector VARCHAR(15), @v4attackComplexity VARCHAR(15), + @v4attackRequirements VARCHAR(15), @v4privilegesRequired VARCHAR(15), @v4userInteraction VARCHAR(15), + @v4vulnConfidentialityImpact VARCHAR(15), @v4vulnIntegrityImpact VARCHAR(15), @v4vulnAvailabilityImpact VARCHAR(15), + @v4subConfidentialityImpact VARCHAR(15), @v4subIntegrityImpact VARCHAR(15), @v4subAvailabilityImpact VARCHAR(15), + @v4exploitMaturity VARCHAR(20), @v4confidentialityRequirement VARCHAR(15), @v4integrityRequirement VARCHAR(15), + @v4availabilityRequirement VARCHAR(15), @v4modifiedAttackVector VARCHAR(15), @v4modifiedAttackComplexity VARCHAR(15), + @v4modifiedAttackRequirements VARCHAR(15), @v4modifiedPrivilegesRequired VARCHAR(15), @v4modifiedUserInteraction VARCHAR(15), + @v4modifiedVulnConfidentialityImpact VARCHAR(15), @v4modifiedVulnIntegrityImpact VARCHAR(15), + @v4modifiedVulnAvailabilityImpact VARCHAR(15), @v4modifiedSubConfidentialityImpact VARCHAR(15), + @v4modifiedSubIntegrityImpact VARCHAR(15), @v4modifiedSubAvailabilityImpact VARCHAR(15), @v4safety VARCHAR(15), + @v4automatable VARCHAR(15), @v4recovery VARCHAR(15), @v4valueDensity VARCHAR(15), @v4vulnerabilityResponseEffort VARCHAR(15), + @v4providerUrgency VARCHAR(15), @v4baseScore DECIMAL(3,1), @v4baseSeverity VARCHAR(15), @v4threatScore DECIMAL(3,1), + @v4threatSeverity VARCHAR(15), @v4environmentalScore DECIMAL(3,1), @v4environmentalSeverity VARCHAR(15), + @v4source VARCHAR(15), @v4type VARCHAR(15)) AS BEGIN DECLARE @vulnerabilityId INT; @@ -141,7 +167,24 @@ BEGIN v3ExploitabilityScore=@v3ExploitabilityScore, v3ImpactScore=@v3ImpactScore, v3AttackVector=@v3AttackVector, v3AttackComplexity=@v3AttackComplexity, v3PrivilegesRequired=@v3PrivilegesRequired, v3UserInteraction=@v3UserInteraction, v3Scope=@v3Scope, v3ConfidentialityImpact=@v3ConfidentialityImpact, v3IntegrityImpact=@v3IntegrityImpact, - v3AvailabilityImpact=@v3AvailabilityImpact, v3BaseScore=@v3BaseScore, v3BaseSeverity=@v3BaseSeverity, v3Version=@v3Version + v3AvailabilityImpact=@v3AvailabilityImpact, v3BaseScore=@v3BaseScore, v3BaseSeverity=@v3BaseSeverity, v3Version=@v3Version, + v4version=@v4version, v4attackVector=@v4attackVector, v4attackComplexity=@v4attackComplexity, v4attackRequirements=@v4attackRequirements, + v4privilegesRequired=@v4privilegesRequired, v4userInteraction=@v4userInteraction, v4vulnConfidentialityImpact=@v4vulnConfidentialityImpact, + v4vulnIntegrityImpact=@v4vulnIntegrityImpact, v4vulnAvailabilityImpact=@v4vulnAvailabilityImpact, + v4subConfidentialityImpact=@v4subConfidentialityImpact, v4subIntegrityImpact=@v4subIntegrityImpact, + v4subAvailabilityImpact=@v4subAvailabilityImpact, v4exploitMaturity=@v4exploitMaturity, + v4confidentialityRequirement=@v4confidentialityRequirement, v4integrityRequirement=@v4integrityRequirement, + v4availabilityRequirement=@v4availabilityRequirement, v4modifiedAttackVector=@v4modifiedAttackVector, + v4modifiedAttackComplexity=@v4modifiedAttackComplexity, v4modifiedAttackRequirements=@v4modifiedAttackRequirements, + v4modifiedPrivilegesRequired=@v4modifiedPrivilegesRequired, v4modifiedUserInteraction=@v4modifiedUserInteraction, + v4modifiedVulnConfidentialityImpact=@v4modifiedVulnConfidentialityImpact, v4modifiedVulnIntegrityImpact=@v4modifiedVulnIntegrityImpact, + v4modifiedVulnAvailabilityImpact=@v4modifiedVulnAvailabilityImpact, v4modifiedSubConfidentialityImpact=@v4modifiedSubConfidentialityImpact, + v4modifiedSubIntegrityImpact=@v4modifiedSubIntegrityImpact, v4modifiedSubAvailabilityImpact=@v4modifiedSubAvailabilityImpact, + v4safety=@v4safety, v4automatable=@v4automatable, v4recovery=@v4recovery, v4valueDensity=@v4valueDensity, + v4vulnerabilityResponseEffort=@v4vulnerabilityResponseEffort, v4providerUrgency=@v4providerUrgency, + v4baseScore=@v4baseScore, v4baseSeverity=@v4baseSeverity, v4threatScore=@v4threatScore, + v4threatSeverity=@v4threatSeverity, v4environmentalScore=@v4environmentalScore, + v4environmentalSeverity=@v4environmentalSeverity, v4source=@v4source, v4type=@v4type WHERE id=@vulnerabilityId; END ELSE @@ -156,7 +199,18 @@ BEGIN v3ImpactScore, v3AttackVector, v3AttackComplexity, v3PrivilegesRequired, v3UserInteraction, v3Scope, v3ConfidentialityImpact, v3IntegrityImpact, v3AvailabilityImpact, - v3BaseScore, v3BaseSeverity, v3Version) + v3BaseScore, v3BaseSeverity, v3Version, v4version, v4attackVector, + v4attackComplexity, v4attackRequirements, v4privilegesRequired, v4userInteraction, + v4vulnConfidentialityImpact, v4vulnIntegrityImpact, v4vulnAvailabilityImpact, + v4subConfidentialityImpact, v4subIntegrityImpact, v4subAvailabilityImpact, + v4exploitMaturity, v4confidentialityRequirement, v4integrityRequirement, + v4availabilityRequirement, v4modifiedAttackVector, v4modifiedAttackComplexity, + v4modifiedAttackRequirements, v4modifiedPrivilegesRequired, v4modifiedUserInteraction, + v4modifiedVulnConfidentialityImpact, v4modifiedVulnIntegrityImpact, v4modifiedVulnAvailabilityImpact, + v4modifiedSubConfidentialityImpact, v4modifiedSubIntegrityImpact, v4modifiedSubAvailabilityImpact, + v4safety, v4automatable, v4recovery, v4valueDensity, v4vulnerabilityResponseEffort, + v4providerUrgency, v4baseScore, v4baseSeverity, v4threatScore, v4threatSeverity, + v4environmentalScore, v4environmentalSeverity, v4source, v4type) VALUES (@cveId, @description, @v2Severity, @v2ExploitabilityScore, @v2ImpactScore, @v2AcInsufInfo, @v2ObtainAllPrivilege, @@ -167,7 +221,19 @@ BEGIN @v3ImpactScore, @v3AttackVector, @v3AttackComplexity, @v3PrivilegesRequired, @v3UserInteraction, @v3Scope, @v3ConfidentialityImpact, @v3IntegrityImpact, @v3AvailabilityImpact, - @v3BaseScore, @v3BaseSeverity, @v3Version); + @v3BaseScore, @v3BaseSeverity, @v3Version, @v4version, @v4attackVector, + @v4attackComplexity, @v4attackRequirements, @v4privilegesRequired, + @v4userInteraction, @v4vulnConfidentialityImpact, @v4vulnIntegrityImpact, + @v4vulnAvailabilityImpact, @v4subConfidentialityImpact, @v4subIntegrityImpact, + @v4subAvailabilityImpact, @v4exploitMaturity, @v4confidentialityRequirement, + @v4integrityRequirement, @v4availabilityRequirement, @v4modifiedAttackVector, + @v4modifiedAttackComplexity, @v4modifiedAttackRequirements, @v4modifiedPrivilegesRequired, + @v4modifiedUserInteraction, @v4modifiedVulnConfidentialityImpact, @v4modifiedVulnIntegrityImpact, + @v4modifiedVulnAvailabilityImpact, @v4modifiedSubConfidentialityImpact, @v4modifiedSubIntegrityImpact, + @v4modifiedSubAvailabilityImpact, @v4safety, @v4automatable, @v4recovery, @v4valueDensity, + @v4vulnerabilityResponseEffort, @v4providerUrgency, @v4baseScore, @v4baseSeverity, + @v4threatScore, @v4threatSeverity, @v4environmentalScore, @v4environmentalSeverity, + @v4source, @v4type); SET @vulnerabilityId = SCOPE_IDENTITY(); END; @@ -245,7 +311,7 @@ END; GO -INSERT INTO properties(id,value) VALUES ('version','5.4'); +INSERT INTO properties(id,value) VALUES ('version','5.5'); GO /** diff --git a/core/src/main/resources/data/initialize_mysql.sql b/core/src/main/resources/data/initialize_mysql.sql index 68bf7d61e7e..52fe18fea6f 100644 --- a/core/src/main/resources/data/initialize_mysql.sql +++ b/core/src/main/resources/data/initialize_mysql.sql @@ -39,7 +39,20 @@ CREATE TABLE vulnerability (id int auto_increment PRIMARY KEY, cve VARCHAR(20) U v3ImpactScore DECIMAL(3,1), v3AttackVector VARCHAR(20), v3AttackComplexity VARCHAR(20), v3PrivilegesRequired VARCHAR(20), v3UserInteraction VARCHAR(20), v3Scope VARCHAR(20), v3ConfidentialityImpact VARCHAR(20), v3IntegrityImpact VARCHAR(20), v3AvailabilityImpact VARCHAR(20), - v3BaseScore DECIMAL(3,1), v3BaseSeverity VARCHAR(20), v3Version VARCHAR(5)); + v3BaseScore DECIMAL(3,1), v3BaseSeverity VARCHAR(20), v3Version VARCHAR(5), + v4version VARCHAR(5), v4attackVector VARCHAR(15), v4attackComplexity VARCHAR(15), + v4attackRequirements VARCHAR(15), v4privilegesRequired VARCHAR(15), v4userInteraction VARCHAR(15), + v4vulnConfidentialityImpact VARCHAR(15), v4vulnIntegrityImpact VARCHAR(15), v4vulnAvailabilityImpact VARCHAR(15), + v4subConfidentialityImpact VARCHAR(15), v4subIntegrityImpact VARCHAR(15), + v4subAvailabilityImpact VARCHAR(15), v4exploitMaturity VARCHAR(20), v4confidentialityRequirement VARCHAR(15), + v4integrityRequirement VARCHAR(15), v4availabilityRequirement VARCHAR(15), v4modifiedAttackVector VARCHAR(15), + v4modifiedAttackComplexity VARCHAR(15), v4modifiedAttackRequirements VARCHAR(15), v4modifiedPrivilegesRequired VARCHAR(15), + v4modifiedUserInteraction VARCHAR(15), v4modifiedVulnConfidentialityImpact VARCHAR(15), v4modifiedVulnIntegrityImpact VARCHAR(15), + v4modifiedVulnAvailabilityImpact VARCHAR(15), v4modifiedSubConfidentialityImpact VARCHAR(15), v4modifiedSubIntegrityImpact VARCHAR(15), + v4modifiedSubAvailabilityImpact VARCHAR(15), v4safety VARCHAR(15), v4automatable VARCHAR(15), v4recovery VARCHAR(15), + v4valueDensity VARCHAR(15), v4vulnerabilityResponseEffort VARCHAR(15), v4providerUrgency VARCHAR(15), + v4baseScore DECIMAL(3,1), v4baseSeverity VARCHAR(15), v4threatScore DECIMAL(3,1), v4threatSeverity VARCHAR(15), + v4environmentalScore DECIMAL(3,1), v4environmentalSeverity VARCHAR(15), v4source VARCHAR(50), v4type VARCHAR(15)); CREATE TABLE `reference` (cveid INT, name VARCHAR(1000), url VARCHAR(1000), source VARCHAR(255), CONSTRAINT fkReference FOREIGN KEY (cveid) REFERENCES vulnerability(id) ON DELETE CASCADE); @@ -74,7 +87,7 @@ CREATE TABLE knownExploited (cveID varchar(20) PRIMARY KEY , notes VARCHAR(2000)); CREATE INDEX idxCwe ON cweEntry(cveid); -CREATE INDEX idxVulnerability ON vulnerability(cve); +--CREATE INDEX idxVulnerability ON vulnerability(cve); CREATE INDEX idxReference ON `reference`(cveid); CREATE INDEX idxCpe ON cpeEntry(vendor, product); CREATE INDEX idxSoftwareCve ON software(cveid); @@ -133,7 +146,20 @@ CREATE PROCEDURE update_vulnerability ( IN p_v3AttackComplexity VARCHAR(20), IN p_v3PrivilegesRequired VARCHAR(20), IN p_v3UserInteraction VARCHAR(20), IN p_v3Scope VARCHAR(20), IN p_v3ConfidentialityImpact VARCHAR(20), IN p_v3IntegrityImpact VARCHAR(20), IN p_v3AvailabilityImpact VARCHAR(20), IN p_v3BaseScore DECIMAL(3,1), IN p_v3BaseSeverity VARCHAR(20), - IN p_v3Version VARCHAR(5)) + IN p_v3Version VARCHAR(5), IN p_v4version VARCHAR(5), IN p_v4attackVector VARCHAR(15), IN p_v4attackComplexity VARCHAR(15), + IN p_v4attackRequirements VARCHAR(15), IN p_v4privilegesRequired VARCHAR(15), IN p_v4userInteraction VARCHAR(15), + IN p_v4vulnConfidentialityImpact VARCHAR(15), IN p_v4vulnIntegrityImpact VARCHAR(15), IN p_v4vulnAvailabilityImpact VARCHAR(15), + IN p_v4subConfidentialityImpact VARCHAR(15), IN p_v4subIntegrityImpact VARCHAR(15), IN p_v4subAvailabilityImpact VARCHAR(15), + IN p_v4exploitMaturity VARCHAR(20), IN p_v4confidentialityRequirement VARCHAR(15), IN p_v4integrityRequirement VARCHAR(15), + IN p_v4availabilityRequirement VARCHAR(15), IN p_v4modifiedAttackVector VARCHAR(15), IN p_v4modifiedAttackComplexity VARCHAR(15), + IN p_v4modifiedAttackRequirements VARCHAR(15), IN p_v4modifiedPrivilegesRequired VARCHAR(15), IN p_v4modifiedUserInteraction VARCHAR(15), + IN p_v4modifiedVulnConfidentialityImpact VARCHAR(15), IN p_v4modifiedVulnIntegrityImpact VARCHAR(15), + IN p_v4modifiedVulnAvailabilityImpact VARCHAR(15), IN p_v4modifiedSubConfidentialityImpact VARCHAR(15), + IN p_v4modifiedSubIntegrityImpact VARCHAR(15), IN p_v4modifiedSubAvailabilityImpact VARCHAR(15), IN p_v4safety VARCHAR(15), + IN p_v4automatable VARCHAR(15), IN p_v4recovery VARCHAR(15), IN p_v4valueDensity VARCHAR(15), IN p_v4vulnerabilityResponseEffort VARCHAR(15), + IN p_v4providerUrgency VARCHAR(15), IN p_v4baseScore DECIMAL(3,1), IN p_v4baseSeverity VARCHAR(15), IN p_v4threatScore DECIMAL(3,1), + IN p_v4threatSeverity VARCHAR(15), IN p_v4environmentalScore DECIMAL(3,1), IN p_v4environmentalSeverity VARCHAR(15), + IN p_v4source VARCHAR(50), IN p_v4type VARCHAR(15)) BEGIN DECLARE vulnerabilityId INT DEFAULT 0; @@ -160,7 +186,25 @@ IF vulnerabilityId > 0 THEN `v3ExploitabilityScore`=p_v3ExploitabilityScore, `v3ImpactScore`=p_v3ImpactScore, `v3AttackVector`=p_v3AttackVector, `v3AttackComplexity`=p_v3AttackComplexity, `v3PrivilegesRequired`=p_v3PrivilegesRequired, `v3UserInteraction`=p_v3UserInteraction, `v3Scope`=p_v3Scope, `v3ConfidentialityImpact`=p_v3ConfidentialityImpact, `v3IntegrityImpact`=p_v3IntegrityImpact, - `v3AvailabilityImpact`=p_v3AvailabilityImpact, `v3BaseScore`=p_v3BaseScore, `v3BaseSeverity`=p_v3BaseSeverity, `v3Version`=p_v3Version + `v3AvailabilityImpact`=p_v3AvailabilityImpact, `v3BaseScore`=p_v3BaseScore, `v3BaseSeverity`=p_v3BaseSeverity, `v3Version`=p_v3Version, + `v4version`=p_v4version, `v4attackVector`=p_v4attackVector, `v4attackComplexity`=p_v4attackComplexity, + `v4attackRequirements`=p_v4attackRequirements, `v4privilegesRequired`=p_v4privilegesRequired, + `v4userInteraction`=p_v4userInteraction, `v4vulnConfidentialityImpact`=p_v4vulnConfidentialityImpact, + `v4vulnIntegrityImpact`=p_v4vulnIntegrityImpact, `v4vulnAvailabilityImpact`=p_v4vulnAvailabilityImpact, + `v4subConfidentialityImpact`=p_v4subConfidentialityImpact, `v4subIntegrityImpact`=p_v4subIntegrityImpact, + `v4subAvailabilityImpact`=p_v4subAvailabilityImpact, `v4exploitMaturity`=p_v4exploitMaturity, + `v4confidentialityRequirement`=p_v4confidentialityRequirement, `v4integrityRequirement`=p_v4integrityRequirement, + `v4availabilityRequirement`=p_v4availabilityRequirement, `v4modifiedAttackVector`=p_v4modifiedAttackVector, + `v4modifiedAttackComplexity`=p_v4modifiedAttackComplexity, `v4modifiedAttackRequirements`=p_v4modifiedAttackRequirements, + `v4modifiedPrivilegesRequired`=p_v4modifiedPrivilegesRequired, `v4modifiedUserInteraction`=p_v4modifiedUserInteraction, + `v4modifiedVulnConfidentialityImpact`=p_v4modifiedVulnConfidentialityImpact, `v4modifiedVulnIntegrityImpact`=p_v4modifiedVulnIntegrityImpact, + `v4modifiedVulnAvailabilityImpact`=p_v4modifiedVulnAvailabilityImpact, `v4modifiedSubConfidentialityImpact`=p_v4modifiedSubConfidentialityImpact, + `v4modifiedSubIntegrityImpact`=p_v4modifiedSubIntegrityImpact, `v4modifiedSubAvailabilityImpact`=p_v4modifiedSubAvailabilityImpact, + `v4safety`=p_v4safety, `v4automatable`=p_v4automatable, `v4recovery`=p_v4recovery, `v4valueDensity`=p_v4valueDensity, + `v4vulnerabilityResponseEffort`=p_v4vulnerabilityResponseEffort, `v4providerUrgency`=p_v4providerUrgency, + `v4baseScore`=p_v4baseScore, `v4baseSeverity`=p_v4baseSeverity, `v4threatScore`=p_v4threatScore, + `v4threatSeverity`=p_v4threatSeverity, `v4environmentalScore`=p_v4environmentalScore, `v4environmentalSeverity`=p_v4environmentalSeverity, + `v4source`=p_v4source, `v4type`=p_v4type WHERE id=vulnerabilityId; ELSE INSERT INTO vulnerability (`cve`, `description`, @@ -173,7 +217,20 @@ ELSE `v3ImpactScore`, `v3AttackVector`, `v3AttackComplexity`, `v3PrivilegesRequired`, `v3UserInteraction`, `v3Scope`, `v3ConfidentialityImpact`, `v3IntegrityImpact`, `v3AvailabilityImpact`, - `v3BaseScore`, `v3BaseSeverity`, `v3Version`) + `v3BaseScore`, `v3BaseSeverity`, `v3Version`, `v4version`, `v4attackVector`, + `v4attackComplexity`, `v4attackRequirements`, `v4privilegesRequired`, `v4userInteraction`, + `v4vulnConfidentialityImpact`, `v4vulnIntegrityImpact`, `v4vulnAvailabilityImpact`, + `v4subConfidentialityImpact`, `v4subIntegrityImpact`, `v4subAvailabilityImpact`, + `v4exploitMaturity`, `v4confidentialityRequirement`, `v4integrityRequirement`, + `v4availabilityRequirement`, `v4modifiedAttackVector`, `v4modifiedAttackComplexity`, + `v4modifiedAttackRequirements`, `v4modifiedPrivilegesRequired`, `v4modifiedUserInteraction`, + `v4modifiedVulnConfidentialityImpact`, `v4modifiedVulnIntegrityImpact`, + `v4modifiedVulnAvailabilityImpact`, `v4modifiedSubConfidentialityImpact`, + `v4modifiedSubIntegrityImpact`, `v4modifiedSubAvailabilityImpact`, `v4safety`, + `v4automatable`, `v4recovery`, `v4valueDensity`, `v4vulnerabilityResponseEffort`, + `v4providerUrgency`, `v4baseScore`, `v4baseSeverity`, `v4threatScore`, + `v4threatSeverity`, `v4environmentalScore`, `v4environmentalSeverity`, + `v4source`, `v4type`) VALUES (p_cveId, p_description, p_v2Severity, p_v2ExploitabilityScore, p_v2ImpactScore, p_v2AcInsufInfo, p_v2ObtainAllPrivilege, @@ -184,7 +241,18 @@ ELSE p_v3ImpactScore, p_v3AttackVector, p_v3AttackComplexity, p_v3PrivilegesRequired, p_v3UserInteraction, p_v3Scope, p_v3ConfidentialityImpact, p_v3IntegrityImpact, p_v3AvailabilityImpact, - p_v3BaseScore, p_v3BaseSeverity, p_v3Version); + p_v3BaseScore, p_v3BaseSeverity, p_v3Version, p_v4version, + p_v4attackVector, p_v4attackComplexity, p_v4attackRequirements, p_v4privilegesRequired, + p_v4userInteraction, p_v4vulnConfidentialityImpact, p_v4vulnIntegrityImpact, p_v4vulnAvailabilityImpact, + p_v4subConfidentialityImpact, p_v4subIntegrityImpact, p_v4subAvailabilityImpact, p_v4exploitMaturity, + p_v4confidentialityRequirement, p_v4integrityRequirement, p_v4availabilityRequirement, + p_v4modifiedAttackVector, p_v4modifiedAttackComplexity, p_v4modifiedAttackRequirements, + p_v4modifiedPrivilegesRequired, p_v4modifiedUserInteraction, p_v4modifiedVulnConfidentialityImpact, + p_v4modifiedVulnIntegrityImpact, p_v4modifiedVulnAvailabilityImpact, p_v4modifiedSubConfidentialityImpact, + p_v4modifiedSubIntegrityImpact, p_v4modifiedSubAvailabilityImpact, p_v4safety, p_v4automatable, p_v4recovery, + p_v4valueDensity, p_v4vulnerabilityResponseEffort, p_v4providerUrgency, p_v4baseScore, p_v4baseSeverity, + p_v4threatScore, p_v4threatSeverity, p_v4environmentalScore, p_v4environmentalSeverity, + p_v4source, p_v4type); SET vulnerabilityId = LAST_INSERT_ID(); END IF; @@ -311,4 +379,4 @@ GRANT EXECUTE ON PROCEDURE dependencycheck.merge_knownexploited TO 'dcuser'; GRANT SELECT, INSERT, UPDATE, DELETE ON dependencycheck.* TO 'dcuser'; -INSERT INTO properties(id, value) VALUES ('version', '5.4'); +INSERT INTO properties(id, value) VALUES ('version', '5.5'); diff --git a/core/src/main/resources/data/initialize_oracle.sql b/core/src/main/resources/data/initialize_oracle.sql index 710098e3c7d..483a0071814 100644 --- a/core/src/main/resources/data/initialize_oracle.sql +++ b/core/src/main/resources/data/initialize_oracle.sql @@ -120,7 +120,20 @@ CREATE TABLE vulnerability (id INT NOT NULL PRIMARY KEY, cve VARCHAR(20) UNIQUE, v3ImpactScore DECIMAL(3,1), v3AttackVector VARCHAR(20), v3AttackComplexity VARCHAR(20), v3PrivilegesRequired VARCHAR(20), v3UserInteraction VARCHAR(20), v3Scope VARCHAR(20), v3ConfidentialityImpact VARCHAR(20), v3IntegrityImpact VARCHAR(20), v3AvailabilityImpact VARCHAR(20), - v3BaseScore DECIMAL(3,1), v3BaseSeverity VARCHAR(20), v3Version VARCHAR(5)); + v3BaseScore DECIMAL(3,1), v3BaseSeverity VARCHAR(20), v3Version VARCHAR(5), + v4version VARCHAR(5), v4attackVector VARCHAR(15), v4attackComplexity VARCHAR(15), + v4attackRequirements VARCHAR(15), v4privilegesRequired VARCHAR(15), v4userInteraction VARCHAR(15), + v4vulnConfidentialityImpact VARCHAR(15), v4vulnIntegrityImpact VARCHAR(15), v4vulnAvailabilityImpact VARCHAR(15), + v4subConfidentialityImpact VARCHAR(15), v4subIntegrityImpact VARCHAR(15), + v4subAvailabilityImpact VARCHAR(15), v4exploitMaturity VARCHAR(20), v4confidentialityRequirement VARCHAR(15), + v4integrityRequirement VARCHAR(15), v4availabilityRequirement VARCHAR(15), v4modifiedAttackVector VARCHAR(15), + v4modifiedAttackComplexity VARCHAR(15), v4modifiedAttackRequirements VARCHAR(15), v4modifiedPrivilegesRequired VARCHAR(15), + v4modifiedUserInteraction VARCHAR(15), v4modifiedVulnConfidentialityImpact VARCHAR(15), v4modifiedVulnIntegrityImpact VARCHAR(15), + v4modifiedVulnAvailabilityImpact VARCHAR(15), v4modifiedSubConfidentialityImpact VARCHAR(15), v4modifiedSubIntegrityImpact VARCHAR(15), + v4modifiedSubAvailabilityImpact VARCHAR(15), v4safety VARCHAR(15), v4automatable VARCHAR(15), v4recovery VARCHAR(15), + v4valueDensity VARCHAR(15), v4vulnerabilityResponseEffort VARCHAR(15), v4providerUrgency VARCHAR(15), + v4baseScore DECIMAL(3,1), v4baseSeverity VARCHAR(15), v4threatScore DECIMAL(3,1), v4threatSeverity VARCHAR(15), + v4environmentalScore DECIMAL(3,1), v4environmentalSeverity VARCHAR(15), v4source VARCHAR(50), v4type VARCHAR(15)); CREATE TABLE reference (cveid INT, name VARCHAR(1000), url VARCHAR(1000), source VARCHAR(255), CONSTRAINT fkReference FOREIGN KEY (cveid) REFERENCES vulnerability(id) ON DELETE CASCADE); @@ -271,6 +284,47 @@ CREATE OR REPLACE PROCEDURE update_vulnerability(p_cveId IN vulnerability.cve%ty p_v3BaseScore IN vulnerability.v3BaseScore%type, p_v3BaseSeverity IN vulnerability.v3BaseSeverity%type, p_v3Version IN vulnerability.v3Version%type, + p_v4version IN vulnerability.v4version%type, + p_v4attackVector IN vulnerability.v4attackVector%type, + p_v4attackComplexity IN vulnerability.v4attackComplexity%type, + p_v4attackRequirements IN vulnerability.v4attackRequirements%type, + p_v4privilegesRequired IN vulnerability.v4privilegesRequired%type, + p_v4userInteraction IN vulnerability.v4userInteraction%type, + p_v4vulnConfidentialityImpact IN vulnerability.v4vulnConfidentialityImpact%type, + p_v4vulnIntegrityImpact IN vulnerability.v4vulnIntegrityImpact%type, + p_v4vulnAvailabilityImpact IN vulnerability.v4vulnAvailabilityImpact%type, + p_v4subConfidentialityImpact IN vulnerability.v4subConfidentialityImpact%type, + p_v4subIntegrityImpact IN vulnerability.v4subIntegrityImpact%type, + p_v4subAvailabilityImpact IN vulnerability.v4subAvailabilityImpact%type, + p_v4exploitMaturity IN vulnerability.v4exploitMaturity%type, + p_v4confidentialityRequirement IN vulnerability.v4confidentialityRequirement%type, + p_v4integrityRequirement IN vulnerability.v4integrityRequirement%type, + p_v4availabilityRequirement IN vulnerability.v4availabilityRequirement%type, + p_v4modifiedAttackVector IN vulnerability.v4modifiedAttackVector%type, + p_v4modifiedAttackComplexity IN vulnerability.v4modifiedAttackComplexity%type, + p_v4modifiedAttackRequirements IN vulnerability.v4modifiedAttackRequirements%type, + p_v4modifiedPrivilegesRequired IN vulnerability.v4modifiedPrivilegesRequired%type, + p_v4modifiedUserInteraction IN vulnerability.v4modifiedUserInteraction%type, + p_v4modifiedVulnConfidentialityImpact IN vulnerability.v4modifiedVulnConfidentialityImpact%type, + p_v4modifiedVulnIntegrityImpact IN vulnerability.v4modifiedVulnIntegrityImpact%type, + p_v4modifiedVulnAvailabilityImpact IN vulnerability.v4modifiedVulnAvailabilityImpact%type, + p_v4modifiedSubConfidentialityImpact IN vulnerability.v4modifiedSubConfidentialityImpact%type, + p_v4modifiedSubIntegrityImpact IN vulnerability.v4modifiedSubIntegrityImpact%type, + p_v4modifiedSubAvailabilityImpact IN vulnerability.v4modifiedSubAvailabilityImpact%type, + p_v4safety IN vulnerability.v4safety%type, + p_v4automatable IN vulnerability.v4automatable%type, + p_v4recovery IN vulnerability.v4recovery%type, + p_v4valueDensity IN vulnerability.v4valueDensity%type, + p_v4vulnerabilityResponseEffort IN vulnerability.v4vulnerabilityResponseEffort%type, + p_v4providerUrgency IN vulnerability.v4providerUrgency%type, + p_v4baseScore IN vulnerability.v4baseScore%type, + p_v4baseSeverity IN vulnerability.v4baseSeverity%type, + p_v4threatScore IN vulnerability.v4threatScore%type, + p_v4threatSeverity IN vulnerability.v4threatSeverity%type, + p_v4environmentalScore IN vulnerability.v4environmentalScore%type, + p_v4environmentalSeverity IN vulnerability.v4environmentalSeverity%type, + p_v4source IN vulnerability.v4source%type, + p_v4type IN vulnerability.v4type%type, vulnerabilityId OUT vulnerability.id%type) AS BEGIN @@ -309,7 +363,25 @@ BEGIN v3AvailabilityImpact=p_v3AvailabilityImpact, v3BaseScore=p_v3BaseScore, v3BaseSeverity=p_v3BaseSeverity, - v3Version=p_v3Version + v3Version=p_v3Version, + v4version=p_v4version, v4attackVector=p_v4attackVector, v4attackComplexity=p_v4attackComplexity, + v4attackRequirements=p_v4attackRequirements, v4privilegesRequired=p_v4privilegesRequired, + v4userInteraction=p_v4userInteraction, v4vulnConfidentialityImpact=p_v4vulnConfidentialityImpact, + v4vulnIntegrityImpact=p_v4vulnIntegrityImpact, v4vulnAvailabilityImpact=p_v4vulnAvailabilityImpact, + v4subConfidentialityImpact=p_v4subConfidentialityImpact, v4subIntegrityImpact=p_v4subIntegrityImpact, + v4subAvailabilityImpact=p_v4subAvailabilityImpact, v4exploitMaturity=p_v4exploitMaturity, + v4confidentialityRequirement=p_v4confidentialityRequirement, v4integrityRequirement=p_v4integrityRequirement, + v4availabilityRequirement=p_v4availabilityRequirement, v4modifiedAttackVector=p_v4modifiedAttackVector, + v4modifiedAttackComplexity=p_v4modifiedAttackComplexity, v4modifiedAttackRequirements=p_v4modifiedAttackRequirements, + v4modifiedPrivilegesRequired=p_v4modifiedPrivilegesRequired, v4modifiedUserInteraction=p_v4modifiedUserInteraction, + v4modifiedVulnConfidentialityImpact=p_v4modifiedVulnConfidentialityImpact, v4modifiedVulnIntegrityImpact=p_v4modifiedVulnIntegrityImpact, + v4modifiedVulnAvailabilityImpact=p_v4modifiedVulnAvailabilityImpact, v4modifiedSubConfidentialityImpact=p_v4modifiedSubConfidentialityImpact, + v4modifiedSubIntegrityImpact=p_v4modifiedSubIntegrityImpact, v4modifiedSubAvailabilityImpact=p_v4modifiedSubAvailabilityImpact, + v4safety=p_v4safety, v4automatable=p_v4automatable, v4recovery=p_v4recovery, v4valueDensity=p_v4valueDensity, + v4vulnerabilityResponseEffort=p_v4vulnerabilityResponseEffort, v4providerUrgency=p_v4providerUrgency, + v4baseScore=p_v4baseScore, v4baseSeverity=p_v4baseSeverity, v4threatScore=p_v4threatScore, + v4threatSeverity=p_v4threatSeverity, v4environmentalScore=p_v4environmentalScore, v4environmentalSeverity=p_v4environmentalSeverity, + v4source=p_v4source, v4type=p_v4type WHERE id = vulnerabilityId; EXCEPTION WHEN NO_DATA_FOUND THEN @@ -323,7 +395,17 @@ BEGIN v3ImpactScore, v3AttackVector, v3AttackComplexity, v3PrivilegesRequired, v3UserInteraction, v3Scope, v3ConfidentialityImpact, v3IntegrityImpact, v3AvailabilityImpact, - v3BaseScore, v3BaseSeverity, v3Version) + v3BaseScore, v3BaseSeverity, v3Version, v4version, + v4attackVector, v4attackComplexity, v4attackRequirements, v4privilegesRequired, + v4userInteraction, v4vulnConfidentialityImpact, v4vulnIntegrityImpact, v4vulnAvailabilityImpact, + v4subConfidentialityImpact, v4subIntegrityImpact, v4subAvailabilityImpact, v4exploitMaturity, + v4confidentialityRequirement, v4integrityRequirement, v4availabilityRequirement, + v4modifiedAttackVector, v4modifiedAttackComplexity, v4modifiedAttackRequirements, + v4modifiedPrivilegesRequired, v4modifiedUserInteraction, v4modifiedVulnConfidentialityImpact, + v4modifiedVulnIntegrityImpact, v4modifiedVulnAvailabilityImpact, v4modifiedSubConfidentialityImpact, + v4modifiedSubIntegrityImpact, v4modifiedSubAvailabilityImpact, v4safety, v4automatable, v4recovery, + v4valueDensity, v4vulnerabilityResponseEffort, v4providerUrgency, v4baseScore, v4baseSeverity, + v4threatScore, v4threatSeverity, v4environmentalScore, v4environmentalSeverity, v4source, v4type) VALUES (p_cveId, p_description, p_v2Severity, p_v2ExploitabilityScore, p_v2ImpactScore, p_v2AcInsufInfo, p_v2ObtainAllPrivilege, @@ -334,7 +416,17 @@ BEGIN p_v3ImpactScore, p_v3AttackVector, p_v3AttackComplexity, p_v3PrivilegesRequired, p_v3UserInteraction, p_v3Scope, p_v3ConfidentialityImpact, p_v3IntegrityImpact, p_v3AvailabilityImpact, - p_v3BaseScore, p_v3BaseSeverity, p_v3Version) + p_v3BaseScore, p_v3BaseSeverity, p_v3Version, p_v4version, + p_v4attackVector, p_v4attackComplexity, p_v4attackRequirements, p_v4privilegesRequired, + p_v4userInteraction, p_v4vulnConfidentialityImpact, p_v4vulnIntegrityImpact, p_v4vulnAvailabilityImpact, + p_v4subConfidentialityImpact, p_v4subIntegrityImpact, p_v4subAvailabilityImpact, p_v4exploitMaturity, + p_v4confidentialityRequirement, p_v4integrityRequirement, p_v4availabilityRequirement, + p_v4modifiedAttackVector, p_v4modifiedAttackComplexity, p_v4modifiedAttackRequirements, + p_v4modifiedPrivilegesRequired, p_v4modifiedUserInteraction, p_v4modifiedVulnConfidentialityImpact, + p_v4modifiedVulnIntegrityImpact, p_v4modifiedVulnAvailabilityImpact, p_v4modifiedSubConfidentialityImpact, + p_v4modifiedSubIntegrityImpact, p_v4modifiedSubAvailabilityImpact, p_v4safety, p_v4automatable, p_v4recovery, + p_v4valueDensity, p_v4vulnerabilityResponseEffort, p_v4providerUrgency, p_v4baseScore, p_v4baseSeverity, + p_v4threatScore, p_v4threatSeverity, p_v4environmentalScore, p_v4environmentalSeverity, p_v4source, p_v4type) RETURNING id INTO vulnerabilityId; WHEN OTHERS THEN RAISE; @@ -446,4 +538,4 @@ CREATE OR REPLACE VIEW v_update_ecosystems AS ON c.vendor=e.vendor AND c.product=e.product; -INSERT INTO properties(id,value) VALUES ('version','5.4'); +INSERT INTO properties(id,value) VALUES ('version','5.5'); diff --git a/core/src/main/resources/data/initialize_postgres.sql b/core/src/main/resources/data/initialize_postgres.sql index 004706a17ad..6cf743115d0 100644 --- a/core/src/main/resources/data/initialize_postgres.sql +++ b/core/src/main/resources/data/initialize_postgres.sql @@ -26,7 +26,20 @@ CREATE TABLE vulnerability (id SERIAL PRIMARY KEY, cve VARCHAR(20) UNIQUE, v3ImpactScore DECIMAL(3,1), v3AttackVector VARCHAR(20), v3AttackComplexity VARCHAR(20), v3PrivilegesRequired VARCHAR(20), v3UserInteraction VARCHAR(20), v3Scope VARCHAR(20), v3ConfidentialityImpact VARCHAR(20), v3IntegrityImpact VARCHAR(20), v3AvailabilityImpact VARCHAR(20), - v3BaseScore DECIMAL(3,1), v3BaseSeverity VARCHAR(20), v3Version VARCHAR(5)); + v3BaseScore DECIMAL(3,1), v3BaseSeverity VARCHAR(20), v3Version VARCHAR(5), + v4version VARCHAR(5), v4attackVector VARCHAR(15), v4attackComplexity VARCHAR(15), + v4attackRequirements VARCHAR(15), v4privilegesRequired VARCHAR(15), v4userInteraction VARCHAR(15), + v4vulnConfidentialityImpact VARCHAR(15), v4vulnIntegrityImpact VARCHAR(15), v4vulnAvailabilityImpact VARCHAR(15), + v4subConfidentialityImpact VARCHAR(15), v4subIntegrityImpact VARCHAR(15), + v4subAvailabilityImpact VARCHAR(15), v4exploitMaturity VARCHAR(20), v4confidentialityRequirement VARCHAR(15), + v4integrityRequirement VARCHAR(15), v4availabilityRequirement VARCHAR(15), v4modifiedAttackVector VARCHAR(15), + v4modifiedAttackComplexity VARCHAR(15), v4modifiedAttackRequirements VARCHAR(15), v4modifiedPrivilegesRequired VARCHAR(15), + v4modifiedUserInteraction VARCHAR(15), v4modifiedVulnConfidentialityImpact VARCHAR(15), v4modifiedVulnIntegrityImpact VARCHAR(15), + v4modifiedVulnAvailabilityImpact VARCHAR(15), v4modifiedSubConfidentialityImpact VARCHAR(15), v4modifiedSubIntegrityImpact VARCHAR(15), + v4modifiedSubAvailabilityImpact VARCHAR(15), v4safety VARCHAR(15), v4automatable VARCHAR(15), v4recovery VARCHAR(15), + v4valueDensity VARCHAR(15), v4vulnerabilityResponseEffort VARCHAR(15), v4providerUrgency VARCHAR(15), + v4baseScore DECIMAL(3,1), v4baseSeverity VARCHAR(15), v4threatScore DECIMAL(3,1), v4threatSeverity VARCHAR(15), + v4environmentalScore DECIMAL(3,1), v4environmentalSeverity VARCHAR(15), v4source VARCHAR(50), v4type VARCHAR(15)); CREATE TABLE reference (cveid INT, name VARCHAR(1000), url VARCHAR(1000), source VARCHAR(255), CONSTRAINT fkReference FOREIGN KEY (cveid) REFERENCES vulnerability(id) ON DELETE CASCADE); @@ -61,7 +74,7 @@ CREATE TABLE knownExploited (cveID varchar(20) PRIMARY KEY, notes VARCHAR(2000)); CREATE INDEX idxCwe ON cweEntry(cveid); -CREATE INDEX idxVulnerability ON vulnerability(cve); +--CREATE INDEX idxVulnerability ON vulnerability(cve); CREATE INDEX idxReference ON reference(cveid); CREATE INDEX idxCpe ON cpeEntry(vendor, product); CREATE INDEX idxSoftwareCve ON software(cveid); @@ -145,7 +158,20 @@ CREATE FUNCTION update_vulnerability ( IN p_v3AttackComplexity VARCHAR(20), IN p_v3PrivilegesRequired VARCHAR(20), IN p_v3UserInteraction VARCHAR(20), IN p_v3Scope VARCHAR(20), IN p_v3ConfidentialityImpact VARCHAR(20), IN p_v3IntegrityImpact VARCHAR(20), IN p_v3AvailabilityImpact VARCHAR(20), IN p_v3BaseScore DECIMAL(3,1), IN p_v3BaseSeverity VARCHAR(20), - IN p_v3Version VARCHAR(5)) + IN p_v3Version VARCHAR(5), IN p_v4version VARCHAR(5), IN p_v4attackVector VARCHAR(15), IN p_v4attackComplexity VARCHAR(15), + IN p_v4attackRequirements VARCHAR(15), IN p_v4privilegesRequired VARCHAR(15), IN p_v4userInteraction VARCHAR(15), + IN p_v4vulnConfidentialityImpact VARCHAR(15), IN p_v4vulnIntegrityImpact VARCHAR(15), IN p_v4vulnAvailabilityImpact VARCHAR(15), + IN p_v4subConfidentialityImpact VARCHAR(15), IN p_v4subIntegrityImpact VARCHAR(15), IN p_v4subAvailabilityImpact VARCHAR(15), + IN p_v4exploitMaturity VARCHAR(20), IN p_v4confidentialityRequirement VARCHAR(15), IN p_v4integrityRequirement VARCHAR(15), + IN p_v4availabilityRequirement VARCHAR(15), IN p_v4modifiedAttackVector VARCHAR(15), IN p_v4modifiedAttackComplexity VARCHAR(15), + IN p_v4modifiedAttackRequirements VARCHAR(15), IN p_v4modifiedPrivilegesRequired VARCHAR(15), IN p_v4modifiedUserInteraction VARCHAR(15), + IN p_v4modifiedVulnConfidentialityImpact VARCHAR(15), IN p_v4modifiedVulnIntegrityImpact VARCHAR(15), + IN p_v4modifiedVulnAvailabilityImpact VARCHAR(15), IN p_v4modifiedSubConfidentialityImpact VARCHAR(15), + IN p_v4modifiedSubIntegrityImpact VARCHAR(15), IN p_v4modifiedSubAvailabilityImpact VARCHAR(15), IN p_v4safety VARCHAR(15), + IN p_v4automatable VARCHAR(15), IN p_v4recovery VARCHAR(15), IN p_v4valueDensity VARCHAR(15), IN p_v4vulnerabilityResponseEffort VARCHAR(15), + IN p_v4providerUrgency VARCHAR(15), IN p_v4baseScore DECIMAL(3,1), IN p_v4baseSeverity VARCHAR(15), IN p_v4threatScore DECIMAL(3,1), + IN p_v4threatSeverity VARCHAR(15), IN p_v4environmentalScore DECIMAL(3,1), IN p_v4environmentalSeverity VARCHAR(15), + IN p_v4source VARCHAR(50), IN p_v4type VARCHAR(15)) RETURNS TABLE (vulnerabilityId INT) AS $$ DECLARE vulnerabilityId integer := 0; @@ -166,7 +192,25 @@ IF vulnerabilityId > 0 THEN v3ExploitabilityScore=p_v3ExploitabilityScore, v3ImpactScore=p_v3ImpactScore, v3AttackVector=p_v3AttackVector, v3AttackComplexity=p_v3AttackComplexity, v3PrivilegesRequired=p_v3PrivilegesRequired, v3UserInteraction=p_v3UserInteraction, v3Scope=p_v3Scope, v3ConfidentialityImpact=p_v3ConfidentialityImpact, v3IntegrityImpact=p_v3IntegrityImpact, - v3AvailabilityImpact=p_v3AvailabilityImpact, v3BaseScore=p_v3BaseScore, v3BaseSeverity=p_v3BaseSeverity, v3Version=p_v3Version + v3AvailabilityImpact=p_v3AvailabilityImpact, v3BaseScore=p_v3BaseScore, v3BaseSeverity=p_v3BaseSeverity, v3Version=p_v3Version, + v4version=p_v4version, v4attackVector=p_v4attackVector, v4attackComplexity=p_v4attackComplexity, + v4attackRequirements=p_v4attackRequirements, v4privilegesRequired=p_v4privilegesRequired, + v4userInteraction=p_v4userInteraction, v4vulnConfidentialityImpact=p_v4vulnConfidentialityImpact, + v4vulnIntegrityImpact=p_v4vulnIntegrityImpact, v4vulnAvailabilityImpact=p_v4vulnAvailabilityImpact, + v4subConfidentialityImpact=p_v4subConfidentialityImpact, v4subIntegrityImpact=p_v4subIntegrityImpact, + v4subAvailabilityImpact=p_v4subAvailabilityImpact, v4exploitMaturity=p_v4exploitMaturity, + v4confidentialityRequirement=p_v4confidentialityRequirement, v4integrityRequirement=p_v4integrityRequirement, + v4availabilityRequirement=p_v4availabilityRequirement, v4modifiedAttackVector=p_v4modifiedAttackVector, + v4modifiedAttackComplexity=p_v4modifiedAttackComplexity, v4modifiedAttackRequirements=p_v4modifiedAttackRequirements, + v4modifiedPrivilegesRequired=p_v4modifiedPrivilegesRequired, v4modifiedUserInteraction=p_v4modifiedUserInteraction, + v4modifiedVulnConfidentialityImpact=p_v4modifiedVulnConfidentialityImpact, v4modifiedVulnIntegrityImpact=p_v4modifiedVulnIntegrityImpact, + v4modifiedVulnAvailabilityImpact=p_v4modifiedVulnAvailabilityImpact, v4modifiedSubConfidentialityImpact=p_v4modifiedSubConfidentialityImpact, + v4modifiedSubIntegrityImpact=p_v4modifiedSubIntegrityImpact, v4modifiedSubAvailabilityImpact=p_v4modifiedSubAvailabilityImpact, + v4safety=p_v4safety, v4automatable=p_v4automatable, v4recovery=p_v4recovery, v4valueDensity=p_v4valueDensity, + v4vulnerabilityResponseEffort=p_v4vulnerabilityResponseEffort, v4providerUrgency=p_v4providerUrgency, + v4baseScore=p_v4baseScore, v4baseSeverity=p_v4baseSeverity, v4threatScore=p_v4threatScore, + v4threatSeverity=p_v4threatSeverity, v4environmentalScore=p_v4environmentalScore, v4environmentalSeverity=p_v4environmentalSeverity, + v4source=p_v4source, v4type=p_v4type WHERE id=vulnerabilityId; ELSE INSERT INTO vulnerability (cve, description, @@ -179,7 +223,17 @@ ELSE v3ImpactScore, v3AttackVector, v3AttackComplexity, v3PrivilegesRequired, v3UserInteraction, v3Scope, v3ConfidentialityImpact, v3IntegrityImpact, v3AvailabilityImpact, - v3BaseScore, v3BaseSeverity, v3Version) + v3BaseScore, v3BaseSeverity, v3Version, v4version, + v4attackVector, v4attackComplexity, v4attackRequirements, v4privilegesRequired, + v4userInteraction, v4vulnConfidentialityImpact, v4vulnIntegrityImpact, v4vulnAvailabilityImpact, + v4subConfidentialityImpact, v4subIntegrityImpact, v4subAvailabilityImpact, v4exploitMaturity, + v4confidentialityRequirement, v4integrityRequirement, v4availabilityRequirement, + v4modifiedAttackVector, v4modifiedAttackComplexity, v4modifiedAttackRequirements, + v4modifiedPrivilegesRequired, v4modifiedUserInteraction, v4modifiedVulnConfidentialityImpact, + v4modifiedVulnIntegrityImpact, v4modifiedVulnAvailabilityImpact, v4modifiedSubConfidentialityImpact, + v4modifiedSubIntegrityImpact, v4modifiedSubAvailabilityImpact, v4safety, v4automatable, v4recovery, + v4valueDensity, v4vulnerabilityResponseEffort, v4providerUrgency, v4baseScore, v4baseSeverity, + v4threatScore, v4threatSeverity, v4environmentalScore, v4environmentalSeverity, v4source, v4type) VALUES (p_cveId, p_description, p_v2Severity, p_v2ExploitabilityScore, p_v2ImpactScore, p_v2AcInsufInfo, p_v2ObtainAllPrivilege, @@ -190,7 +244,17 @@ ELSE p_v3ImpactScore, p_v3AttackVector, p_v3AttackComplexity, p_v3PrivilegesRequired, p_v3UserInteraction, p_v3Scope, p_v3ConfidentialityImpact, p_v3IntegrityImpact, p_v3AvailabilityImpact, - p_v3BaseScore, p_v3BaseSeverity, p_v3Version); + p_v3BaseScore, p_v3BaseSeverity, p_v3Version, p_v4version, + p_v4attackVector, p_v4attackComplexity, p_v4attackRequirements, p_v4privilegesRequired, + p_v4userInteraction, p_v4vulnConfidentialityImpact, p_v4vulnIntegrityImpact, p_v4vulnAvailabilityImpact, + p_v4subConfidentialityImpact, p_v4subIntegrityImpact, p_v4subAvailabilityImpact, p_v4exploitMaturity, + p_v4confidentialityRequirement, p_v4integrityRequirement, p_v4availabilityRequirement, + p_v4modifiedAttackVector, p_v4modifiedAttackComplexity, p_v4modifiedAttackRequirements, + p_v4modifiedPrivilegesRequired, p_v4modifiedUserInteraction, p_v4modifiedVulnConfidentialityImpact, + p_v4modifiedVulnIntegrityImpact, p_v4modifiedVulnAvailabilityImpact, p_v4modifiedSubConfidentialityImpact, + p_v4modifiedSubIntegrityImpact, p_v4modifiedSubAvailabilityImpact, p_v4safety, p_v4automatable, p_v4recovery, + p_v4valueDensity, p_v4vulnerabilityResponseEffort, p_v4providerUrgency, p_v4baseScore, p_v4baseSeverity, + p_v4threatScore, p_v4threatSeverity, p_v4environmentalScore, p_v4environmentalSeverity, p_v4source, p_v4type); SELECT lastval() INTO vulnerabilityId; END IF; @@ -204,7 +268,14 @@ GRANT EXECUTE ON FUNCTION public.update_vulnerability(VARCHAR(20), VARCHAR(8000) BOOLEAN, DECIMAL(3,1), VARCHAR(20), VARCHAR(20), VARCHAR(20), VARCHAR(20), VARCHAR(20), VARCHAR(20), VARCHAR(5), DECIMAL(3,1), DECIMAL(3,1), VARCHAR(20), VARCHAR(20), VARCHAR(20), VARCHAR(20), VARCHAR(20), VARCHAR(20), VARCHAR(20), - VARCHAR(20), DECIMAL(3,1), VARCHAR(20), VARCHAR(5)) TO dcuser; + VARCHAR(20), DECIMAL(3,1), VARCHAR(20), VARCHAR(5), VARCHAR(5), VARCHAR(15), + VARCHAR(15), VARCHAR(15), VARCHAR(15), VARCHAR(15), VARCHAR(15), VARCHAR(15), + VARCHAR(15), VARCHAR(15), VARCHAR(15), VARCHAR(15), VARCHAR(20), VARCHAR(15), + VARCHAR(15), VARCHAR(15), VARCHAR(15), VARCHAR(15), VARCHAR(15), VARCHAR(15), + VARCHAR(15), VARCHAR(15), VARCHAR(15), VARCHAR(15), VARCHAR(15), VARCHAR(15), + VARCHAR(15), VARCHAR(15), VARCHAR(15), VARCHAR(15), VARCHAR(15), VARCHAR(15), + VARCHAR(15), DECIMAL(3,1), VARCHAR(15), DECIMAL(3,1), VARCHAR(15), DECIMAL(3,1), + VARCHAR(15), VARCHAR(50), VARCHAR(15)) TO dcuser; CREATE FUNCTION insert_software ( IN p_vulnerabilityId INT, IN p_part CHAR(1), IN p_vendor VARCHAR(255), IN p_product VARCHAR(255), @@ -253,4 +324,4 @@ GRANT EXECUTE ON FUNCTION public.insert_software (INT, CHAR(1), VARCHAR(255), -INSERT INTO properties(id,value) VALUES ('version','5.4'); +INSERT INTO properties(id,value) VALUES ('version','5.5'); diff --git a/core/src/main/resources/data/upgrade_2.9.sql b/core/src/main/resources/data/upgrade_2.9.sql deleted file mode 100644 index 20603809a53..00000000000 --- a/core/src/main/resources/data/upgrade_2.9.sql +++ /dev/null @@ -1 +0,0 @@ -UPDATE Properties SET `value`='3.0' WHERE ID='version'; diff --git a/core/src/main/resources/data/upgrade_3.0.sql b/core/src/main/resources/data/upgrade_3.0.sql deleted file mode 100644 index e27316dd158..00000000000 --- a/core/src/main/resources/data/upgrade_3.0.sql +++ /dev/null @@ -1,55 +0,0 @@ -SET REFERENTIAL_INTEGRITY FALSE; -TRUNCATE TABLE reference; -TRUNCATE TABLE vulnerability; -TRUNCATE TABLE software; -TRUNCATE TABLE cpeEntry; -SET REFERENTIAL_INTEGRITY TRUE; - - -ALTER TABLE vulnerability ALTER COLUMN cvssScore RENAME TO cvssV2Score; -ALTER TABLE vulnerability ALTER COLUMN cvssAccessVector RENAME TO cvssV2AccessVector; -ALTER TABLE vulnerability ALTER COLUMN cvssAccessComplexity RENAME TO cvssV2AccessComplexity; -ALTER TABLE vulnerability ALTER COLUMN cvssAuthentication RENAME TO cvssV2Authentication; -ALTER TABLE vulnerability ALTER COLUMN cvssConfidentialityImpact RENAME TO cvssV2ConfidentialityImpact; -ALTER TABLE vulnerability ALTER COLUMN cvssIntegrityImpact RENAME TO cvssV2IntegrityImpact; -ALTER TABLE vulnerability ALTER COLUMN cvssAvailabilityImpact RENAME TO cvssV2AvailabilityImpact; -ALTER TABLE vulnerability DROP COLUMN cwe; -ALTER TABLE vulnerability ADD COLUMN cvssV2Severity VARCHAR(20); -ALTER TABLE vulnerability ADD COLUMN cvssV3AttackVector VARCHAR(20); -ALTER TABLE vulnerability ADD COLUMN cvssV3AttackComplexity VARCHAR(20); -ALTER TABLE vulnerability ADD COLUMN cvssV3PrivilegesRequired VARCHAR(20); -ALTER TABLE vulnerability ADD COLUMN cvssV3UserInteraction VARCHAR(20); -ALTER TABLE vulnerability ADD COLUMN cvssV3Scope VARCHAR(20); -ALTER TABLE vulnerability ADD COLUMN cvssV3ConfidentialityImpact VARCHAR(20); -ALTER TABLE vulnerability ADD COLUMN cvssV3IntegrityImpact VARCHAR(20); -ALTER TABLE vulnerability ADD COLUMN cvssV3AvailabilityImpact VARCHAR(20); -ALTER TABLE vulnerability ADD COLUMN cvssV3BaseScore DECIMAL(3,1); -ALTER TABLE vulnerability ADD COLUMN cvssV3BaseSeverity VARCHAR(20); - - -CREATE TABLE cweEntry (cveid INT, cwe VARCHAR(20), - CONSTRAINT fkCweEntry FOREIGN KEY (cveid) REFERENCES vulnerability(id) ON DELETE CASCADE); -CREATE INDEX idxCwe ON cweEntry(cveid); - -ALTER TABLE cpeEntry DROP COLUMN cpe; -ALTER TABLE cpeEntry ADD COLUMN version VARCHAR(255); -ALTER TABLE cpeEntry ADD COLUMN update_version VARCHAR(255); -ALTER TABLE cpeEntry ADD COLUMN edition VARCHAR(255); -ALTER TABLE cpeEntry ADD COLUMN lang VARCHAR(20); -ALTER TABLE cpeEntry ADD COLUMN sw_edition VARCHAR(255); -ALTER TABLE cpeEntry ADD COLUMN target_sw VARCHAR(255); -ALTER TABLE cpeEntry ADD COLUMN target_hw VARCHAR(255); -ALTER TABLE cpeEntry ADD COLUMN other VARCHAR(255); -DROP INDEX idxCpeEntry; -CREATE INDEX idxCpeEntry ON cpeEntry(vendor, product, version, update_version, edition, lang, sw_edition, target_sw, target_hw, other); - -ALTER TABLE software DROP COLUMN previousversion; -ALTER TABLE software ADD COLUMN versionEndExcluding VARCHAR(50); -ALTER TABLE software ADD COLUMN versionEndIncluding VARCHAR(50); -ALTER TABLE software ADD COLUMN versionStartExcluding VARCHAR(50); -ALTER TABLE software ADD COLUMN versionStartIncluding VARCHAR(50); -ALTER TABLE software ADD COLUMN vulnerable BOOLEAN; - - -DELETE FROM properties WHERE ID like 'NVD CVE%'; -UPDATE Properties SET `value`='4.0' WHERE ID='version'; \ No newline at end of file diff --git a/core/src/main/resources/data/upgrade_4.0.sql b/core/src/main/resources/data/upgrade_4.0.sql deleted file mode 100644 index bd3210ec226..00000000000 --- a/core/src/main/resources/data/upgrade_4.0.sql +++ /dev/null @@ -1,7 +0,0 @@ -ALTER TABLE cpeEntry ADD COLUMN part CHAR(1); -UPDATE cpeEntry SET part='a'; -CREATE INDEX idxCpeEntry ON cpeEntry(part, vendor, product, version, update_version, edition, lang, sw_edition, target_sw, target_hw, other); - -ALTER TABLE cpeEntry ADD COLUMN ecosystem VARCHAR(255); - -UPDATE Properties SET `value`='4.1' WHERE ID='version'; diff --git a/core/src/main/resources/data/upgrade_4.1.sql b/core/src/main/resources/data/upgrade_4.1.sql deleted file mode 100644 index ec89d1d27c9..00000000000 --- a/core/src/main/resources/data/upgrade_4.1.sql +++ /dev/null @@ -1,34 +0,0 @@ -UPDATE CPEENTRY SET ECOSYSTEM='native' WHERE ECOSYSTEM='CMAKE'; -UPDATE CPEENTRY SET ECOSYSTEM='php' WHERE ECOSYSTEM='Composer'; -UPDATE CPEENTRY SET ECOSYSTEM='java' WHERE ECOSYSTEM='Java'; -UPDATE CPEENTRY SET ECOSYSTEM='java' WHERE ECOSYSTEM='android'; -UPDATE CPEENTRY SET ECOSYSTEM='nodejs' WHERE ECOSYSTEM='npm'; -UPDATE CPEENTRY SET ECOSYSTEM='native' WHERE ECOSYSTEM='windows'; -UPDATE CPEENTRY SET ECOSYSTEM='ios' WHERE ECOSYSTEM='iphone_os'; -UPDATE CPEENTRY SET ECOSYSTEM='nodejs' WHERE ECOSYSTEM='node.js'; -UPDATE CPEENTRY SET ECOSYSTEM='ios' WHERE ECOSYSTEM='mac_os_x'; -UPDATE CPEENTRY SET ECOSYSTEM='php' WHERE ECOSYSTEM='wordpress'; -UPDATE CPEENTRY SET ECOSYSTEM='native' WHERE ECOSYSTEM='linux'; -UPDATE CPEENTRY SET ECOSYSTEM='dotnet' WHERE ECOSYSTEM='asp.net'; -UPDATE CPEENTRY SET ECOSYSTEM='native' WHERE ECOSYSTEM='linux_kernel'; -UPDATE CPEENTRY SET ECOSYSTEM='native' WHERE ECOSYSTEM='c/c++'; -UPDATE CPEENTRY SET ECOSYSTEM='ruby' WHERE ECOSYSTEM='puppet'; -UPDATE CPEENTRY SET ECOSYSTEM='dotnet' WHERE ECOSYSTEM='.net'; -UPDATE CPEENTRY SET ECOSYSTEM='native' WHERE ECOSYSTEM='unix'; -UPDATE CPEENTRY SET ECOSYSTEM='dotnet' WHERE ECOSYSTEM='c#'; -UPDATE CPEENTRY SET ECOSYSTEM='php' WHERE ECOSYSTEM='typo3'; -UPDATE CPEENTRY SET ECOSYSTEM='php' WHERE ECOSYSTEM='mybb'; -UPDATE CPEENTRY SET ECOSYSTEM='php' WHERE ECOSYSTEM='joomla!'; -UPDATE CPEENTRY SET ECOSYSTEM='native' WHERE ECOSYSTEM='suse_linux'; -UPDATE CPEENTRY SET ECOSYSTEM='native' WHERE ECOSYSTEM='redhat_enterprise_linux'; -UPDATE CPEENTRY SET ECOSYSTEM='native' WHERE ECOSYSTEM='debian'; -UPDATE CPEENTRY SET ECOSYSTEM='php' WHERE ECOSYSTEM='joomla'; -UPDATE CPEENTRY SET ECOSYSTEM='js' WHERE ECOSYSTEM='jquery'; -UPDATE CPEENTRY SET ECOSYSTEM='php' WHERE ECOSYSTEM='simplesamlphp'; -UPDATE CPEENTRY SET ECOSYSTEM='ruby' WHERE ECOSYSTEM='puppet_enterprise'; -UPDATE CPEENTRY SET ECOSYSTEM='native' WHERE ECOSYSTEM='borland_c++'; -UPDATE CPEENTRY SET ECOSYSTEM='native' WHERE ECOSYSTEM='visual_c++'; -UPDATE CPEENTRY SET ECOSYSTEM='native' WHERE ECOSYSTEM='gnu_c++'; -UPDATE CPEENTRY SET ECOSYSTEM=null WHERE ECOSYSTEM NOT IN ('ruby', 'dotnet', 'cmake', 'ios', 'php', 'golang', 'java', 'native', 'python', 'js', 'nodejs', 'rust', 'coldfusion', 'perl', 'exlixir'); - -UPDATE Properties SET `value`='4.2' WHERE ID='version'; diff --git a/core/src/main/resources/data/upgrade_5.0.sql b/core/src/main/resources/data/upgrade_5.0.sql deleted file mode 100644 index 0c7231634e1..00000000000 --- a/core/src/main/resources/data/upgrade_5.0.sql +++ /dev/null @@ -1,5 +0,0 @@ -UPDATE cpeecosystemcache SET ecosystem='MULTIPLE' WHERE vendor='tensorflow' AND product='tensorflow'; - -UPDATE cpeecosystemcache SET ecosystem='MULTIPLE' WHERE vendor='scikit-learn' AND product='scikit-learn'; - -UPDATE Properties SET `value`='5.1' WHERE ID='version'; diff --git a/core/src/main/resources/data/upgrade_5.1.sql b/core/src/main/resources/data/upgrade_5.1.sql deleted file mode 100644 index ba0f7e75330..00000000000 --- a/core/src/main/resources/data/upgrade_5.1.sql +++ /dev/null @@ -1,6 +0,0 @@ -ALTER TABLE software ALTER COLUMN versionEndExcluding SET DATA TYPE VARCHAR(60); -ALTER TABLE software ALTER COLUMN versionEndIncluding SET DATA TYPE VARCHAR(60); -ALTER TABLE software ALTER COLUMN versionStartExcluding SET DATA TYPE VARCHAR(60); -ALTER TABLE software ALTER COLUMN versionStartIncluding SET DATA TYPE VARCHAR(60); - -UPDATE Properties SET `value`='5.2' WHERE ID='version'; \ No newline at end of file diff --git a/core/src/main/resources/data/upgrade_5.2.1.sql b/core/src/main/resources/data/upgrade_5.2.1.sql deleted file mode 100644 index a82a2dba76f..00000000000 --- a/core/src/main/resources/data/upgrade_5.2.1.sql +++ /dev/null @@ -1,6 +0,0 @@ -ALTER TABLE software ALTER COLUMN versionEndExcluding SET DATA TYPE VARCHAR(100); -ALTER TABLE software ALTER COLUMN versionEndIncluding SET DATA TYPE VARCHAR(100); -ALTER TABLE software ALTER COLUMN versionStartExcluding SET DATA TYPE VARCHAR(100); -ALTER TABLE software ALTER COLUMN versionStartIncluding SET DATA TYPE VARCHAR(100); - -UPDATE Properties SET `value`='5.3' WHERE ID='version'; \ No newline at end of file diff --git a/core/src/main/resources/data/upgrade_5.2.sql b/core/src/main/resources/data/upgrade_5.2.sql deleted file mode 100644 index 3ff3121a047..00000000000 --- a/core/src/main/resources/data/upgrade_5.2.sql +++ /dev/null @@ -1,4 +0,0 @@ -UPDATE cpeEcosystemCache set ecosystem='MULTIPLE' where vendor = 'icu-project' and product = 'international_components_for_unicode'; -INSERT INTO cpeEcosystemCache (vendor, product, ecosystem) VALUES ('unicode', 'international_components_for_unicode', 'MULTIPLE'); - -UPDATE Properties SET `value`='5.2.1' WHERE ID='version'; \ No newline at end of file diff --git a/core/src/main/resources/data/upgrade_5.4.sql b/core/src/main/resources/data/upgrade_5.4.sql new file mode 100644 index 00000000000..e8d3910ba73 --- /dev/null +++ b/core/src/main/resources/data/upgrade_5.4.sql @@ -0,0 +1,43 @@ +ALTER TABLE vulnerability ADD COLUMN v4version VARCHAR(5); +ALTER TABLE vulnerability ADD COLUMN v4attackVector VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4attackComplexity VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4attackRequirements VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4privilegesRequired VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4userInteraction VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4vulnConfidentialityImpact VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4vulnIntegrityImpact VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4vulnAvailabilityImpact VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4subConfidentialityImpact VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4subIntegrityImpact VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4subAvailabilityImpact VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4exploitMaturity VARCHAR(20); +ALTER TABLE vulnerability ADD COLUMN v4confidentialityRequirement VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4integrityRequirement VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4availabilityRequirement VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4modifiedAttackVector VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4modifiedAttackComplexity VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4modifiedAttackRequirements VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4modifiedPrivilegesRequired VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4modifiedUserInteraction VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4modifiedVulnConfidentialityImpact VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4modifiedVulnIntegrityImpact VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4modifiedVulnAvailabilityImpact VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4modifiedSubConfidentialityImpact VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4modifiedSubIntegrityImpact VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4modifiedSubAvailabilityImpact VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4safety VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4automatable VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4recovery VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4valueDensity VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4vulnerabilityResponseEffort VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4providerUrgency VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4baseScore DECIMAL(3,1); +ALTER TABLE vulnerability ADD COLUMN v4baseSeverity VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4threatScore DECIMAL(3,1); +ALTER TABLE vulnerability ADD COLUMN v4threatSeverity VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4environmentalScore DECIMAL(3,1); +ALTER TABLE vulnerability ADD COLUMN v4environmentalSeverity VARCHAR(15); +ALTER TABLE vulnerability ADD COLUMN v4source VARCHAR(50); +ALTER TABLE vulnerability ADD COLUMN v4type VARCHAR(15); + +UPDATE Properties SET `value`='5.5' WHERE ID='version'; diff --git a/core/src/main/resources/dependencycheck-base-hint.xml b/core/src/main/resources/dependencycheck-base-hint.xml index 044a7b1432d..976569148da 100644 --- a/core/src/main/resources/dependencycheck-base-hint.xml +++ b/core/src/main/resources/dependencycheck-base-hint.xml @@ -148,48 +148,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -489,4 +447,13 @@ + + + + + + + + + diff --git a/core/src/main/resources/dependencycheck-base-suppression.xml b/core/src/main/resources/dependencycheck-base-suppression.xml index 103a10ceed0..d244aafc1d8 100644 --- a/core/src/main/resources/dependencycheck-base-suppression.xml +++ b/core/src/main/resources/dependencycheck-base-suppression.xml @@ -19,7 +19,7 @@ obvious fp - currently not returning any CVEs ]]> ^pkg:maven/joda\-time/joda\-time@.*$ - cpe:/a:time_project:time + cpe:/a:time(_project)?:time.* ^pkg:maven/org\.sonatype\.ossindex/ossindex\-service\-api@.*$ - cpe:/a:service_project:service + cpe:/a:service(_project)?:service.* ^pkg:maven/org\.apache\.james/apache\-mime4j\-storage@.*$ - cpe:/a:storage_project:storage + cpe:/a:storage(_project)?:storage.* cpe:/a:apache:james @@ -136,14 +136,14 @@ ]]> ^pkg:maven/org\.seleniumhq\.selenium/selenium\-chromium\-driver@.*$ cpe:/a:chromium:chromium - cpe:/a:chromium_project:chromium + cpe:/a:chromium(_project)?:chromium.* ^pkg:maven/org\.apache\.geronimo\.specs/geronimo\-ws\-metadata_2\.0_spec@.*$ - cpe:/a:tad_web_project:tad_web + cpe:/a:tad_web(_project)?:tad_web.* ^pkg:maven/org\.apache\.directory\.server/apacheds\-i18n@.*$ - cpe:/a:i18n_project:i18n + cpe:/a:i18n(_project)?:i18n.* ^pkg:maven/org\.synchronoss\.cloud/nio\-stream\-storage@.*$ - cpe:/a:storage_project:storage + cpe:/a:storage(_project)?:storage.* ^io\.awspring\.cloud:spring-cloud-.*$ cpe:/a:pivotal_software:spring_framework cpe:/a:pivotal_software:spring_framework - cpe:/a:context_project:context + cpe:/a:context(_project)?:context.* ^pkg:maven/io\.github\.x\-stream/mxparser@.*$ - cpe:/a:xstream_project:xstream + cpe:/a:xstream(_project)?:xstream.* cpe:/a:oracle:jdk @@ -271,14 +271,14 @@ FP per #3005 ]]> ^pkg:maven/com\.google\.apis/google\-api\-services\-sqladmin@.*$ - cpe:/a:www-sql_project:www-sql + cpe:/a:www-sql(_project)?:www-sql.* ^pkg:maven/com\.google\.cloud\.sql/jdbc\-socket\-factory\-core@.*$ - cpe:/a:www-sql_project:www-sql + cpe:/a:www-sql(_project)?:www-sql.* - ^pkg:composer/php\-.*$ + ^pkg:composer/[^/]+/[^/]+@.*$ cpe:/a:php:php + + + ^pkg:composer/symfony/(polyfill-|ux-|panther|webpack-encore-bundle|mercure@|mercure-bundle|monolog-bundle).*$ + cpe:/a:sensiolabs:symfony + + + + ^pkg:composer/symfony/.*(contracts|-pack)@.*$ + cpe:/a:sensiolabs:symfony + + + + ^pkg:composer/(?!pimcore/pimcore@).*$ + cpe:/a:pimcore:pimcore + + + + ^pkg:composer/(?!pear/pear@|pear/pear-core-minimal@).*$ + cpe:/a:pear:pear + + + + ^pkg:composer/(?!laravel/framework@|laravel/laravel@).*$ + cpe:/a:laravel:laravel + cpe:/a:laravel:framework + + + + ^pkg:composer/(?!drupal/services@).*$ + cpe:/a:services_project:services + + + + ^pkg:composer/(?!doctrine/orm@).*$ + cpe:/a:doctrine-project:doctrine + ^pkg:npm/cross\-env@.*$ - cpe:/a:crossenv_project:crossenv + cpe:/a:crossenv(_project)?:crossenv.* cpe:/a:file_project:file cpe:/a:file:file cpe:/a:shim:shim - cpe:/a:shim_project:shim - cpe:/a:date_project:date + cpe:/a:shim(_project)?:shim.* + cpe:/a:date(_project)?:date.* cpe:/a:net_dns:net_dns cpe:/a:nodejs:node.js cpe:/a:nodejs:nodejs - cpe:/a:context_project:context - cpe:/a:mail_project:mail - cpe:/a:ldap_project:ldap - cpe:/a:user_import_project:user_import + cpe:/a:context(_project)?:context.* + cpe:/a:mail(_project)?:mail.* + cpe:/a:ldap(_project)?:ldap.* + cpe:/a:user_import(_project)?:user_import.* cpe:/a:root:root - cpe:/a:xmlsec_project:xmlsec - cpe:/a:rest-client_project:rest-client - cpe:/a:hub_project:hub - cpe:/a:views_project:views - cpe:/a:restful_web_services_project:restful_web_services + cpe:/a:xmlsec(_project)?:xmlsec.* + cpe:/a:rest-client(_project)?:rest-client.* + cpe:/a:hub(_project)?:hub.* + cpe:/a:views(_project)?:views.* + cpe:/a:restful_web_services(_project)?:restful_web_services.* cpe:/a:php:php - cpe:/a:font_project:font - cpe:/a:amazon_aws_project:amazon_aws + cpe:/a:font(_project)?:font.* + cpe:/a:amazon_aws(_project)?:amazon_aws.* cpe:/a:google:android - cpe:/a:first_project:first + cpe:/a:first(_project)?:first.* cpe:/a:interact:interact - cpe:/a:finder_project:finder - cpe:/a:archiver_project:archiver - cpe:/a:r_project:r - cpe:/a:jwt_project:jwt - cpe:/a:git_project:git + cpe:/a:finder(_project)?:finder.* + cpe:/a:archiver(_project)?:archiver.* + cpe:/a:r(_project)?:r.* + cpe:/a:jwt(_project)?:jwt.* + cpe:/a:git(_project)?:git.* cpe:/a:git:git - cpe:/a:git_for_windows_project:git_for_windows + cpe:/a:git_for_windows(_project)?:git_for_windows.* cpe:/a:mono-project:mono cpe:/a:mono:mono - cpe:/a:mono_project:mono - cpe:/a:app_project:app - cpe:/a:json-jwt_project:json-jwt - cpe:/a:zip_project:zip - cpe:/a:echo_project:echo - cpe:/a:util-linux_project:util-linux - cpe:/a:bitmap_project:bitmap - cpe:/a:security-framework_project:security-framework + cpe:/a:mono(_project)?:mono.* + cpe:/a:app(_project)?:app.* + cpe:/a:json-jwt(_project)?:json-jwt.* + cpe:/a:zip(_project)?:zip.* + cpe:/a:echo(_project)?:echo.* + cpe:/a:util-linux(_project)?:util-linux.* + cpe:/a:bitmap(_project)?:bitmap.* + cpe:/a:security-framework(_project)?:security-framework.* cpe:/a:next:next cpe:/a:property_pro:property_pro CVE-2020-10663 cpe:/a:facebook:facebook cpe:/a:gitlab:gitlab cpe:/a:delegate:delegate - cpe:/a:thread_project:thread - cpe:/a:data_tools_project:data_tools - cpe:/a:tag_project:tag + cpe:/a:thread(_project)?:thread.* + cpe:/a:data_tools(_project)?:data_tools.* + cpe:/a:tag(_project)?:tag.* cpe:/a:kubernetes:kubernetes - cpe:/a:websockets_project:websockets - cpe:/a:cron_project:cron - cpe:/a:html2pdf_project:html2pdf - cpe:/a:shadow_project:shadow + cpe:/a:websockets(_project)?:websockets.* + cpe:/a:cron(_project)?:cron.* + cpe:/a:html2pdf(_project)?:html2pdf.* + cpe:/a:shadow(_project)?:shadow.* cpe:/a:cde:cde cpe:/a:docker:docker cpe:/a:travis-ci:travis_ci - cpe:/a:storage_project:storage + cpe:/a:storage(_project)?:storage.* cpe:/a:pivotal_software:rabbitmq - cpe:/a:saml_project:saml - cpe:/a:yaml_project:yaml + cpe:/a:saml(_project)?:saml.* + cpe:/a:yaml(_project)?:yaml.* .*(\.(jar|ear|war|pom)|pom\.xml)$ cpe:/a:dash:dash - cpe:/a:mustache.js_project:mustache.js + cpe:/a:mustache.js(_project)?:mustache.js cpe:/a:microsoft:active_directory cpe:/a:microsoft:active_directory_federation_services cpe:/a:microsoft:active_directory_services @@ -724,14 +776,14 @@ cpe:/a:python:python cpe:/a:python_software_foundation:python CVE-2017-16046 - cpe:/a:sqlserver_project:sqlserver + cpe:/a:sqlserver(_project)?:sqlserver cpe:/a:auth0:auth0 cpe:/a:github:github - cpe:/a:data-tools_project:data_tools - cpe:/a:flow_project:flow + cpe:/a:data-tools(_project)?:data_tools.* + cpe:/a:flow(_project)?:flow.* cpe:/a:ghost:ghost - cpe:/a:ws_project:ws - cpe:/a:i18n_project:i18n + cpe:/a:ws(_project)?:ws.* + cpe:/a:i18n(_project)?:i18n.* cpe:/a:redis:redis cpe:/a:perl:perl @@ -740,7 +792,7 @@ Suppresses false positives per #2511 ]]> ^pkg:maven/com\.vaadin/vaadin\-sass\-compiler@.*$ - cpe:/a:compile-sass_project:compile-sass + cpe:/a:compile-sass(_project)?:compile-sass.* ^pkg:npm/rc@.*$ - cpe:/a:rc_project:rc + cpe:/a:rc(_project)?:rc.* ^pkg:maven/io\.smallrye/smallrye\-context\-propagation\-storage@.*$ - cpe:/a:storage_project:storage + cpe:/a:storage(_project)?:storage.* ^eu\.bitwalker:UserAgentUtils:.*$ - cpe:/a:useragent_project:useragent + cpe:/a:useragent(_project)?:useragent.* ^com\.cybersource:flex-server-sdk:.*$ - cpe:/a:flex_project:flex + cpe:/a:flex(_project)?:flex.* cpe:/a:id:id-software @@ -920,7 +972,7 @@ Suppresses false positives per issue #1587 ]]> ^org\.apache\.felix:org\.apache\.felix\.configadmin:.*$ - cpe:/a:cm_project:cm + cpe:/a:cm(_project)?:cm.* ^pkg:maven/org\.evolvis\.tartools/rfc822@.*$ - cpe:/a:man-cgi_project:man-cgi + cpe:/a:man-cgi(_project)?:man-cgi.* ^com\.liferay:org\.apache\.felix\.configadmin:.*$ - cpe:/a:cm_project:cm + cpe:/a:cm(_project)?:cm.* ^pkg:maven/com\.microsoft\.azure/msal4j@.*$ - cpe:/a:http_authentication_library_project:http_authentication_library + cpe:/a:http_authentication_library(_project)?:http_authentication_library.* ^pkg:maven/com\.microsoft\.azure/msal4j@.*$ - cpe:/a:http_authentication_library_project:http_authentication_library + cpe:/a:http_authentication_library(_project)?:http_authentication_library.* ^pkg:(generic|nuget)/Microsoft\.AspNetCore\.JsonPatch@.*$ - cpe:/a:json-patch_project:json-patch + cpe:/a:json-patch(_project)?:json-patch.* ^org\.sonatype\.plexus:plexus-sec-dispatcher:.*$ - cpe:/a:sec_project:sec + cpe:/a:sec(_project)?:sec.* ^com.amazonaws:aws-java-sdk-simpleworkflow:.*$ - cpe:/a:flow_project:flow + cpe:/a:flow(_project)?:flow.* ^com.amazonaws:aws-java-sdk-swf-libraries:.*$ - cpe:/a:flow_project:flow + cpe:/a:flow(_project)?:flow.* ^com\.facebook\.android:facebook-android-sdk:.*$ cpe:/a:facebook:facebook ^com\.amazonaws:aws-android-sdk-cognitoidentityprovider-asf:.*$ cpe:/a:android:android_sdk @@ -1555,7 +1607,7 @@ ^org\.jetbrains:annotations:.*$ cpe:/a:jetbrains:intellij_idea @@ -1599,7 +1651,7 @@ FP found when researching #1091 ]]> ^com\.nimbusds:nimbus-jose-jwt:.*$ - cpe:/a:jwt_project:jwt + cpe:/a:jwt(_project)?:jwt.* ^pkg:maven/com\.h3xstream\.retirejs/retirejs\-core@.*$ - cpe:/a:xstream_project:xstream + cpe:/a:xstream(_project)?:xstream.* ^pkg:maven/org\.gagravarr/vorbis\-java\-tika@.*$ cpe:/a:apache:tika - cpe:/a:flac_project:flac + cpe:/a:flac(_project)?:flac.* ^pkg:maven/org\.ops4j\.pax\..*$ - cpe:/a:pax_project:pax + cpe:/a:pax(_project)?:pax.* ^org\.eclipse\.jetty\.toolchain:jetty-schemas:.*$ cpe:/a:mortbay_jetty:jetty @@ -1998,7 +2050,7 @@ cpe:/a:apache:apache_http_server cpe:/a:apache:directory_studio cpe:/a:apache:ldap_studio - cpe:/a:net-ldap_project:net-ldap + cpe:/a:net-ldap(_project)?:net-ldap.* ^io\.springfox:springfox-.+:.*$ cpe:/a:gradle:gradle ^io\.micrometer:micrometer-registry-prometheus:.*$ CVE-2019-3826 @@ -2165,14 +2217,14 @@ ^io\.prometheus:simpleclient_common:.*$ CVE-2019-3826 ^io\.prometheus:simpleclient:.*$ CVE-2019-3826 @@ -2196,8 +2248,8 @@ Grizzly is not Async Http Client ]]> ^org\.glassfish\.grizzly:grizzly-http-client:.*$ - cpe:/a:async-http-client_project:async-http-client - cpe:/a:asynchttpclient_project:async-http-client + cpe:/a:async-http-client(_project)?:async-http-client.* + cpe:/a:asynchttpclient(_project)?:async-http-client.* ^pkg:maven/org\.eclipse\.microprofile\.config/.*@.*$ - cpe:/a:config_file_provider_project:config_file_provider + cpe:/a:config_file_provider(_project)?:config_file_provider.* .*(\.(jar|ear|war|pom)|pom\.xml) - cpe:/a:services_project:services - cpe:/a:pyro_project:pyro + cpe:/a:services(_project)?:services.* + cpe:/a:pyro(_project)?:pyro.* ^org\.glassfish\.jersey\.ext:jersey-metainf-services:.*$ - cpe:/a:services_project:services: + cpe:/a:services(_project)?:services:.* ^pkg:npm/faye\-websocket@.*$ - cpe:/a:faye_project:faye + cpe:/a:faye(_project)?:faye.* .*package\.json$ - cpe:/a:file_project:file + cpe:/a:file(_project)?:file.* cpe:/a:file:file cpe:/a:shim:shim - cpe:/a:shim_project:shim + cpe:/a:shim(_project)?:shim.* cpe:/a:apple:java cpe:/a:unicode:unicode: + + + ^pkg:maven/org\.graalvm\.shadowed/icu4j@.*$ + CVE-2020-21913 + CVE-2014-9654 + CVE-2014-9911 + CVE-2016-6293 + CVE-2016-7415 + CVE-2017-14952 + CVE-2017-17484 + CVE-2015-5922 + CVE-2007-4771 + CVE-2020-10531 + CVE-2011-4599 + CVE-2014-7923 + CVE-2014-7926 + CVE-2014-7940 + CVE-2014-8146 + CVE-2014-8147 + CVE-2017-7867 + CVE-2017-7868 + CVE-2007-4770 + CVE-2017-15396 + CVE-2017-15422 + cpe:/a:apple:java + cpe:/a:unicode:unicode: + .*activerecord.*oracle.*\.gemspec cpe:/a:ruby-i18n:i18n cpe:/a:mikel_lindsaar:mail - cpe:/a:rest-client_project:rest-client + cpe:/a:rest-client(_project)?:rest-client.* ^net\.thisptr:jackson-jq:.*$ - cpe:/a:jq_project:jq + cpe:/a:jq(_project)?:jq.* cpe:/a:id:id-software @@ -2681,7 +2767,7 @@ false positives per issue #915 ]]> ^javax\.validation:validation-api:.*$ - cpe:/a:bean_project:bean + cpe:/a:bean(_project)?:bean.* ^net\.lingala\.zip4j:zip4j:.*$ - cpe:/a:zip_project:zip + cpe:/a:zip(_project)?:zip.* ^net\.java\.truevfs:truevfs-comp-zip:.*$ - cpe:/a:zip_project:zip + cpe:/a:zip(_project)?:zip.* ^net\.java\.truevfs:truevfs-driver-zip:.*$ - cpe:/a:zip_project:zip + cpe:/a:zip(_project)?:zip.* ^stax:stax-api:.*$ - cpe:/a:st_project:st + cpe:/a:st(_project)?:st.* ^org\.apache\.pdfbox:fontbox:.*$ - cpe:/a:font_project:font + cpe:/a:font(_project)?:font.* ^com\.itextpdf:font-asian:.*$ - cpe:/a:font_project:font + cpe:/a:font(_project)?:font.* ^org\.kohsuke:github-api:.*$ - cpe:/a:hub_project:hub + cpe:/a:hub(_project)?:hub.* ^org\.asynchttpclient:netty-codec-dns:.*$ - cpe:/a:dns-sync_project:dns-sync + cpe:/a:dns-sync(_project)?:dns-sync.* ^org\.asynchttpclient:async-http-client-netty-utils:.*$ - cpe:/a:async-http-client_project:async-http-client - cpe:/a:asynchttpclient_project:async-http-client + cpe:/a:async-http-client(_project)?:async-http-client.* + cpe:/a:asynchttpclient(_project)?:async-http-client.* ^org\.asynchttpclient:netty-resolver-dns:.*$ - cpe:/a:dns-sync_project:dns-sync + cpe:/a:dns-sync(_project)?:dns-sync.* ^org\.apache\.xbean:xbean-finder:.*$ - cpe:/a:finder_project:finder + cpe:/a:finder(_project)?:finder.* ^org\.sonatype\..*$ - cpe:/a:spice_project:spice + cpe:/a:spice(_project)?:spice.* ^com\.sun\.jersey:jersey-core:.*$ - cpe:/a:restful_web_services_project:restful_web_services + cpe:/a:restful_web_services(_project)?:restful_web_services.* - ^pkg:maven/com\.vaadin\.(addon|external).*$ + ^pkg:maven/com\.vaadin\.(addon|external|flow\.ai).*$ cpe:/a:vaadin:vaadin + + + ^pkg:maven/com\.vaadin\.flow\.ai.*$ + cpe:/a:vaadin:flow + ^pkg:maven/com\.softwaremill\.sttp.*$ - cpe:/a:async-http-client_project:async-http-client - cpe:/a:asynchttpclient_project:async-http-client + cpe:/a:async-http-client(_project)?:async-http-client.* + cpe:/a:asynchttpclient(_project)?:async-http-client.* ^org\.mapstruct:mapstruct:.*$ - cpe:/a:bean_project:bean + cpe:/a:bean(_project)?:bean.* ^com\.amazonaws:jmespath-java:.*$ - cpe:/a:amazon_aws_project:amazon_aws + cpe:/a:amazon_aws(_project)?:amazon_aws.* ^org\.codehaus\.plexus:plexus-utils:.*$ - cpe:/a:spice_project:spice + cpe:/a:spice(_project)?:spice.* ^org\.projectlombok:lombok:.*$ - cpe:/a:spice_project:spice + cpe:/a:spice(_project)?:spice.* cpe:/a:oracle:connector%2fj cpe:/a:oracle:jdbc - - - ^(mysql:mysql-connector-java|com\.mysql:mysql-connector-j|org\.drizzle\.jdbc:drizzle-jdbc):.*$ - CVE-2017-15945 - CVE-2018-3081 - CVE-2018-3137 - CVE-2018-3145 - CVE-2018-3170 - CVE-2018-3182 - CVE-2018-3186 - CVE-2018-3195 - CVE-2018-3203 - CVE-2018-3212 - CVE-2018-3279 - CVE-2018-3286 - CVE-2018-3071 - CVE-2018-2759 - CVE-2017-3331 - CVE-2017-3452 - CVE-2007-6304 - CVE-2016-5442 - CVE-2014-6555 - CVE-2015-4861 - CVE-2013-3796 - CVE-2012-0553 - CVE-2016-0659 - CVE-2002-1923 - CVE-2012-0119 - CVE-2015-0508 - CVE-2016-8283 - CVE-2017-3463 - CVE-2016-6663 - CVE-2013-5881 - CVE-2015-2573 - CVE-2016-5436 - CVE-2002-1376 - CVE-2015-0432 - CVE-2005-2558 - CVE-2017-3308 - CVE-2014-0402 - CVE-2015-0499 - CVE-2009-0819 - CVE-2012-1757 - CVE-2010-3838 - CVE-2006-4031 - CVE-2012-3180 - CVE-2015-3152 - CVE-2014-0393 - CVE-2012-3163 - CVE-2016-0594 - CVE-2014-2450 - CVE-2014-0430 - CVE-2017-3457 - CVE-2015-2567 - CVE-2017-3319 - CVE-2015-4866 - CVE-2010-1621 - CVE-2015-0409 - CVE-2016-8288 - CVE-2014-6484 - CVE-2017-3243 - CVE-2016-5633 - CVE-2017-3468 - CVE-2012-2122 - CVE-2014-2444 - CVE-2016-0642 - CVE-2012-0882 - CVE-2012-0102 - CVE-2012-5614 - CVE-2013-1567 - CVE-2016-0504 - CVE-2017-3643 - CVE-2010-2008 - CVE-2016-0608 - CVE-2015-4756 - CVE-2017-10284 - CVE-2014-6495 - CVE-2013-5793 - CVE-2014-4233 - CVE-2010-3680 - CVE-2012-0493 - CVE-2001-1275 - CVE-2013-0385 - CVE-2016-0599 - CVE-2016-5627 - CVE-2012-0113 - CVE-2013-0368 - CVE-2014-2438 - CVE-2013-1511 - CVE-2014-6478 - CVE-2017-3637 - CVE-2004-0837 - CVE-2016-0653 - CVE-2010-1626 - CVE-2013-3810 - CVE-2015-2643 - CVE-2015-4767 - CVE-2017-3265 - CVE-2009-4019 - CVE-2014-6489 - CVE-2017-3302 - CVE-2012-0087 - CVE-2016-3477 - CVE-2017-3648 - CVE-2012-1697 - CVE-2012-0487 - CVE-2016-0647 - CVE-2015-4815 - CVE-2012-1734 - CVE-2013-3804 - CVE-2013-5807 - CVE-2008-7247 - CVE-2016-5441 - CVE-2007-6303 - CVE-2014-2494 - CVE-2017-3313 - CVE-2013-3795 - CVE-2014-4238 - CVE-2015-4826 - CVE-2016-0658 - CVE-2012-0118 - CVE-2015-0507 - CVE-2015-2648 - CVE-2006-7232 - CVE-2009-5026 - CVE-2017-3462 - CVE-2016-6662 - CVE-2016-2047 - CVE-2006-4227 - CVE-2014-0001 - CVE-2002-1375 - CVE-2015-0498 - CVE-2017-10365 - CVE-2014-0401 - CVE-2013-1544 - CVE-2006-1518 - CVE-2010-3679 - CVE-2012-1756 - CVE-2004-0628 - CVE-2017-10227 - CVE-2010-3837 - CVE-2013-3809 - CVE-2016-5584 - CVE-2008-4456 - CVE-2013-5891 - CVE-2015-4761 - CVE-2013-5770 - CVE-2017-3456 - CVE-2014-2432 - CVE-2015-2566 - CVE-2014-6559 - CVE-2012-0574 - CVE-2014-0412 - CVE-2013-1555 - CVE-2017-3318 - CVE-2015-2620 - CVE-2009-4030 - CVE-2016-8287 - CVE-2016-3471 - CVE-2007-2693 - CVE-2003-0150 - CVE-2012-3173 - CVE-2014-6520 - CVE-2017-10283 - CVE-2017-3467 - CVE-2014-0386 - CVE-2004-0388 - CVE-2004-2149 - CVE-2012-0101 - CVE-2012-5613 - CVE-2013-1566 - CVE-2013-2376 - CVE-2016-5632 - CVE-2016-0503 - CVE-2017-3329 - CVE-2016-0607 - CVE-2015-4913 - CVE-2017-3642 - CVE-2012-3156 - CVE-2015-4772 - CVE-2016-0641 - CVE-2017-10320 - CVE-2014-6494 - CVE-2007-2583 - CVE-2017-3653 - CVE-2012-0492 - CVE-2001-1274 - CVE-2012-0075 - CVE-2012-3167 - CVE-2017-3636 - CVE-2012-0112 - CVE-2013-0367 - CVE-2013-0384 - CVE-2016-0652 - CVE-2012-4414 - CVE-2017-10294 - CVE-2004-0957 - CVE-2004-0836 - CVE-2016-0598 - CVE-2012-1705 - CVE-2017-10314 - CVE-2016-8318 - CVE-2015-4766 - CVE-2016-5626 - CVE-2017-3599 - CVE-2016-5609 - CVE-2014-4260 - CVE-2015-0501 - CVE-2014-4243 - CVE-2013-3783 - CVE-2013-5786 - CVE-2016-0663 - CVE-2012-0540 - CVE-2012-1696 - CVE-2000-0045 - CVE-2006-0369 - CVE-2013-1521 - CVE-2016-3459 - CVE-2012-0486 - CVE-2016-0646 - CVE-2017-3647 - CVE-2017-10167 - CVE-2017-3450 - CVE-2016-5440 - CVE-2015-0382 - CVE-2017-3312 - CVE-2011-2262 - CVE-2013-3794 - CVE-2005-0004 - CVE-2001-1454 - CVE-2013-0389 - CVE-2016-0657 - CVE-2013-1532 - CVE-2002-1921 - CVE-2012-0117 - CVE-2015-0506 - CVE-2017-3258 - CVE-2017-3461 - CVE-2012-3150 - CVE-2003-0073 - CVE-2005-2573 - CVE-2014-6564 - CVE-2006-4226 - CVE-2002-1374 - CVE-2015-4870 - CVE-2005-0711 - CVE-2010-1850 - CVE-2006-1517 - CVE-2010-3678 - CVE-2013-1526 - CVE-2004-0627 - CVE-2016-0705 - CVE-2010-3836 - CVE-2016-3518 - CVE-2013-3808 - CVE-2016-0601 - CVE-2015-4836 - CVE-2015-2571 - CVE-2016-0668 - CVE-2012-5060 - CVE-2015-4819 - CVE-2013-2381 - CVE-2015-2582 - CVE-2017-3455 - CVE-2003-0780 - CVE-2014-2431 - CVE-2003-1331 - CVE-2015-4864 - CVE-2012-3144 - CVE-2017-3317 - CVE-2005-1636 - CVE-2015-0441 - CVE-2001-0407 - CVE-2016-8286 - CVE-2007-2692 - CVE-2003-1480 - CVE-2013-2392 - CVE-2017-3641 - CVE-2016-5631 - CVE-2012-1690 - CVE-2007-5646 - CVE-2013-2375 - CVE-2016-2105 - CVE-2007-5925 - CVE-2012-5612 - CVE-2016-0502 - CVE-2014-2442 - CVE-2015-4858 - CVE-2013-1548 - CVE-2016-0606 - CVE-2015-2576 - CVE-2014-4287 - CVE-2002-0969 - CVE-2016-0640 - CVE-2015-4737 - CVE-2015-4771 - CVE-2016-5439 - CVE-1999-1188 - CVE-2007-5970 - CVE-2014-6530 - CVE-2017-3652 - CVE-2008-3963 - CVE-2013-0383 - CVE-2012-3166 - CVE-2012-0491 - CVE-2014-4214 - CVE-2016-5625 - CVE-2014-0433 - CVE-2012-3149 - CVE-2014-2436 - CVE-2016-3501 - CVE-2012-0578 - CVE-2004-0956 - CVE-2004-0835 - CVE-2014-2419 - CVE-2017-3635 - CVE-2017-10155 - CVE-2015-0500 - CVE-2016-0651 - CVE-2010-1849 - CVE-2017-10313 - CVE-2017-10276 - CVE-2015-4802 - CVE-2015-2641 - CVE-2016-0597 - CVE-2016-3492 - CVE-2007-1420 - CVE-2012-3177 - CVE-2016-0662 - CVE-2017-3646 - CVE-2012-0485 - CVE-2015-0511 - CVE-2014-6507 - CVE-2000-0148 - CVE-2013-3802 - CVE-2014-0427 - CVE-2015-4830 - CVE-2017-3291 - CVE-2015-3194 - CVE-2008-2079 - CVE-2009-4028 - CVE-2016-3486 - CVE-2012-5383 - CVE-2013-3793 - CVE-2012-4452 - CVE-2017-3257 - CVE-2010-3683 - CVE-2001-1453 - CVE-2012-0496 - CVE-2004-0457 - CVE-2013-1531 - CVE-2012-0116 - CVE-2012-1689 - CVE-2016-0639 - CVE-2015-4807 - CVE-2015-0505 - CVE-2016-0656 - CVE-2015-0381 - CVE-2006-4380 - CVE-2017-3460 - CVE-2004-0381 - CVE-2005-2572 - CVE-2002-1373 - CVE-2017-3305 - CVE-2005-0710 - CVE-2016-0667 - CVE-2006-1516 - CVE-2010-3677 - CVE-2016-0546 - CVE-2016-0600 - CVE-2010-3835 - CVE-2013-3807 - CVE-2009-4484 - CVE-2012-3160 - CVE-2017-3454 - CVE-2013-1570 - CVE-2014-2430 - CVE-2016-5444 - CVE-2014-4258 - CVE-2012-0572 - CVE-2012-2750 - CVE-2013-3798 - CVE-2016-0611 - CVE-2016-3424 - CVE-2015-0423 - CVE-2007-2691 - CVE-2013-2391 - CVE-2014-6464 - CVE-2017-3465 - CVE-2013-0371 - CVE-2014-0384 - CVE-2015-2575 - CVE-2014-6568 - CVE-2012-0583 - CVE-2012-2102 - CVE-2012-5611 - CVE-2005-0799 - CVE-2016-5630 - CVE-2006-0903 - CVE-2016-0605 - CVE-2017-3640 - CVE-2016-3452 - CVE-2017-3251 - CVE-2017-3651 - CVE-2012-0490 - CVE-2013-5894 - CVE-2016-0596 - CVE-2017-3634 - CVE-2017-3459 - CVE-2001-1255 - CVE-2014-2435 - CVE-2016-0650 - CVE-2017-10379 - CVE-2016-0616 - CVE-2015-4905 - CVE-2012-1703 - CVE-2005-0709 - CVE-2010-1848 - CVE-2016-5624 - CVE-2002-1809 - CVE-2015-4792 - CVE-2016-8327 - CVE-2016-0661 - CVE-2014-6469 - CVE-2012-0484 - CVE-2017-10286 - CVE-2016-5635 - CVE-2000-0981 - CVE-2014-4207 - CVE-2013-3801 - CVE-2013-1502 - CVE-2015-0439 - CVE-2013-5767 - CVE-2016-3615 - CVE-2012-2749 - CVE-2013-5908 - CVE-2016-0644 - CVE-2015-2617 - CVE-2017-3645 - CVE-2017-10165 - CVE-2015-4879 - CVE-2008-4098 - CVE-2017-3273 - CVE-2014-6551 - CVE-2017-3256 - CVE-2010-3682 - CVE-2012-0495 - CVE-2016-0655 - CVE-2010-3840 - CVE-2016-5629 - CVE-2012-0115 - CVE-2012-1688 - CVE-2014-0437 - CVE-2013-3812 - CVE-2012-5627 - CVE-2017-3639 - CVE-2015-4769 - CVE-2015-0391 - CVE-2013-5860 - CVE-2015-4730 - CVE-2017-3600 - CVE-2015-0374 - CVE-2015-0411 - CVE-2016-0666 - CVE-2010-3676 - CVE-2012-0489 - CVE-2017-3529 - CVE-2010-3834 - CVE-2013-3806 - CVE-2016-8290 - CVE-2016-0649 - CVE-2015-2639 - CVE-2014-4274 - CVE-2017-3453 - CVE-2016-5443 - CVE-2009-2446 - CVE-2015-0385 - CVE-2006-2753 - CVE-2016-3440 - CVE-2013-1552 - CVE-2016-0610 - CVE-2015-4862 - CVE-2015-0405 - CVE-2016-8284 - CVE-2015-4890 - CVE-2014-6463 - CVE-2017-3464 - CVE-2016-6664 - CVE-2014-2440 - CVE-2014-6500 - CVE-2016-5612 - CVE-2017-10384 - CVE-2014-0420 - CVE-2015-4910 - CVE-2013-5882 - CVE-2015-4752 - CVE-2017-3309 - CVE-2016-5437 - CVE-2015-0433 - CVE-2015-2611 - CVE-2010-3839 - CVE-2006-3081 - CVE-2014-6491 - CVE-2014-6474 - CVE-2017-3650 - CVE-2014-2451 - CVE-2016-0595 - CVE-2017-3633 - CVE-2017-3458 - CVE-2014-0431 - CVE-2012-3147 - CVE-2014-2434 - CVE-2015-2568 - CVE-2017-10378 - CVE-2015-4904 - CVE-2015-4800 - CVE-2012-1702 - CVE-2017-10311 - CVE-2013-3839 - CVE-2016-8289 - CVE-2014-4240 - CVE-2015-4791 - CVE-2017-3244 - CVE-2013-2395 - CVE-2015-4895 - CVE-2016-5634 - CVE-2012-0120 - CVE-2013-0375 - CVE-2013-2378 - CVE-2012-3158 - CVE-2014-6505 - CVE-2017-10268 - CVE-2012-5615 - CVE-2016-0505 - CVE-2016-0643 - CVE-2016-3614 - CVE-2015-0438 - CVE-2016-0609 - CVE-2015-4757 - CVE-2017-3644 - CVE-2008-4097 - CVE-2016-7440 - CVE-2014-6496 - CVE-2006-3486 - CVE-2013-1492 - CVE-2015-2661 - CVE-2016-3521 - CVE-2010-3681 - CVE-2017-10296 - CVE-2006-3469 - CVE-2013-2389 - CVE-2012-0494 - CVE-2016-5628 - CVE-2017-3638 - CVE-2012-0114 - CVE-2013-0386 - CVE-2013-1512 - CVE-2016-3588 - CVE-2017-3238 - CVE-2013-3811 - CVE-2016-0654 - CVE-2016-5507 - CVE-2017-10279 - CVE-2015-0503 - CVE-2012-5096 - CVE-2016-3495 - CVE-2017-3320 - CVE-2012-3197 - CVE-2014-2484 - CVE-2008-0226 - CVE-2011-5049 - CVE-2016-0665 - CVE-2017-3649 - CVE-2012-0488 - CVE-2013-1523 - CVE-2016-0648 - CVE-2010-3833 - CVE-2012-1735 - CVE-2013-3805 - CVE-2013-1506 - CVE-2015-4833 - CVE-2015-4816 - CVE-2018-2767 - CVE-2018-3054 - CVE-2018-3056 - CVE-2018-3058 - CVE-2018-3060 - CVE-2018-3061 - CVE-2018-3062 - CVE-2018-3063 - CVE-2018-3064 - CVE-2018-3065 - CVE-2018-3066 - CVE-2018-3067 - CVE-2018-3070 - CVE-2018-3073 - CVE-2018-3074 - CVE-2018-3075 - CVE-2018-3077 - CVE-2018-3078 - CVE-2018-3079 - CVE-2018-3080 - CVE-2018-3082 - CVE-2018-3084 - ^name\.neuhalfen\.projects\.crypto\.bouncycastle\.openpgp:bouncy-gpg:.*$ - cpe:/a:gpg-pgp_project::gpg-pgp + cpe:/a:gpg-pgp(_project)?::gpg-pgp.* cpe:/a:openpgp:openpgp @@ -4235,7 +3719,7 @@ false positive per #3271 on org.apache.sis.storage ]]> ^pkg:maven/org\.apache\.sis\.storage/sis\-.*$ - cpe:/a:storage_project:storage + cpe:/a:storage(_project)?:storage.* ^pkg:maven/com\.amazonaws/aws\-java\-sdk\-storagegateway@.*$ - cpe:/a:storage_project:storage + cpe:/a:storage(_project)?:storage.* ^pkg:pypi/mssql\-django@.*$ - cpe:/a:django_project:django + cpe:/a:django(_project)?:django.* ^pkg:maven/com\.eatthepath/fast\-uuid@.*$ - cpe:/a:fast_ber_project:fast_ber + cpe:/a:fast_ber(_project)?:fast_ber.* - ^pkg:pypi/.*python\-.*$ + ^pkg:pypi/.*python.*$ cpe:/a:python:python cpe:/a:python_software_foundation:python @@ -4490,42 +3974,42 @@ file name: 'DateTime::Format::MySQL', '0.04' ]]> ^pkg:cpan/DateTime%3A%3AFormat/MySQL@.*$ - cpe:/a:www-sql_project:www-sql + cpe:/a:www-sql(_project)?:www-sql.* ^pkg:cpan/MARC%3A%3AFile.*$ - cpe:/a:file_project:file + cpe:/a:file(_project)?:file.* ^pkg:cpan/(IO%3A%3A)?File.*$ - cpe:/a:file_project:file + cpe:/a:file(_project)?:file.* ^pkg:cpan/SQL/.*$ - cpe:/a:www-sql_project:www-sql + cpe:/a:www-sql(_project)?:www-sql.* ^pkg:cpan/.*DateTime.*$ - cpe:/a:time_project:time + cpe:/a:time(_project)?:time.* ^pkg:cpan/Dist%3A%3AZilla%3A%3APlugin%3A%3AGit.*$ - cpe:/a:git_project:git + cpe:/a:git(_project)?:git.* ^pkg:maven/io\.netty/netty-tcnative-boringssl-static@.*$ cpe:/a:chromium:chromium - cpe:/a:chromium_project:chromium + cpe:/a:chromium(_project)?:chromium.* ^pkg:maven/com\.carrotsearch\.thirdparty/simple-xml-safe@.*$ - cpe:/a:simplexml_project:simplexml + cpe:/a:simplexml(_project)?:simplexml.* ^pkg:maven/.*async.*@.*$ - cpe:/a:async_project:async + cpe:/a:async(_project)?:async.* ^pkg:maven/org\.pac4j/ratpack\-pac4j@.*$ cpe:/a:pac4j:pac4j cpe:/a:ratpack:ratpack - cpe:/a:ratpack_project:ratpack + cpe:/a:ratpack(_project)?:ratpack.* ^pkg:maven/io\.swagger/.*$ - cpe:/a:http-swagger_project:http-swagger + cpe:/a:http-swagger(_project)?:http-swagger.* ^pkg:npm/archiver@.*$ - cpe:/a:archiver_project:archiver + cpe:/a:archiver(_project)?:archiver.* cpe:/a:pivotal_software:spring_security cpe:/a:vmware:spring_security cpe:/a:vmware:springsource_spring_security - cpe:/a:security-framework_project:security-framework + cpe:/a:security-framework(_project)?:security-framework.* cpe:/a:vmware:springsource_spring_security cpe:/a:vmware:spring_security cpe:/a:pivotal_software:spring_security - cpe:/a:security-framework_project:security-framework + cpe:/a:security-framework(_project)?:security-framework.* ^pkg:maven/org\.springframework\.security/spring-security-jwt@.*$ cpe:/a:pivotal:spring_security_oauth cpe:/a:pivotal_software:spring_security_oauth - cpe:/a:jwt_project:jwt + cpe:/a:jwt(_project)?:jwt.* @@ -5129,7 +4613,7 @@ FP per issue #4576; spring-security-saml2-core is an (end-of-life) extension project separate from spring-security https://github.com/spring-projects/spring-security-saml ]]> ^pkg:maven/org\.springframework\.security\.extensions/spring-security-saml2-core@.*$ - cpe:/a:saml_project:saml + cpe:/a:saml(_project)?:saml.* cpe:/a:vmware:spring_security @@ -5140,7 +4624,7 @@ cpe:/a:pivotal_software:spring_security cpe:/a:vmware:springsource_spring_security cpe:/a:vmware:spring_security - cpe:/a:security-framework_project:security-framework + cpe:/a:security-framework(_project)?:security-framework.* cpe:/a:pivotal_software:spring_security cpe:/a:vmware:springsource_spring_security cpe:/a:vmware:spring_security - cpe:/a:security-framework_project:security-framework + cpe:/a:security-framework(_project)?:security-framework.* @@ -5325,7 +4809,7 @@ False positives per issue #642 ]]> ^pkg:maven/org\.springframework/spring-context@.*$ - cpe:/a:context_project:context + cpe:/a:context(_project)?:context.* ^pkg:maven/org\.springframework\.cloud/spring-cloud-.*$ - cpe:/a:context_project:context + cpe:/a:context(_project)?:context.* cpe:/a:pivotal_software:spring_batch @@ -5371,7 +4855,7 @@ spring ldap cleanup per issue #1060 ]]> ^pkg:maven/org\.springframework\.ldap/spring-ldap-core@.*$ - cpe:/a:net-ldap_project:net-ldap + cpe:/a:net-ldap(_project)?:net-ldap.* ^pkg:npm/parseurl@.*$ - cpe:/a:parse-url_project:parse-url + cpe:/a:parse-url(_project)?:parse-url.* ^pkg:maven/com\.graphql-java-kickstart/graphql-java-kickstart@.*$ - cpe:/a:graphql-java_project:graphql-java + cpe:/a:graphql-java(_project)?:graphql-java.* ^pkg:maven/net\.sourceforge\.htmlunit/htmlunit-cssparser@.*$ - cpe:/a:htmlunit_project:htmlunit + cpe:/a:htmlunit(_project)?:htmlunit.* @@ -5515,49 +4999,49 @@ FP per issue #4853 ]]> ^pkg:maven/com\.graphql-java-kickstart/graphql-java-servlet@.*$ - cpe:/a:graphql-java_project:graphql-java + cpe:/a:graphql-java(_project)?:graphql-java.* ^pkg:maven/com\.apollographql\.federation/federation-graphql-java-support@.*$ - cpe:/a:graphql-java_project:graphql-java + cpe:/a:graphql-java(_project)?:graphql-java.* ^pkg:maven/com\.graphql-java/graphql-java-extended-scalars@.*$ - cpe:/a:graphql-java_project:graphql-java + cpe:/a:graphql-java(_project)?:graphql-java.* ^pkg:maven/com\.apollographql\.federation/federation-graphql-java-support-api@.*$ - cpe:/a:graphql-java_project:graphql-java + cpe:/a:graphql-java(_project)?:graphql-java.* ^pkg:maven/io\.github\.graphql-java/graphql-java-annotations@.*$ - cpe:/a:graphql-java_project:graphql-java + cpe:/a:graphql-java(_project)?:graphql-java.* ^pkg:maven/com\.graphql-java/java-dataloader@.*$ - cpe:/a:graphql-java_project:graphql-java + cpe:/a:graphql-java(_project)?:graphql-java.* ^pkg:maven/com\.graphql-java-kickstart/graphql-java-tools@.*$ - cpe:/a:graphql-java_project:graphql-java + cpe:/a:graphql-java(_project)?:graphql-java.* ^pkg:maven/net\.minidev/accessors-smart@.*$ - cpe:/a:json-smart_project:json-smart-v1 + cpe:/a:json-smart(_project)?:json-smart-v1.* ^pkg:maven/com\.github\.pagehelper/pagehelper-spring-boot-starter@.*$ - cpe:/a:pagehelper_project:pagehelper + cpe:/a:pagehelper(_project)?:pagehelper.* ^pkg:cocoapods/GoogleUtilities%2FAppDelegateSwizzler@.*$ - cpe:/a:app_project:app + cpe:/a:app(_project)?:app.* cpe:/a:delegate:delegate @@ -5791,10 +5275,10 @@ ^pkg:maven/org\.msgpack/.*@.*$ - cpe:/a:messagepack_project:messagepack + cpe:/a:messagepack(_project)?:messagepack.* ^pkg:maven/io\.zipkin\.reporter2/zipkin-reporter@.*$ - cpe:/a:pki-core_project:pki-core + cpe:/a:pki-core(_project)?:pki-core.* ^pkg:maven/io\.zipkin\.zipkin2/zipkin@.*$ - cpe:/a:pki-core_project:pki-core + cpe:/a:pki-core(_project)?:pki-core.* ^pkg:maven/org\.junit\.jupiter/junit-jupiter-engine@.*$ - cpe:/a:fan_platform_project:fan_platform + cpe:/a:fan_platform(_project)?:fan_platform.* ^pkg:maven/com\.github\.pagehelper/pagehelper-spring-boot-autoconfigure@.*$ - cpe:/a:pagehelper_project:pagehelper + cpe:/a:pagehelper(_project)?:pagehelper.* ^pkg:maven/io\.zipkin\.zipkin2/zipkin-collector@.*$ - cpe:/a:pki-core_project:pki-core + cpe:/a:pki-core(_project)?:pki-core.* CVE-2021-4277 - - ^pkg:maven/com\.google\.crypto\.tink/apps-webpush@.*$ - cpe:/a:google:google_apps + ^pkg:maven/com\.google\.crypto\.tink/apps-webpush@.*$ + cpe:/a:google:google_apps - - ^pkg:maven/com\.github\.java-json-tools/json-patch@.*$ - cpe:/a:json-patch_project:json-patch + ^pkg:maven/com\.github\.java-json-tools/json-patch@.*$ + cpe:/a:json-patch(_project)?:json-patch.* - - ^pkg:maven/net\.pwall\.json/json-pointer@.*$ - cpe:/a:json-pointer_project:json-pointer + ^pkg:maven/net\.pwall\.json/json-pointer@.*$ + cpe:/a:json-pointer(_project)?:json-pointer.* - - ^pkg:maven/com\.graphql-java-kickstart/graphql-spring-boot-starter@.*$ - cpe:/a:graphql-java_project:graphql-java + ^pkg:maven/com\.graphql-java-kickstart/graphql-spring-boot-starter@.*$ + cpe:/a:graphql-java(_project)?:graphql-java.* - - ^pkg:maven/org\.apache\.hadoop\.thirdparty/hadoop-shaded-guava@.*$ - cpe:/a:apache:hadoop + ^pkg:maven/org\.apache\.hadoop\.thirdparty/hadoop-shaded-guava@.*$ + cpe:/a:apache:hadoop - - ^pkg:maven/com\.datastax\.oss/native-protocol@.*$ - cpe:/a:apache:cassandra + ^pkg:maven/com\.datastax\.oss/native-protocol@.*$ + cpe:/a:apache:cassandra - - ^pkg:maven/org\.apache\.camel/camel-ftp@.*$ - cpe:/a:ftp_project:ftp + ^pkg:maven/org\.apache\.camel/camel-ftp@.*$ + cpe:/a:ftp(_project)?:ftp.* - - ^pkg:npm/jsonpointer@.*$ - cpe:/a:json-pointer_project:json-pointer + ^pkg:npm/jsonpointer@.*$ + cpe:/a:json-pointer(_project)?:json-pointer.* - - ^pkg:maven/com\.google\.flatbuffers/flatbuffers-java@.*$ - cpe:/a:flat_project:flat + ^pkg:maven/com\.google\.flatbuffers/flatbuffers-java@.*$ + cpe:/a:flat(_project)?:flat.* ^pkg:maven/com\.graphql\-java\-kickstart/.*$ - cpe:/a:graphql-java_project:graphql-java + cpe:/a:graphql-java(_project)?:graphql-java.* ^(?!pkg:maven/org\.json/json@).+$ - cpe:/a:json-java_project:json-java + cpe:/a:json-java(_project)?:json-java.* ^(?!pkg:npm/flat@).+$ - cpe:/a:flat_project:flat + cpe:/a:flat(_project)?:flat.* ^pkg:maven/com\.apollographql\.apollo/.*$ - cpe:/a:apollo_project:apollo + cpe:/a:apollo(_project)?:apollo.* + FP per issue #5333 + ]]> ^pkg:maven/com\.graphql-java-kickstart/graphql-kickstart-spring-support@.*$ - cpe:/a:graphql-java_project:graphql-java + cpe:/a:graphql-java(_project)?:graphql-java.* + FP per issue #5336 + ]]> ^pkg:maven/org\.openrewrite\.recipe/rewrite-jhipster@.*$ cpe:/a:jhipster:jhipster + FP per issue #5361 + ]]> ^pkg:maven/jakarta\.resource/jakarta\.resource-api@.*$ cpe:/a:payara:payara + FP per issue #5373 + ]]> ^pkg:maven/org\.locationtech\.spatial4j/spatial4j@.*$ - cpe:/a:voyager_project:voyager + cpe:/a:voyager(_project)?:voyager.* + FP per issue #5372 + ]]> ^pkg:maven/org\.locationtech\.spatial4j/spatial4j@.*$ - cpe:/a:smiley_project:smiley + cpe:/a:smiley(_project)?:smiley.* + FP per issue #5380 + ]]> ^pkg:maven/dev\.ludovic\.netlib/lapack@.*$ - cpe:/a:lapack_project:lapack + cpe:/a:lapack(_project)?:lapack.* + FP per issue #5375 + ]]> ^pkg:maven/org\.eclipse\.microprofile\.jwt/microprofile-jwt-auth-api@.*$ cpe:/a:payara:payara + FP per issue #5368 + ]]> ^pkg:maven/org\.apache\.hadoop\.thirdparty/hadoop-shaded-protobuf_3_7@.*$ cpe:/a:apache:hadoop + FP per issue #5325 + ]]> ^pkg:maven/com\.enterprisedt/edtFTPj@.*$ - cpe:/a:ftp_project:ftp + cpe:/a:ftp(_project)?:ftp.* + FP per issue #5436 + ]]> ^pkg:maven/org\.codehaus\.woodstox/stax2-api@.*$ cpe:/a:fasterxml:woodstox + FP per issue #5459 + ]]> ^pkg:maven/com\.oracle\.database\.nls/orai18n@.*$ cpe:/a:oracle:database + FP per issue #5460 + ]]> ^pkg:maven/com\.oracle\.database\.nls/orai18n@.*$ cpe:/a:oracle:oracle_database + FP per issue #5501 + ]]> ^pkg:maven/org\.jsonschema2pojo/jsonschema2pojo-jdk-annotation@.*$ - cpe:/a:json-schema_project:json-schema + cpe:/a:json-schema(_project)?:json-schema.* + FP per issue #5500 + ]]> ^pkg:maven/org\.apache\.iceberg/iceberg-orc@.*$ cpe:/a:apache:orc + FP per issue #5499 + ]]> ^pkg:maven/org\.apache\.iceberg/iceberg-flink-1\.15@.*$ cpe:/a:apache:flink + FP per issue #5498 + ]]> ^pkg:maven/com\.googlecode\.javaewah/JavaEWAH@.*$ cpe:/a:google:google_search + FP per issue #5497 + ]]> ^pkg:maven/com\.google\.cloud/grpc-gcp@.*$ cpe:/a:grpc:grpc + FP per issue #5496 + ]]> ^pkg:maven/org\.apache\.flink/flink-s3-fs-hadoop@.*$ cpe:/a:apache:hadoop + FP per issue #5492 + ]]> ^pkg:maven/com\.microsoft\.azure/azure-cosmosdb-direct@.*$ cpe:/a:microsoft:platform_sdk + FP per issue #5491 + ]]> ^pkg:maven/com\.microsoft\.azure/azure-cosmosdb@.*$ - cpe:/a:www-sql_project:www-sql + cpe:/a:www-sql(_project)?:www-sql.* + FP per issue #5490 + ]]> ^pkg:maven/com\.microsoft\.azure/azure-cosmosdb@.*$ - cpe:/a:async_project:async + cpe:/a:async(_project)?:async.* + FP per issue #5471 + ]]> ^pkg:maven/org\.apache\.spark/spark-token-provider-kafka-0-10_2\.12@.*$ cpe:/a:apache:kafka + FP per issue #5462 + ]]> ^pkg:maven/org\.apache\.ws\.commons\.axiom/axiom-impl@.*$ - cpe:/a:web_project:web + cpe:/a:web(_project)?:web.* + FP per issue #5461 + ]]> ^pkg:maven/com\.github\.luben/zstd-jni@.*$ cpe:/a:freebsd:freebsd + FP per issue #5506 + ]]> ^pkg:maven/io\.kamon/kamon-prometheus_2\.13@.*$ cpe:/a:prometheus:prometheus + + + + + ^pkg:maven/com\.github\.dasniko/testcontainers-keycloak@.*$ + cpe:/a:keycloak:keycloak + + + + ^pkg:maven/org\.apache\.kerby/zookeeper-backend@.*$ + cpe:/a:apache:zookeeper + + + + ^pkg:maven/org\.apache\.camel\.springboot/camel-ftp-starter@.*$ + cpe:/a:ftp(_project)?:ftp.* + + + + ^pkg:maven/javax\.resource/connector@.*$ + cpe:/a:sun:j2ee + + + + ^pkg:maven/org\.springframework\.cloud/spring-cloud-sleuth-autoconfigure@.*$ + cpe:/a:vmware:spring_cloud_config + + + + ^pkg:maven/org\.jfrog\.artifactory\.client/artifactory-java-client-services@.*$ + cpe:/a:jfrog:artifactory + + + + ^pkg:maven/net\.minidev/accessors-smart@.*$ + cpe:/a:json-smart(_project)?:json-smart.* + + + + ^pkg:maven/org\.springframework\.integration/spring-integration-ftp@.*$ + cpe:/a:vmware:spring_integration + + + + ^pkg:maven/com\.graphql-java/graphql-java-extended-scalars@.*$ + cpe:/a:graphql-java:graphql-java + + + + ^pkg:maven/com\.graphql-java-kickstart/graphql-java-tools@.*$ + cpe:/a:graphql-java:graphql-java + + + + ^pkg:maven/com\.graphql-java-kickstart/graphql-java-servlet@.*$ + cpe:/a:graphql-java:graphql-java + + + + ^pkg:maven/com\.graphql-java-kickstart/graphql-java-kickstart@.*$ + cpe:/a:graphql-java:graphql-java + + + + ^pkg:maven/com\.graphql-java-kickstart/graphql-kickstart-spring-support@.*$ + cpe:/a:graphql-java:graphql-java + + + + ^pkg:maven/org\.bouncycastle/bcpg-jdk15on@.*$ + cpe:/a:open_cas(_project)?:open_cas.* + + + + ^pkg:maven/org\.jboss\.resteasy\.microprofile/microprofile-config@.*$ + cpe:/a:redhat:resteasy + + + + ^pkg:maven/org\.apache\.ignite/ignite-log4j2@.*$ + cpe:/a:apache:log4j + + + + ^pkg:maven/org\.apache\.directory\.api/api-ldap-net-mina@.*$ + cpe:/a:apache:mina + + + + ^pkg:maven/com\.graphql-java-kickstart/graphql-webclient@.*$ + cpe:/a:graphql-java:graphql-java + + + + ^pkg:maven/io\.quarkiverse\.openapi\.generator/quarkus-openapi-generator@.*$ + cpe:/a:openapi-generator:openapi_generator + + + + ^pkg:nuget/MagicFileEncoding@.*$ + cpe:/a:file(_project)?:file.* + + + + ^pkg:nuget/FluentFTP@.*$ + cpe:/a:ftp:ftp + + + + ^pkg:nuget/KubernetesClient@.*$ + cpe:/a:kubernetes:kubernetes + + + + ^pkg:maven/org\.apache\.sling/org\.apache\.sling\.commons\.johnzon@.*$ + cpe:/a:apache:sling_commons_json + + + + ^pkg:nuget/AspNetCoreRateLimit\.Redis@.*$ + cpe:/a:asp-project:asp-project + + + + ^pkg:maven/io\.swagger\.parser\.v3/swagger-parser-safe-url-resolver@.*$ + cpe:/a:parse-url(_project)?:.* + + + + ^pkg:maven/org\.jruby/jzlib@.*$ + cpe:/a:jruby:jruby + + + + ^pkg:maven/com\.bazaarvoice\.jolt/json-utils@.*$ + cpe:/a:utils(_project)?:utils.* + + + + ^pkg:maven/org\.springframework\.integration/spring-integration-ftp@.*$ + cpe:/a:ftp(_project)?:ftp.* + + + + ^pkg:maven/org\.mockftpserver/MockFtpServer@.*$ + cpe:/a:ftp(_project)?:ftp.* + + + + ^pkg:maven/com\.sun\.xml\.bind\.jaxb/isorelax@.*$ + cpe:/a:xml_library_project:xml_library.* + + + + ^pkg:maven/org\.jboss\.resteasy\.microprofile/.*$ + cpe:/a:redhat:resteasy + + + + + ^pkg:maven/org\.jboss\.resteasy\.microprofile/microprofile-rest-client@.*$ + cpe:/a:redhat:resteasy + + + + ^pkg:maven/org\.apache\.sling/org\.apache\.sling\.commons\.osgi@.*$ + cpe:/a:apache:sling + + + + ^pkg:maven/cloud\.localstack/localstack-utils@.*$ + cpe:/a:utils(_project)?:utils + + + + ^pkg:nuget/Minio\.AspNetCore@.*$ + cpe:/a:minio:minio + + + + ^pkg:maven/org\.apache\.thrift/libfb303@.*$ + cpe:/a:apache:thrift + + + + ^pkg:nuget/RazorEngine\.NetCore@.*$ + cpe:/a:razorengine(_project)?:razorengine.* + + + + ^pkg:maven/io\.github\.graphql-java/graphql-java-annotations@.*$ + cpe:/a:graphql-java:graphql-java + + + + ^pkg:maven/com\.graphql-java-kickstart/graphql-spring-boot-starter@.*$ + cpe:/a:graphql-java:graphql-java + + + + ^pkg:maven/com\.graphql-java/java-dataloader@.*$ + cpe:/a:graphql-java:graphql-java + + + + ^pkg:maven/com\.apollographql\.federation/federation-graphql-java-support-api@.*$ + cpe:/a:graphql-java:graphql-java + + + + ^pkg:maven/com\.apollographql\.federation/federation-graphql-java-support@.*$ + cpe:/a:graphql-java:graphql-java + + + + ^pkg:maven/org\.apache\.cxf/cxf-rt-bindings-soap@.*$ + cpe:/a:apache:soap + + + + ^pkg:nuget/Microsoft\.Win32\.SystemEvents@.*$ + cpe:/a:events(_project)?:events.* + + + + ^(?!pkg:maven/net\.pwall\.json/jsonutil).*$ + cpe:/a:jsonutil(_project)?:jsonutil.* + + + + ^pkg:maven/com\.apollographql\.apollo3/.*$ + cpe:/a:apollo(_project)?:apollo.* + + + + + ^pkg:maven/com\.apollographql\.apollo3/apollo-annotations-jvm@.*$ + cpe:/a:apollo(_project)?:apollo.* + + + + ^pkg:maven/com\.itextpdf\.licensing/licensing-base@.*$ + cpe:/a:itextpdf:itext + + + + ^pkg:maven/com\.itextpdf\.licensing/licensing-remote@.*$ + cpe:/a:itextpdf:itext + + + + ^pkg:npm/wordwrap@.*$ + cpe:/a:word-wrap(_project)?:word-wrap.* + + + + ^pkg:maven/com\.exactpro\.th2/netty-bytebuf-utils@.*$ + cpe:/a:utils(_project)?:utils.* + + + + ^pkg:maven/io\.github\.detekt\.sarif4k/sarif4k-jvm@.*$ + cpe:/a:detekt:detekt + + + + ^pkg:maven/org\.apache\.avro/avro@.*$ + cpe:/a:avro(_project)?:avro.* + + + + ^pkg:maven/commons-logging/commons-logging@.*$ + cpe:/a:morgan(_project)?:morgan.* + + + + ^pkg:maven/com\.lightbend\.akka\.grpc/.*$ + cpe:/a:akka:akka + cpe:/a:lightbend:akka + cpe:/a:grpc:grpc + + + + ^pkg:maven/com\.lightbend\.akka/akka-persistence-r2dbc.*$ + cpe:/a:akka:akka + cpe:/a:lightbend:akka + + + + ^pkg:maven/com\.lightbend\.akka/akka-projection-.*$ + cpe:/a:akka:akka + cpe:/a:lightbend:akka + + + + ^pkg:maven/com\.lightbend\.akka/akka-projection-grpc.*$ + cpe:/a:grpc:grpc + + + + ^pkg:maven/org\.apache\.jackrabbit/oak-.*$ + cpe:/a:apache:jackrabbit + + + + ^pkg:maven/org\.apache\.jackrabbit/oak-core@.*$ + cpe:/a:apache:jackrabbit + + + + ^pkg:maven/com\.vaadin/vaadin-swing-kit-flow@.*$ + cpe:/a:vaadin:flow + + + + ^pkg:maven/org\.apache\.sling/org\.apache\.sling\.commons\.johnzon@.*$ + cpe:/a:apache:sling + + + + ^pkg:maven/io\.netty\.incubator/netty-incubator-codec-classes-quic@.*$ + cpe:/a:quic(_project)?:quic.* + + + + ^pkg:maven/org\.apache\.geronimo\.specs/geronimo-saaj_1\.3_spec@.*$ + cpe:/a:apache:soap + + + + ^pkg:maven/org\.ops4j\.pax\.logging/pax-logging-log4j2@.*$ + cpe:/a:apache:log4j + + + + ^pkg:maven/software\.amazon\.awssdk\.crt/aws-crt@.*$ + cpe:/a:amazon:aws-sdk-java + + + + + ^pkg:(pypi|nuget|generic|npm|composer)/.*[rR]edis.*@.*$ + cpe:/a:redis:redis: + + + + + ^pkg:maven/com\.adobe\.cq/core\.wcm\.components\.core@.*$ + cpe:/a:adobe:download_manager + + + + ^pkg:maven/com\.adobe\.cq/core\.wcm\.components\.core@.*$ + cpe:/a:adobe:experience_manager + + + + ^pkg:maven/com\.adobe\.cq/core\.wcm\.components\.core@.*$ + cpe:/a:adobe:experience_manager_forms + + + + ^pkg:maven/com\.adobe\.cq/core\.wcm\.components\.core@.*$ + cpe:/a:adobe:form_client + + + + ^pkg:maven/com\.adobe\.cq/core\.wcm\.components\.core@.*$ + cpe:/a:list_site_pro:list_site_pro + + + + ^pkg:maven/com\.adobe\.cq/core\.wcm\.components\.core@.*$ + cpe:/a:oembed(_project)?:oembed.* + + + + ^pkg:maven/com\.adobe\.cq/core\.wcm\.components\.core@.*$ + cpe:/a:xml_library(_project)?:xml_library.* + + + + ^pkg:maven/org\.springframework\.plugin/spring-plugin-core@.*$ + cpe:/a:vmware:spring + + + + ^pkg:maven/org\.springframework(?!\.kafka).*$ + CVE-2023-34040 + + + + ^pkg:maven/org\.logback-extensions/logback-ext-spring@.*$ + cpe:/a:qos:logback + + + + ^pkg:npm/mysql@.*$ + cpe:/a:mysql:mysql + + + + ^pkg:maven/io\.projectreactor\.netty\.incubator/reactor-netty-incubator-quic@.*$ + cpe:/a:quic(_project)?:quic.* + + + + ^pkg:maven/net\.rossillo\.mvc\.cache/spring-mvc-cache-control@.*$ + cpe:/a:spring:spring + + + + ^pkg:maven/ch\.qos\.logback\.contrib/logback-json-core@.*$ + cpe:/a:json-c:json-c + + + + ^pkg:maven/io\.netty\.incubator/netty-incubator-codec-native-quic@.*$ + cpe:/a:quic(_project)?:quic.* + + + + ^pkg:maven/ch\.qos\.logback\.contrib/logback-json-classic@.*$ + cpe:/a:json-c:json-c + + + + ^pkg:maven/io\.asyncer/r2dbc-mysql@.*$ + cpe:/a:mysql:mysql + + + + ^pkg:maven/io\.netty\.incubator/netty-incubator-codec-native-quic@.*$ + cpe:/a:chromium(_project)?:chromium.* + + + + ^pkg:maven/io\.netty\.incubator/netty-incubator-codec-native-quic@.*$ + cpe:/a:chromium:chromium + + + + ^pkg:maven/xalan/xalan@.*$ + cpe:/a:apache:commons_bcel + + + + ^pkg:nuget/CommandLineParser@.*$ + cpe:/a:line:line + + + + ^pkg:nuget/Serilog\.Sinks\.Async@.*$ + cpe:/a:async(_project)?:async.* + + + + ^pkg:maven/org\.flywaydb/flyway-database-postgresql@.*$ + cpe:/a:postgresql:postgresql + + + + ^pkg:maven/net\.lbruun\.springboot/preliquibase-spring-boot-starter@.*$ + cpe:/a:liquibase:liquibase + + + + ^pkg:maven/rubygems/.*@.*$ + cpe:/a:rubygems:rubygems + + + + ^pkg:maven/org\.apache\.parquet/parquet-avro@.*$ + cpe:/a:apache:avro + + + + ^pkg:maven/commons-net/commons-net@.*$ + cpe:/a:ftp(_project)?:ftp.* + + + + ^pkg:maven/org\.apache\.camel/camel-reactive-executor-tomcat@.*$ + cpe:/a:apache_tomcat:apache_tomcat + + + + ^pkg:maven/info\.picocli/picocli@.*$ + cpe:/a:line:line + + + + ^pkg:maven/org\.jruby\.rack/jruby-rack@.*$ + cpe:/a:rack(_project)?:rack.* + + + + ^pkg:maven/io\.r2dbc/r2dbc-mssql@.*$ + cpe:/a:microsoft:sql_server + + + + ^pkg:maven/org\.thymeleaf\.extras/thymeleaf-extras-java8time@.*$ + cpe:/a:thymeleaf:thymeleaf + + + + ^pkg:maven/com\.idealista/format-preserving-encryption@.*$ + cpe:/a:vega(_project)?:vega.* + + + + ^pkg:maven/org\.keycloak/keycloak-model-infinispan@.*$ + cpe:/a:infinispan:infinispan + + + + ^pkg:maven/org\.wildfly\.security\.elytron-web/undertow-server@.*$ + cpe:/a:web(_project)?:web.* + + + + ^pkg:maven/org\.jgroups\.azure/jgroups-azure@.*$ + cpe:/a:redhat:jgroups + + + + ^pkg:maven/com\.bornium/oauth2-openid@.*$ + cpe:/a:openid:openid + + + + ^pkg:maven/org\.hsqldb/hsqldb@.*$ + cpe:/a:hyper:hyper + + + + ^pkg:maven/io\.swagger/swagger-parser-safe-url-resolver@.*$ + cpe:/a:parse-url(_project)?:parse-url.* + + + + ^pkg:maven/org\.jboss\.activemq\.artemis\.integration/artemis-wildfly-integration@.*$ + cpe:/a:redhat:wildfly + + + + ^pkg:npm/bare-os@.*$ + cpe:/a:bareos:bareos + + + + ^pkg:maven/io\.ktor/ktor-server-metrics-micrometer-jvm@.*$ + cpe:/a:csm_server(_project)?:csm_server.* + + + + ^pkg:maven/org\.apache\.camel\.quarkus/camel-quarkus-core@.*$ + cpe:/a:apache:camel + + + + + ^pkg:maven/org\.apache\.rat/apache-rat@.*$ + cpe:/a:line:line + + + + ^pkg:nuget/MagicFileEncoding@.*$ + cpe:/a:file:file + + + + ^pkg:nuget/MongoDB\.Bson@.*$ + cpe:/a:mongodb:mongodb + + + + ^pkg:maven/io\.opentelemetry\.contrib/opentelemetry-prometheus-client-bridge@.*$ + cpe:/a:prometheus:prometheus + + + + ^pkg:maven/org\.springframework\.batch\.extensions/spring-batch-excel@.*$ + cpe:/a:pivotal_software:spring_batch + + + + ^pkg:maven/org\.glassfish(?!\.main).*$ + cpe:/a:eclipse:glassfish + + + + ^pkg:maven/org\.apache\.shiro\.crypto/shiro.*@2.0.0$ + CVE-2023-34478 + CVE-2023-46749 + CVE-2023-46750 + + + + ^pkg:maven/org\.apache\.shiro/shiro.*@2.0.0$ + CVE-2023-34478 + CVE-2023-46749 + CVE-2023-46750 + + + + ^pkg:(?!maven/org\.clojure/clojure@).*$ + cpe:/a:clojure:clojure + + + + + ^pkg:maven/io\.pivotal\.cfenv/java-cfenv@.*$ + cpe:/a:vmware:spring_framework + + + + ^pkg:maven/io\.pivotal\.cfenv/java-cfenv-jdbc@.*$ + cpe:/a:vmware:spring_framework + + + + ^pkg:maven/io\.pivotal\.cfenv/java-cfenv-boot@.*$ + cpe:/a:vmware:spring_framework + + + + ^pkg:maven/org\.togglz/togglz-mongodb@.*$ + cpe:/a:mongodb:mongodb + + + + ^pkg:nuget/dbup-postgresql@.*$ + cpe:/a:postgresql:postgresql + + + + ^pkg:maven/org\.eclipse\.jetty\.toolchain/.*@.*$ + cpe:/a:jetty:jetty + cpe:/a:eclipse:jetty + + + + ^pkg:maven/org\.lz4/lz4-java@.*$ + cpe:/a:lz4(_project)?:lz4.* + + + + ^pkg:maven/org\.apache\.logging\.log4j/log4j-slf4j2-impl@.*$ + cpe:/a:log4js(_project)?:log4js.* + + + + ^pkg:maven/io\.ktor/ktor-server-call-logging-jvm@.*$ + cpe:/a:call(_project)?:call.* + + + + ^pkg:maven/io\.ktor/ktor-client-content-negotiation-jvm@.*$ + cpe:/a:content(_project)?:content.* + + + + ^pkg:maven/org\.hibernate\.validator/hibernate-validator@.*$ + cpe:/a:validator(_project)?:validator.* + + + + ^pkg:generic/Mono.Cecil@.*$ + cpe:/a:cecil:cecil + + + + ^pkg:maven/com\.google\.http-client/google-http-client-protobuf@.*$ + cpe:/a:google:protobuf-java + + + + ^pkg:maven/io\.prometheus/prometheus-metrics-model@.*$ + cpe:/a:model(_project)?:model.* + + + + ^pkg:maven/io\.zipkin\.contrib\.brave-propagation-w3c/brave-propagation-tracecontext@.*$ + cpe:/a:brave:brave + + + + ^pkg:maven/io\.micrometer/micrometer-tracing-bridge-brave@.*$ + cpe:/a:brave:brave + + + + ^pkg:maven/org\.junit\..*/junit-.*@.*$ + cpe:/a:1e:platform + + + + ^pkg:maven/org\.springframework\.boot/spring-boot-jarmode-tools@.*$ + cpe:/a:vmware:tools + + + + ^pkg:maven/org\.apache\.sandesha2/sandesha2.*$ + cpe:/a:apache:axis2 + cpe:/a:apache:axis + + + + ^pkg:maven/org\.eclipse\.jetty/jetty-openid@.*$ + cpe:/a:openid:openid + + + + ^pkg:maven/org\.springframework\.security/spring-security-oauth2-resource-server@.*$ + cpe:/a:vmware:server + + + + ^pkg:maven/org\.springframework\.security/spring-security-oauth2-authorization-server@.*$ + cpe:/a:oauth2-server(_project)?:oauth2-server.* + + + + ^pkg:maven/commons-validator/commons-validator@.*$ + cpe:/a:validator(_project)?:validator.* + + + + ^pkg:maven/io\.pivotal\.cfenv/java-cfenv-boot@.*$ + cpe:/a:vmware:spring_boot + + + + ^pkg:maven/org\.jeecgframework/autopoi-web@.*$ + cpe:/a:web(_project)?:web.* + + + + ^pkg:maven/com\.yahoo\.datasketches/sketches-core@.*$ + cpe:/a:sketch:sketch + + + + ^pkg:maven/org\.springframework\.boot/spring-boot-starter-cache@.*$ + cpe:/a:cache(_project)?:cache.* + + + + ^pkg:maven/javax\.cache/cache-api@.*$ + cpe:/a:cache(_project)?:cache.* + + + + + ^pkg:maven/com\.azure/azure-core-http-netty@.*$ + cpe:/a:microsoft:azure_cli + + + + ^pkg:maven/com\.azure/azure-core@.*$ + cpe:/a:microsoft:azure_cli + + + + ^pkg:maven/org\.tukaani/xz@.*$ + cpe:/a:tukaani:xz + + + + ^pkg:maven/org\.bouncycastle/bc(pg)?-fips@.*$ + cpe:/a:bouncycastle:legion-of-the-bouncy-castle + + + + ^pkg:maven/org\.bouncycastle/bc(pg)?-fips@.*$ + cpe:/a:bouncycastle:bouncy_castle_for_java + + + + ^pkg:maven/commons-discovery/commons-discovery@.*$ + cpe:/a:spirit-project:spirit + + + + .*(\.(dll|jar|ear|war|pom|nupkg|nuspec|aar)|pom\.xml|package.json|packages.config)$ + cpe:/a:services(_project)?:services.* + + + + ^pkg:maven/io\.github\.reactivecircus\.cache4k/cache4k-jvm@.*$ + cpe:/a:cache(_project)?:cache.* + + + + ^pkg:maven/org\.jmdns/jmdns@.*$ + cpe:/a:openhab:openhab + + + + ^pkg:maven/com\.azure/azure-identity@.*$ + cpe:/a:microsoft:azure_cli + + + + ^pkg:maven/com\.apollographql\.federation/federation-graphql-java-support@.*$ + cpe:/a:apollo(_project)?:apollo.* + + + + ^pkg:maven/fi\.solita\.clamav/clamav-client@.*$ + cpe:/a:clamav:clamav + + + + ^pkg:maven/jakarta\.json/jakarta\.json-api@.*$ + cpe:/a:eclipse:glassfish + + + + ^pkg:maven/org\.glassfish\.jaxb/jaxb-runtime@.*$ + cpe:/a:eclipse:glassfish + + + + ^pkg:maven/org\.apache\.ftpserver/ftplet-api@.*$ + cpe:/a:apache:apache_http_server + + + + ^pkg:maven/org\.apache\.ftpserver/ftpserver-core@.*$ + cpe:/a:apache:apache_http_server + + + + ^pkg:maven/org\.apache\.ftpserver/ftplet-api@.*$ + ^cpe:/a:apache:mina:.* + + + + ^pkg:maven/io\.prometheus/prometheus-.*$ + cpe:/a:prometheus:prometheus + + + + ^(mysql:mysql-connector-java|com\.mysql:mysql-connector-j|org\.drizzle\.jdbc:drizzle-jdbc):.*$ + cpe:/a:mysql:mysql: + cpe:/a:oracle:mysql: + + + + ^pkg:nuget/IronPython@.*$ + cpe:/a:python:python + + + + ^pkg:maven/(?!.*org\.eclipse\.equinox\.p2).*$ + CVE-2021-41033 + diff --git a/core/src/main/resources/dependencycheck-cache.properties b/core/src/main/resources/dependencycheck-cache.properties index a3d4fc49d0e..30ae65bd314 100644 --- a/core/src/main/resources/dependencycheck-cache.properties +++ b/core/src/main/resources/dependencycheck-cache.properties @@ -1,11 +1,11 @@ # DEFAULT CACHE REGION jcs.default=ODC -jcs.default.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes -jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs.engine.memory.lru.LRUMemoryCache +jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes +jcs.default.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache jcs.default.cacheattributes.UseMemoryShrinker=false jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600 jcs.default.cacheattributes.ShrinkerIntervalSeconds=60 -jcs.default.elementattributes=org.apache.commons.jcs.engine.ElementAttributes +jcs.default.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes jcs.default.elementattributes.IsEternal=false # use zero max objects with an update pattern to force disk caching jcs.default.cacheattributes.MaxObjects=0 @@ -19,8 +19,8 @@ jcs.default.elementattributes.IsLateral=false #note - some region attributes are defined at load tiem in the DataCacheFactory. jcs.region.CENTRAL=ODC -jcs.region.CENTRAL.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes -jcs.region.CENTRAL.elementattributes=org.apache.commons.jcs.engine.ElementAttributes +jcs.region.CENTRAL.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes +jcs.region.CENTRAL.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes jcs.region.CENTRAL.cacheattributes.MaxObjects=0 jcs.region.CENTRAL.cacheattributes.DiskUsagePattern=UPDATE #30 day cache life for Central @@ -31,8 +31,8 @@ jcs.region.CENTRAL.elementattributes.IsLateral=false #note - some region attributes are defined at load tiem in the DataCacheFactory. jcs.region.POM=ODC -jcs.region.POM.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes -jcs.region.POM.elementattributes=org.apache.commons.jcs.engine.ElementAttributes +jcs.region.POM.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes +jcs.region.POM.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes jcs.region.POM.cacheattributes.MaxObjects=0 jcs.region.POM.cacheattributes.DiskUsagePattern=UPDATE #90 day cache life for POM files from Central - this should likely be higher... @@ -43,8 +43,8 @@ jcs.region.POM.elementattributes.IsLateral=false jcs.region.NODEAUDIT=ODC -jcs.region.NODEAUDIT.cacheattributes=org.apache.commons.jcs.engine.CompositeCacheAttributes -jcs.region.NODEAUDIT.elementattributes=org.apache.commons.jcs.engine.ElementAttributes +jcs.region.NODEAUDIT.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes +jcs.region.NODEAUDIT.elementattributes=org.apache.commons.jcs3.engine.ElementAttributes jcs.region.NODEAUDIT.cacheattributes.MaxObjects=0 jcs.region.NODEAUDIT.cacheattributes.DiskUsagePattern=UPDATE #24 hour default cache life @@ -54,8 +54,8 @@ jcs.region.NODEAUDIT.elementattributes.IsRemote=false jcs.region.NODEAUDIT.elementattributes.IsLateral=false # AVAILABLE AUXILIARY CACHES -jcs.auxiliary.ODC=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory -jcs.auxiliary.ODC.attributes=org.apache.commons.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes +jcs.auxiliary.ODC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory +jcs.auxiliary.ODC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes #jcs.auxiliary.ODC.attributes.DiskPath=$ {user.dir}/jcs_swap jcs.auxiliary.ODC.attributes.MaxPurgatorySize=10000000 jcs.auxiliary.ODC.attributes.MaxKeySize=1000000 diff --git a/core/src/main/resources/dependencycheck.properties b/core/src/main/resources/dependencycheck.properties index 69a5cc6142b..edfc4f96b06 100644 --- a/core/src/main/resources/dependencycheck.properties +++ b/core/src/main/resources/dependencycheck.properties @@ -3,7 +3,7 @@ odc.application.version=${pom.version} odc.autoupdate=true # the url to obtain the current engine version from -engine.version.url=https://jeremylong.github.io/DependencyCheck/current.txt +engine.version.url=https://dependency-check.github.io/DependencyCheck/current.txt #temp.directory defaults to System.getProperty("java.io.tmpdir") #temp.directory=[path to temp directory] @@ -14,20 +14,20 @@ engine.version.url=https://jeremylong.github.io/DependencyCheck/current.txt # to be supplied. If you are using another database (MySQL, Oracle, etc.) this property # will not be used. The data.directory will be resolved and if the connection string # below contains a %s then the data.directory will replace the %s. -data.directory=[JAR]/data/7.0 +data.directory=[JAR]/data/11.0 #if the filename has a %s it will be replaced with the current expected version data.file_name=odc.mv.db ### if you increment the DB version then you must increment the database file path ### in the mojo.properties, task.properties (maven and ant respectively), and ### the gradle PurgeDataExtension. -data.version=5.4 +data.version=5.5 #The analysis timeout in minutes odc.analysis.timeout=180 # define which settings are masked when logged -odc.settings.mask=.*password.*,.*token.* +odc.settings.mask=.*password.*,.*token.*,.*api.key.* data.connection_string=jdbc:h2:file:%s;AUTOCOMMIT=ON;CACHE_SIZE=65536;RETENTION_TIME=1000;MAX_COMPACT_TIME=10000; #data.connection_string=jdbc:mysql://localhost:3306/dependencycheck @@ -44,32 +44,23 @@ data.password=DC-Pass1337! # to ensure any and all needed files can be added to the classpath to load the driver. # For non-JDBC4 drivers in the classpath only the driver_name needs to be set. # For MOST situations these properties likely do not need to be set. +# data.driver_path= data.driver_name=org.h2.Driver -#data.driver_path= # the class name of the write lock shutdown hook data.writelock.shutdownhook=org.owasp.dependencycheck.utils.WriteLockCleanupHook proxy.disableSchemas=true -# the number of days that the modified nvd cve data holds data for. We don't need -# to update the other files if we are within this timespan. Per NIST this file -# holds 8 days of updates, we are using 7 just to be safe. -cve.url.modified.validfordays=7 -# the number of hours to wait before checking if updates are available from the NVD. -cve.check.validforhours=4 -#first year to pull data from the URLs below -cve.startyear=2002 -# the time in milliseconds to wait between downloads from the NVD -cve.download.waittime=4000 -#the original URL and modified URL should be the same; this is used to detect if we are using an internal NVD CVE copy -cve.url.original=https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-modified.json.gz -cve.url.modified=https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-modified.json.gz -cve.url.modified.defaultFilename=nvdcve-1.1-modified.json.gz -cve.url.base=https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-%d.json.gz -cve.url.base.defaultFilename=nvdcve-1.1-%d.json.gz -cve.cpe.startswith.filter=cpe:2.3:a: -nvd.newyear.grace.period=10 +nvd.api.check.validforhours=4 +nvd.api.datafeed.validfordays=7 +nvd.api.max.retry.count=30 +nvd.api.delay=0 +#nvd.api.datafeed.url=https://example.com/nvd-cache/ +#nvd.api.datafeed.user= +#nvd.api.datafeed.password= + +cve.cpe.startswith.filter=cpe:2.3:a: max.download.threads=1 #Known Exploited Vulnerabilities @@ -87,7 +78,7 @@ analyzer.central.url=https://search.maven.org/solrsearch/select # Note - the central query is used in a String.format(query, url, sha1)).analyzer.jar.enabled # As such, it must have two %s and any other % must be escapped by doubling it analyzer.central.query=%s?q=1:%s&wt=xml -analyzer.central.retry.count=7 +analyzer.central.retry.count=3 analyzer.central.parallel.analysis=false analyzer.central.use.cache=true central.content.url=https://search.maven.org/remotecontent?filepath= @@ -147,6 +138,7 @@ analyzer.openssl.enabled=true analyzer.central.enabled=true analyzer.nexus.enabled=false analyzer.cocoapods.enabled=true +analyzer.carthage.enabled=true analyzer.swift.package.manager.enabled=true analyzer.swift.package.resolved.enabled=true #whether the nexus analyzer uses the proxy @@ -170,10 +162,12 @@ ecosystem.skip.cpeanalyzer=npm database.batchinsert.enabled=true database.batchinsert.maxsize=1000 analyzer.artifactory.enabled=false +analyzer.libman.enabled=true odc.reports.pretty.print=false +analyzer.suppression.unused.fail=false hosted.suppressions.enabled=true -hosted.suppressions.url=https://jeremylong.github.io/DependencyCheck/suppressions/publishedSuppressions.xml +hosted.suppressions.url=https://dependency-check.github.io/DependencyCheck/suppressions/publishedSuppressions.xml hosted.suppressions.validforhours=2 ## The following controls the max query limit used in the CPE searches for each ecosystem diff --git a/core/src/main/resources/schema/dependency-check.4.0.xsd b/core/src/main/resources/schema/dependency-check.4.0.xsd new file mode 100644 index 00000000000..e885b0b866e --- /dev/null +++ b/core/src/main/resources/schema/dependency-check.4.0.xsd @@ -0,0 +1,285 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/src/main/resources/schema/dependency-check.4.1.xsd b/core/src/main/resources/schema/dependency-check.4.1.xsd new file mode 100644 index 00000000000..aa9a4584391 --- /dev/null +++ b/core/src/main/resources/schema/dependency-check.4.1.xsd @@ -0,0 +1,339 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/src/main/resources/templates/csvReport.vsl b/core/src/main/resources/templates/csvReport.vsl index 891b1572b4a..620a52098b3 100644 --- a/core/src/main/resources/templates/csvReport.vsl +++ b/core/src/main/resources/templates/csvReport.vsl @@ -17,7 +17,7 @@ Copyright (c) 2017 Jeremy Long. All Rights Reserved. @author Jeremy Long @version 1 *### -"Project","ScanDate","DependencyName","DependencyPath","Description","License","Md5","Sha1","Identifiers","CPE","CVE","CWE","Vulnerability","Source","CVSSv2_Severity","CVSSv2_Score","CVSSv2","CVSSv3_BaseSeverity","CVSSv3_BaseScore","CVSSv3","CPE Confidence","Evidence Count","VendorProject","Product","Name","DateAdded","ShortDescription","RequiredAction","DueDate","Notes"#[[ +"Project","ScanDate","DependencyName","DependencyPath","Description","License","Md5","Sha1","Identifiers","CPE","CVE","CWE","Vulnerability","Source","CVSSv2_Severity","CVSSv2_Score","CVSSv2","CVSSv3_BaseSeverity","CVSSv3_BaseScore","CVSSv3","CVSSv4_BaseSeverity","CVSSv4_BaseScore","CVSSv4","CPE Confidence","Evidence Count","VendorProject","Product","Name","DateAdded","ShortDescription","RequiredAction","DueDate","Notes"#[[ ]]##foreach($dependency in $dependencies)#if($dependency.getVulnerabilities().size()>0)#foreach($vuln in $dependency.getVulnerabilities(true)) -$enc.csv($applicationName),$enc.csv($scanDate),$enc.csv($dependency.DisplayFileName),$enc.csv($dependency.FilePath),$enc.csv($dependency.description),$enc.csv($dependency.license),#if(!$dependency.isVirtual())$enc.csv($dependency.Md5sum)#else""#end,#if(!$dependency.isVirtual())$enc.csv($dependency.Sha1sum)#else""#end,$enc.csvIdentifiers($dependency.softwareIdentifiers),$enc.csvIdentifiers($dependency.vulnerableSoftwareIdentifiers),$enc.csv($vuln.name),$enc.csv($vuln.getCwes().toString()),$enc.csv($vuln.description),$enc.csv($vuln.getSource().name()),#if($vuln.cvssV2)$enc.csv($vuln.cvssV2.severity)#else""#end,#if($vuln.cvssV2)$enc.csv($vuln.cvssV2.score)#else""#end,#if($vuln.cvssV2)$enc.csv($vuln.cvssV2.toString())#else""#end,#if($vuln.cvssV3)$enc.csv($vuln.cvssV3.baseSeverity)#else""#end,#if($vuln.cvssV3)$enc.csv($vuln.cvssV3.baseScore)#else""#end,#if($vuln.cvssV3)$enc.csv($vuln.cvssV3.toString())#else""#end,$enc.csvCpeConfidence($dependency.softwareIdentifiers),$dependency.size(),#if($vuln.getKnownExploitedVulnerability())$enc.csv($vuln.getKnownExploitedVulnerability().getVendorProject()),$enc.csv($vuln.getKnownExploitedVulnerability().getProduct()),$enc.csv($vuln.getKnownExploitedVulnerability().getVulnerabilityName()),$enc.csv($vuln.getKnownExploitedVulnerability().getDateAdded()),$enc.csv($vuln.getKnownExploitedVulnerability().getShortDescription()),$enc.csv($vuln.getKnownExploitedVulnerability().getRequiredAction()),$enc.csv($vuln.getKnownExploitedVulnerability().getDueDate()),$enc.csv($vuln.getKnownExploitedVulnerability().getNotes())#else"","","","","","","",""#end +$enc.csv($applicationName),$enc.csv($scanDate),$enc.csv($dependency.DisplayFileName),$enc.csv($dependency.FilePath),$enc.csv($dependency.description),$enc.csv($dependency.license),#if(!$dependency.isVirtual())$enc.csv($dependency.Md5sum)#else""#end,#if(!$dependency.isVirtual())$enc.csv($dependency.Sha1sum)#else""#end,$enc.csvIdentifiers($dependency.softwareIdentifiers),$enc.csvIdentifiers($dependency.vulnerableSoftwareIdentifiers),$enc.csv($vuln.name),$enc.csv($vuln.getCwes().toString()),$enc.csv($vuln.description),$enc.csv($vuln.getSource().name()),#if($vuln.cvssV2)$enc.csv($vuln.cvssV2.cvssData.baseSeverity)#else""#end,#if($vuln.cvssV2)$enc.csv($vuln.cvssV2.cvssData.baseScore)#else""#end,#if($vuln.cvssV2)$enc.csv($vuln.cvssV2.toString())#else""#end,#if($vuln.cvssV3)$enc.csv($vuln.cvssV3.cvssData.baseSeverity)#else""#end,#if($vuln.cvssV3)$enc.csv($vuln.cvssV3.cvssData.baseScore)#else""#end,#if($vuln.cvssV3)$enc.csv($vuln.cvssV3.toString())#else""#end,#if($vuln.cvssV4)$enc.csv($vuln.cvssV4.cvssData.baseSeverity)#else""#end,#if($vuln.cvssV4)$enc.csv($vuln.cvssV4.cvssData.baseScore)#else""#end,#if($vuln.cvssV4)$enc.csv($vuln.cvssV4.toString())#else""#end,$enc.csvCpeConfidence($dependency.softwareIdentifiers),$dependency.size(),#if($vuln.getKnownExploitedVulnerability())$enc.csv($vuln.getKnownExploitedVulnerability().getVendorProject()),$enc.csv($vuln.getKnownExploitedVulnerability().getProduct()),$enc.csv($vuln.getKnownExploitedVulnerability().getVulnerabilityName()),$enc.csv($vuln.getKnownExploitedVulnerability().getDateAdded()),$enc.csv($vuln.getKnownExploitedVulnerability().getShortDescription()),$enc.csv($vuln.getKnownExploitedVulnerability().getRequiredAction()),$enc.csv($vuln.getKnownExploitedVulnerability().getDueDate()),$enc.csv($vuln.getKnownExploitedVulnerability().getNotes())#else"","","","","","","",""#end #end#end#end \ No newline at end of file diff --git a/core/src/main/resources/templates/gitlabReport.vsl b/core/src/main/resources/templates/gitlabReport.vsl new file mode 100644 index 00000000000..62c0c79c8b1 --- /dev/null +++ b/core/src/main/resources/templates/gitlabReport.vsl @@ -0,0 +1,181 @@ +{ + "version": "15.0.6", + "schema": "https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/raw/v15.0.6/dist/dependency-scanning-report-format.json?ref_type=tags", ##todo + "scan": { + ## this describes the tool responsible for scanning + "scanner": { + "id": "org.owasp.dependency-check", + "name": "Dependency-Check Core", + "version": "$enc.json($version)", + "vendor": { + "name": "OWASP" + }, + + ## optional properties + "url": "https://github.com/dependency-check/DependencyCheck/" + }, + ## this describes the tool responsible for interpreting the scan result + ## in our case it's the same as the scanner + "analyzer": { + "id": "org.owasp.dependency-check", + "name": "Dependency-Check Core", + "version": "$enc.json($version)", + "vendor": { + "name": "OWASP" + }, + + ## optional properties + "url": "https://github.com/dependency-check/DependencyCheck/" + }, + + "end_time": "$enc.json($scanDateGitLab)", + ## we don't acutally have the real start time, so this is the best we can do + "start_time": "$enc.json($scanDateGitLab)", + ## we only generate a scan report, if the scan has successfully finished + "status": #if($exceptions) "failure" #else "success" #end , + ## this is the only type of scan there is according to the format definition + "type": "dependency_scanning" + + ## optional properties + ## "messages": [], --> not implemented + ##"options": [], --> not implemented + ##"primary_identifiers": [], --> not implemented + }, + "vulnerabilities": [ + #set( $vulnerability_first = true ) + #foreach( $dependency in $dependencies ) + #if( $dependency.vulnerabilities.size() != 0 ) + #foreach( $vulnerability in $dependency.getVulnerabilities(true) ) + ## make sure to insert comma between array elements + #if( $vulnerability_first == true ) + #set( $vulnerability_first = false ) + #else + , + #end + ## ((List)context.get("dependencies")).get(5).getVulnerabilities().stream().collect(Collectors.toList()).get(0) + { + "id": "$enc.json($vulnerability.name)", + "identifiers": [ + { + "type": "$enc.json($vulnerability.getSource().name())" + #if( $vulnerability.getSource().name().equals("NVD") ) + , "name": "$enc.json($vulnerability.name)" + #elseif( $vulnerability.getSource().name().equals("NPM") ) + , "name": "$enc.json($vulnerability.name) (NPM)" + #else + , "name": "$enc.json($vulnerability.name)" + #end + , "value": "$enc.json($dependency.Sha1sum)" + + ## optional properties + #if( $vulnerability.getSource().name().equals("NVD") ) + , "url": "https://web.nvd.nist.gov/view/vuln/detail?vulnId=$enc.url($vulnerability.name)" + #elseif( $vulnerability.getSource().name().equals("NPM") ) + , "url": "https://github.com/advisories/$enc.url($vulnerability.name)" + #end + } + ], + "location": { + "file": "$enc.json($dependency.filePath)", + "dependency": { + "package": { + "name": "$enc.json($dependency.name)" + }, + "version": "$enc.json($dependency.version)" + ## optional properties + ## "iid": "", --> not implemented + ## "direct": false, --> not implemented + ## we don't have a good way of assigning iids, so this won't work + ##"dependency_path": [ + ## #foreach( $inc in $dependency.includedBy ) + ## { + ## "iid": + ## } + ## #if( $foreach.hasNext ),#end + ## #end + ##] + } + }, + + ## optional properties + "name": "$enc.json($StringUtils.truncate($vulnerability.name, 255))", + #if($vulnerability.description) + "description": "$enc.json($vulnerability.description)", + #end + #if($vulnerability.unscoredSeverity) + #if($vulnerability.unscoredSeverity.equals("0.0")) + #set($severity = "Unknown") + #else + #set($severity = $rpt.normalizeSeverity($vulnerability.unscoredSeverity)) + #end + #elseif($vulnerability.cvssV4 && $vulnerability.cvssV4.cvssData && $vulnerability.cvssV4.cvssData.baseSeverity) + #set($severity = $rpt.normalizeSeverity($vulnerability.cvssV4.cvssData.baseSeverity)) + #elseif($vulnerability.cvssV3 && $vulnerability.cvssV3.cvssData && $vulnerability.cvssV3.cvssData.baseSeverity) + #set($severity = $rpt.normalizeSeverity($vulnerability.cvssV3.cvssData.baseSeverity)) + #elseif($vulnerability.cvssV2 && $vulnerability.cvssV2.cvssData && $vulnerability.cvssV2.cvssData.baseSeverity) + #set($severity = $rpt.normalizeSeverity($vulnerability.cvssV2.cvssData.baseSeverity)) + #end + "severity": "$severity.substring(0,1).toUpperCase()$severity.substring(1)", + ## "solution": "" --> not implemented + "links": [ + #set($prepend_comma = false) + #foreach( $ref in $vulnerability.getReferences(true) ) + #if($ref.url) + #if($prepend_comma) + , + #set($prepend_comma = false) + #end + { + #if($ref.name) + ## optional property + "name": "$enc.json($ref.name)", + #end + "url": "$enc.json($ref.url)" + } + #if( $foreach.hasNext ) + #set($prepend_comma = true) + #end + #end + #end + ] + ## "details": [], --> not implemented + ## "tracking": {}, --> not implemented + ## "flags": [], --> not implemented. + } + #end + #end + #end + ], + "dependency_files": [ + ## for lack of better knowledge, we just assume we have only scanned a single pom.xml file… + { + "path": "pom.xml", + "package_manager": "maven", + "dependencies": [ + #set($addComma=0) + #foreach( $dependency in $dependencies ) + #if( $dependency.name ) + #if( $addComma>0 ),#end + { + "package": { + "name": "$enc.json($dependency.name)" + }, + "version": "$enc.json($dependency.version)" + + ## optional properties + ## "iid": number, --> not implemtend + ##"direct": false, --> not implemeten + ##"dependency_path": [] --> not implemented + } + #set($addComma=1) + #end + #end + ] + ## no optional properties + } + ], + + ## optional properties + "remediations": [] ## not implemented + +} diff --git a/core/src/main/resources/templates/htmlReport.vsl b/core/src/main/resources/templates/htmlReport.vsl index f1857f9ad52..c91f549ca0a 100644 --- a/core/src/main/resources/templates/htmlReport.vsl +++ b/core/src/main/resources/templates/htmlReport.vsl @@ -22,14 +22,14 @@ Copyright (c) 2012 Jeremy Long. All Rights Reserved. #[[ - + Dependency-Check Report -