Skip to content

Commit 3491a65

Browse files
committed
Add openssl support in univers
- closes #36 - For `OpenSSL-FIPS Module` see #41 Signed-off-by: Keshav Priyadarshi <git@keshav.space>
1 parent 7206c1f commit 3491a65

4 files changed

Lines changed: 155 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: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,28 @@ def from_native(cls, string):
868868
return cls(constraints=constraints)
869869

870870

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

src/univers/versions.py

Lines changed: 84 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,86 @@ 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+
def __eq__(self, other):
356+
if isinstance(other, SemverVersion):
357+
return False
358+
if not isinstance(other, self.__class__):
359+
return NotImplemented
360+
return self.value == other.value
361+
362+
def __lt__(self, other):
363+
"""
364+
All legacy scheme is behind those using semver.
365+
"""
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+
"""
378+
All openssl version using semver is ahead of legacy scheme.
379+
"""
380+
if isinstance(other, SemverVersion):
381+
return False
382+
if not isinstance(other, self.__class__):
383+
return NotImplemented
384+
re_vers1 = re.findall(r"^(\d+\.\d+\.\d+)([a-z-]+)$", self.value)[0]
385+
re_vers2 = re.findall(r"^(\d+\.\d+\.\d+)([a-z-]+)$", other.value)[0]
386+
if int(re_vers1[0].replace(".", "")) > int(re_vers2[0].replace(".", "")):
387+
return True
388+
return re_vers1[0] == re_vers2[0] and re_vers1[1] > re_vers2[1]
389+
390+
def __le__(self, other):
391+
return self.__lt__(other) or self.__eq__(other)
392+
393+
def __ge__(self, other):
394+
return self.__gt__(other) or self.__eq__(other)
395+
396+
397+
@attr.s(frozen=True, order=False, eq=False, hash=True)
398+
class OpensslVersion:
399+
"""
400+
Handles the object creation for openssl depending on
401+
whether version is legacy or semver.
402+
"""
403+
404+
def __new__(cls, string):
405+
if OpensslVersion.is_valid_legacy(string):
406+
return LegacyOpensslVersion(string)
407+
elif OpensslVersion.is_valid_new_openssl(string):
408+
return SemverVersion(string)
409+
raise InvalidVersion(f"{string!r} is not a valid/supported OpensslVersion")
410+
411+
@classmethod
412+
def is_valid_legacy(cls, string):
413+
"""
414+
All legacy base version of openssl that ever exited/exists.
415+
"""
416+
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"]
417+
if string in all_legacy_base:
418+
return True
419+
regexed_string = re.findall(r"^(\d+\.\d+\.\d+)([a-z-]+)$", string)
420+
if not regexed_string or regexed_string[0][0] not in all_legacy_base:
421+
return False
422+
return True
423+
424+
@classmethod
425+
def is_valid_new_openssl(cls, string):
426+
regexed_string = re.findall(r"^(\d+)(\.)(.*)$", string)
427+
if not regexed_string or int(regexed_string[0][0]) < 3:
428+
return False
429+
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)