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

com.metaeffekt.artifact.analysis.version.Version 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.artifact.analysis.version;

import com.metaeffekt.artifact.analysis.utils.StringUtils;
import com.metaeffekt.artifact.analysis.version.curation.VersionContext;
import com.metaeffekt.mirror.contents.vulnerability.VulnerableSoftwareVersionRange;

import java.util.concurrent.atomic.AtomicReference;

import static org.metaeffekt.core.inventory.processor.model.Constants.ASTERISK;

public interface Version extends Comparable {

    default boolean matchesVersionOf(final String checkVersion, final String checkUpdate,
                                     final String versionEndIncluding, final String versionEndExcluding,
                                     final String versionStartExcluding, final String versionStartIncluding
    ) {
        return matchesVersionOf(checkVersion, checkUpdate, versionEndIncluding, versionEndExcluding, versionStartExcluding, versionStartIncluding, VersionContext.EMPTY);
    }

    default boolean matchesVersionOf(final String checkVersion, final String checkUpdate,
                                     final String versionEndIncluding, final String versionEndExcluding,
                                     final String versionStartExcluding, final String versionStartIncluding,
                                     VersionContext context
    ) {

        // if the version is unknown, match any vulnerable software version
        if (this.getVersion() != null && this.getUpdate() == null && (this.getVersion().equals(ASTERISK) || this.getVersion().equals("-"))) {
            return true;
        }

        // FIXME: I would say that this is the correct interpretation of the documentation.
        // https://cpe.mitre.org/files/cpe-specification_2.2.pdf page 9
        // a dash in the version or update part means that only versions with a "*" or "" will match that part.
        // if a concrete version or update part is given, it shall not match the version.
        if ("-".equals(checkVersion)) {
            if (StringUtils.hasText(this.getVersion()) && !(this.getVersion().equals(ASTERISK) || this.getVersion().equals("-"))) {
                return false;
            }
        } else if ("-".equals(checkUpdate)) {
            if (StringUtils.hasText(this.getUpdate()) && !(this.getUpdate().equals(ASTERISK) || this.getUpdate().equals("-"))) {
                return false;
            }
        }

        final String normalisedCheckVersion = normalizePart(checkVersion);
        final String normalisedCheckUpdate = normalizePart(checkUpdate);

        final Version vsVersion = Version.of(normalisedCheckVersion, normalisedCheckUpdate, context);
        if (vsVersion.isNotEmpty()) {
            if (vsVersion.equals(this)) {
                return true;
            }
        }

        if (normalizePart(this.getVersion()) != null) {
            final String normalisedVersionEndIncluding = normalizePart(versionEndIncluding);
            final String normalisedVersionEndExcluding = normalizePart(versionEndExcluding);
            final String normalisedVersionStartExcluding = normalizePart(versionStartExcluding);
            final String normalisedVersionStartIncluding = normalizePart(versionStartIncluding);

            final Version vsVersionStartExcluding = Version.of(normalisedVersionStartExcluding, context);
            if (vsVersionStartExcluding.isNotEmpty() && !this.after(vsVersionStartExcluding)) {
                return false;
            }

            final Version vsVersionEndExcluding = Version.of(normalisedVersionEndExcluding, context);
            if (vsVersionEndExcluding.isNotEmpty() && !this.before(vsVersionEndExcluding)) {
                return false;
            }

            final Version vsVersionStartIncluding = Version.of(StringUtils.nonNull(normalisedVersionStartIncluding, normalisedVersionStartExcluding, normalisedCheckVersion), context);
            if (vsVersionStartIncluding.isNotEmpty() && !this.afterOrEqual(vsVersionStartIncluding)) {
                return false;
            }

            final Version vsVersionEndIncluding = Version.of(StringUtils.nonNull(normalisedVersionEndIncluding, normalisedVersionEndExcluding, normalisedCheckVersion), context);
            if (vsVersionEndIncluding.isNotEmpty() && !this.beforeOrEqual(vsVersionEndIncluding)) {
                return false;
            }
        }

        return true;
    }

    default String normalizePart(String cpeVersion) {
        return cpeVersion == null || cpeVersion.equals(ASTERISK) || cpeVersion.equals("-") ? null : cpeVersion;
    }

    default boolean matchesVersionOf(VulnerableSoftwareVersionRange vulnerableSoftware) {
        return matchesVersionOf(vulnerableSoftware.getVersion(), vulnerableSoftware.getUpdate(),
                vulnerableSoftware.getVersionEndIncluding(), vulnerableSoftware.getVersionEndExcluding(),
                vulnerableSoftware.getVersionStartExcluding(), vulnerableSoftware.getVersionStartIncluding(),
                vulnerableSoftware.getContext()
        );
    }

    // FIXME: Remove this method and use the equals method instead at all occurrences.
    default boolean matchesVersionOf(Version version) {
        return equals(version);
    }

    default boolean equals(Version other) {
        return compareTo(other) == 0;
    }

    default boolean before(Version other) {
        return compareTo(other) < 0;
    }

    default boolean after(Version other) {
        return compareTo(other) > 0;
    }

    default boolean beforeOrEqual(Version other) {
        // less than zero (before) OR equals
        return compareTo(other) <= 0;
    }

    default boolean afterOrEqual(Version other) {
        // greater than zero (after) OR equals
        return compareTo(other) >= 0;
    }

    String getVersion();

    String getUpdate();

    /**
     * Check if the version or update is not empty.
* This is the case if the version or update is not null.
* This is mostly used in the {@link Version#matchesVersionOf(String, String, String, String, String, String)} * method. * * @return true if the version or update is not empty, false otherwise. */ default boolean isNotEmpty() { return getVersion() != null || getUpdate() != null; } default boolean isEmpty() { return !isNotEmpty(); } /** * Available version implementations: *
    *
  • {@link NormalizationVersionImpl}
  • *
  • {@link TokenVersionImpl}
  • *
  • {@link AllCategorizedPartsVersionImpl}
  • *
  • {@link CommonPartsVersionImpl}
  • *
*/ AtomicReference> DEFAULT_VERSION_FACTORY = new AtomicReference<>(CommonPartsVersionImpl::new); static void setDefaultVersionFactory(VersionConstructor versionFactory) { DEFAULT_VERSION_FACTORY.set(versionFactory); } static Version of(String version, String update) { return of(version, update, VersionContext.EMPTY, DEFAULT_VERSION_FACTORY.get()); } static Version of(String version) { return of(version, null, VersionContext.EMPTY, DEFAULT_VERSION_FACTORY.get()); } static Version of(String version, String update, VersionContext context) { return of(version, update, context, DEFAULT_VERSION_FACTORY.get()); } static Version of(String version, VersionContext context) { return of(version, null, context, DEFAULT_VERSION_FACTORY.get()); } static T of(String version, VersionContext context, VersionConstructor versionFactory) { return of(version, null, context, versionFactory); } static T of(String version, String update, VersionContext context, VersionConstructor versionFactory) { final String normalizedVersion = normalizeStringForOf(version); final String normalizedUpdate = normalizeStringForOf(update); return versionFactory.create(normalizedVersion, normalizedUpdate, context); } static String normalizeStringForOf(String str) { if (StringUtils.isEmpty(str)) { return null; } return str; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy