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