summaryrefslogtreecommitdiff
blob: 272f5eec70670a1c3e1c891c93d32d2a617573a5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
from typing import TypeGuard

from glsamaker.extensions import base, db


class InvalidReferenceFormatException(Exception):
    pass


class Reference(base):
    __tablename__ = "reference"

    ref_text = db.Column(db.String(), primary_key=True)
    url = db.Column(db.String())

    PREFIXES = [
        "CVE",
        "GHSA",
        "GLIBC-SA",
        "GStreamer",
        "MFSA",
        "TALOS",
        "TROVE",
        "VMSA",
        "WNPA-SEC",
        "WSA",
        "XSA",
        "YSA",
        "ZDI-CAN",
    ]

    def __init__(self, ref_text, url=None):
        # note that we can't actually raise exception on a validation
        # failure here yet because there are lots of old references
        # that wouldn't pass the validation, and this would block the
        # ingestion of old GLSAs
        # if not self.valid_reference(ref_text):
        #     raise InvalidReferenceFormatException

        self.ref_text = ref_text

        if url:
            self.url = url
        else:
            if ref_text.startswith("CVE"):
                self.url = f"https://nvd.nist.gov/vuln/detail/{self.ref_text}"
            elif ref_text.startswith("WSA"):
                self.url = f"https://webkitgtk.org/security/{self.ref_text}.html"
            elif ref_text.startswith("GStreamer"):
                self.url = "https://gstreamer.freedesktop.org/security/"
                ref = ref_text.replace("GStreamer-", "")
                self.url += f"{ref.lower()}.html"
            elif ref_text.startswith("YSA"):
                self.url = f"https://www.yubico.com/support/security-advisories/{self.ref_text}"

    # TODO: see bug.py's new TODO
    @classmethod
    def new(cls, ref, url=None):
        row = db.session.query(cls).filter_by(ref_text=ref).first()
        if row:
            return row
        return Reference(ref, url)

    @classmethod
    def valid_reference(cls, ref_text: str) -> bool:
        # not using a lambda here and returning a type of
        # TypeGuard[object] seemingly for:
        # https://github.com/python/mypy/issues/12682
        def _ref_startswith_prefix(prefix: str) -> TypeGuard[object]:
            return ref_text.startswith(prefix)

        if not any(filter(_ref_startswith_prefix, cls.PREFIXES)):
            return False
        return True

    def __lt__(self, other) -> bool:
        parts = self.ref_text.split("-")
        other_parts = other.ref_text.split("-")

        if len(parts) != len(other_parts):
            return False

        for part, other_part in zip(parts, other_parts):
            if part != other_part:
                try:
                    return int(part) < int(other_part)
                except ValueError:
                    return False
        return False