All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.metaeffekt.mirror.download.nvd.NvdDownload Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2021-2024 the original author or authors.
 *
 * 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.
 */
package com.metaeffekt.mirror.download.nvd;

import com.metaeffekt.artifact.analysis.utils.ArchiveUtils;
import com.metaeffekt.mirror.download.documentation.MirrorMetadata;
import com.metaeffekt.mirror.Retry;
import com.metaeffekt.mirror.download.Download;
import com.metaeffekt.mirror.download.ResourceLocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.net.URL;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * Uses the deprecated 1.x NVD JSON feeds to download the NVD data.
* These data feeds are no longer available and can no longer be used. More information can be found at * https://nvd.nist.gov/general/news/api-20-announcements. */ @Deprecated @MirrorMetadata(directoryName = "nvd", mavenPropertyName = "nvdLegacyDownload", deprecated = true) public class NvdDownload extends Download { private final static Logger LOG = LoggerFactory.getLogger(NvdDownload.class); private final List availableArchiveYears; private Map cachedChangedYearlyArchives; private final static int META_FILE_YEAR_PLACEHOLDER = 1; public NvdDownload(File baseMirrorDirectory) { super(baseMirrorDirectory, NvdDownload.class); availableArchiveYears = Collections.unmodifiableList(IntStream.range(2002, Calendar.getInstance().get(Calendar.YEAR) + 1) .boxed() .collect(Collectors.toList())); } @Override protected boolean additionalIsDownloadRequired() { final Map changedArchiveYears = fetchChangedArchiveYears(); if (cachedChangedYearlyArchives == null) { cachedChangedYearlyArchives = changedArchiveYears; } return changedArchiveYears.size() > 0; } @Override protected void performDownload() { final Map changedArchiveYears; if (cachedChangedYearlyArchives == null) { changedArchiveYears = fetchChangedArchiveYears(); } else { changedArchiveYears = cachedChangedYearlyArchives; cachedChangedYearlyArchives = null; } LOG.info("Starting downloads for years {}", changedArchiveYears.keySet()); for (Map.Entry changedYearEntry : changedArchiveYears.entrySet()) { super.executor.submit(() -> new Retry<>(() -> { final Integer year = changedYearEntry.getKey(); final String lastModifiedDate = changedYearEntry.getValue(); final URL requestUrl; final File archiveFile; final File targetFile; final String propertyName; if (year == META_FILE_YEAR_PLACEHOLDER) { requestUrl = getRemoteResourceLocationUrl(ResourceLocationNvd.CVE_MODIFIED_URL); archiveFile = new File(super.downloadIntoDirectory, "nvd-modified.json.gz"); targetFile = new File(super.downloadIntoDirectory, "nvd-modified.json"); propertyName = InfoFileAttributes.NVD_PREFIX.getKey() + "last-modified-meta"; } else { requestUrl = getRemoteResourceLocationUrl(ResourceLocationNvd.CVE_YEAR_BASE_URL, year); archiveFile = new File(super.downloadIntoDirectory, "nvd-" + year + ".json.gz"); targetFile = new File(super.downloadIntoDirectory, "nvd-" + year + ".json"); propertyName = InfoFileAttributes.NVD_PREFIX.getKey() + "last-modified-" + year; } if (targetFile.exists()) { targetFile.delete(); } if (archiveFile.exists()) { archiveFile.delete(); } super.downloader.fetchResponseBodyFromUrlToFile(requestUrl, archiveFile); ArchiveUtils.unpackIfPossible(archiveFile, super.downloadIntoDirectory, new ArrayList<>()); archiveFile.delete(); super.propertyFiles.set(super.downloadIntoDirectory, "info", propertyName, lastModifiedDate); }).onException(Exception.class) .retryCount(5) .run() ); } super.executor.start(); try { super.executor.join(); } catch (InterruptedException e) { throw new RuntimeException("Failed to wait for download threads to finish.", e); } } private Map fetchChangedArchiveYears() { final Map changedYearsWithLastModifiedDate = new HashMap<>(); for (Integer year : availableArchiveYears) { super.executor.submit(() -> { final String previousLastModifiedDate = super.propertyFiles.getString(super.downloadIntoDirectory, "info", InfoFileAttributes.NVD_PREFIX.getKey() + "last-modified-" + year) .orElse(""); final URL requestUrl = getRemoteResourceLocationUrl(ResourceLocationNvd.CVE_YEAR_META_URL, year); final String currentLastModifiedDate = fetchLastModifiedDateFromMetaFile(requestUrl); final File targetFile = new File(super.downloadIntoDirectory, "nvd-" + year + ".json"); if (currentLastModifiedDate.length() == 0) { LOG.warn("Meta file did not contain lastModifiedDate for year [{}], download required", year); changedYearsWithLastModifiedDate.put(year, currentLastModifiedDate); } else if (!targetFile.exists() || previousLastModifiedDate.length() == 0) { LOG.info("Archive year [{}] does not yet exist, download required", year); changedYearsWithLastModifiedDate.put(year, currentLastModifiedDate); } else if (!previousLastModifiedDate.equals(currentLastModifiedDate)) { LOG.info("Archive year [{}] is not up-to-date, download required [{}] -> [{}]", year, previousLastModifiedDate, currentLastModifiedDate); changedYearsWithLastModifiedDate.put(year, currentLastModifiedDate); } }); } super.executor.submit(() -> { final String previousLastModifiedDate = super.propertyFiles.getString(super.downloadIntoDirectory, "info", InfoFileAttributes.NVD_PREFIX.getKey() + "last-modified-meta") .orElse(""); final URL requestUrl = getRemoteResourceLocationUrl(ResourceLocationNvd.CVE_MODIFIED_META_URL); final String currentLastModifiedDate = fetchLastModifiedDateFromMetaFile(requestUrl); final File targetFile = new File(super.downloadIntoDirectory, "nvd-modified.json"); if (currentLastModifiedDate.length() == 0) { LOG.warn("Meta file did not contain lastModifiedDate for meta, download required"); changedYearsWithLastModifiedDate.put(META_FILE_YEAR_PLACEHOLDER, currentLastModifiedDate); } else if (!targetFile.exists() || previousLastModifiedDate.length() == 0) { LOG.info("Meta archive does not yet exist, download required"); changedYearsWithLastModifiedDate.put(META_FILE_YEAR_PLACEHOLDER, currentLastModifiedDate); } else if (!previousLastModifiedDate.equals(currentLastModifiedDate)) { LOG.info("Meta archive is not up-to-date, download required [{}] -> [{}]", previousLastModifiedDate, currentLastModifiedDate); changedYearsWithLastModifiedDate.put(META_FILE_YEAR_PLACEHOLDER, currentLastModifiedDate); } }); super.executor.start(); try { super.executor.join(); } catch (InterruptedException e) { throw new RuntimeException("Failed to wait for download threads to finish.", e); } return changedYearsWithLastModifiedDate; } private String fetchLastModifiedDateFromMetaFile(URL requestUrl) { final AtomicReference lastModifiedDate = new AtomicReference<>(); new Retry<>(() -> { final List metaProperties = super.downloader.fetchResponseBodyFromUrlAsList(requestUrl); lastModifiedDate.set(metaProperties.stream() .filter(e -> e.contains(":")) .map(e -> e.split(":", 2)) .filter(e -> e[0].equals("lastModifiedDate")) .map(e -> e[1]) .findFirst() .orElse("")); }).onException(Exception.class) .withValidator((result) -> lastModifiedDate.get() != null && lastModifiedDate.get().length() > 0) .retryCount(5) .run(); return lastModifiedDate.get(); } @Override public void setRemoteResourceLocation(String location, String url) { super.setRemoteResourceLocation(ResourceLocationNvd.valueOf(location), url); } public enum ResourceLocationNvd implements ResourceLocation { /** * The URL to retrieve the recently modified and added CVE entries (last 8 days) using the JSON data feeds.
* modified feeds are updated every two hours. */ CVE_MODIFIED_URL("https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-modified.json.gz"), /** * Meta-information on the last modified and added CVE entries, such as the last modified date. */ CVE_MODIFIED_META_URL("https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-modified.meta"), /** * The URL to get a specific yearly CVE list using the JSON data feeds. *
    *
  1. %d Year (example: 2022)
  2. *
*/ CVE_YEAR_BASE_URL("https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-%d.json.gz"), /** * Meta-information on the specific year files, such as the last modified date.
* Content is of style: key:value *
    *
  1. %d Year (example: 2022)
  2. *
*/ CVE_YEAR_META_URL("https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-%d.meta"); private final String defaultValue; ResourceLocationNvd(String defaultValue) { this.defaultValue = defaultValue; } @Override public String getDefault() { return this.defaultValue; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy