diff options
Diffstat (limited to 'lib/orm/models.py')
-rw-r--r-- | lib/orm/models.py | 363 |
1 files changed, 235 insertions, 128 deletions
diff --git a/lib/orm/models.py b/lib/orm/models.py index 3a4a39a7..0d287bb4 100644 --- a/lib/orm/models.py +++ b/lib/orm/models.py @@ -42,10 +42,8 @@ from signal import SIGUSR1 import logging logger = logging.getLogger("srt") -def _log(msg): - f1=open('/tmp/srt.log', 'a') - f1.write("|" + msg + "|\n" ) - f1.close() +# quick development/debugging support +from srtgui.api import _log # Sqlite support @@ -127,7 +125,6 @@ class SrtSetting(models.Model): def __unicode__(self): return "Setting %s = %s" % (self.name, self.value) - class HelpText(models.Model): VARIABLE = 0 HELPTEXT_AREA = ((VARIABLE, 'variable'), ) @@ -136,7 +133,25 @@ class HelpText(models.Model): key = models.CharField(max_length=100) text = models.TextField() + +#UPDATE_FREQUENCY: 0 = every minute, 1 = every hour, 2 = every day, 3 = every week, 4 = every month, 5 = every year class DataSource(models.Model): + #UPDATE FREQUENCT + MINUTELY = 0 + HOURLY = 1 + DAILY = 2 + WEEKLY = 3 + MONTHLY = 4 + ONDEMAND = 5 + FREQUENCY = ( + (MINUTELY, 'New'), + (HOURLY, 'Hourly'), + (DAILY, 'Daily'), + (WEEKLY, 'Weekly'), + (MONTHLY, 'Monthly'), + (ONDEMAND, 'OnDemand'), + ) + data = models.CharField(max_length=20) source = models.CharField(max_length=20) type = models.CharField(max_length=20) @@ -144,6 +159,15 @@ class DataSource(models.Model): file_path = models.FilePathField() url = models.TextField(blank=True) loaded = models.BooleanField(default=False) + meta_url = models.TextField(blank=True) + lastModifiedDate = models.CharField(max_length=50, blank=True) + update_frequency = models.IntegerField(choices=FREQUENCY, default=DAILY) + update_time = models.CharField(max_length=50, blank=True) + command = models.TextField(blank=True) + + + def get_frequency_text(self): + return DataSource.FREQUENCY[int(self.update_frequency)][1] class CweTable(models.Model): search_allowed_fields = ['name', 'href', 'description', 'summary'] @@ -155,9 +179,25 @@ class CweTable(models.Model): vulnerable_count = models.IntegerField(default=0) found = models.BooleanField(default=False) + class Cve(models.Model): search_allowed_fields = ['name', 'description', 'publishedDate', 'lastModifiedDate', 'comments', 'comments_private'] + + # SRTool Priority + UNDEFINED = 0 + MINOR = 1 + LOW = 2 + MEDIUM = 3 + HIGH = 4 + PRIORITY = ( + (UNDEFINED, ''), + (MINOR, 'Minor'), + (LOW, 'Low'), + (MEDIUM, 'Medium'), + (HIGH, 'High'), + ) + # WR Status NEW = 0 INVESTIGATE = 1 @@ -170,18 +210,20 @@ class Cve(models.Model): (NOT_VULNERABLE, 'Not Vulnerable'), ) - # Publish options - PUBLISH_UNDEF = 0 - PUBLISH_AUTO = 1 - PUBLISH_REQUEST = 2 - PUBLISH_PUBLISHED = 3 - PUBLISH_NOPUBLISH = 4 - PUBLISH = ( - (PUBLISH_UNDEF, 'Undetermined'), - (PUBLISH_AUTO, 'Automatic Publish Date'), - (PUBLISH_REQUEST, 'Request Publish Date'), + # Publish state + PUBLISH_UNPUBLISHED = 0 + PUBLISH_NOPUBLISH = 1 + PUBLISH_PUBLISHED = 2 + PUBLISH_REQUEST = 3 + PUBLISH_UPDATE = 4 + PUBLISH_SUBMITTED = 5 + PUBLISH_STATE = ( + (PUBLISH_UNPUBLISHED, 'Unpublished'), + (PUBLISH_NOPUBLISH, 'Not to be Published'), (PUBLISH_PUBLISHED, 'Published'), - (PUBLISH_NOPUBLISH, 'Do Not Published'), + (PUBLISH_REQUEST, 'Publish Request (New)'), + (PUBLISH_UPDATE, 'Publish Request (Update)'), + (PUBLISH_SUBMITTED, 'Publish Submitted'), ) # CPE item list @@ -193,69 +235,44 @@ class Cve(models.Model): name = models.CharField(max_length=50) source = models.CharField(max_length=50) + datasource = models.ForeignKey(DataSource,related_name="cve_datasource") + priority = models.IntegerField(default=0) status = models.IntegerField(choices=STATUS, default=NEW) comments = models.TextField(blank=True) comments_private = models.TextField(blank=True) - + cve_data_type = models.CharField(max_length=100, blank=True) cve_data_format = models.CharField(max_length=50, blank=True) cve_data_version = models.CharField(max_length=50, blank=True) public = models.BooleanField(default=True) - publish = models.IntegerField(choices=PUBLISH, default=PUBLISH_UNDEF) + publish_state = models.IntegerField(choices=PUBLISH_STATE, default=PUBLISH_UNPUBLISHED) publish_date = models.CharField(max_length=50, blank=True) description = models.TextField(blank=True) publishedDate = models.CharField(max_length=50, blank=True) lastModifiedDate = models.CharField(max_length=50, blank=True) -# problemtype = models.CharField(max_length=40, blank=True) -# problemtype = models.ForeignKey(CweTable, related_name='cwe') recommend = models.IntegerField(default=0) - - cpe_list= models.TextField(blank=True) + recommend_list = models.TextField(blank=True) cvssV3_baseScore = models.CharField(max_length=50, blank=True) cvssV3_baseSeverity = models.CharField(max_length=50, blank=True) - cvssV3_vectorString = models.TextField(blank=True) - cvssV3_exploitabilityScore = models.CharField(max_length=50, blank=True) - cvssV3_impactScore = models.CharField(max_length=50, blank=True) - cvssV3_attackVector = models.CharField(max_length=50, blank=True) - cvssV3_attackComplexity = models.CharField(max_length=50, blank=True) - cvssV3_privilegesRequired = models.CharField(max_length=50, blank=True) - cvssV3_userInteraction = models.CharField(max_length=50, blank=True) - cvssV3_scope = models.CharField(max_length=50, blank=True) - cvssV3_confidentialityImpact = models.CharField(max_length=50, blank=True) - cvssV3_integrityImpact = models.CharField(max_length=50, blank=True) - cvssV3_availabilityImpact = models.CharField(max_length=50, blank=True) cvssV2_baseScore = models.CharField(max_length=50, blank=True) cvssV2_severity = models.CharField(max_length=50, blank=True) - cvssV2_vectorString = models.TextField(blank=True) - cvssV2_exploitabilityScore = models.CharField(max_length=50, blank=True) - cvssV2_impactScore = models.CharField(max_length=50, blank=True) - cvssV2_accessVector = models.CharField(max_length=50, blank=True) - cvssV2_accessComplexity = models.CharField(max_length=50, blank=True) - cvssV2_authentication = models.CharField(max_length=50, blank=True) - cvssV2_confidentialityImpact = models.CharField(max_length=50, blank=True) - cvssV2_integrityImpact = models.CharField(max_length=50, blank=True) class Meta: unique_together = ('name', 'source' ) @property - def problemtype_summary(self): - """ Return the summary of the CWE """ - summary = '?' - try: - r = CweTable.objects.get(name=self.problemtype) - summary = r.summary - except Exception as e: - logger.warning("ERROR: could not find CWE %s" % self.problemtype) - return summary + def get_priority_text(self): + return Cve.PRIORITY[int(self.priority)][1] + @property def get_publish_text(self): - return Cve.PUBLISH[int(self.publish)][1] + return Cve.PUBLISH_STATE[int(self.publish_state)][1] + @property def get_status_text(self): return Cve.STATUS[int(self.status)][1] def get_cpe_list(self): @@ -264,31 +281,54 @@ class Cve(models.Model): cpe_array.append(cpe.split(',')) return cpe_array - FOR_LIST = ['linux','openjpeg','libtiff','libav','tcp','binutil ','ssl','ssh','glibc'] - AGAINST_LIST = ['cisco','microsoft','windows','ibm','oracle','sun','java','peoplesoft','hancom','zyxel','wordpress','sugarcrm','cobham', - 'juniper'] - - def recommendation(self): - recommendation = 0 - for s in Cve.FOR_LIST: - if 0 <= self.description.lower().find(s): - recommendation += 1 - for s in Cve.AGAINST_LIST: - if 0 <= self.description.lower().find(s): - recommendation -= 1 - return recommendation - def reasons_for(self): - reason = '' - for s in Cve.FOR_LIST: - if 0 <= self.description.lower().find(s): - reason += '%s ' % s - return reason - def reasons_against(self): - reason = '' - for s in Cve.AGAINST_LIST: - if 0 <= self.description.lower().find(s): - reason += '%s ' % s - return reason + +class CveDetail(): + # CPE item list + CPE_LIST_KEY = 0 # entry is <[/]component|and|or> tag or '|' delimited list + CPE_LIST_VULNERABLE = 0 + CPE_LIST_CPE23 = 1 + CPE_LIST_CPE22 = 2 + CPE_LIST_VERSIONEND = 3 + + name = '' +# problemtype = '' + + recommend = '' + recommend_list = '' + + cpe_list= '' + + cvssV3_baseScore = '' + cvssV3_baseSeverity = '' + cvssV3_vectorString = '' + cvssV3_exploitabilityScore = '' + cvssV3_impactScore = '' + cvssV3_attackVector = '' + cvssV3_attackComplexity = '' + cvssV3_privilegesRequired = '' + cvssV3_userInteraction = '' + cvssV3_scope = '' + cvssV3_confidentialityImpact = '' + cvssV3_integrityImpact = '' + cvssV3_availabilityImpact = '' + + cvssV2_baseScore = '' + cvssV2_severity = '' + cvssV2_vectorString = '' + cvssV2_exploitabilityScore = '' + cvssV2_impactScore = '' + cvssV2_accessVector = '' + cvssV2_accessComplexity = '' + cvssV2_authentication = '' + cvssV2_confidentialityImpact = '' + cvssV2_integrityImpact = '' + + def get_cpe_list(self): + cpe_array = [] + for cpe in self.cpe_list.split('|'): + cpe_array.append(cpe.split(',')) + return cpe_array + # Same CVE from multiple sources and/or revisions class CveSet(models.Model): @@ -319,7 +359,7 @@ class CpeTable(models.Model): cpeMatchString = models.TextField(blank=True) cpe23Uri = models.TextField(blank=True) versionEndIncluding = models.TextField(blank=True) - + class CpeToCve(models.Model): cpe = models.ForeignKey(CpeTable,related_name="cpe2cve") cve = models.ForeignKey(Cve,related_name="cve2cpe") @@ -353,7 +393,7 @@ class CpeFilter(models.Model): @property def get_status_text(self): return CpeFilter.STATUS[int(self.status)][1] - + # CVE/CWE Mapping @@ -373,6 +413,8 @@ class CveReference(models.Model): # PRODUCT class Product(models.Model): + search_allowed_fields = ['name', 'version', 'profile'] + name = models.CharField(max_length=40) version = models.CharField(max_length=40) profile = models.CharField(max_length=40) @@ -382,13 +424,14 @@ class Product(models.Model): class Meta: unique_together = ('name', 'version', 'profile', ) + @property def long_name(self): return '%s %s %s' % (self.name,self.version,self.profile) # VULNERABILITY -# Company-level Vulnerablility Record +# Company-level Vulnerablility Record class Vulnerability(models.Model): search_allowed_fields = ['name', 'comments', 'comments_private'] @@ -410,22 +453,27 @@ class Vulnerability(models.Model): (FIXED, 'Closed (Fixed)'), (NOT_FIX, "Closed (Won't Fix)"), ) - LOW = 0 - MEDIUM = 1 - HIGH = 2 + # SRTool Severity, matched with Cve/Defect Priority with placeholder for 'minor' + UNDEFINED = 0 + MINOR = 1 + LOW = 2 + MEDIUM = 3 + HIGH = 4 SEVERITY = ( + (UNDEFINED, ''), + (MINOR, 'Minor'), (LOW, 'Low'), (MEDIUM, 'Medium'), (HIGH, 'High'), ) name = models.CharField(max_length=50) - cve_primary_name = models.CharField(max_length=50) - description = models.TextField(blank=True) + cve_primary_name = models.CharField(max_length=50, default='') + description = models.TextField(blank=True, default='') - public = models.BooleanField(default=False) - comments = models.TextField(blank=True) - comments_private = models.TextField(blank=True) + public = models.BooleanField(default=True) + comments = models.TextField(blank=True, default='') + comments_private = models.TextField(blank=True, default='') status = models.IntegerField(choices=STATUS, default=INVESTIGATE) outcome = models.IntegerField(choices=OUTCOME, default=OPEN) @@ -485,7 +533,7 @@ class Vulnerability(models.Model): except IntegrityError: print("Error in new_vulnerability_name") raise - return "V%04d" % index + return "V%05d" % index class VulnerabilityComments(models.Model): vulnerability = models.ForeignKey(Vulnerability,related_name="vulnerability_comments") @@ -513,7 +561,7 @@ class CveToVulnerablility(models.Model): # Defects -# Defect Record +# Defect Record class Defect(models.Model): search_allowed_fields = ['name', 'summary', 'release_version'] #, 'product'] @@ -521,11 +569,13 @@ class Defect(models.Model): #Issue Type,Key,Summary,Priority,Status,Resolution,Publish To OLS,Fix Version #Bug,LIN10-2031,Security Advisory - libvorbis - CVE-2017-14633,P3,Closed,Fixed,Reviewed - Publish,10.17.41.3 - MINOR = 0 - LOW = 1 - MEDIUM = 2 - HIGH = 3 + NONE = 0 + MINOR = 1 + LOW = 2 + MEDIUM = 3 + HIGH = 4 Priority = ( + (NONE, 'None'), (MINOR, 'P4'), (LOW, 'P3'), (MEDIUM, 'P2'), @@ -546,35 +596,49 @@ class Defect(models.Model): (CLOSED, 'Closed'), ) UNRESOLVED = 0 - FIXED = 1 - WILL_NOT_FIX = 2 - WITHDRAWN = 3 - REJECTED = 4 - DUPLICATE = 5 + RESOLVED = 1 + FIXED = 2 + WILL_NOT_FIX = 3 + WITHDRAWN = 4 + REJECTED = 5 + DUPLICATE = 6 + NOT_APPLICABLE = 7 + REPLACED_BY_REQUIREMENT = 8 + CANNOT_REPRODUCE = 9 + DONE = 10 Resolution = ( (UNRESOLVED, 'Unresolved'), + (RESOLVED, 'Resolved'), (FIXED, 'Fixed'), (WILL_NOT_FIX, 'Won\'t Fix'), (WITHDRAWN, 'Withdrawn'), (REJECTED, 'Rejected'), (DUPLICATE, 'Duplicate'), + (NOT_APPLICABLE, 'Not Applicable'), + (REPLACED_BY_REQUIREMENT, 'Replaced By Requirement'), + (CANNOT_REPRODUCE, 'Cannot Reproduce'), + (DONE, 'Done'), ) name = models.CharField(max_length=50) summary = models.TextField(blank=True) + url = models.TextField(blank=True) priority = models.IntegerField(choices=Priority, default=MINOR) status = models.IntegerField(choices=Status, default=OPEN) resolution = models.IntegerField(choices=Resolution, default=UNRESOLVED) - publishOLS = models.TextField(blank=True) + publish = models.TextField(blank=True) release_version = models.CharField(max_length=50) product = models.ForeignKey(Product,related_name="product_defect") date_created = models.CharField(max_length=50) date_updated = models.CharField(max_length=50) # Methods + @property def get_priority_text(self): return Defect.Priority[int(self.priority)][1] + @property def get_status_text(self): return Defect.Status[int(self.status)][1] + @property def get_resolution_text(self): return Defect.Resolution[int(self.resolution)][1] def get_long_name(self): @@ -585,7 +649,7 @@ class Defect(models.Model): # INVESTIGATION -# Product-level Vulnerablility Investigation Record +# Product-level Vulnerablility Investigation Record class Investigation(models.Model): search_allowed_fields = ['name', 'comments', 'comments_private'] @@ -607,10 +671,15 @@ class Investigation(models.Model): (FIXED, 'Fixed'), (NOT_FIX, "Won't Fix"), ) - LOW = 0 - MEDIUM = 1 - HIGH = 2 + # SRTool Severity, matched with Cve/Defect Priority with placeholder for 'minor' + UNDEFINED = 0 + MINOR = 1 + LOW = 2 + MEDIUM = 3 + HIGH = 4 SEVERITY = ( + (UNDEFINED, ''), + (MINOR, 'Minor'), (LOW, 'Low'), (MEDIUM, 'Medium'), (HIGH, 'High'), @@ -650,7 +719,7 @@ class Investigation(models.Model): index = int(current_investigation_index.value) + 1 current_investigation_index.value = str(index) current_investigation_index.save() - return "I%04d" % index + return "I%05d" % index class InvestigationToDefect(models.Model): investigation = models.ForeignKey(Investigation,related_name="investigation_to_defect") @@ -700,7 +769,7 @@ class User(models.Model): # the default guest user account is ID=1 USER_GUEST = 1 - # Access model + # Access model READER = 0 CONTRIBUTOR = 1 CREATOR = 2 @@ -720,6 +789,32 @@ class User(models.Model): def get_access_text(self): return User.ACCESS[int(self.access)][1] + @property + def builtin(self): + return( ('Guest' == self.name) or ('SRTool' == self.name)) + +# Minimal and safe User object to pass to web pages (no passwords) +class UserSafe(): + def __init__(self, pk, name, email): + self.pk = pk + self.name = name + self.email = email + + def __str__(self): + return "UserSafeStr=%d,%s,%s" % (self.pk, self.name, self.email) + + @staticmethod + def get_safe_userlist(allow_assignment=True): + user_list = [] + for user in User.objects.all(): + if 'SRTool' == user.name: + continue + if allow_assignment and ('Guest' == user.name): + continue + u = UserSafe(user.id,user.name,user.email) + user_list.append(u) + return user_list + class VulnerabilityAccess(models.Model): vulnerability = models.ForeignKey(Vulnerability,related_name="vulnerability_users") user = models.ForeignKey(User,related_name="vulnerability_user") @@ -759,47 +854,59 @@ class Keywords(models.Model): def get_keytype_text(self): return Keywords.KeyType[int(self.key_type)][1] - - -# ==== +# Items waiting for SRTool external publishing +class PublishPending(models.Model): + cve = models.ForeignKey(Cve,related_name="publish_pending_cves",blank=True,null=True) + vulnerability = models.ForeignKey(Vulnerability,related_name="publish_pending_vulnerabilities",blank=True,null=True) + investigation = models.ForeignKey(Investigation,related_name="publish_pending_investigations",blank=True,null=True) + date = models.DateField(null=True, blank=True) + note = models.TextField(blank=True) + +# ==== Support clases, meta classes ==== + +def _log_args(msg, *args, **kwargs): + s = '%s:(' % msg + if args: + for a in args: + s += '%s,' % a + s += '),(' + if kwargs: + for key, value in kwargs.iteritems(): + s += '(%s=%s),' % (key,value) + s += ')' + _log(s) class Access(): # default user is "Guest" - - def read_values(self): - v, created = SrtSetting.objects.get_or_create(name='current_user') - if created: - v.value = User.USER_GUEST - v.save() - self.current_user = int(v.value) + + def __init__(self, *args, **kwargs): + _log_args("ACCESS:", *args, **kwargs) + srt_user_id = args[0] + + # default to "Guest" + if 0 == srt_user_id: + srt_user_id = 1 + + self.current_user = srt_user_id try: - self.current_user_name = User.objects.get(pk=self.current_user).name + user = User.objects.get(pk=self.current_user) + self.current_user_name = user.name + self.current_user_access = user.access except: self.current_user_name = '<not_found>' - - v, created = SrtSetting.objects.get_or_create(name='current_user_access') - if created: - v.value = User.READER - v.save() - self.current_user_access = int(v.value) + self.current_user_access = User.READER def is_guest(self): - self.read_values() return self.current_user == User.USER_GUEST def is_reader(self): - self.read_values() return self.current_user_access >= User.READER def is_contributor(self): - self.read_values() return self.current_user_access >= User.CONTRIBUTOR def is_creator(self): - self.read_values() return self.current_user_access >= User.CREATOR def is_admin(self): - self.read_values() return self.current_user_access >= User.ADMIN def user_name(self): - self.read_values() return self.current_user_name # Database Cache Support |