Skip to content

Commit 97c4b1f

Browse files
committed
Add openssl support in univers
- closes #36 - For `OpenSSL-FIPS Module` see #41 Signed-off-by: keshav-space <keshav6240@gmail.com>
1 parent 7206c1f commit 97c4b1f

4 files changed

Lines changed: 148 additions & 0 deletions

File tree

src/univers/version_constraint.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,22 @@ def from_string(cls, string, version_class):
157157
version = None
158158
else:
159159
version = version_class(version)
160+
161+
"""
162+
Can't always be certain that a particular class would create an object
163+
of its own kind it may return an object of a different class.
164+
165+
Example:
166+
OpensslVersion when instantiated will return either an object of
167+
LegacyOpensslVersion or SemverVersion depending on version.
168+
OpensslVersion("0.9.8a") -> LegacyOpensslVersion(string="0.9.8a")
169+
OpensslVersion("3.0.1") -> SemverVersion(string="3.0.1")
170+
171+
Hence the need for updating `version_class` after creation of version object
172+
"""
173+
if version != None:
174+
version_class = version.__class__
175+
160176
return cls(comparator=comparator, version=version, version_class=version_class)
161177

162178
@staticmethod

src/univers/version_range.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,25 @@ def from_native(cls, string):
868868
return cls(constraints=constraints)
869869

870870

871+
class OpensslVersionRange(VersionRange):
872+
scheme = "openssl"
873+
version_class = versions.OpensslVersion
874+
# openssl doesn't use <,>,<=,>=
875+
# https://www.openssl.org/news/vulnerabilities.xml
876+
vers_by_native_comparators = {"=": "="}
877+
878+
@classmethod
879+
def from_native(cls, string):
880+
cleaned = remove_spaces(string).lower()
881+
constraints = set()
882+
# plain single version
883+
for clause in cleaned.split(","):
884+
version = cls.version_class(clause)
885+
constraint = VersionConstraint(comparator="=", version=version)
886+
constraints.add(constraint)
887+
return cls(constraints=list(constraints))
888+
889+
871890
def is_even(s):
872891
"""
873892
Return True if the string "s" is an even number and False if this is an odd
@@ -902,4 +921,5 @@ def is_even(s):
902921
"ebuild": EbuildVersionRange,
903922
"archlinux": ArchLinuxVersionRange,
904923
"nginx": NginxVersionRange,
924+
"openssl": OpensslVersionRange,
905925
}

src/univers/versions.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
# Visit https://aboutcode.org and https://github.com/nexB/univers for support and download.
66

77
from functools import total_ordering
8+
import re
89

910
import attr
1011
import semantic_version
@@ -343,3 +344,82 @@ def __gt__(self, other):
343344
if not isinstance(other, self.__class__):
344345
return NotImplemented
345346
return gentoo.vercmp(self.value, other.value) > 0
347+
348+
349+
@attr.s(frozen=True, order=False, eq=False, hash=True)
350+
class LegacyOpensslVersion(Version):
351+
@classmethod
352+
def is_valid(cls, string):
353+
return OpensslVersion.is_valid_legacy(string)
354+
355+
# OpenSSL doesn't seems to use >,<,>=,=<
356+
# See: https://www.openssl.org/news/vulnerabilities.xml
357+
def __eq__(self, other):
358+
if isinstance(other, SemverVersion):
359+
return False
360+
if not isinstance(other, self.__class__):
361+
return NotImplemented
362+
return self.value == other.value
363+
364+
def __lt__(self, other):
365+
# All legacy scheme is behind those using semver
366+
if isinstance(other, SemverVersion):
367+
return True
368+
if not isinstance(other, self.__class__):
369+
return NotImplemented
370+
re_vers1 = re.findall(r"^(\d+\.\d+\.\d+)(.*)$", self.value)[0]
371+
re_vers2 = re.findall(r"^(\d+\.\d+\.\d+)(.*)$", other.value)[0]
372+
if int(re_vers1[0].replace(".", "")) < int(re_vers2[0].replace(".", "")):
373+
return True
374+
return re_vers1[0] == re_vers2[0] and re_vers1[1] < re_vers2[1]
375+
376+
def __gt__(self, other):
377+
# All openssl version using semver is ahead of legacy scheme
378+
if isinstance(other, SemverVersion):
379+
return False
380+
if not isinstance(other, self.__class__):
381+
return NotImplemented
382+
re_vers1 = re.findall(r"^(\d+\.\d+\.\d+)([a-z-]+)$", self.value)[0]
383+
re_vers2 = re.findall(r"^(\d+\.\d+\.\d+)([a-z-]+)$", other.value)[0]
384+
if int(re_vers1[0].replace(".", "")) > int(re_vers2[0].replace(".", "")):
385+
return True
386+
return re_vers1[0] == re_vers2[0] and re_vers1[1] > re_vers2[1]
387+
388+
def __le__(self, other):
389+
return self.__lt__(other) or self.__eq__(other)
390+
391+
def __ge__(self, other):
392+
return self.__gt__(other) or self.__eq__(other)
393+
394+
395+
@attr.s(frozen=True, order=False, eq=False, hash=True)
396+
class OpensslVersion:
397+
"""
398+
Handles the object creation for openssl depending on
399+
whether version is legacy or semver
400+
"""
401+
402+
def __new__(cls, string):
403+
if OpensslVersion.is_valid_legacy(string):
404+
return LegacyOpensslVersion(string)
405+
elif OpensslVersion.is_valid_new_openssl(string):
406+
return SemverVersion(string)
407+
raise InvalidVersion(f"{string!r} is not a valid/supported OpensslVersion")
408+
409+
@classmethod
410+
def is_valid_legacy(cls, string):
411+
# all legacy base version of openssl that ever exited/exists
412+
all_legacy_base = ["0.9.6", "0.9.7", "0.9.8", "1.0.0", "1.0.1", "1.0.2", "1.1.0", "1.1.1"]
413+
if string in all_legacy_base:
414+
return True
415+
regexed_string = re.findall(r"^(\d+\.\d+\.\d+)([a-z-]+)$", string)
416+
if not regexed_string or regexed_string[0][0] not in all_legacy_base:
417+
return False
418+
return True
419+
420+
@classmethod
421+
def is_valid_new_openssl(cls, string):
422+
regexed_string = re.findall(r"^(\d+)(\.)(.*)$", string)
423+
if not regexed_string or int(regexed_string[0][0]) < 3:
424+
return False
425+
return SemverVersion.is_valid(string)

tests/test_version_range.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414
from univers.version_range import VersionRange
1515
from univers.version_range import RANGE_CLASS_BY_SCHEMES
1616
from univers.version_range import NpmVersionRange
17+
from univers.version_range import OpensslVersionRange
1718
from univers.versions import PypiVersion
1819
from univers.versions import RubygemsVersion
1920
from univers.versions import SemverVersion
21+
from univers.versions import LegacyOpensslVersion
2022

2123

2224
class TestVersionRange(TestCase):
@@ -233,10 +235,40 @@ def test_NpmVersionRange_from_native_with_approximately_equal_to_operator(self):
233235
version_range = NpmVersionRange.from_native(npm_range)
234236
assert version_range == expected
235237

238+
def test_OpensslVersionRange_from_native_single_legacy(self):
239+
openssl_range = "0.9.8j"
240+
expected = OpensslVersionRange(
241+
constraints=(
242+
VersionConstraint(comparator="=", version=LegacyOpensslVersion(string="0.9.8j")),
243+
)
244+
)
245+
version_range = OpensslVersionRange.from_native(openssl_range)
246+
assert version_range == expected
247+
248+
def test_OpensslVersionRange_from_native_single_new_semver(self):
249+
openssl_range = "3.0.1"
250+
expected = OpensslVersionRange(
251+
constraints=(VersionConstraint(comparator="=", version=SemverVersion(string="3.0.1")),)
252+
)
253+
version_range = OpensslVersionRange.from_native(openssl_range)
254+
assert version_range == expected
255+
256+
def test_OpensslVersionRange_from_native_mixed(self):
257+
openssl_range = "3.0.0, 1.0.1b"
258+
expected = OpensslVersionRange(
259+
constraints=(
260+
VersionConstraint(comparator="=", version=LegacyOpensslVersion(string="1.0.1b")),
261+
VersionConstraint(comparator="=", version=SemverVersion(string="3.0.0")),
262+
)
263+
)
264+
version_range = OpensslVersionRange.from_native(openssl_range)
265+
assert version_range == expected
266+
236267

237268
VERSION_RANGE_TESTS_BY_SCHEME = {
238269
"nginx": ["0.8.40+", "0.7.52-0.8.39", "0.9.10", "1.5.0+, 1.4.1+"],
239270
"npm": ["^1.2.9", "~3.8.2", "5.0.0 - 7.2.3", "2.1 || 2.6", "1.1.2 1.2.2", "<=2.1 >=1.1"],
271+
"openssl": ["1.1.1ak", "1.1.0", "3.0.2", "3.0.1, 0.9.7a", "1.0.2ck, 3.1.2"],
240272
}
241273

242274

0 commit comments

Comments
 (0)