diff options
Diffstat (limited to 'lib/srtgui/views.py')
-rw-r--r-- | lib/srtgui/views.py | 973 |
1 files changed, 743 insertions, 230 deletions
diff --git a/lib/srtgui/views.py b/lib/srtgui/views.py index d87dca38..79bf7b17 100644 --- a/lib/srtgui/views.py +++ b/lib/srtgui/views.py @@ -37,13 +37,15 @@ from orm.models import Investigation, InvestigationHistory, InvestigationToDefec from orm.models import SrtSetting, Product from orm.models import Package from orm.models import DataSource -from orm.models import Defect, PublishPending +from orm.models import Defect, DefectHistory, PublishPending, PublishSet from orm.models import Notify, NotifyAccess, NotifyCategories +from orm.models import SRTool, Update from users.models import SrtUser, UserSafe from srtgui.reports import ReportManager from srtgui.api import readCveDetails, writeCveDetails, summaryCveDetails, execute_process +from srtgui.api import publishCalculate, publishReset, publishMarkNew, publishMarkModified, publishMarkNone from django.urls import reverse, resolve from django.core.paginator import EmptyPage, PageNotAnInteger @@ -59,6 +61,10 @@ logger = logging.getLogger("srt") # quick development/debugging support from srtgui.api import _log +# +# ================= Helper Routines ============================================ +# + def get_name_sort(cve_name): try: a = cve_name.split('-') @@ -67,6 +73,10 @@ def get_name_sort(cve_name): cve_name_sort = cve_name return cve_name_sort +# +# ================= Page Helper Routines ============================================ +# + class MimeTypeFinder(object): # setting this to False enables additional non-standard mimetypes # to be included in the guess @@ -450,10 +460,10 @@ def management(request): return redirect(landing) # Keep it simple now, later use Q sets - defect_open = Defect.objects.filter(status=Defect.OPEN) - defects_inprogress = Defect.objects.filter(status=Defect.IN_PROGRESS) - defect_p1 = defect_open.filter(priority=Defect.HIGH).count() + defects_inprogress.filter(priority=Defect.HIGH).count() - defect_p2 = defect_open.filter(priority=Defect.MEDIUM).count() + defects_inprogress.filter(priority=Defect.MEDIUM).count() + defect_open = Defect.objects.filter(status=Defect.DEFECT_STATUS_OPEN) + defects_inprogress = Defect.objects.filter(status=Defect.DEFECT_STATUS_IN_PROGRESS) + defect_p1 = defect_open.filter(priority=Defect.CRITICAL).count() + defects_inprogress.filter(priority=Defect.CRITICAL).count() + defect_p2 = defect_open.filter(priority=Defect.HIGH).count() + defects_inprogress.filter(priority=Defect.HIGH).count() defect_open = defect_open.count() defects_inprogress = defects_inprogress.count() @@ -467,15 +477,15 @@ def management(request): 'vulnerability_total' : Vulnerability.objects.all().count(), 'vulnerability_open' : Vulnerability.objects.filter(outcome=Vulnerability.OPEN).count(), + 'vulnerability_critical' : Vulnerability.objects.filter(outcome=Vulnerability.OPEN).filter(priority=Vulnerability.CRITICAL).count(), 'vulnerability_high' : Vulnerability.objects.filter(outcome=Vulnerability.OPEN).filter(priority=Vulnerability.HIGH).count(), 'vulnerability_medium' : Vulnerability.objects.filter(outcome=Vulnerability.OPEN).filter(priority=Vulnerability.MEDIUM).count(), - 'vulnerability_low' : Vulnerability.objects.filter(outcome=Vulnerability.OPEN).filter(priority=Vulnerability.HIGH).count(), 'investigation_total' : Investigation.objects.all().count(), 'investigation_open' : Investigation.objects.filter(outcome=Investigation.OPEN).count(), + 'investigation_critical' : Investigation.objects.filter(outcome=Investigation.OPEN).filter(priority=Investigation.CRITICAL).count(), 'investigation_high' : Investigation.objects.filter(outcome=Investigation.OPEN).filter(priority=Investigation.HIGH).count(), 'investigation_medium' : Investigation.objects.filter(outcome=Investigation.OPEN).filter(priority=Investigation.MEDIUM).count(), - 'investigation_low' : Investigation.objects.filter(outcome=Investigation.OPEN).filter(priority=Investigation.HIGH).count(), 'defect_total' : Defect.objects.all().count(), 'defect_open' : defect_open, @@ -487,6 +497,20 @@ def management(request): } return render(request, 'management.html', context) +def maintenance(request): + # does this user have permission to see this record? + if not UserSafe.is_creator(request.user): + return redirect(landing) + + context = { + 'history_cve_total' : CveHistory.objects.all().count(), + 'history_vulnerability_total' : VulnerabilityHistory.objects.all().count(), + 'history_investigation_total' : InvestigationHistory.objects.all().count(), + 'defect_investigation_total' : DefectHistory.objects.all().count(), + } + return render(request, 'maintenance.html', context) + + def cve(request, cve_pk, active_tab="1"): if request.method == "GET": template = "cve.html" @@ -520,23 +544,31 @@ def cve(request, cve_pk, active_tab="1"): cve_index = ord('1') is_edit = ('Edit' == active_tab) - # Prepend summary page? + # Fetch source tabs list cve_sources = CveSource.objects.filter(cve=cve_object.id).order_by('datasource__key') - if True or (1 < len(cve_sources)): - tab_states[chr(cve_index)] = '' - cveDetails,cve_html = summaryCveDetails(cve_object,cve_sources) - cve_list_table.append([cveDetails,tab_states[chr(cve_index)],'Summary',cve_html]) - cve_index += 1 + # Always pre-pend a summary page + tab_states[chr(cve_index)] = 'active' + cveDetails,cve_html = summaryCveDetails(cve_object,cve_sources) + cve_list_table.append([cveDetails,tab_states[chr(cve_index)],'Summary',cve_html]) + cve_index += 1 # Add the source/edit tabs - for cs in cve_sources: + for i in range(len(cve_sources)): + if (i < (len(cve_sources)-1)) and (cve_sources[i].datasource.source == cve_sources[i+1].datasource.source): + # Insure one source per vendor where the highest key wins (e.g. NIST Modified) + continue + pass + + cs = cve_sources[i] if active_tab == cs.datasource.name: active_tab = chr(cve_index) if ('Edit' == active_tab) and ('Local' == cs.datasource.name): - tab_states[chr(cve_index)] = 'active' + #tab_states[chr(cve_index)] = 'active' + tab_states[chr(cve_index)] = '' cve_list_table.append([readCveDetails(cve_object,cs.datasource),tab_states[chr(cve_index)],'Edit',{}]) else: - tab_states[chr(cve_index)] = 'active' if (active_tab == chr(cve_index)) else '' + tab_states[chr(cve_index)] = '' + #tab_states[chr(cve_index)] = 'active' if (active_tab == chr(cve_index)) else '' cve_list_table.append([readCveDetails(cve_object,cs.datasource),tab_states[chr(cve_index)],cs.datasource.name,{}]) cve_index += 1 if 0 == len(cve_sources): @@ -552,11 +584,6 @@ def cve(request, cve_pk, active_tab="1"): tab_states['1'] = 'active' cve_list_table[0][1] = 'active' - - # cve_summary = copy.copy(cve_object) - # cve_summary_detail = copy.copy(cve_object_detail) - # cve_summary.source = 'Summary' - # context = { 'object' : cve_object, 'cve_list_table' : cve_list_table, @@ -583,7 +610,7 @@ def cve(request, cve_pk, active_tab="1"): # Is this not a save? if not request.POST.get('cve-edit','').startswith('Save'): - return redirect(cve, cve_object.id, "Local") + return redirect(cve, cve_object.id, "Summary") # does this user have permission to see this record? if (not cve_object.public) and (not UserSafe.is_admin(request.user)): @@ -594,7 +621,7 @@ def cve(request, cve_pk, active_tab="1"): writeCveDetails(cve_object.name,request) # show the results - return redirect(cve, cve_object.id, "Local") + return redirect(cve, cve_object.id, "Summary") def cve_edit(request, cve_pk): _log("CVE_EDIT1(%s):" % cve_pk) @@ -677,12 +704,14 @@ def vulnerability(request, vulnerability_pk): _log("EXPORT_POST:'fileupload' does not exist: %s" % e) try: - with open(path + "/" + file.name, 'xb+') as destination: + local_file_path = path + "/" + file.name + with open(local_file_path, 'xb+') as destination: for line in file: destination.write(line) username = UserSafe.user_name(request.user) - VulnerabilityUploads.objects.get_or_create(vulnerability_id=vulnerability_object.id, description=description, path=path + "/" + file.name, size=file.size, date=datetime.today().strftime('%Y-%m-%d'), author=username) + VulnerabilityUploads.objects.get_or_create(vulnerability_id=vulnerability_object.id, description=description, path=local_file_path, size=file.size, date=datetime.today().strftime('%Y-%m-%d'), author=username) + VulnerabilityHistory.objects.create(vulnerability_id=vulnerability_object.id, comment=Update.ATTACH_DOC % file.name, date=datetime.now().strftime(SRTool.DATE_FORMAT), author=username) except Exception as e: _log("EXPORT_POST:FILE ALREADY EXISTS: %s" % e) return redirect(vulnerability,vulnerability_pk) @@ -722,16 +751,32 @@ def investigation(request, investigation_pk): except: return redirect(landing) + ### TO-DO: replace with dynamic lookahead instead of static huge list defects = Defect.objects.all() + + # Calculate the default 'affected_components' list, if any + affected_components = '' + affected_components_list = [] + vulnerability = investigation_object.vulnerability + vc_list = vulnerability.vulnerability_to_cve.all() + for vc in vc_list: + if vc.cve.packages: + affected_components_list.append(vc.cve.packages) + if affected_components_list: + affected_components = ' '.join(affected_components_list) + + # Pass Investigation's defect list investigation_to_defect = investigation_object.investigation_to_defect.all() context = { 'object' : investigation_object, 'defects' : defects, 'investigation_to_defect' : investigation_to_defect, + 'affected_components' : affected_components, 'defect_example' : SrtSetting.objects.get(name='SRTOOL_DEFECT_SAMPLENAME').value, 'notify_categories' : NotifyCategories.objects.all(), 'users' : UserSafe.get_safe_userlist(True), 'components' : Defect.Components, + 'found_version' : investigation_object.product.get_defect_tag('found_version'), } return render(request, template, context) elif request.method == "POST": @@ -757,11 +802,13 @@ def investigation(request, investigation_pk): _log("EXPORT_POST:'fileupload' does not exist: %s" % e) try: - with open(path + "/" + file.name, 'xb+') as destination: + local_file_path = path + "/" + file.name + with open(local_file_path, 'xb+') as destination: for line in file: destination.write(line) username = UserSafe.user_name(request.user) - InvestigationUploads.objects.get_or_create(investigation_id=investigation_object.id, description=description, path=path + "/" + file.name, size=file.size, date=datetime.today().strftime('%Y-%m-%d'), author=username) + InvestigationUploads.objects.get_or_create(investigation_id=investigation_object.id, description=description, path=local_file_path, size=file.size, date=datetime.today().strftime('%Y-%m-%d'), author=username) + InvestigationHistory.objects.create(investigation_id=investigation_object.id, comment=Update.ATTACH_DOC % file.name, date=datetime.now().strftime(SRTool.DATE_FORMAT), author=username) except Exception as e: _log("EXPORT_POST:FILE ALREADY EXISTS: %s" % e) return redirect(investigation,investigation_pk) @@ -797,6 +844,7 @@ def defect(request, defect_pk): context = { 'object' : defect_object, 'users' : users, + 'SRTOOL_DEFECT_URLBASE' : SrtSetting.objects.get(name='SRTOOL_DEFECT_URLBASE').value } return render(request, template, context) @@ -876,6 +924,7 @@ def users(request): return render(request, template, context) def report(request,page_name): + _log("REPORT!:%s" % (request)) if request.method == "GET": context = ReportManager.get_context_data(page_name,request=request) record_list = request.GET.get('record_list', '') @@ -883,7 +932,7 @@ def report(request,page_name): context['record_list'] = record_list return render(request, 'report.html', context) elif request.method == "POST": - _log("EXPORT_POST!:%s|%s" % (request,request.FILES)) + _log("EXPORT_POST!:%s" % (request)) parent_page = request.POST.get('parent_page', '') file_name,response_file_name = ReportManager.exec_report(parent_page,request=request) @@ -926,13 +975,153 @@ def create_vulnerability(request): context = {} return render(request, 'create_vulnerability.html', context) +class Snap(): + def __init__(self,snap_index=0,snap_mode='None',snap_dir='',snap_date='',snap_time='',snap_day=''): + self.index = '%02d' % snap_index + self.mode = snap_mode + self.dir = snap_dir + self.date = snap_date + self.time = snap_time + self.day = snap_day + +class ReportFile(): + def __init__(self,name='',size=0,date=None): + self.name = name + self.size = size + self.date = date + def publish(request): # does this user have permission to see this record? if not UserSafe.is_creator(request.user): return redirect(landing) + if request.method == "GET": + + # Prepare available snapshots + snapshot_list = [] + snap_start_index = 0 + snap_stop_index = 0 + snap_date_base = SrtSetting.get_setting('publish_snap_date_base','2019-06-08') + snap_date_top = SrtSetting.get_setting('publish_snap_date_top','2019-06-16') + snap_date_start = SrtSetting.get_setting('publish_snap_date_start','2019-06-08') + snap_date_stop = SrtSetting.get_setting('publish_snap_date_stop','2019-06-16') + snap_last_calc = SrtSetting.get_setting('publish_snap_last_calc','') + backup_returncode,backup_stdout,backup_result = execute_process('bin/common/srtool_backup.py','--list-backups-db') + for i,line in enumerate(backup_stdout.decode("utf-8").splitlines()): + # Week|backup_2019_19|2019-05-18|12:51:51|Saturday, May 18 2019 + backup_mode,backup_dir,backup_date,backup_time,backup_day = line.split('|') + if 'Now' != backup_mode: + snap = Snap(i,backup_mode,backup_dir,backup_date,backup_time,backup_day) + snapshot_list.append(snap) + if snap_date_base == snap.date: + snap_start_index = i + if snap_date_start < snap.date: + snap_date_start = snap.date + if snap_date_stop < snap.date: + snap_date_stop = snap.date + if snap_date_top == snap.date: + snap_stop_index = i + if snap_date_stop > snap.date: + snap_date_stop = snap.date + if not snap_stop_index: + snap_stop_index = i + if snap_date_stop < snap.date: + snap_date_stop = snap.date + # Report automation + snap_frequency_select = SrtSetting.get_setting('publish_snap_frequency','Off') + snapshot_frequency_list = [ + 'Off', + 'Monthly', + 'Bi-monthly', + 'Weekly', + 'Daily', + ] + # List of available reports + generated_report_list = [] + for entry in os.scandir('data/wr'): + if entry.name.startswith('cve-svns-srtool'): + generated_report_list.append(ReportFile(entry.name,entry.stat().st_size,datetime.fromtimestamp(entry.stat().st_mtime))) +# generated_report_list.sort() + generated_report_list = sorted(generated_report_list,key=lambda x: x.name) + + # Prepare History data + last_calc = SrtSetting.get_setting('publish_last_calc','06/08/2019') + date_start = SrtSetting.get_setting('publish_date_start','06/08/2019') + date_stop = SrtSetting.get_setting('publish_date_stop','06/21/2019') + + context = { + 'date_start' : date_start, + 'date_stop' : date_stop, + 'last_calc' : last_calc, + + 'snap_date_start' : snap_date_start, + 'snap_date_stop' : snap_date_stop, + 'snap_date_base' : snap_date_base, + 'snap_date_top' : snap_date_top, + 'snapshot_list' : snapshot_list, + 'snap_start_index' : '%02d' % snap_start_index, + 'snap_stop_index' : '%02d' % snap_stop_index, + 'snap_last_calc' : snap_last_calc, + 'generated_report_list' : generated_report_list, + + 'snapshot_frequency_list' : snapshot_frequency_list, + 'snap_frequency_select' : snap_frequency_select, + } + return render(request, 'publish.html', context) + elif request.method == "POST": + action = request.POST['action'] + + if request.POST["action"] == "download": + report_name = request.POST['report_name'] + file_path = 'data/wr/%s' % report_name + if file_path: + fsock = open(file_path, "rb") + content_type = MimeTypeFinder.get_mimetype(file_path) + response = HttpResponse(fsock, content_type = content_type) + disposition = 'attachment; filename="{}"'.format(file_path) + response['Content-Disposition'] = 'attachment; filename="{}"'.format(file_path) + _log("EXPORT_POST_Q{%s} %s || %s " % (response, response['Content-Disposition'], disposition)) + return response + else: + return render(request, "unavailable_artifact.html", context={}) + + # Dates (make as no timezone) + msg = '' + try: + msg = 'Start:%s' % request.POST.get('date_start', '') + date_start = datetime.strptime(request.POST.get('date_start', ''), '%m/%d/%Y') + msg = 'Stop:%s' % request.POST.get('date_stop', '') + date_stop = datetime.strptime(request.POST.get('date_stop', ''), '%m/%d/%Y') + if date_stop < date_start: +# return 'Error:stop date is before start date' + _log('Error:stop date is before start date') + pass + except Exception as e: +# return 'Error:bad format for dates (must be mm/dd/yyyy) (%s)(%s)' % (msg,e),'' + _log('Error:bad format for dates (must be mm/dd/yyyy) (%s)(%s)' % (msg,e)) + pass + SrtSetting.set_setting('publish_date_start',date_start.strftime('%m/%d/%Y')) + SrtSetting.set_setting('publish_date_stop',date_stop.strftime('%m/%d/%Y')) + if 'recalculate' == action: + # Calculate + publishCalculate(date_start,date_stop) + return redirect('publish') + if 'view' == action: + # Go to publish list page + return redirect('publish-list') + if 'add-cve' == action: + # Go to publish list page + return redirect('publish-cve') + if 'add-defect' == action: + # Go to publish list page + return redirect('publish-defect') + if 'reset' == action: + publishReset(date_start,date_stop) + publishCalculate(date_start,date_stop) + return redirect('publish') + if 'export' == action: + return redirect('/wr/report/publish') + return redirect('publish') - context = {} - return render(request, 'publish.html', context) def manage_report(request): # does this user have permission to see this record? @@ -952,31 +1141,66 @@ def guided_tour(request): def quicklink(request): return redirect("/srtgui/select-publish") -def _create_defect(investigation,defect_reason,components): - _log("SRT_DEFECT=%s|%s|%s|" % (investigation.name,defect_reason,components)) +# Return defect_name,isCreated +def _create_defect(investigation,reason,defect_reason,domain_components,affected_components,username): + _log("SRT_DEFECT=%s|%s|%s|%s|" % (investigation.name,defect_reason,domain_components,affected_components)) + + # Check to see if defect creation is allowed for this product + if 'no' == investigation.product.get_defect_tag('auto_create','yes'): + _log("SRT_DEFECT_SKIPPED:NO_auto_create:%s" % (investigation.product.defect_tags)) + return '(%s skipped)' % investigation.product.key,False + + # Check to see if a defect already is created for this investigation + try: + for id in InvestigationToDefect.objects.filter(investigation=investigation): + # First defect wins + _log("SRT_DEFECT_EXISTING:%s" % (id.defect.name)) + return id.defect.name, False + except: + pass vulnerability = investigation.vulnerability vc_list = vulnerability.vulnerability_to_cve.all() - # gather name(s) and link(s) of parent CVE(s) + # Gather name(s) and link(s) of parent CVE(s) cve_list = [vc.cve.name for vc in vc_list] cves = ','.join(cve_list) + + # Offer a default defect description description = ['%s\n' % vc.cve.description for vc in vc_list] + ### TODO: normal NIST link might not always work - link_list = ['https://nvd.nist.gov/vuln/detail/%s' % vc.cve.name for vc in vc_list] - links = ','.join(cve_list) + link_list = [] + for vc in vc_list: + link_list.append('https://nvd.nist.gov/vuln/detail/%s' % vc.cve.name) + + # Fix links to make if Jira friendly + # CREATE(Triage): {Link=https://nvd.nist.gov/vuln/detail/CVE-2019-8934 User=admin} +# links = "%s {%sLink=%s User=%s}" % (Update.CREATE_STR % Update.SOURCE_TRIAGE,"Reason='%s' " % reason if reason else '',' '.join(link_list),username) + # CREATE(Triage):(User=admin) [CVE-2019-8934|https://nvd.nist.gov/vuln/detail/CVE-2019-8934] + links = "%s%s(User=%s)" % (Update.CREATE_STR % Update.SOURCE_TRIAGE,"(Reason='%s')" % reason if reason else '',username) + for link in link_list: + links += ' [%s|%s]' % (os.path.basename(link),link) # Assign the defect the same priority as the Investigation priority = investigation.get_priority_text + _log("_create_defect:%s:%s:%s" % (investigation.name,priority,links)) - # Component string (e.g. 'kernel', 'userspace', ...) - if not components: - components = 'unknown' - # Offer a defect summary + # Offer a default defect summary + if not defect_reason: + defect_reason = affected_components if defect_reason: summary = "Security Advisory - %s - %s" % (defect_reason,cves) else: summary = "Security Advisory %s" % (cves) + + # Add the affect components + if affected_components: + affected_components.replace(',',' ').replace(';',' ').replace(' ',' ') + components = "%s {COMPONENTS:%s}" % (domain_components,affected_components) + else: + components = domain_components + defect_tool = SrtSetting.objects.get(name='SRTOOL_DEFECT_TOOL').value result_returncode,result_stdout,result_stderr = execute_process( defect_tool, '--new', @@ -1019,6 +1243,11 @@ def _create_defect(investigation,defect_reason,components): d = Defect.objects.create(name=d_name) d.summary = summary d.priority = investigation.priority + d.status = Defect.DEFECT_STATUS_OPEN + d.resolution = Defect.DEFECT_UNRESOLVED + d.srt_priority = investigation.priority + d.srt_status = Defect.VULNERABLE + d.srt_outcome = Defect.OPEN d.product = investigation.product d.url = d_url d.save() @@ -1026,7 +1255,24 @@ def _create_defect(investigation,defect_reason,components): # Create Investigation to Defect id = InvestigationToDefect.objects.create(investigation=investigation,defect=d,product=investigation.product) id.save() - return d.name + return d.name,True + +def _auto_map_cve_priority(cve,force=True): + if not force and (SRTool.UNDEFINED != cve.priority): + return(cve.priority) + severity = cve.cvssV3_baseSeverity.strip() + if not severity: + severity = cve.cvssV2_severity.strip() + if not severity: + severity = 'MEDIUM' + if 'CRITICAL' == severity: + return(SRTool.CRITICAL) + elif 'HIGH' == severity: + return(SRTool.HIGH) + elif 'MEDIUM' == severity: + return(SRTool.MEDIUM) + else: + return(SRTool.LOW) def xhr_triage_commit(request): _log("xhr_triage_commit(%s)" % request.POST) @@ -1035,7 +1281,8 @@ def xhr_triage_commit(request): try: username = UserSafe.user_name(request.user) action = request.POST['action'] - today = datetime.today().strftime("%Y-%m-%d") + srtool_today_time = datetime.today() + srtool_today = datetime.today().strftime("%Y-%m-%d") if 'submit-notvulnerable' == action: reason = request.POST['reason'] cves = request.POST['cves'] @@ -1044,85 +1291,83 @@ def xhr_triage_commit(request): created_list = '' for cve_name in cves.split(','): cve = Cve.objects.get(name=cve_name) + history_update = [] + history_update.append(Update.STATUS % (SRTool.status_text(cve.status),SRTool.status_text(Cve.NOT_VULNERABLE))) + cve.priority = _auto_map_cve_priority(cve,False) cve.status = Cve.NOT_VULNERABLE if cve.comments: cve.comments += ', ' + reason else: cve.comments = reason + cve.acknowledge_date = srtool_today_time cve.save() created_list += ' %s' % cve_name # add audit comment cc = CveHistory.objects.create(cve=cve) - cc.date = today - cc.comment = "ACTION: marked not vulnerable, reason='%s'" % (reason) + cc.date = srtool_today + cc.comment = "%s%s {%s}" % (Update.UPDATE_STR % Update.SOURCE_USER,';'.join(history_update),"Set by triage, reason='%s'" % reason) cc.author = username cc.save() if created_list: created_list = "NotVulnerable:" + created_list - if 'submit-investigate' == action: - cves = request.POST['cves'] - created_list = '' - for cve_name in cves.split(','): - cve = Cve.objects.get(name=cve_name) - cve.status = Cve.INVESTIGATE - cve.save() - created_list += ' %s' % cve_name - # add audit comment - cc = CveHistory.objects.create(cve=cve) - cc.date = today - cc.comment = "ACTION: marked investigate" - cc.author = username - cc.save() - if created_list: - created_list = "Investigate:" + created_list - if 'submit-other' == action: cves = request.POST['cves'] status = int(request.POST['status']) created_list = '' for cve_name in cves.split(','): cve = Cve.objects.get(name=cve_name) + history_update = [] + history_update.append(Update.STATUS % (SRTool.status_text(cve.status),SRTool.status_text(status))) + cve.priority = _auto_map_cve_priority(cve,False) cve.status = status + cve.acknowledge_date = srtool_today_time cve.save() created_list += ' %s' % cve_name # add audit comment cc = CveHistory.objects.create(cve=cve) - cc.date = today - cc.comment = "ACTION: set status to %s" % cve.get_status_text + cc.date = srtool_today + cc.comment = "%s%s {%s}" % (Update.UPDATE_STR % Update.SOURCE_USER,';'.join(history_update),"Set by triage") cc.author = username cc.save() if created_list: created_list = "Status=%s:%s" % (cve.get_status_text,created_list) - if 'submit-isvulnerable' == action: + if action in ('submit-isvulnerable','submit-investigate'): + if 'submit-isvulnerable' == action: + notify_message = 'Triage:Vulnerable:' + new_status = SRTool.VULNERABLE + elif 'submit-investigate' == action: + notify_message = 'Triage:Investigate:' + new_status = SRTool.INVESTIGATE reason = request.POST['reason'].strip() defect_reason = request.POST['defect_reason'].strip() cves = request.POST['cves'] products = request.POST['products'] components = request.POST['components'] - priority = request.POST['priority'] + affected_components = request.POST['affected_components'].strip() + priority = int(request.POST['priority']) make_defects = ('yes' == request.POST['mk_d']) mark_publish = ('yes' == request.POST['pub']) group_vulnerability = int(request.POST['vul_group']) group_vulnerability_name = request.POST['vul_name'].strip() notifications = ('yes' == request.POST['notify']) + acknowledge_date = request.POST['acknowledge_date'] add_for = request.POST['for'] _log("xhr_triage_commit:IS:%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|" % (reason,defect_reason,cves,products,components,make_defects,mark_publish,add_for,priority,group_vulnerability,group_vulnerability_name)) # Set up - investigation_names = {} created_list = '' - notify_message = 'Triage:Vulnerable:' + # Map vulnerability grouping - v = None + vulnerability = None if 2 == group_vulnerability: # Existing V all C first_vulnerability = False group_vulnerabilities = True try: - v = Vulnerability.objects.get(name=group_vulnerability_name) - created_list += ' %s(found)' % v.name - notify_message += ' Found:%s' % v.name + vulnerability = Vulnerability.objects.get(name=group_vulnerability_name) + created_list += ' %s(found)' % vulnerability.name + notify_message += ' Found:%s' % vulnerability.name except Exception as e: _log("xhr_triage_commit:No such Vulnerability name found (%s,%s)" % (group_vulnerability_name,e)) return HttpResponse(json.dumps({"error":"No such Vulnerability name found (%s)" % (group_vulnerability_name)}), content_type = "application/json") @@ -1134,91 +1379,159 @@ def xhr_triage_commit(request): # One V per C first_vulnerability = True group_vulnerabilities = False + # Process the CVE list for cve_name in cves.split(','): # update CVE cve = Cve.objects.get(name=cve_name) - cve.status = Cve.VULNERABLE - cve.priority = priority + # Auto priority? + cve_priority = _auto_map_cve_priority(cve) if 99 == priority else priority if cve.comments: - cve.comments += ', ' + reason + cve_comments = '%s, %s' % (cve.comments,reason) else: - cve.comments = reason + cve_comments = reason + # Acknowledge date selection + try: + if ('publish' == acknowledge_date) and cve.publishedDate: + cve_acknowledge_date = datetime.strptime(cve.publishedDate, '%Y-%m-%d') + elif ('update' == acknowledge_date) and cve.lastModifiedDate: + cve_acknowledge_date = datetime.strptime(cve.lastModifiedDate, '%Y-%m-%d') + elif ('no_change' == acknowledge_date): + cve_acknowledge_date = cve.acknowledge_date + else: + cve_acknowledge_date = srtool_today_time + except: + cve_acknowledge_date = srtool_today_time + # Update history changes + history_update = [] + if cve.status != new_status: + history_update.append(Update.STATUS % (SRTool.status_text(cve.status),SRTool.status_text(new_status))) + if cve.priority != cve_priority: + history_update.append(Update.PRIORITY % (SRTool.priority_text(cve.priority),SRTool.priority_text(cve_priority))) + if cve.acknowledge_date != cve_acknowledge_date: + history_update.append(Update.ACKNOWLEDGE_DATE % (cve.acknowledge_date.strftime("%Y/%m/%d") if cve.acknowledge_date else '',cve_acknowledge_date.strftime("%Y/%m/%d"))) + # Update record + cve.status = new_status + cve.priority = cve_priority + cve.comments = cve_comments + cve.acknowledge_date = cve_acknowledge_date + cve.packages = affected_components cve.save() notify_message += " %s" % cve_name - # create vulnerability + # Add history comment + if history_update: + cc = CveHistory.objects.create(cve=cve) + cc.date = srtool_today + cc.comment = "%s%s {%s}" % (Update.UPDATE_STR % Update.SOURCE_USER,';'.join(history_update), "Triage:reason='%s'" % reason) + cc.author = username + cc.save() + + # Find or create vulnerability if first_vulnerability or not group_vulnerabilities: first_vulnerability = False - v_name = Vulnerability.new_vulnerability_name() - v = Vulnerability.objects.create(name=v_name) - v.public = True - v.status = Vulnerability.VULNERABLE - v.priority = priority - v.comments = reason - v.save() - notify_message += " %s" % v_name - created_list += ' %s' % v.name - _log("Create First Vulnerability:%s" % v.name) - # add audit comment - cc = CveHistory.objects.create(cve=cve) - cc.date = today - cc.comment = "ACTION: created vulnerability '%s', reason='%s'" % (v.name,reason) - cc.author = username - cc.save() + + # Check to see if a vulnerability already is created for this cve + vulnerability = None + try: + for cv in CveToVulnerablility.objects.filter(cve=cve): + # First vulnerability wins + vulnerability = cv.vulnerability + created_list += ' (%s)' % vulnerability.name + break + except: + pass + + if not vulnerability: + v_name = Vulnerability.new_vulnerability_name() + vulnerability = Vulnerability.objects.create(name=v_name) + vulnerability.public = True + vulnerability.priority = cve_priority + vulnerability.status = new_status + vulnerability.outcome = Vulnerability.OPEN + vulnerability.comments = reason + vulnerability.save() + notify_message += " %s" % v_name + created_list += ' %s' % vulnerability.name + _log("Create First Vulnerability:%s" % vulnerability.name) + + # add audit comment + vh = VulnerabilityHistory.objects.create(vulnerability=vulnerability) + vh.date = srtool_today + vh.comment = "%s {%s}" % (Update.CREATE_STR % Update.SOURCE_TRIAGE,'Created from triage') + vh.author = username + vh.save() # map vulnerability to CVE - cv = CveToVulnerablility.objects.create(vulnerability=v,cve=cve) - cv.save() - # add audit comment - vc = VulnerabilityHistory.objects.create(vulnerability=v) - vc.date = today - vc.comment = "ACTION: created vulnerability for '%s', reason='%s'" % (cve.name,reason) - vc.author = username - vc.save() + cv,created = CveToVulnerablility.objects.get_or_create(vulnerability=vulnerability,cve=cve) + if created: + cv.save() if products: for product_id in products.split(','): # fetch product - p = Product.objects.get(pk=product_id) + product = Product.objects.get(pk=product_id) # create (or group) investigation - investigation_key = "%s-%s" % (v_name,product_id) - i_name = '' - if investigation_key in investigation_names: - i_name = investigation_names[investigation_key] - if not i_name or not group_vulnerabilities: + + # Check to see if a investigation for this product already is created for this vulnerability + investigation = None + try: + for vi in VulnerabilityToInvestigation.objects.filter(vulnerability=vulnerability,investigation__product=product): + # First Investigation for this product wins + investigation = vi.investigation + created_list += ' (%s)' % investigation.name + break + except: + pass + + if not investigation: i_name = Investigation.new_investigation_name() - i = Investigation.objects.create(name=i_name) - i.vulnerability = v - i.product = p - i.priority = priority - i.save() - notify_message += " %s" % i_name - created_list += ' %s' % i.name - investigation_names[investigation_key] = i_name + investigation = Investigation.objects.create(name=i_name) + investigation.vulnerability = vulnerability + investigation.product = product + investigation.priority = cve_priority + investigation.outcome = Investigation.OPEN + # Check to see if product is active + _log("BOO1:") + if 'no' == product.get_product_tag('active','yes'): + _log("BOO2:%s,%s" % (investigation.status,SRTool.status_to_inactive(new_status))) + investigation.status = SRTool.status_to_inactive(new_status) + else: + _log("BOO3:") + investigation.status = new_status + _log("BOO4:%s" % investigation.status ) + + investigation.save() + + notify_message += " %s" % investigation.name + created_list += ' %s' % investigation.name # map vulnerability to investigation/product - vi = VulnerabilityToInvestigation.objects.create(vulnerability=v,investigation = i) + vi = VulnerabilityToInvestigation.objects.create(vulnerability=vulnerability,investigation=investigation) vi.save() - else: - i = Investigation.objects.get(name=i_name) - # add audit comment - ic = InvestigationHistory.objects.create(investigation=i) - ic.date = today - ic.comment = "ACTION: created investigation for '%s', reason='%s'" % (cve.name,reason) - ic.author = username - ic.save() + + # add audit comment + ih = InvestigationHistory.objects.create(investigation=investigation) + ih.date = srtool_today + ih.comment = "%s {%s}" % (Update.CREATE_STR % Update.SOURCE_TRIAGE,'Created from triage') + ih.author = username + ih.save() + # create defects if make_defects: - defect_name = _create_defect(i,defect_reason,components) - notify_message += " %s" % defect_name - created_list += ' %s' % defect_name - _log("NEW_DEFECT:%s|%s|%s|" % (defect_name,components,priority)) + defect_name,created = _create_defect(investigation,reason,defect_reason,components,affected_components,username) + if created: + notify_message += ' %s' % defect_name + created_list += ' %s' % defect_name + else: + notify_message += ' (%s)' % defect_name + created_list += ' (%s)' % defect_name + _log("NEW_DEFECT:%s|%s|%s|" % (defect_name,components,cve_priority)) # Finish up if notifications: # Create the notify record _log("xhr_notifications3") notify = Notify() notify.category = 'TRIAGE' - notify.priority = priority + notify.priority = cve_priority notify.description = notify_message notify.url = '' notify.author = username @@ -1280,35 +1593,64 @@ def xhr_cve_commit(request): try: cve = Cve.objects.get(id=request.POST['cve_id']) action = request.POST['action'] - history_comment = '' + history_update = [] new_name = '' if 'submit-quickedit' == action: - note = request.POST['note'] priority = int(request.POST['priority']) status = int(request.POST['status']) - private_note = request.POST['private_note'] - publish_state = request.POST['publish_state'] - publish_date = request.POST['publish_date'] - if (priority != cve.priority): + note = request.POST['note'].strip() + private_note = request.POST['private_note'].strip() + tags = request.POST['tags'].strip() + publish_state = int(request.POST['publish_state']) + publish_date = request.POST['publish_date'].strip() + acknowledge_date = request.POST['acknowledge_date'].strip() + affected_components = request.POST['affected_components'].strip() + # Convert simple date back to datetime + try: + if not acknowledge_date: + acknowledge_date = None + else: + acknowledge_date = datetime.strptime(acknowledge_date, '%Y-%m-%d') + except Exception as e: + acknowledge_date = cve.acknowledge_date + if (cve.priority != priority): + history_update.append(Update.PRIORITY % (SRTool.priority_text(cve.priority),SRTool.priority_text(priority))) cve.priority = priority - history_comment += "Priority, " - if (status != cve.status): + if (cve.status != status): + history_update.append(Update.STATUS % (SRTool.status_text(cve.status),SRTool.status_text(status))) cve.status = status - history_comment += "Status, " - if (note != cve.comments): + if (cve.comments != note): + history_update.append(Update.NOTE) cve.comments = note - history_comment += "Note, " - if (private_note != cve.comments_private): + if (cve.comments_private != private_note): + history_update.append(Update.PRIVATE_NOTE) cve.comments_private = private_note - history_comment += "Private Note, " - if (publish_state != cve.publish_state): + if ( cve.tags !=tags): + history_update.append(Update.TAG) + cve.tags = tags + if (cve.publish_state != publish_state): + history_update.append(Update.PUBLISH_STATE % (SRTool.publish_text(cve.publish_state),SRTool.publish_text(publish_state))) cve.publish_state = publish_state - history_comment += "Publish State, " - if (publish_date != cve.publish_date): + if (cve.publish_date != publish_date): + history_update.append(Update.PUBLISH_DATE % (SRTool.date_ymd_text(cve.publish_date),SRTool.date_ymd_text(publish_date))) cve.publish_date = publish_date - history_comment += "Publish Date, " + if (cve.packages != affected_components): + history_update.append(Update.AFFECTED_COMPONENT % (cve.packages,affected_components)) + cve.packages = affected_components + # Allow for either acknowledge_date to be empty/None + if (cve.acknowledge_date and not acknowledge_date): + history_update.append(Update.ACKNOWLEDGE_DATE % (SRTool.date_ymd_text(cve.acknowledge_date),'')) + cve.acknowledge_date = None + elif (not cve.acknowledge_date and acknowledge_date): + cve.acknowledge_date = acknowledge_date + history_update.append(Update.ACKNOWLEDGE_DATE % (cve.acknowledge_date,SRTool.date_ymd_text(acknowledge_date))) + elif (cve.acknowledge_date != acknowledge_date): + history_update.append(Update.ACKNOWLEDGE_DATE % (SRTool.date_ymd_text(cve.acknowledge_date),SRTool.date_ymd_text(acknowledge_date))) + cve.acknowledge_date = acknowledge_date + cve.save() if 'submit-notification' == action: + # Note: no history update _submit_notification(request) if 'submit-newname' == action: old_name = request.POST['old_name'] @@ -1319,6 +1661,7 @@ def xhr_cve_commit(request): return HttpResponse(json.dumps({"error":"name '%s' is already used\n" % new_name}), content_type = "application/json") except: _log("NewName3:%s -> %s" % (old_name,new_name)) + history_update.append(Update.NEW_NAME % (old_name,new_name)) # Apply this unique name to CVE cve.name = new_name cve.name_sort = get_name_sort(new_name) @@ -1337,6 +1680,7 @@ def xhr_cve_commit(request): priority = cve.priority, ) vulnerability.save() + history_update.append(Update.ATTACH_INV % (vname)) cve2vul = CveToVulnerablility.objects.create(cve = cve,vulnerability = vulnerability) cve2vul.save() _log("SUBMIT-CREATE-VULNERABILITY:%s,%s,%s" % (cve.id,vulnerability.id,cve2vul.id)) @@ -1348,9 +1692,16 @@ def xhr_cve_commit(request): except Exception as e: _log("xhr_triage_commit:No such Vulnerability name found (%s,%s)" % (vname,e)) return HttpResponse(json.dumps({"error":"No such Vulnerability name found (%s)" % (vname)}), content_type = "application/json") + history_update.append(Update.ATTACH_INV % (vname)) cve2vul = CveToVulnerablility.objects.create(cve = cve,vulnerability = vulnerability) cve2vul.save() _log("SUBMIT-CREATE-VULNERABILITY:%s,%s,%s" % (cve.id,vulnerability.id,cve2vul.id)) + if 'submit-delete-cve' == action: + _log("SUBMIT-DELETE-CVE(%s)" % cve.name) + #history_update.append(Update.ATTACH_INV % (vname)) + cve.delete() + _log("SUBMIT-DELETED-CVE(%s)!" % cve.name) + new_name = 'url:/srtgui/cves' return_data = { "error": "ok", @@ -1358,10 +1709,9 @@ def xhr_cve_commit(request): } username = UserSafe.user_name(request.user) - if (history_comment != ''): - history_comment = history_comment[:-2] - history_comment += " edited" - CveHistory.objects.create(cve_id=cve.id, comment=history_comment, date=datetime.now().strftime('%Y-%m-%d'), author=username) + if history_update: + update_comment = "%s%s" % (Update.UPDATE_STR % Update.SOURCE_USER,';'.join(history_update)) + CveHistory.objects.create(cve_id=cve.id, comment=update_comment, date=datetime.now().strftime('%Y-%m-%d'), author=username) _log("xhr_cve_commit:SUCCESS") return HttpResponse(json.dumps( return_data ), content_type = "application/json") @@ -1416,34 +1766,38 @@ def xhr_vulnerability_commit(request): action = request.POST['action'] v_id = request.POST['vulnerability_id'] username = UserSafe.user_name(request.user) - history_comment = '' try: + history_update = [] if 'submit-quickedit' == action: - note = request.POST['note'] - private_note = request.POST['private_note'] + note = request.POST['note'].strip() + private_note = request.POST['private_note'].strip() + tags = request.POST['tags'].strip() + priority = int(request.POST['priority']) + status = int(request.POST['status']) + outcome = int(request.POST['outcome']) v = Vulnerability.objects.get(id=v_id) + if (v.priority != priority): + history_update.append(Update.PRIORITY % (SRTool.priority_text(v.priority),SRTool.priority_text(priority))) + v.priority = priority + if (v.status != status): + history_update.append(Update.STATUS % (SRTool.status_text(v.status),SRTool.status_text(status))) + v.status = status + if (v.outcome != outcome): + history_update.append(Update.OUTCOME % (SRTool.status_text(v.outcome),SRTool.status_text(outcome))) + v.outcome = outcome if (v.comments != note): + history_update.append(Update.NOTE) v.comments = note - history_comment += "Note, " if (v.comments_private != private_note): + history_update.append(Update.PRIVATE_NOTE) v.comments_private = private_note - history_comment += "Private Note, " - if (v.status != request.POST['status']): - v.status = request.POST['status'] - history_comment += "Status, " - if (v.outcome != request.POST['outcome']): - v.outcome = request.POST['outcome'] - history_comment += "Outcome, " - if (v.priority != request.POST['priority']): - v.priority = request.POST['priority'] - history_comment += "Priority, " - if (history_comment != ''): - history_comment = history_comment[:-2] - history_comment += " edited" + if (tags != v.tags): + history_update.append(Update.TAG) + v.tags = tags v.save() if 'submit-addproduct' == action: products = request.POST['products'] - product_names = '' + investigation_names = [] vulnerability_obj = Vulnerability.objects.get(id=v_id) for product_id in products.split(','): product_obj = Product.objects.get(pk=product_id) @@ -1460,72 +1814,70 @@ def xhr_vulnerability_commit(request): ) vul2inv = VulnerabilityToInvestigation.objects.create(vulnerability=vulnerability_obj,investigation=investigation_obj) vul2inv.save() - product_names += "%s " % product_obj.long_name - product_names = product_names[:-2] - history_comment = product_names + " added to affected products" + investigation_names.append(iname) + history_update.append(Update.ATTACH_INV % ','.join(investigation_names)) if 'submit-trashinvestigation' == action: inv_id = request.POST['record_id'] investigation_obj = Investigation.objects.get(pk=inv_id) vul2inv = VulnerabilityToInvestigation.objects.filter(investigation=investigation_obj) vul2inv.delete() - history_comment = investigation_obj.name + " investigation(s) removed" + history_update.append(Update.DETACH_INV % (investigation_obj.name)) investigation_obj.delete() if 'submit-newcomment' == action: comment = request.POST['comment'] VulnerabilityComments.objects.create(vulnerability_id=v_id, comment=comment, date=datetime.today().strftime('%Y-%m-%d'), author=username) - history_comment = "New comment submitted" + #NOTE: No History for this if 'submit-trashcomment' == action: record_id = request.POST['record_id'] comment = VulnerabilityComments.objects.get(id=record_id) - history_comment = "Comment from " + comment.author + " deleted" comment.delete() + #NOTE: No History for this if 'submit-trashattachment' == action: record_id = request.POST['record_id'] upload = VulnerabilityUploads.objects.get(id=record_id) - history_comment = "Upload '" + upload.description + "' from " + upload.author + " deleted" try: os.remove(upload.path) except OSError: pass + history_update.append(Update.DETACH_DOC % (upload.path)) upload.delete() if 'submit-addusernotify' == action: users = request.POST['users'] - usernames = '' + usernames = [] for user_id in users.split(','): - usernames += SrtUser.objects.get(pk=user_id).name + ', ' + usernames.append(SrtUser.objects.get(pk=user_id).name) VulnerabilityNotification.objects.get_or_create(vulnerability_id=v_id, user_id=user_id) - usernames = usernames[:-2] - history_comment = usernames + " added to notifications" + history_update.append(Update.ATTACH_USER_NOTIFY % ','.join(usernames)) if 'submit-trashusernotification' == action: record_id = request.POST['record_id'] notification_record = VulnerabilityNotification.objects.get(id=record_id) removed_user = SrtUser.objects.get(pk=notification_record.user_id).name - history_comment = removed_user + " removed from notifications" notification_record.delete() + history_update.append(Update.DETACH_USER_NOTIFY % removed_user) if 'submit-adduseraccess' == action: users = request.POST['users'] - usernames = '' + usernames = [] for user_id in users.split(','): - usernames += SrtUser.objects.get(pk=user_id).name + ', ' + usernames.append(SrtUser.objects.get(pk=user_id).name) VulnerabilityAccess.objects.get_or_create(vulnerability_id=v_id, user_id=user_id) - usernames = usernames[:-2] - history_comment = usernames + " granted access" + history_update.append(Update.ATTACH_ACCESS % ','.join(usernames)) if 'submit-trashuseraccess' == action: record_id = request.POST['record_id'] access_record = VulnerabilityAccess.objects.get(id=record_id) - removed_user = username - history_comment = removed_user + "'s access removed" access_record.delete() + history_update.append(Update.DETACH_ACCESS % username) if 'submit-notification' == action: _submit_notification(request) + #NOTE: No History for this if 'submit-trashvulnerability' == action: record_id = request.POST['record_id'] vulnerability_obj = Vulnerability.objects.get(pk=record_id) - history_comment = "Vulnerability '%s' is deleted" % vulnerability_obj.name +# history_update.append(Update.DETACH_VUL % vulnerability_obj.name) vulnerability_obj.delete() - if (history_comment != ''): - VulnerabilityHistory.objects.create(vulnerability_id=v_id, comment=history_comment, date=datetime.now().strftime('%Y-%m-%d'), author=username) + if history_update: + update_comment = "%s%s" % (Update.UPDATE_STR % Update.SOURCE_USER,';'.join(history_update)) + VulnerabilityHistory.objects.create(vulnerability_id=v_id, comment=update_comment, date=datetime.now().strftime('%Y-%m-%d'), author=username) return_data = { "error": "ok", } @@ -1644,43 +1996,48 @@ def xhr_investigation_commit(request): action = request.POST['action'] invst_id = request.POST['investigation_id'] username = UserSafe.user_name(request.user) - history_comment = "Nothing happened." try: + history_update = [] if 'submit-quickedit' == action: - note = request.POST['note'] - private_note = request.POST['private_note'] + priority = int(request.POST['priority']) + status = int(request.POST['status']) + outcome = int(request.POST['outcome']) + note = request.POST['note'].strip() + private_note = request.POST['private_note'].strip() + tags = request.POST['tags'].strip() invst = Investigation.objects.get(id=invst_id) + if (invst.priority != priority): + history_update.append(Update.PRIORITY % (SRTool.priority_text(invst.priority),SRTool.priority_text(priority))) + invst.priority = priority + if (invst.status != request.POST['status']): + history_update.append(Update.STATUS % (SRTool.status_text(invst.status),SRTool.status_text(status))) + invst.status = request.POST['status'] + if (invst.outcome != outcome): + history_update.append(Update.OUTCOME % (SRTool.status_text(invst.outcome),SRTool.status_text(outcome))) + invst.outcome = outcome if (invst.comments != note): invst.comments = note - history_comment += "Note, " + history_update.append(Update.NOTE) if (invst.comments_private != private_note): invst.comments_private = private_note - history_comment += "Private Note, " - if (invst.status != request.POST['status']): - invst.status = request.POST['status'] - history_comment += "Status, " - if (invst.outcome != request.POST['outcome']): - invst.outcome = request.POST['outcome'] - history_comment += "Outcome, " - if (invst.priority != request.POST['priority']): - invst.priority = request.POST['priority'] - history_comment += "Priority, " - if (history_comment != ''): - history_comment = history_comment[:-2] - history_comment += " edited" + history_update.append(Update.PRIVATE_NOTE) + if (invst.tags != tags): + invst.tags = tags + history_update.append(Update.TAG) invst.save() if 'submit-attachdefectlist' == action: defects = request.POST['defects'] product_id = Investigation.objects.get(id=invst_id).product_id - defect_names = "" + defect_names = [] for defect_id in defects.split(','): - defect_names += Defect.objects.get(pk=defect_id).name + ", " + defect_names.append(Defect.objects.get(pk=defect_id).name) InvestigationToDefect.objects.get_or_create(investigation_id=invst_id, defect_id=defect_id) - defect_names = defect_names[:-2] - history_comment = defect_names + " added to defects" + history_update.append(Update.ATTACH_DEV % ','.join(defect_names)) if 'submit-attachdefect' == action: query = request.POST['query'].upper() product_id = Investigation.objects.get(id=invst_id).product_id + # Courtesy removal of URL (or other) prefix + query = re.sub(r".*/", "", query) #check if defect already in SRTool data try: defect = Defect.objects.get(name=query) @@ -1697,79 +2054,86 @@ def xhr_investigation_commit(request): defect = Defect.objects.get(name=query) except subprocess.CalledProcessError as e: _log("ERROR:submit-attachdefect:%d:STDOUT='%s':" % (e.returncode, e.output)) - return HttpResponse(json.dumps({"error":str(e) + "\n"}), content_type = "application/json") + error_message = "Could not find defect with the name '%s'\n\n(detail:%s)\n" % (query,str(e)) + return HttpResponse(json.dumps({"error":error_message}), content_type = "application/json") if defect: InvestigationToDefect.objects.get_or_create(investigation_id=invst_id, defect_id=defect.id, product_id=product_id) - history_comment = "Attached " + defect.name + # Enforce minimum status on open defects + if Defect.DEFECT_UNRESOLVED == defect.resolution: + invst = Investigation.objects.get(id=invst_id) + if defect.srt_status < invst.status: + defect.srt_status = invst.status + defect.save() + history_update.append(Update.ATTACH_DEV % defect.name) if 'submit-createdefect' == action: investigation = Investigation.objects.get(id=invst_id) defect_reason = request.POST['defect_reason'] components = request.POST['components'] priority = request.POST['priority'] - defect_name = _create_defect(investigation,defect_reason,components) - history_comment = "New defect '%s' created" % defect_name + affected_components = request.POST['affected_components'].strip() + defect_name,created = _create_defect(investigation,'',defect_reason,components,affected_components,username) + history_update.append(Update.ATTACH_DEV % defect_name) if 'submit-detachdefect' == action: defect_name = request.POST['defect'] product_id = Investigation.objects.get(id=invst_id).product_id defect_id = Defect.objects.get(name=defect_name).id InvestigationToDefect.objects.get(investigation_id=invst_id, defect_id=defect_id).delete() - history_comment = defect_name + " detached from investigation" + history_update.append(Update.DETACH_DEV % defect_name) if 'submit-newcomment' == action: comment = request.POST['comment'] InvestigationComments.objects.create(investigation_id=invst_id, comment=comment, date=datetime.today().strftime('%Y-%m-%d'), author=username) - history_comment = "New comment submitted" + #NOTE: No History for this if 'submit-trashcomment' == action: record_id = request.POST['record_id'] comment = InvestigationComments.objects.get(id=record_id) - history_comment = "Comment from " + comment.author + " deleted" comment.delete() + #NOTE: No History for this if 'submit-trashattachment' == action: record_id = request.POST['record_id'] upload = InvestigationUploads.objects.get(id=record_id) - history_comment = "Upload '" + upload.description + "' from " + upload.author + " deleted" try: os.remove(upload.path) except OSError: pass + history_update.append(Update.DETACH_DOC % (upload.path)) upload.delete() if 'submit-addusernotify' == action: users = request.POST['users'] - usernames = "" + usernames = [] for user_id in users.split(','): - usernames += SrtUser.objects.get(pk=user_id).name + ", " + usernames.append(SrtUser.objects.get(pk=user_id).name) InvestigationNotification.objects.get_or_create(investigation_id=invst_id, user_id=user_id) - usernames = usernames[:-2] - history_comment = usernames + " added to notifications" + history_update.append(Update.ATTACH_USER_NOTIFY % ','.join(usernames)) if 'submit-trashusernotification' == action: record_id = request.POST['record_id'] notification_record = InvestigationNotification.objects.get(id=record_id) removed_user = SrtUser.objects.get(pk=notification_record.user_id).name - history_comment = removed_user + " removed from notifications" + history_update.append(Update.DETACH_USER_NOTIFY % removed_user) notification_record.delete() if 'submit-adduseraccess' == action: users = request.POST['users'] - usernames = "" + usernames = [] for user_id in users.split(','): - usernames += SrtUser.objects.get(pk=user_id).name + ", " + usernames.append(SrtUser.objects.get(pk=user_id).name) InvestigationAccess.objects.get_or_create(investigation_id=invst_id, user_id=user_id) - history_comment = usernames + " granted access" + history_update.append(Update.ATTACH_ACCESS % ','.join(usernames)) if 'submit-trashuseraccess' == action: record_id = request.POST['record_id'] access_record = InvestigationAccess.objects.get(id=record_id) - removed_user = username - history_comment = removed_user + "'s access removed" + history_update.append(Update.DETACH_ACCESS % username) access_record.delete() if 'submit-notification' == action: _submit_notification(request) - history_comment = '' + #NOTE: No History for this if 'submit-trashinvestigation' == action: record_id = request.POST['record_id'] investigation_obj = Investigation.objects.get(pk=record_id) - history_comment = "Investigation '%s' is deleted" % investigation_obj.name +# history_update.append(Update.DETACH_INV % investigation_obj.name) investigation_obj.delete() - if history_comment: - InvestigationHistory.objects.create(investigation_id=invst_id, comment=history_comment, date=datetime.now().strftime('%Y-%m-%d'), author=username) + if history_update: + update_comment = "%s%s" % (Update.UPDATE_STR % Update.SOURCE_USER,';'.join(history_update)) + InvestigationHistory.objects.create(investigation_id=invst_id, comment=update_comment, date=datetime.now().strftime('%Y-%m-%d'), author=username) return_data = { "error": "ok", } @@ -1779,6 +2143,146 @@ def xhr_investigation_commit(request): _log("xhr_investigation_commit:no(%s)" % e) return HttpResponse(json.dumps({"error":str(e) + "\n"}), content_type = "application/json") +def xhr_publish(request): + _log("xhr_publish(%s)" % request.POST) + + def remove_mark(mark,line): + pos1 = line.find(mark) + if -1 == pos1: + return line + pos2 = line.find(')',pos1) + if -1 == pos2: + return line.replace(mark,'') + line = line[0:pos1] + line[pos2+1:] + return line + + if not 'action' in request.POST: + return HttpResponse(json.dumps({"error":"missing action\n"}), content_type = "application/json") + try: + username = UserSafe.user_name(request.user) + action = request.POST['action'] + + if 'export-snapshot' == action: + snap_date_base = request.POST['snap_date_base'] + snap_date_top = request.POST['snap_date_top'] + snap_date_start = request.POST['snap_date_start'] + snap_date_stop = request.POST['snap_date_stop'] + _log("xhr_publish:export-snapshot:%s,%s,%s,%s" % (snap_date_base,snap_date_top,snap_date_start,snap_date_stop)) + + SrtSetting.set_setting('publish_snap_date_base',snap_date_base) + SrtSetting.set_setting('publish_snap_date_top',snap_date_top) + SrtSetting.set_setting('publish_snap_date_start',snap_date_start) + SrtSetting.set_setting('publish_snap_date_stop',snap_date_stop) + + backup_returncode,backup_stdout,backup_result = execute_process('bin/common/srtool_backup.py','--list-backups-db') + base_dir = '' + top_dir = '' + for i,line in enumerate(backup_stdout.decode("utf-8").splitlines()): + # Week|backup_2019_19|2019-05-18|12:51:51|Saturday, May 18 2019 + backup_mode,backup_dir,backup_date,backup_time,backup_day = line.split('|') + if (not base_dir) and (snap_date_base == backup_date): + base_dir = 'backups/%s' % backup_dir + if (not top_dir) and (snap_date_top == backup_date) and ('Now' != backup_mode): + top_dir = 'backups/%s' % backup_dir + + _log('Publish:./bin/wr/srtool_publish.py --srt2update ' + base_dir) + report_returncode,report_stdout,report_error = execute_process('./bin/wr/srtool_publish.py','--srt2update',base_dir) + if 0 != report_returncode: + return_data = {"error": "Error: base dir prep:%s:%s" % (report_error,report_stdout),} + return HttpResponse(json.dumps( return_data ), content_type = "application/json") + _log('Publish:./bin/wr/srtool_publish.py --srt2update ' + top_dir) + report_returncode,report_stdout,report_error = execute_process('./bin/wr/srtool_publish.py','--srt2update',top_dir) + if 0 != report_returncode: + return_data = {"error": "Error: top dir prep:%s:%s" % (report_error,report_stdout),} + return HttpResponse(json.dumps( return_data ), content_type = "application/json") + _log('Publish:./bin/wr/srtool_publish.py --validate-update-svns --previous '+base_dir+' --current '+top_dir+' --start '+snap_date_start+' --stop '+snap_date_stop) + report_returncode,report_stdout,report_error = execute_process('./bin/wr/srtool_publish.py', + '--validate-update-svns','--previous',base_dir,'--current',top_dir, + '--start',snap_date_start,'--stop',snap_date_stop) + if 0 != report_returncode: + return_data = {"error": "Error: publish report:%s:%s" % (report_error,report_stdout),} + return HttpResponse(json.dumps( return_data ), content_type = "application/json") + + publish_snap_last_calc = 'Base:%s, Top:%s, Start:%s, Stop:%s, On:%s' % ( + snap_date_base,snap_date_top,snap_date_start,snap_date_stop, + datetime.today().strftime("%Y-%m-%d %H:%M:%S") + ) + SrtSetting.set_setting('publish_snap_last_calc',publish_snap_last_calc) + + _log('Publish:Done!') + elif 'submit-trashreport' == action: + report_name = request.POST['report_name'] + os.remove('data/wr/%s' % report_name) + else: + srtool_today_time = datetime.today() + srtool_today = datetime.today().strftime("%Y-%m-%d") + reason_map = {} + if 'defects' in request.POST: + cve_table = [] + for defect_name in request.POST['defects'].split(','): + try: + defect = Defect.objects.get(name = defect_name) + cve_names = defect.get_cve_names + for cve_name in cve_names.split(','): + cve_table.append(cve_name) + reason_map[cve_name] = defect_name + except Exception as e: + _log("ERROR:xhr_publish:defectlist:%s" % e) + cve_list = ','.join(cve_table) + else: + cve_list = request.POST['cves'] + for cve_name in cve_list.split(','): + reason_map[cve_name] = '' + _log("xhr_publish_defect2cves3:%s:%d" % (cve_list,len(cve_list))) + + date_start = datetime.strptime(SrtSetting.get_setting('publish_date_start','02/15/2019'), '%m/%d/%Y') + date_stop = datetime.strptime(SrtSetting.get_setting('publish_date_stop','03/15/2019'), '%m/%d/%Y') + # set date_stop to 11:59pm for end of 'incusive' day + date_stop = date_stop.replace(hour=11, minute=59) + if 'mark-new' == action: + for cve_name in cve_list.split(','): + _log("xhr_publish_defect2cvesNEW:%s" % (cve_name)) + cve = Cve.objects.get(name=cve_name) + publish_object,created = PublishSet.objects.get_or_create(cve=cve) + publish_object.state = PublishSet.PUBLISH_SET_NEW_USER + publish_object.reason = remove_mark('Mark_New',publish_object.reason) + publish_object.reason = remove_mark('Mark_Updated',publish_object.reason) + publish_object.reason += ' Mark_New(%s)' % reason_map[cve_name] + publish_object.reason = publish_object.reason.replace(' ',' ').strip() + publish_object.save() + publishMarkNew(cve_list,reason_map,date_start,date_stop) + if 'mark-modified' == action: + for cve_name in cve_list.split(','): + _log("xhr_publish_defect2cvesMOD:%s" % (cve_name)) + cve = Cve.objects.get(name=cve_name) + publish_object,created = PublishSet.objects.get_or_create(cve=cve) + publish_object.state = PublishSet.PUBLISH_SET_MODIFIED_USER + publish_object.reason = remove_mark('Mark_New',publish_object.reason) + publish_object.reason = remove_mark('Mark_Updated',publish_object.reason) + publish_object.reason += ' Mark_Updated(%s)' % reason_map[cve_name] + publish_object.reason = publish_object.reason.replace(' ',' ').strip() + publish_object.save() + publishMarkModified(cve_list,reason_map,date_start,date_stop) + if 'unmark' == action: + for cve_name in cve_list.split(','): + cve = Cve.objects.get(name=cve_name) + publish_object,created = PublishSet.objects.get_or_create(cve=cve) + publish_object.state = PublishSet.PUBLISH_SET_NONE + publish_object.reason = remove_mark('Mark_New',publish_object.reason) + publish_object.reason = remove_mark('Mark_Updated',publish_object.reason) + publish_object.reason = publish_object.reason.replace(' ',' ').strip() + publish_object.save() + publishMarkNone(cve_list,date_start,date_stop) + + return_data = { + "error": "ok", + } + + return HttpResponse(json.dumps( return_data ), content_type = "application/json") + except Exception as e: + _log("xhr_publish:no(%s)(%s)" % (e,traceback.print_stack())) + return HttpResponse(json.dumps({"error":str(e) + "\n"}), content_type = "application/json") + def cve_alternates(request, cve_pk): try: @@ -1795,6 +2299,15 @@ def cve_alternates(request, cve_pk): cve_source_object,created = CveSource.objects.get_or_create(cve=cve_object,datasource=ds) _log("Alternate CVE source %s for %s (created=%s)" % (ds.key,cve_object.name,created)) + # Force update the CVE summary data from sources + result_returncode,result_stdout,result_stderr = execute_process( + './bin/nist/srtool_nist.py', + '--update-cve-list', + cve_object.name, + '--force' + ) + _log("CVE_ALT_REFRESH=%s|%s|%s" % (result_returncode,result_stdout,result_stderr)) + return redirect(cve, cve_pk) |