|
14 | 14 | import hyperlink |
15 | 15 | import tagulous.admin |
16 | 16 | from auditlog.registry import auditlog |
17 | | -from cvss import CVSS3 |
18 | 17 | from dateutil.relativedelta import relativedelta |
19 | 18 | from django import forms |
20 | 19 | from django.conf import settings |
|
44 | 43 | from tagulous.models import TagField |
45 | 44 | from tagulous.models.managers import FakeTagRelatedManager |
46 | 45 |
|
| 46 | +from dojo.validators import cvss3_validator |
| 47 | + |
47 | 48 | logger = logging.getLogger(__name__) |
48 | 49 | deduplicationLogger = logging.getLogger("dojo.specific-loggers.deduplication") |
49 | 50 |
|
@@ -2331,12 +2332,11 @@ class Finding(models.Model): |
2331 | 2332 | verbose_name=_("EPSS percentile"), |
2332 | 2333 | help_text=_("EPSS percentile for the CVE. Describes how many CVEs are scored at or below this one."), |
2333 | 2334 | validators=[MinValueValidator(0.0), MaxValueValidator(1.0)]) |
2334 | | - cvssv3_regex = RegexValidator(regex=r"^AV:[NALP]|AC:[LH]|PR:[UNLH]|UI:[NR]|S:[UC]|[CIA]:[NLH]", message="CVSS must be entered in format: 'AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H'") |
2335 | | - cvssv3 = models.TextField(validators=[cvssv3_regex], |
| 2335 | + cvssv3 = models.TextField(validators=[cvss3_validator], |
2336 | 2336 | max_length=117, |
2337 | 2337 | null=True, |
2338 | | - verbose_name=_("CVSS v3"), |
2339 | | - help_text=_("Common Vulnerability Scoring System version 3 (CVSSv3) score associated with this flaw.")) |
| 2338 | + verbose_name=_("CVSS v3 vector"), |
| 2339 | + help_text=_("Common Vulnerability Scoring System version 3 (CVSSv3) score associated with this finding.")) |
2340 | 2340 | cvssv3_score = models.FloatField(null=True, |
2341 | 2341 | blank=True, |
2342 | 2342 | verbose_name=_("CVSSv3 score"), |
@@ -2698,11 +2698,17 @@ def save(self, dedupe_option=True, rules_option=True, product_grading_option=Tru |
2698 | 2698 | # Synchronize cvssv3 score using cvssv3 vector |
2699 | 2699 | if self.cvssv3: |
2700 | 2700 | try: |
2701 | | - cvss_object = CVSS3(self.cvssv3) |
2702 | | - # use the environmental score, which is the most refined score |
2703 | | - self.cvssv3_score = cvss_object.scores()[2] |
| 2701 | + |
| 2702 | + cvss_data = parse_cvss_data(self.cvssv3) |
| 2703 | + if cvss_data: |
| 2704 | + self.cvssv3 = cvss_data.get("vector") |
| 2705 | + self.cvssv3_score = cvss_data.get("score") |
| 2706 | + |
2704 | 2707 | except Exception as ex: |
2705 | | - logger.error("Can't compute cvssv3 score for finding id %i. Invalid cvssv3 vector found: '%s'. Exception: %s", self.id, self.cvssv3, ex) |
| 2708 | + logger.warning("Can't compute cvssv3 score for finding id %i. Invalid cvssv3 vector found: '%s'. Exception: %s.", self.id, self.cvssv3, ex) |
| 2709 | + # remove invalid cvssv3 vector for new findings, or should we just throw a ValidationError? |
| 2710 | + if self.pk is None: |
| 2711 | + self.cvssv3 = None |
2706 | 2712 |
|
2707 | 2713 | self.set_hash_code(dedupe_option) |
2708 | 2714 |
|
@@ -3515,8 +3521,8 @@ class Finding_Template(models.Model): |
3515 | 3521 | blank=False, |
3516 | 3522 | verbose_name="Vulnerability Id", |
3517 | 3523 | help_text="An id of a vulnerability in a security advisory associated with this finding. Can be a Common Vulnerabilities and Exposures (CVE) or from other sources.") |
3518 | | - cvssv3_regex = RegexValidator(regex=r"^AV:[NALP]|AC:[LH]|PR:[UNLH]|UI:[NR]|S:[UC]|[CIA]:[NLH]", message="CVSS must be entered in format: 'AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H'") |
3519 | | - cvssv3 = models.TextField(validators=[cvssv3_regex], max_length=117, null=True) |
| 3524 | + cvssv3 = models.TextField(help_text=_("Common Vulnerability Scoring System version 3 (CVSSv3) score associated with this finding."), validators=[cvss3_validator], max_length=117, null=True, verbose_name=_("CVSS v3 vector")) |
| 3525 | + |
3520 | 3526 | severity = models.CharField(max_length=200, null=True, blank=True) |
3521 | 3527 | description = models.TextField(null=True, blank=True) |
3522 | 3528 | mitigation = models.TextField(null=True, blank=True) |
@@ -4632,7 +4638,11 @@ def __str__(self): |
4632 | 4638 | auditlog.register(Notification_Webhooks, exclude_fields=["header_name", "header_value"]) |
4633 | 4639 |
|
4634 | 4640 |
|
4635 | | -from dojo.utils import calculate_grade, to_str_typed # noqa: E402 # there is issue due to a circular import |
| 4641 | +from dojo.utils import ( # noqa: E402 # there is issue due to a circular import |
| 4642 | + calculate_grade, |
| 4643 | + parse_cvss_data, |
| 4644 | + to_str_typed, |
| 4645 | +) |
4636 | 4646 |
|
4637 | 4647 | tagulous.admin.register(Product.tags) |
4638 | 4648 | tagulous.admin.register(Test.tags) |
|
0 commit comments