Mercurial > farol > farolluz
comparison farolluz/cvrf.py @ 18:8a89b7a591e6
merged
author | Benoît Allard <benoit.allard@greenbone.net> |
---|---|
date | Tue, 14 Oct 2014 16:49:36 +0200 |
parents | 90852c11fabd |
children | 4b53e7bcff0d |
comparison
equal
deleted
inserted
replaced
3:8e23ba7d4167 | 18:8a89b7a591e6 |
---|---|
63 self._aliases = [] | 63 self._aliases = [] |
64 | 64 |
65 def addAlias(self, alias): | 65 def addAlias(self, alias): |
66 self._aliases.append(alias) | 66 self._aliases.append(alias) |
67 | 67 |
68 def getId(self): | |
69 return self._id | |
70 | |
68 def validate(self): | 71 def validate(self): |
69 if not self._id: | 72 if not self._id: |
70 raise ValidationError('Document ID cannot be left empty') | 73 raise ValidationError('Document ID cannot be left empty') |
71 | 74 |
72 def __str__(self): | 75 def __str__(self): |
89 def addRevision(self, revision): | 92 def addRevision(self, revision): |
90 self._history.append(revision) | 93 self._history.append(revision) |
91 | 94 |
92 def setGenerator(self, generator): | 95 def setGenerator(self, generator): |
93 self._generator = generator | 96 self._generator = generator |
97 | |
98 def getId(self): | |
99 return self._identification.getId() | |
94 | 100 |
95 def validate(self): | 101 def validate(self): |
96 if self._identification is None: | 102 if self._identification is None: |
97 raise ValidationError('Document Tracking needs to have an Identification') | 103 raise ValidationError('Document Tracking needs to have an Identification') |
98 self._identification.validate() | 104 self._identification.validate() |
223 if not self._description: | 229 if not self._description: |
224 raise ValidationError('A Reference must contain a description') | 230 raise ValidationError('A Reference must contain a description') |
225 | 231 |
226 | 232 |
227 class CVRFAcknowledgment(object): | 233 class CVRFAcknowledgment(object): |
228 def __init__(self, name=None, organization=None, description=None, | 234 def __init__(self, names=[], organizations=[], description=None, |
229 url=None): | 235 url=None): |
230 self._name = name | 236 self._names = names |
231 self._organization = organization | 237 self._organizations = organizations |
232 self._description = description | 238 self._description = description |
233 self._url = url | 239 self._url = url |
234 | 240 |
235 def getTitle(self): | 241 def getTitle(self): |
236 return "%s - %s" % (self._name, self._organization) | 242 return "%s - %s" % (', '.join(self._names), |
237 | 243 ', '.join(self._organizations)) |
238 def validate(self): | 244 |
239 if (not self._name) and (not self._organization) and (not self._description): | 245 def validate(self): |
246 if (not self._names) and (not self._organizations) and (not self._description): | |
240 raise ValidationError('An Acknowledgment must have at least a Name, an Organization or a Description') | 247 raise ValidationError('An Acknowledgment must have at least a Name, an Organization or a Description') |
241 | 248 |
242 | 249 |
243 class CVRFProductTree(object): | 250 class CVRFProductTree(object): |
244 def __init__(self): | 251 def __init__(self): |
247 self._groups = [] | 254 self._groups = [] |
248 self._relationships = [] | 255 self._relationships = [] |
249 self._products = [] | 256 self._products = [] |
250 self._groups = [] | 257 self._groups = [] |
251 | 258 |
252 def addBranch(self, branch): | |
253 parent = self.getBranch(branch.getParent().getPath()) | |
254 if parent is self: | |
255 self._branches.append(branch) | |
256 else: | |
257 parent._childs.append(branch) | |
258 | |
259 def addProduct(self, product): | 259 def addProduct(self, product): |
260 if product not in self._products: | 260 """ Add to the product list """ |
261 self._products.append(product) | 261 self._products.append(product) |
262 if product._parent is not self: | |
263 product._parent._product = product | |
264 | 262 |
265 def addRelationship(self, rel): | 263 def addRelationship(self, rel): |
266 self._relationships.append(rel) | 264 self._relationships.append(rel) |
267 | 265 |
268 def addGroup(self, group): | 266 def addGroup(self, group): |
394 'Patch Level', 'Service Pack', 'Architecture', 'Language', | 392 'Patch Level', 'Service Pack', 'Architecture', 'Language', |
395 'Legacy', 'Specification') | 393 'Legacy', 'Specification') |
396 def __init__(self, _type, name, parentbranch): | 394 def __init__(self, _type, name, parentbranch): |
397 self._type = _type | 395 self._type = _type |
398 self._name = name | 396 self._name = name |
399 self._parentbranch = parentbranch | |
400 self._childs = [] | 397 self._childs = [] |
401 self._product = None | 398 self._product = None |
399 self.link(parentbranch) | |
402 | 400 |
403 def getParent(self): | 401 def getParent(self): |
404 return self._parentbranch | 402 return self._parentbranch |
405 | 403 |
406 def getPath(self, string=False): | 404 def getPath(self, string=False): |
453 self.getParent()._branches.remove(self) | 451 self.getParent()._branches.remove(self) |
454 else: | 452 else: |
455 self.getParent()._childs.remove(self) | 453 self.getParent()._childs.remove(self) |
456 self._parentbranch = None | 454 self._parentbranch = None |
457 | 455 |
456 def link(self, parent): | |
457 """ Actually, only set the parent """ | |
458 self._parentbranch = parent | |
459 if self.isRoot(): | |
460 parent._branches.append(self) | |
461 else: | |
462 parent._childs.append(self) | |
463 | |
464 | |
458 def validate(self): | 465 def validate(self): |
459 if not self._type: | 466 if not self._type: |
460 raise ValidationError('A Branch must have a Type') | 467 raise ValidationError('A Branch must have a Type') |
461 if self._type not in self.TYPES: | 468 if self._type not in self.TYPES: |
462 raise ValidationError('A Branch Type must be one of %s' % ', '.join(self.TYPES)) | 469 raise ValidationError('A Branch Type must be one of %s' % ', '.join(self.TYPES)) |
473 | 480 |
474 class CVRFFullProductName(object): | 481 class CVRFFullProductName(object): |
475 def __init__(self, productid, name, parent, cpe=None): | 482 def __init__(self, productid, name, parent, cpe=None): |
476 self._productid = productid | 483 self._productid = productid |
477 self._name = name | 484 self._name = name |
485 self._cpe = cpe | |
478 # Can be None (directly under the tree), a ProductBranch, or a | 486 # Can be None (directly under the tree), a ProductBranch, or a |
479 # Relationship | 487 # Relationship |
480 self._parent = parent | 488 self.link(parent) |
481 self._cpe = cpe | |
482 | 489 |
483 def isRoot(self): | 490 def isRoot(self): |
484 return isinstance(self._parent, CVRFProductTree) | 491 return isinstance(self._parent, CVRFProductTree) |
485 | 492 |
486 def isRelationship(self): | 493 def isRelationship(self): |
500 if self.isRelationship(): | 507 if self.isRelationship(): |
501 return self._parent | 508 return self._parent |
502 return None | 509 return None |
503 | 510 |
504 def unlink(self): | 511 def unlink(self): |
505 """ Unset our _parent, and remove us from the _parent._childs """ | 512 """ Unset our _parent, and remove us from the _parent._childs |
506 if self.isRoot(): | 513 We are still in the product list. |
507 self._parent._products.remove(self) | 514 """ |
508 else: | 515 if not self.isRoot(): |
509 self._parent._product = None | 516 self._parent._product = None |
510 self._parent = None | 517 self._parent = None |
518 | |
519 def link(self, parent): | |
520 self._parent = parent | |
521 if not self.isRoot(): | |
522 parent._product = self | |
511 | 523 |
512 def validate(self): | 524 def validate(self): |
513 if not self._productid: | 525 if not self._productid: |
514 raise ValidationError('A Product must have a ProductID') | 526 raise ValidationError('A Product must have a ProductID') |
515 if not self._name: | 527 if not self._name: |
653 return self._title | 665 return self._title |
654 if self._id: | 666 if self._id: |
655 return self._id._value | 667 return self._id._value |
656 return "#%d" % self._ordinal | 668 return "#%d" % self._ordinal |
657 | 669 |
670 def getNote(self, ordinal): | |
671 for note in self._notes: | |
672 if note._ordinal == ordinal: | |
673 return note | |
674 return None | |
675 | |
676 def mentionsProdId(self, productid): | |
677 """ Returns in which sub element, self is mentioning the productid """ | |
678 for category in (self._productstatuses, self._threats, self._cvsss, self._remediations): | |
679 for subelem in category: | |
680 if productid in subelem._productids: | |
681 yield subelem | |
682 | |
683 def isMentioningProdId(self, productid): | |
684 """ Returns if self is mentioning the productid """ | |
685 for e in self.mentionsProdId(productid): | |
686 # We only need to know if the generator yield at least one elem. | |
687 return True | |
688 return False | |
689 | |
690 def mentionsGroupId(self, groupid): | |
691 for category in (self._threats, self._remediations): | |
692 for subelem in category: | |
693 if groupid in subelem._groupids: | |
694 yield subelem | |
695 | |
696 def isMentioningGroupId(self, groupids): | |
697 """ Make sure you call this with a list (not a generator or a tuple) | |
698 when wished """ | |
699 if not isinstance(groupids, list): | |
700 groupids = [groupids] | |
701 for groupid in groupids: | |
702 print "testing GroupId: ", groupid | |
703 for _ in self.mentionsGroupId(groupid): | |
704 # We only need to know if the generator yield at least one elem. | |
705 print 'True' | |
706 return True | |
707 print 'False' | |
708 return False | |
709 | |
658 def validate(self, productids, groupids): | 710 def validate(self, productids, groupids): |
659 if not self._ordinal: | 711 if not self._ordinal: |
660 raise ValidationError('A Vulnerability must have an ordinal') | 712 raise ValidationError('A Vulnerability must have an ordinal') |
661 if self._id is not None: | 713 if self._id is not None: |
662 self._id.validate() | 714 self._id.validate() |
670 involvement.validate() | 722 involvement.validate() |
671 for cwe in self._cwes: | 723 for cwe in self._cwes: |
672 cwe.validate() | 724 cwe.validate() |
673 for status in self._productstatuses: | 725 for status in self._productstatuses: |
674 status.validate(productids) | 726 status.validate(productids) |
727 pids = set() | |
728 for status in self._productstatuses: | |
729 for pid in status._productids: | |
730 if pid in pids: | |
731 raise ValidationError('ProductID %s mentionned in two different ProductStatuses for Vulnerability %d' % (pid, self._ordinal)) | |
732 pids.add(pid) | |
675 for threat in self._threats: | 733 for threat in self._threats: |
676 threat.validate(productids, groupids) | 734 threat.validate(productids, groupids) |
677 for cvss in self._cvsss: | 735 for cvss in self._cvsss: |
678 cvss.validate(productids) | 736 cvss.validate(productids) |
737 pids = set() | |
738 for cvss in self._cvsss: | |
739 for pid in (cvss._productids or productids): | |
740 if pid in pids: | |
741 raise ValidationError('ProductID %s mentionned in two different CVSS Score Sets for Vulnerability %d' % (pid, self._ordinal)) | |
742 pids.add(pid) | |
679 for remediation in self._remediations: | 743 for remediation in self._remediations: |
680 remediation.validate(productids, groupids) | 744 remediation.validate(productids, groupids) |
681 for reference in self._references: | 745 for reference in self._references: |
682 reference.validate() | 746 reference.validate() |
683 for acknowledgment in self._acknowledgments: | 747 for acknowledgment in self._acknowledgments: |
684 acknowledgment.validate() | 748 acknowledgment.validate() |
685 | |
686 | 749 |
687 | 750 |
688 class CVRFInvolvement(object): | 751 class CVRFInvolvement(object): |
689 PARTIES = CVRFPublisher.TYPES | 752 PARTIES = CVRFPublisher.TYPES |
690 STATUSES = ('Open', 'Disputed', 'In Progress', 'Completed', | 753 STATUSES = ('Open', 'Disputed', 'In Progress', 'Completed', |
724 | 787 |
725 | 788 |
726 class CVRFProductStatus(object): | 789 class CVRFProductStatus(object): |
727 TYPES = ('First Affected', 'Known Affected', 'Known Not Affected', | 790 TYPES = ('First Affected', 'Known Affected', 'Known Not Affected', |
728 'First Fixed', 'Fixed', 'Recommended', 'Last Affected') | 791 'First Fixed', 'Fixed', 'Recommended', 'Last Affected') |
792 NAME = "Product Status" | |
729 def __init__(self, _type): | 793 def __init__(self, _type): |
730 self._type = _type | 794 self._type = _type |
731 self._productids = [] | 795 self._productids = [] |
732 | 796 |
733 def addProductID(self, productid): | 797 def addProductID(self, productid): |
748 raise ValidationError('Unknown ProductID: %s' % productid) | 812 raise ValidationError('Unknown ProductID: %s' % productid) |
749 | 813 |
750 | 814 |
751 class CVRFThreat(object): | 815 class CVRFThreat(object): |
752 TYPES = ('Impact', 'Exploit Status', 'Target Set') | 816 TYPES = ('Impact', 'Exploit Status', 'Target Set') |
817 NAME = "Threat" | |
753 def __init__(self, _type, description): | 818 def __init__(self, _type, description): |
754 self._type = _type | 819 self._type = _type |
755 self._description = description | 820 self._description = description |
756 self._date = None | 821 self._date = None |
757 self._productids = [] | 822 self._productids = [] |
790 'AC': {'H':0.35, 'M':0.61 ,'L':0.71}, | 855 'AC': {'H':0.35, 'M':0.61 ,'L':0.71}, |
791 'Au': {'M':0.45, 'S':0.56, 'N':0.704}, | 856 'Au': {'M':0.45, 'S':0.56, 'N':0.704}, |
792 'C': {'N':0.0, 'P':0.275, 'C':0.66}, | 857 'C': {'N':0.0, 'P':0.275, 'C':0.66}, |
793 'I': {'N':0.0, 'P':0.275, 'C':0.66}, | 858 'I': {'N':0.0, 'P':0.275, 'C':0.66}, |
794 'A': {'N':0.0, 'P':0.275, 'C':0.66}} | 859 'A': {'N':0.0, 'P':0.275, 'C':0.66}} |
860 NAME = "CVSS Score Set" | |
795 def __init__(self, basescore): | 861 def __init__(self, basescore): |
796 self._basescore = basescore | 862 self._basescore = basescore |
797 self._temporalscore = None | 863 self._temporalscore = None |
798 self._environmentalscore = None | 864 self._environmentalscore = None |
799 self._vector = None | 865 self._vector = None |
842 | 908 |
843 | 909 |
844 class CVRFRemediation(object): | 910 class CVRFRemediation(object): |
845 TYPES = ('Workaround', 'Mitigation', 'Vendor Fix', 'None Available', | 911 TYPES = ('Workaround', 'Mitigation', 'Vendor Fix', 'None Available', |
846 'Will Not Fix') | 912 'Will Not Fix') |
913 NAME = "Remediation" | |
847 def __init__(self, _type, description): | 914 def __init__(self, _type, description): |
848 self._type = _type | 915 self._type = _type |
849 self._description = description | 916 self._description = description |
850 self._date = None | 917 self._date = None |
851 self._entitlement = None | 918 self._entitlement = None |
970 continue | 1037 continue |
971 for productid in status._productids: | 1038 for productid in status._productids: |
972 products.add(productid) | 1039 products.add(productid) |
973 return set(self.getProductForID(p) for p in products) | 1040 return set(self.getProductForID(p) for p in products) |
974 | 1041 |
1042 def isProductOrphan(self, productid): | |
1043 """ Returns if a productid is mentionned nowhere in the document """ | |
1044 # We first look at the ProductTree | |
1045 ptree = self._producttree | |
1046 for relation in ptree._relationships: | |
1047 if productid == relation._productreference: | |
1048 return False | |
1049 if productid == relation._relatestoproductreference: | |
1050 return False | |
1051 groupids = [g._groupid for g in ptree._groups if productid in g._productids] | |
1052 if len(groupids) > 0: | |
1053 return False | |
1054 # Go through all the Vulnerabilities | |
1055 for vulnerability in self._vulnerabilities: | |
1056 if vulnerability.isMentioningProdId(productid): | |
1057 return False | |
1058 for groupid in groupids: | |
1059 if vulnerability.isMentioningGroupId(groupid): | |
1060 return False | |
1061 return True | |
1062 | |
975 def getNote(self, ordinal): | 1063 def getNote(self, ordinal): |
976 for note in self._notes: | 1064 for note in self._notes: |
977 if note._ordinal == ordinal: | 1065 if note._ordinal == ordinal: |
978 return note | 1066 return note |
979 return None | 1067 return None |
1068 | |
1069 def getDocId(self): | |
1070 if self._tracking is not None: | |
1071 return self._tracking.getId() | |
1072 # Make up something ... | |
1073 return self._title.lower() | |
980 | 1074 |
981 def validate(self): | 1075 def validate(self): |
982 if not self._title: | 1076 if not self._title: |
983 raise ValidationError('Document Title cannot be empty') | 1077 raise ValidationError('Document Title cannot be empty') |
984 if not self._type: | 1078 if not self._type: |