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

com.metaeffekt.artifact.enrichment.configurations.VadDetailLevelMatcher Maven / Gradle / Ivy

There is a newer version: 0.132.0
Show 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.artifact.enrichment.configurations;

import com.metaeffekt.artifact.analysis.vulnerability.CommonEnumerationUtil;
import com.metaeffekt.artifact.analysis.vulnerability.enrichment.vulnerabilitystatus.VulnerabilityStatus;
import com.metaeffekt.artifact.analysis.vulnerability.enrichment.vulnerabilitystatus.VulnerabilityStatusHistoryEntry;
import com.metaeffekt.mirror.contents.vulnerability.Vulnerability;
import org.metaeffekt.core.inventory.processor.configuration.ProcessConfiguration;
import org.metaeffekt.core.inventory.processor.configuration.ProcessMisconfiguration;
import org.metaeffekt.core.inventory.processor.model.Artifact;
import org.metaeffekt.core.inventory.processor.model.VulnerabilityMetaData;
import us.springett.parsers.cpe.Cpe;

import java.util.*;

public class VadDetailLevelMatcher extends ProcessConfiguration {

    private final static Set VALID_STATUS_NAMES = new HashSet() {{
        add(VulnerabilityMetaData.STATUS_VALUE_APPLICABLE);
        add(VulnerabilityMetaData.STATUS_VALUE_NOTAPPLICABLE);
        add(VulnerabilityMetaData.STATUS_VALUE_INSIGNIFICANT);
        add(VulnerabilityMetaData.STATUS_VALUE_IN_REVIEW);
        add(VulnerabilityMetaData.STATUS_VALUE_VOID);
    }};

    private String status;
    private String allCpe;
    private String anyCpe;
    private String vulnerabilityName;

    private List cachedAllCpes;
    private List cachedAnyCpes;

    public String[] getStatus() {
        return status == null ? null : status.split(", ");
    }

    public List getAllCpe() {
        if (cachedAllCpes == null) {
            cachedAllCpes = CommonEnumerationUtil.parseCpes(allCpe);
        }
        return cachedAllCpes;
    }

    public List getAnyCpe() {
        if (cachedAnyCpes == null) {
            cachedAnyCpes = CommonEnumerationUtil.parseCpes(anyCpe);
        }
        return cachedAnyCpes;
    }

    public String[] getVulnerabilityName() {
        return vulnerabilityName == null ? null : vulnerabilityName.split(", ");
    }

    public VadDetailLevelMatcher setStatus(String status) {
        this.status = status;
        return this;
    }

    public VadDetailLevelMatcher setAllCpe(String allCpe) {
        this.allCpe = allCpe;
        cachedAllCpes = null;
        return this;
    }

    public VadDetailLevelMatcher setAnyCpe(String anyCpe) {
        this.anyCpe = anyCpe;
        cachedAnyCpes = null;
        return this;
    }

    public VadDetailLevelMatcher setVulnerabilityName(String vulnerabilityName) {
        this.vulnerabilityName = vulnerabilityName;
        return this;
    }

    public VadDetailLevelMatcher setVulnerabilityName(String[] vulnerabilityName) {
        this.vulnerabilityName = vulnerabilityName == null ? null : String.join(", ", vulnerabilityName);
        return this;
    }

    public boolean matches(Vulnerability vulnerability, VulnerabilityStatus status, Set artifacts) {
        final VulnerabilityStatusHistoryEntry latestActiveEntry = status.getLatestActiveStatusHistoryEntry();
        if (latestActiveEntry != null) {
            if (!isStatusApplicable(latestActiveEntry.getStatus())) {
                return false;
            }
        }

        final List allCpe = getAllCpe();
        if (allCpe != null && !allCpe.isEmpty()) {
            for (Cpe cpe : allCpe) {
                boolean cpeMatched = false;

                for (Artifact artifact : artifacts) {
                    final List effectiveArtifactCpes = CommonEnumerationUtil.parseEffectiveCpe(artifact);
                    for (Cpe effectiveArtifactCpe : effectiveArtifactCpes) {
                        if (CommonEnumerationUtil.compareCpeUsingWildcardsOneWay(cpe, effectiveArtifactCpe)) {
                            cpeMatched = true;
                            break;
                        }
                    }
                    if (cpeMatched) break;
                }

                if (!cpeMatched) {
                    return false;
                }
            }
        }

        final List anyCpe = getAnyCpe();
        if (anyCpe != null && !anyCpe.isEmpty()) {
            boolean cpeMatched = false;

            for (Artifact artifact : artifacts) {
                final List effectiveArtifactCpes = CommonEnumerationUtil.parseEffectiveCpe(artifact);
                for (Cpe effectiveArtifactCpe : effectiveArtifactCpes) {
                    for (Cpe cpe : anyCpe) {
                        if (CommonEnumerationUtil.compareCpeUsingWildcardsOneWay(cpe, effectiveArtifactCpe)) {
                            cpeMatched = true;
                            break;
                        }
                    }
                    if (cpeMatched) break;
                }
                if (cpeMatched) break;
            }

            if (!cpeMatched) {
                return false;
            }
        }

        final String[] vulnerabilityName = getVulnerabilityName();
        if (vulnerabilityName != null && vulnerabilityName.length > 0) {
            boolean vulnerabilityNameMatched = false;

            for (String name : vulnerabilityName) {
                if (vulnerability.getId().contains(name)) {
                    vulnerabilityNameMatched = true;
                    break;
                }
            }

            if (!vulnerabilityNameMatched) {
                return false;
            }
        }

        return true;
    }

    public boolean isStatusApplicable(String checkStatus) {
        final String[] statusNames = this.getStatus();
        if (statusNames == null) return true;

        for (String statusName : statusNames) {
            if (checkStatus.equals(statusName.trim())) {
                return true;
            }
        }

        return false;
    }

    @Override
    public LinkedHashMap getProperties() {
        final LinkedHashMap properties = new LinkedHashMap<>();

        properties.put("status", status);

        properties.put("allCpe", allCpe);
        properties.put("anyCpe", anyCpe);

        properties.put("vulnerabilityName", vulnerabilityName);

        return properties;
    }

    @Override
    public void setProperties(LinkedHashMap properties) {
        super.loadStringProperty(properties, "status", this::setStatus);
        super.loadStringProperty(properties, "allCpe", this::setAllCpe);
        super.loadStringProperty(properties, "anyCpe", this::setAnyCpe);
        super.loadStringProperty(properties, "vulnerabilityName", this::setVulnerabilityName);
    }

    @Override
    protected void collectMisconfigurations(List misconfigurations) {
        if (status != null) {
            final String[] statusNames = this.getStatus();
            for (String statusName : statusNames) {
                if (!VALID_STATUS_NAMES.contains(statusName.trim())) {
                    misconfigurations.add(new ProcessMisconfiguration("status", "Invalid status name: [" + statusName + "]. Valid names are: " + VALID_STATUS_NAMES));
                }
            }
        }
    }

    /**
     * matcher: status = "in review"; anyCpe = "cpe:/a:linux:kernel". See method in comment block above for more details.
     *
     * @param configString The configuration string to parse
     * @return The parsed matcher
     * @see VadDetailLevelConfiguration#fromConfigurationString(String)
     */
    public static VadDetailLevelMatcher fromConfigurationString(String configString) {
        if (!configString.startsWith("matcher:")) {
            throw new IllegalArgumentException("Invalid configuration string, expected 'matcher:' but got '" + configString + "'");
        }
        final String trimmedConfigString = configString.substring("matcher:".length()).trim();
        final Map properties = VadDetailLevelConfiguration.extractPropertiesFromConfigLine(trimmedConfigString);

        final VadDetailLevelMatcher matcher = new VadDetailLevelMatcher();

        if (properties.containsKey("status")) {
            matcher.setStatus(properties.get("status"));
        }
        if (properties.containsKey("allCpe")) {
            matcher.setAllCpe(properties.get("allCpe"));
        }
        if (properties.containsKey("anyCpe")) {
            matcher.setAnyCpe(properties.get("anyCpe"));
        }
        if (properties.containsKey("vulnerabilityName")) {
            matcher.setVulnerabilityName(properties.get("vulnerabilityName"));
        }

        return matcher;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy