diff --git a/CHANGELOG.md b/CHANGELOG.md index df3cae0..45b9ca1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # VINCE Changelog +Version 1.50.5: 2022-10-25 +========================== + +Updates to settings_.py to match public GitHub +UI tweaks for Loading div, asynchronous search via delaySearch +Add Access-Control-Origin header to CSAF output for Secvisogram +Fix Python Pickle Code Injection vulnerability CVE-2022-40238 +Address reported failure with better error reporting from Encrypt-and-Send +Avoid TimeZone spurious warning errors flooding logs + Version 1.50.4: 2022-10-05 ========================== diff --git a/bigvince/settings_.py b/bigvince/settings_.py index 4218db3..0c68c5b 100644 --- a/bigvince/settings_.py +++ b/bigvince/settings_.py @@ -56,7 +56,7 @@ ROOT_DIR = environ.Path(__file__) - 3 # any change that requires database migrations is a minor release -VERSION = "1.50.3" +VERSION = "1.50.5" # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/ @@ -206,7 +206,7 @@ LOGGER_HANDLER = 'console' # EMAIL_BACKEND = os.environ.get('EMAIL_BACKEND', 'django.core.mail.backends.console.EmailBackend') EMAIL_BACKEND = os.environ.get('EMAIL_BACKEND', 'django.core.mail.backends.smtp.EmailBackend') - EMAIL_HOST = os.environ.get('EMAIL_HOST', 'smtp.vince.org') + EMAIL_HOST = os.environ.get('EMAIL_HOST', 'smtp.vince.example') EMAIL_PORT = os.environ.get('EMAIL_PORT', 25) #BELOW IS FOR A LOCAL (DEBUG) setup - use the local static directory @@ -493,12 +493,6 @@ def get_secret(secret_arn): # VINCETrack group COGNITO_SUPERUSER_GROUP = os.environ.get('AWS_COGNITO_SUPERUSER_GROUP', COGNITO_ADMIN_GROUP) -# the following 2 vars can be comma separated string if more than 1 group -# anyone in the COGNITO_VINCETRACK_GROUPS will be put in a "vincetrack" local group -COGNITO_VINCETRACK_GROUPS = os.environ.get("AWS_COGNITO_VINCETRACK_GROUPS", default="Coordinator") - -COGNITO_SUPERUSER_GROUP = os.environ.get('AWS_COGNITO_SUPERUSER_GROUP', "ADMIN") - #COGNITO_LIMITED_ACCESS_GROUPS can be used to give special permission to views # in VINCECOMM @@ -565,9 +559,9 @@ def get_secret(secret_arn): } #from emails on auto-notifications -DEFAULT_FROM_EMAIL = os.environ.get('NO_REPLY_EMAIL', "vuls+donotreply@vince.org") +DEFAULT_FROM_EMAIL = os.environ.get('NO_REPLY_EMAIL', "vuls+donotreply@vince.example") #from for emails sent from VINCE -DEFAULT_REPLY_EMAIL = os.environ.get('REPLY_EMAIL', "vuls@vince.org") +DEFAULT_REPLY_EMAIL = os.environ.get('REPLY_EMAIL', "vuls@vince.example") #EMAIL_BUCKET = os.environ.get('S3_EMAIL_BUCKET', 'vince-email') @@ -585,7 +579,7 @@ def get_secret(secret_arn): VINCE_MAX_EMAIL_LENGTH = 300000 -IGNORE_EMAILS_TO = ['vuls+donotreply@vince.org'] +IGNORE_EMAILS_TO = ['vuls+donotreply@vince.example'] LOGLEVEL = os.environ.get('LOGLEVEL', 'info').upper() DJANGO_LOGLEVEL = os.environ.get('DJANGO_LOGLEVEL', 'info').upper() diff --git a/vince/mailer.py b/vince/mailer.py index 74c5346..e245b62 100644 --- a/vince/mailer.py +++ b/vince/mailer.py @@ -654,10 +654,10 @@ def send_templated_mail(template_name, locale = context['queue'].get('locale') or VINCE_EMAIL_FALLBACK_LOCALE else: locale = VINCE_EMAIL_FALLBACK_LOCALE - + context['homepage'] = f"{settings.KB_SERVER_NAME}/vince/comm/dashboard/" - + try: t = EmailTemplate.objects.get(template_name__iexact=template_name, locale=locale) except EmailTemplate.DoesNotExist: @@ -999,10 +999,9 @@ def encrypt_mail(contents, admin_email): logger.debug(encrypted_data.ok) logger.debug(encrypted_data.status) logger.debug(encrypted_data.stderr) - except: - send_sns(traceback.format_exc()) - logger.warning(traceback.format_exc()) - logger.warning("Could not encrypt data") + except Exception as e: + logger.warning("PGP Encryption failed due to error "+str(e)) + send_sns(str(e)) return None return encrypted_data @@ -1020,7 +1019,6 @@ def send_encrypted_mail(to_email, subject, contents, attachment=None): msg.add_header(_name="Content-Type", _value="multipart/mixed", protected_headers="v1") msg["From"] = settings.DEFAULT_REPLY_EMAIL msg["To"] = admin_email.email - #msg["Cc"] = "test@example.org" msg['Subject'] = subject msg_text = Message() @@ -1050,7 +1048,6 @@ def send_encrypted_mail(to_email, subject, contents, attachment=None): pgp_msg = MIMEBase(_maintype="multipart", _subtype="encrypted", protocol="application/pgp-encrypted") pgp_msg["From"] = settings.DEFAULT_REPLY_EMAIL pgp_msg["To"] = admin_email.email - #pgp_msg["Cc"] = "test@example.org" pgp_msg["Subject"] = subject pgp_msg_part1 = Message() @@ -1064,7 +1061,8 @@ def send_encrypted_mail(to_email, subject, contents, attachment=None): pgp_msg_part2.add_header(_name="Content-Disposition", _value="inline", filename="encrypted.asc") try: payload = encrypt_mail(msg.as_string(), admin_email) - except: + except Exception as e: + logger.warning("Encrypting PGP Email failed due to error "+str(e)) return f"Error encrypting data. Check key for {admin_email.email}" if payload == None: diff --git a/vince/models.py b/vince/models.py index 4680e6d..66edf49 100644 --- a/vince/models.py +++ b/vince/models.py @@ -1759,6 +1759,7 @@ def __str__(self): return f"{self.vulnote.vulnote.case.vu_vuid} review by {self.reviewer.usersettings.preferred_username}" else: return f"{self.vulnote.vulnote.case.vu_vuid} review unassigned." + class EmailTemplate(models.Model): """ @@ -3952,6 +3953,9 @@ class UserSettings(models.Model): def _set_settings(self, data): # data should always be a Python dictionary. + if not isinstance(data,dict): + logger.warn("Non dictionary item sent to pickle %s" % str(data)) + data = {} try: import pickle except ImportError: @@ -3965,12 +3969,24 @@ def _get_settings(self): import pickle except ImportError: import cPickle as pickle - - + class RestrictedUnpickler(pickle.Unpickler): + def find_class(self, module, name): + """ If find_class gets called then return error """ + raise pickle.UnpicklingError("global '%s.%s' is forbidden" % + (module, name)) try: from base64 import decodebytes as b64decode - return pickle.loads(b64decode(self.settings_pickled.encode('utf-8'))) - except pickle.UnpicklingError: + if self.settings_pickled: + s = b64decode(self.settings_pickled.encode('utf-8')) + #replacement for pickle.loads() + return RestrictedUnpickler(io.BytesIO(s)).load() + else: + return {} + except (pickle.UnpicklingError, AttributeError) as e: + logger.warn("Error when trying to unpickle data %s " %(str(e))) + return {} + except Exception as e: + logger.warn("Generic error when trying to unpickle data %s " %(str(e))) return {} settings = property(_get_settings, _set_settings) diff --git a/vince/static/vince/js/activity_search.js b/vince/static/vince/js/activity_search.js index 6d11210..9ad9a77 100644 --- a/vince/static/vince/js/activity_search.js +++ b/vince/static/vince/js/activity_search.js @@ -55,28 +55,38 @@ function nextActivity(page) { } -var priorSearchReq = null; +var txhr = null; function searchActivity(e) { if (e) { e.preventDefault(); } - $("#searchresults").html("

LOADING

"); $("#id_page").val("1"); var url = "/vince/activity/results/"; - if(priorSearchReq) { - priorSearchReq.abort(); + if(window.txhr && 'abort' in window.txhr) { + window.txhr.abort(); } - - priorSearchReq = $.ajax({ + lockunlock(true,'div.mainbody,div.vtmainbody','#searchresults'); + txhr = $.ajax({ url: url, type: "POST", data: $('#searchform').serialize(), - success: function(data) { - $("#searchresults").html(data); - } - }); + success: function(data) { + lockunlock(false,'div.mainbody,div.vtmainbody','#searchresults'); + $("#searchresults").html(data); + }, + error: function() { + lockunlock(false,'div.mainbody,div.vtmainbody','#searchresults'); + console.log(arguments); + alert("Search failed or canceled! See console log for details."); + }, + complete: function() { + /* Just safety net */ + lockunlock(false,'div.mainbody,div.vtmainbody','#searchresults'); + window.txhr = null; + } + }); } diff --git a/vince/static/vince/js/allsearch.js b/vince/static/vince/js/allsearch.js index 18d0c17..bfe271f 100644 --- a/vince/static/vince/js/allsearch.js +++ b/vince/static/vince/js/allsearch.js @@ -47,8 +47,6 @@ function nextResults(page) { } - - function searchAll(e) { if (e) { e.preventDefault(); @@ -64,14 +62,26 @@ function searchAll(e) { } var data = $('#searchall').serialize() + "&facet=" + facet; - $.ajax({ + lockunlock(true,'div.mainbody,div.vtmainbody','#searchresults'); + window.txhr = $.ajax({ url: url, type: "GET", data: data, - success: function(data) { - $("#searchresults").html(data); - } - }); + success: function(data) { + lockunlock(false); + $("#searchresults").html(data); + }, + error: function() { + lockunlock(false,'div.mainbody,div.vtmainbody','#searchresults'); + console.log(arguments); + alert("Search failed or canceled! See console log for details."); + }, + complete: function() { + /* Just safety net */ + lockunlock(false,'div.mainbody,div.vtmainbody','#searchresults'); + window.txhr = null; + } + }); } $(document).ready(function() { diff --git a/vince/static/vince/js/case.js b/vince/static/vince/js/case.js index 429ba49..3dc8ce2 100644 --- a/vince/static/vince/js/case.js +++ b/vince/static/vince/js/case.js @@ -82,8 +82,8 @@ function reloadVendorStats(case_id) { -function reloadVendors(case_id, table) { - table.replaceData(); +function reloadVendors(case_id, tablet) { + tablet.replaceData(); /*$.ajax({ url: "/vince/ajax_calls/case/vendors/"+case_id+"/", success: function(data) { @@ -97,7 +97,7 @@ function reloadVuls(case_id, table) { $.ajax({ url: "/vince/ajax_calls/case/vulnerabilities/"+case_id+"/", success: function(data) { - table.replaceData(data) + tablet.replaceData(data) }}); } @@ -121,11 +121,11 @@ function reloadArtifacts(case_id) { }}); } -function reloadParticipants(case_id, table) { +function reloadParticipants(case_id, tablet) { $.ajax({ url: "/vince/ajax_calls/case/participants/"+case_id+"/", success: function(data) { - table.replaceData(data); + tablet.replaceData(data); }}); } @@ -141,38 +141,51 @@ function reload_case_activity() { }); } +var txhr = null; + function searchComms(e) { if (e) { e.preventDefault(); } - $.ajax({ + lockunlock(true,'div.mainbody,div.vtmainbody','#timeline'); + window.txhr = $.ajax({ url: $("#filterform").attr("action"), type: "POST", data: $('#filterform').serialize(), success: function(data) { + lockunlock(false,'div.mainbody,div.vtmainbody','#timeline'); $("#timeline").html(data); /* reload plugins */ $(document).foundation(); + }, + error: function() { + lockunlock(false,'div.mainbody,div.vtmainbody','#timeline'); + console.log(arguments); + alert("Search failed or canceled! See console log for details."); + }, + complete: function() { + /* Just safety net */ + lockunlock(false,'div.mainbody,div.vtmainbody','#timeline'); + window.txhr = null; } }); } -var priorSearchReq = null; - -function searchTasks(e, table) { +function searchTasks(e, tablet) { var csrftoken = getCookie('csrftoken'); if (e) { e.preventDefault(); } - if (priorSearchReq) { - priorSearchReq.abort(); + if (window.txhr && 'abort' in window.txhr) { + window.txhr.abort(); } var url = $("#filter_tasks").attr("href"); var sort = $("#filterstatus option:selected").val(); - priorSearchReq = $.ajax({ + lockunlock(true,'div.mainbody,div.vtmainbody','#case_tasks'); + window.txhr = $.ajax({ url : url, type: "POST", data: {"keyword": $("#filter_tasks").val(), @@ -180,9 +193,20 @@ function searchTasks(e, table) { "sort": sort }, success: function(data) { - table.replaceData(data); + lockunlock(false,'div.mainbody,div.vtmainbody','#case_tasks'); + tablet.replaceData(data); //$("#case_tasks").html(data); - } + }, + error: function() { + console.log(arguments); + lockunlock(false,'div.mainbody,div.vtmainbody','#case_tasks'); + alert("Search failed or canceled! See console log for details."); + }, + complete: function() { + /* Just safety net */ + lockunlock(false,'div.mainbody,div.vtmainbody','#case_tasks'); + window.txhr = null; + } }); } @@ -223,8 +247,6 @@ function auto(data, taggle, tag_url, modal) { } $(document).ready(function() { - - $('a').each(function () { $(this).qtip({ content: $(this).attr("title"), @@ -1216,8 +1238,8 @@ $(document).ready(function() { } if (data) { - var table = new Tabulator("#vuls-table", { - data:data, //set initial table data + var tablet = new Tabulator("#vuls-table", { + data:data, layout:"fitColumns", placeholder: "No vulnerabilites have been added", tooltipsHeader:true, @@ -1751,7 +1773,7 @@ $(document).ready(function() { } } - var assignable_users = JSON.parse(document.getElementById('user_data').textContent) + var assignable_users = JSON.parse(document.getElementById('user_data').textContent); tasks_table = new Tabulator("#case_tasks", { ajaxURL:"/vince/ajax_calls/case/tasks/"+$(".addvulmodal").attr("caseid"), ajaxProgressiveLoad:"scroll", @@ -1841,9 +1863,9 @@ $(document).ready(function() { var filter_task = document.getElementById("filter_tasks"); if (filter_task) { - filter_task.addEventListener("keyup", function(event) { - searchTasks(event, tasks_table); - }); + filter_task.addEventListener("keyup", delaySearch(function(event) { + searchTasks(event, tasks_table); + },1000)); } $("#filterstatus").change(function(event) { diff --git a/vince/static/vince/js/case_management.js b/vince/static/vince/js/case_management.js index 03ef7bb..42c5b59 100644 --- a/vince/static/vince/js/case_management.js +++ b/vince/static/vince/js/case_management.js @@ -54,7 +54,6 @@ function getCookie(name) { } return cookieValue; } - function searchTmpls(e, table) { var csrftoken = getCookie('csrftoken'); @@ -64,7 +63,8 @@ function searchTmpls(e, table) { var url = $("#filter_templates").attr("href"); var owner = $("input[id^='id_owner_']:checked").val(); - $.ajax({ + lockunlock(true,'div.vtmainbody,div.mainboxy','#' + table.id); + window.txhr = $.ajax({ url : url, type: "POST", data: {"keyword": $("#filter_templates").val(), @@ -72,8 +72,19 @@ function searchTmpls(e, table) { "csrfmiddlewaretoken": csrftoken }, success: function(data) { + lockunlock(false,'div.vtmainbody,div.mainbody','#' + table.id); table.replaceData(data['templates']) - } + }, + error: function() { + lockunlock(false,'div.vtmainbody,div.mainbody','#' + table.id); + console.log(arguments); + alert("Search failed or canceled! See console log for details."); + }, + complete: function() { + /* Just safety net */ + lockunlock(false,'div.vtmainbody,div.mainbody','#' + table.id); + window.txhr = null; + } }); } @@ -81,12 +92,11 @@ function searchTmpls(e, table) { $(document).ready(function() { - var filter_msg = document.getElementById("filter_templates"); if (filter_msg) { - filter_msg.addEventListener("keyup", function(event) { + filter_msg.addEventListener("keyup", delaySearch(function(event) { searchTmpls(event, table); - }); + },1000)); } $("input[id^='id_owner_']").change(function() { diff --git a/vince/static/vince/js/case_search.js b/vince/static/vince/js/case_search.js index 1865452..3310f58 100644 --- a/vince/static/vince/js/case_search.js +++ b/vince/static/vince/js/case_search.js @@ -56,32 +56,41 @@ function nextTickets(page) { } -var priorSearchReq = null; +var txhr = null; function searchTickets(e) { if (e) { e.preventDefault(); } - $("#searchresults").html("

LOADING

"); - $("#id_page").val("1"); var url = "/vince/case/results/"; - if(priorSearchReq) { - priorSearchReq.abort(); + if(txhr && 'abort' in txhr) { + txhr.abort(); } - priorSearchReq = $.ajax({ + lockunlock(true,'div.mainbody,div.vtmainbody','#searchresults'); + txhr = $.ajax({ url: url, type: "POST", data: $('#searchform').serialize(), success: function(data) { - $("#searchresults").html(data); - priorSearchReq = null; - } - }); + lockunlock(false,'div.mainbody,div.vtmainbody','#searchresults'); + $("#searchresults").html(data); + }, + error: function() { + lockunlock(false,'div.mainbody,div.vtmainbody','#searchresults'); + console.log(arguments); + alert("Search failed or canceled! See console log for details."); + }, + complete: function() { + /* Just safety net */ + lockunlock(false,'div.mainbody,div.vtmainbody','#searchresults'); + window.txhr = null; + } + }); } $(document).ready(function() { - + $(document).on("click", '.search_page', function(event) { var page = $(this).attr('next'); nextPage(page); diff --git a/vince/static/vince/js/contact.js b/vince/static/vince/js/contact.js index e48974d..3bae307 100644 --- a/vince/static/vince/js/contact.js +++ b/vince/static/vince/js/contact.js @@ -51,7 +51,7 @@ function nextResults(page) { } -var priorSearchReq = null; +var txhr = null; function searchContacts() { var url = $("#searchform").attr("action"); @@ -63,25 +63,35 @@ function searchContacts() { window.history.pushState({path:newurl},'',newurl); } var data = $('#searchform').serialize() + "&facet=" + facet; - if(priorSearchReq) { - priorSearchReq.abort(); + if(window.txhr && 'abort' in window.txhr) { + txhr.abort(); } - priorSearchReq = $.ajax({ + lockunlock(true,'div.mainbody,div.vtmainbody','#searchresults'); + txhr = $.ajax({ url: url, type: "GET", data: data, success: function(data) { $("#searchresults").html(data); $(document).foundation(); - priorSearchReq = null; - } + txhr = null; + }, + error: function() { + lockunlock(false,'div.mainbody,div.vtmainbody','#searchresults'); + console.log(arguments); + alert("Search failed or canceled! See console log for details."); + }, + complete: function() { + /* Just safety net */ + lockunlock(false,'div.mainbody,div.vtmainbody','#searchresults'); + window.txhr = null; + } }); } $(document).ready(function() { - $(document).on("click", '.search_page', function(event) { var page = $(this).attr('next'); nextPage(page); @@ -128,12 +138,11 @@ $(document).ready(function() { }); - var input = document.getElementById("search_vector"); if (input) { - input.addEventListener("keyup", function(event) { + input.addEventListener("keyup", delaySearch(function(event) { searchContacts(); - }); + },1000)); } $(document).on("submit", "#searchform", function(event) { diff --git a/vince/static/vince/js/cve_service.js b/vince/static/vince/js/cve_service.js index 224d929..6ae47cb 100644 --- a/vince/static/vince/js/cve_service.js +++ b/vince/static/vince/js/cve_service.js @@ -1,31 +1,31 @@ -/*######################################################################### -# VINCE -# -# Copyright 2022 Carnegie Mellon University. -# -# NO WARRANTY. THIS CARNEGIE MELLON UNIVERSITY AND SOFTWARE ENGINEERING +/*######################################################################### +# VINCE +# +# Copyright 2022 Carnegie Mellon University. +# +# NO WARRANTY. THIS CARNEGIE MELLON UNIVERSITY AND SOFTWARE ENGINEERING # INSTITUTE MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON -# UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, -# AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR -# PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE -# MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND +# UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, +# AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR +# PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE +# MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND # WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT. -# -# Released under a MIT (SEI)-style license, please see license.txt or contact -# permission@sei.cmu.edu for full terms. -# -# [DISTRIBUTION STATEMENT A] This material has been approved for public -# release and unlimited distribution. Please see Copyright notice for non-US +# +# Released under a MIT (SEI)-style license, please see license.txt or contact +# permission@sei.cmu.edu for full terms. +# +# [DISTRIBUTION STATEMENT A] This material has been approved for public +# release and unlimited distribution. Please see Copyright notice for non-US # Government use and distribution. -# -# Carnegie Mellon®, CERT® and CERT Coordination Center® are registered in the -# U.S. Patent and Trademark Office by Carnegie Mellon University. -# -# This Software includes and/or makes use of Third-Party Software each subject -# to its own license. -# -# DM21-1126 -######################################################################## +# +# Carnegie Mellon®, CERT® and CERT Coordination Center® are registered in the +# U.S. Patent and Trademark Office by Carnegie Mellon University. +# +# This Software includes and/or makes use of Third-Party Software each subject +# to its own license. +# +# DM21-1126 +######################################################################## */ function permissionDenied(modal) { @@ -36,27 +36,35 @@ function permissionDenied(modal) { $(document).ready(function() { - function searchCVEs(e) { if (e) { e.preventDefault(); } var url = $("#search").attr("action"); - $.ajax({ + lockunlock(true,'div.mainbody,div.vtmainbody','#cve-table'); + window.txhr = $.ajax({ url: url, type: "POST", data: $('#search').serialize(), success: function(data) { - table.clearData(); + tablet.clearData(); $("#searchresults").html(data); var data = JSON.parse(document.getElementById('cve_data').textContent); - table.replaceData(data); + tablet.replaceData(data); + }, + error: function() { + lockunlock(false,'div.mainbody,div.vtmainbody','#cve-table'); + console.log(arguments); + alert("Search failed or canceled! See console log for details."); + }, + complete: function() { + /* Just safety net */ + lockunlock(false,'div.mainbody,div.vtmainbody','#cve-table'); + window.txhr = null; } }); } - - var modal = $("#smallmodal"); @@ -136,9 +144,9 @@ $(document).ready(function() { if (document.getElementById('cve_data')) { var data = JSON.parse(document.getElementById('cve_data').textContent); - - var table = new Tabulator("#cve-table", { - data:data, //set initial table data + /* table is inbuilt function in Safari */ + var tablet = new Tabulator("#cve-table", { + data:data, layout:"fitColumns", placeholder: "No CVEs reserved", tooltipsHeader:true, diff --git a/vince/static/vince/js/email_management.js b/vince/static/vince/js/email_management.js index 6d70cd2..d6ca821 100644 --- a/vince/static/vince/js/email_management.js +++ b/vince/static/vince/js/email_management.js @@ -55,16 +55,17 @@ function getCookie(name) { return cookieValue; } -function searchTmpls(e, table) { +function searchTmpls(e, tablet) { var csrftoken = getCookie('csrftoken'); if (e) { e.preventDefault(); } - + var url = $("#filter_templates").attr("href"); var owner = $("input[id^='id_owner_']:checked").val(); - $.ajax({ + lockunlock(true,'div.vtmainbody','#template-table'); + window.txhr = $.ajax({ url : url, type: "POST", data: {"keyword": $("#filter_templates").val(), @@ -72,7 +73,18 @@ function searchTmpls(e, table) { "csrfmiddlewaretoken": csrftoken }, success: function(data) { - table.replaceData(data['templates']) + lockunlock(false,'div.vtmainbody','#template-table'); + tablet.replaceData(data['templates']) + }, + error: function() { + lockunlock(false,'div.vtmainbody','#template-table'); + console.log(arguments); + alert("Search failed or canceled! See console log for details."); + }, + complete: function() { + /* Just safety net */ + lockunlock(false,'div.vtmainbody','#template-table'); + window.txhr = null; } }); } @@ -80,22 +92,20 @@ function searchTmpls(e, table) { $(document).ready(function() { - - var filter_msg = document.getElementById("filter_templates"); if (filter_msg) { - filter_msg.addEventListener("keyup", function(event) { - searchTmpls(event, table); - }); + filter_msg.addEventListener("keyup", delaySearch(function(event) { + searchTmpls(event, tablet); + },1000)); } $("input[id^='id_owner_']").change(function() { - searchTmpls(null, table); + searchTmpls(null, tablet); }); $("#filter_by_dropdown_select_all_0").click(function(){ $("input[type=checkbox]").prop('checked', $(this).prop('checked')); - searchTmpls(null, table); + searchTmpls(null, tablet); }); @@ -131,8 +141,9 @@ $(document).ready(function() { }); }); - if (data) { - var table = new Tabulator("#template-table", { + if (data) { + /* table is an inbuilt function in Safari */ + var tablet = new Tabulator("#template-table", { data:data, //set initial table data layout:"fitColumns", columns:[ diff --git a/vince/static/vince/js/email_search.js b/vince/static/vince/js/email_search.js index 6db128d..1aef615 100644 --- a/vince/static/vince/js/email_search.js +++ b/vince/static/vince/js/email_search.js @@ -55,22 +55,31 @@ function nextEmails(page) { } - - - function searchEmails(e) { if (e) { e.preventDefault(); } $("#id_page").val("1"); var url = "/vince/email/results/"; - $.ajax({ + lockunlock(true,'div.mainbody,div.vtmainbody','#searchresults'); + window.txhr = $.ajax({ url: url, type: "POST", data: $('#searchform').serialize(), success: function(data) { + lockunlock(false); $("#searchresults").html(data); - } + }, + error: function() { + lockunlock(false,'div.mainbody,div.vtmainbody','#searchresults'); + console.log(arguments); + alert("Search failed or canceled! See console log for details."); + }, + complete: function() { + /* Just safety net */ + lockunlock(false,'div.mainbody,div.vtmainbody','#searchresults'); + window.txhr = null; + } }); } @@ -79,7 +88,7 @@ function searchEmails(e) { $(document).ready(function() { - + $(document).on("click", '.search_page', function(event) { var page = $(this).attr('next'); nextPage(page); diff --git a/vince/static/vince/js/scontact.js b/vince/static/vince/js/scontact.js index e98c9da..f827396 100644 --- a/vince/static/vince/js/scontact.js +++ b/vince/static/vince/js/scontact.js @@ -150,7 +150,6 @@ function auto(data, taggle) { }); } - function searchTasks(e) { var csrftoken = getCookie('csrftoken'); @@ -161,7 +160,8 @@ function searchTasks(e) { var url = $("#filter_tasks").attr("href"); var sort = $("#filterstatus option:selected").val(); var name = $("#filter_tasks").attr("name"); - $.ajax({ + lockunlock(true,'div.vtmainbody,div.mainbody','#case_tasks'); + window.txhr = $.ajax({ url : url, type: "POST", data: {"wordSearch": $("#filter_tasks").val(), @@ -170,14 +170,24 @@ function searchTasks(e) { "contact": name, }, success: function(data) { + lockunlock(false,'div.vtmainbody,div.mainbody','#case_tasks'); $("#case_tasks").html(data); - } + }, + error: function() { + lockunlock(false,'div.vtmainbody,div.mainbody','#case_tasks'); + console.log(arguments); + alert("Search failed or canceled! See console log for details."); + }, + complete: function() { + /* Just safety net */ + lockunlock(false,'div.vtmainbody,div.mainbody','#case_tasks'); + window.txhr = null; + } }); } $(document).ready(function() { - var filter_task = document.getElementById("filter_tasks"); if (filter_task) { filter_task.addEventListener("keyup", function(event) { diff --git a/vince/static/vince/js/search.js b/vince/static/vince/js/search.js index c8a890d..3409f0c 100644 --- a/vince/static/vince/js/search.js +++ b/vince/static/vince/js/search.js @@ -55,59 +55,36 @@ function nextTickets(page) { }); } -function lockunlock(f) { - if(f) { - /* Show search is in progress */ - $('div.vtmainbody').css({opacity:0.5}); - if($('#searchresults > .loading').length != 1) - $('#searchresults').prepend($('#hiddenloading').html()); - } else { - /* Back to normal */ - $('div.vtmainbody').css({opacity:1}); - $('#searchresults > #loadingbanner').remove(); - } -} - function searchTickets(e) { if (e) { e.preventDefault(); } $("#id_page").val("1"); var url = "/vince/ticket/results/"; - lockunlock(true); + lockunlock(true,'div.mainbody,div.vtmainbody','#searchresults'); window.txhr = $.ajax({ url: url, type: "POST", data: $('#searchform').serialize(), success: function(data) { - lockunlock(false); + lockunlock(false,'div.mainbody,div.vtmainbody','#searchresults'); $("#searchresults").html(data); }, error: function() { - lockunlock(false); + lockunlock(false,'div.mainbody,div.vtmainbody','#searchresults'); console.log(arguments); alert("Search failed or canceled! See console log for details."); }, complete: function() { /* Just safety net */ - lockunlock(false); - delete window.txhr; + lockunlock(false,'div.mainbody,div.vtmainbody','#searchresults'); + window.txhr = null; } }); } $(document).ready(function() { - $(document).keyup(function(e) { - if (e.key === "Escape") { - if('txhr' in window && 'abort' in window.txhr) { - console.log("Aborting search because user hit Escape"); - window.txhr.abort(); - delete window.txhr; - } - } - }); - $(document).on("click", '.search_page', function(event) { var page = $(this).attr('next'); nextPage(page); diff --git a/vince/static/vince/js/triage.js b/vince/static/vince/js/triage.js index 541ddba..9d64eb6 100644 --- a/vince/static/vince/js/triage.js +++ b/vince/static/vince/js/triage.js @@ -55,24 +55,37 @@ function nextTickets(page) { }); } + function searchTickets(e) { if (e) { e.preventDefault(); } $("#id_page").val("1"); var url = $("#searchform").attr("action"); - $.ajax({ + lockunlock(true,'div.mainbody,div.vtmainbody','#searchresults'); + window.txhr = $.ajax({ url: url, type: "POST", data: $('#searchform').serialize(), success: function(data) { + lockunlock(false,'div.mainbody,div.vtmainbody','#searchresults'); $("#searchresults").html(data); - } + }, + error: function() { + lockunlock(false,'div.mainbody,div.vtmainbody','#searchresults'); + console.log(arguments); + alert("Search failed or canceled! See console log for details."); + }, + complete: function() { + /* Just safety net */ + lockunlock(false,'div.mainbody,div.vtmainbody','#searchresults'); + window.txhr = null; + } }); } $(document).ready(function() { - + $(document).on("click", '.search_page', function(event) { var page = $(this).attr('next'); nextPage(page); diff --git a/vince/static/vince/js/vcuser.js b/vince/static/vince/js/vcuser.js index debc6e5..7b64771 100644 --- a/vince/static/vince/js/vcuser.js +++ b/vince/static/vince/js/vcuser.js @@ -27,6 +27,7 @@ # DM21-1126 ######################################################################## */ + function searchTasks(e) { var csrftoken = getCookie('csrftoken'); @@ -37,7 +38,8 @@ function searchTasks(e) { var url = $("#filter_tasks").attr("href"); var sort = $("#filterstatus option:selected").val(); var name = $("#filter_tasks").attr("name"); - $.ajax({ + lockunlock(true,'div.vtmainbody,div.mainbody','#case_tasks'); + window.txhr = $.ajax({ url : url, type: "POST", data: {"wordSearch": $("#filter_tasks").val(), @@ -46,7 +48,18 @@ function searchTasks(e) { "submitted_by": name, }, success: function(data) { + lockunlock(false,'div.vtmainbody,div.mainbody','#case_tasks'); $("#case_tasks").html(data); + }, + error: function() { + lockunlock(false,'div.vtmainbody,div.mainbody','#case_tasks'); + console.log(arguments); + alert("Search failed or canceled! See console log for details."); + }, + complete: function() { + /* Just safety net */ + lockunlock(false,'div.vtmainbody,div.mainbody','#case_tasks'); + window.txhr = null; } }); } @@ -121,9 +134,9 @@ $(document).ready(function() { var filter_task = document.getElementById("filter_tasks"); if (filter_task) { - filter_task.addEventListener("keyup", function(event) { - searchTasks(event); - }); + filter_task.addEventListener("keyup", delaySearch(function(event) { + searchTasks(event); + },1000)); } $("#filterstatus").change(function(event) { diff --git a/vince/static/vince/js/vince.js b/vince/static/vince/js/vince.js index d8c890b..dc7b961 100644 --- a/vince/static/vince/js/vince.js +++ b/vince/static/vince/js/vince.js @@ -27,7 +27,8 @@ # DM21-1126 ######################################################################## */ -//Emily Test + +/* Global functions for VINCETrack */ function getCookie(name) { var cookieValue = null; @@ -35,7 +36,7 @@ function getCookie(name) { var cookies = document.cookie.split(';'); for (var i = 0; i < cookies.length; i++) { var cookie = jQuery.trim(cookies[i]); - // Does this cookie string begin with the name we want? + // Does this cookie string begin with the name we want? if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; @@ -53,8 +54,28 @@ function copyToClipboard(text) { document.execCommand("copy"); $temp.remove(); } - - +function lockunlock(f,divmain,divhtml) { + if(f) { + /* Show search is in progress */ + $(divmain).css({opacity:0.5}); + if($(divhtml + ' > .loading').length < 1) + $(divhtml).prepend($('#hiddenloading').html()); + } else { + /* Back to normal */ + $(divmain).css({opacity:1}); + $(divhtml + ' > .loading').remove(); + } +} +function delaySearch(callfun,wait) { + var timeout; + return (...args) => { + clearTimeout(timeout); + timeout = setTimeout( + function () { + callfun.apply(this, args); + }, wait); + }; +} $(function () { /*$('span[title]').qtip({ @@ -113,6 +134,15 @@ $(function () { }, 600); return false; }); + $(document).keyup(function(e) { + if (e.key === "Escape") { + if(window.txhr && 'abort' in window.txhr) { + console.log("Aborting search because user hit Escape"); + window.txhr.abort(); + window.txhr = null; + } + } + }); }); diff --git a/vince/static/vince/js/vinny_dashboard.js b/vince/static/vince/js/vinny_dashboard.js index abae74e..b81ca09 100644 --- a/vince/static/vince/js/vinny_dashboard.js +++ b/vince/static/vince/js/vinny_dashboard.js @@ -29,7 +29,6 @@ */ - function searchThreads(e, newpage) { var csrftoken = getCookie('csrftoken'); @@ -42,24 +41,35 @@ function searchThreads(e, newpage) { } var url = $("#searchform").attr("action"); - $.ajax({ + lockunlock(true,'div.mainbody,div.vtmainbody','#casecontainer'); + window.txhr = $.ajax({ url : url, type: "POST", data: $('#searchform').serialize(), success: function(data) { + lockunlock(false,'div.mainbody,div.vtmainbody','#casecontainer'); $("#casecontainer").html(data); - } - }); + }, + error: function() { + lockunlock(false,'div.mainbody,div.vtmainbody','#casecontainer'); + console.log(arguments); + alert("Search failed or canceled! See console log for details."); + }, + complete: function() { + /* Just safety net */ + lockunlock(false,'div.mainbody,div.vtmainbody','#casecontainer'); + window.txhr = null; + } + }); } $(document).ready(function() { - var filter_msg = document.getElementById("filter_threads"); if (filter_msg) { - filter_msg.addEventListener("keyup", function(event) { - searchThreads(event); - }); + filter_msg.addEventListener("keyup",delaySearch(function(event) { + searchThreads(event); + },1000)); } $("input[id^='id_owner_']").change(function() { diff --git a/vince/static/vince/js/vulnote.js b/vince/static/vince/js/vulnote.js index bad7fa4..898137e 100644 --- a/vince/static/vince/js/vulnote.js +++ b/vince/static/vince/js/vulnote.js @@ -287,3 +287,20 @@ $(document).ready(function() { }); +/* Request from INL to create a HTML download button*/ +function getHTML() { + var vulnote = $('#vulnote a').attr('href'); + $.get(vulnote).done(function(h) { + var plainText = $($.parseHTML(h)).find("#id_content").val(); + $('body').append(''); + var simplemde = new EasyMDE({element: document.getElementById('ccB')}) + var simpleHTML = simplemde.markdown(plainText); + var link = document.createElement("a"); + link.download = "VulReport.html"; + link.href = "data:text/html;charset=utf8,"+ encodeURIComponent(simpleHTML); + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + delete link; + }); +} diff --git a/vince/templates/vince/activity.html b/vince/templates/vince/activity.html index afc5902..5820c06 100644 --- a/vince/templates/vince/activity.html +++ b/vince/templates/vince/activity.html @@ -69,7 +69,6 @@

Activity

-

LOADING

diff --git a/vince/views.py b/vince/views.py index be32355..a37c8b6 100755 --- a/vince/views.py +++ b/vince/views.py @@ -5778,8 +5778,12 @@ def get_context_data(self, **kwargs): user_groups= self.request.user.groups.exclude(groupsettings__contact__isnull=True) context['case_tags'] = [tag.tag for tag in context['case'].casetag_set.all()] context['case_available_tags'] = [tag.tag for tag in TagManager.objects.filter(tag_type=3).filter(Q(team__in=user_groups)|Q(team__isnull=True)).exclude(tag__in=context['case_tags']).order_by('tag').distinct('tag')] - context['casepage']=1 - context['reminders'] = VinceReminder.objects.filter(case=context['case'], alert_date__lte=datetime.today()).order_by('-alert_date') + context['casepage'] = 1 + #Use TZ to avoid RunTimeWarning + #RuntimeWarning: DateTimeField VinceReminder.alert_date received + #a naive datetime (2022-10-21 17:54:18.020583) while time zone + #support is active + context['reminders'] = VinceReminder.objects.filter(case=context['case'], alert_date__lte=datetime.now(pytz.utc)).order_by('-alert_date') context['allow_edit'] = True # need this for task reassignment context['assignable_users'] = User.objects.filter(is_active=True, groups__name='vince') diff --git a/vincepub/serializers.py b/vincepub/serializers.py index 5cf9264..9f8a693 100644 --- a/vincepub/serializers.py +++ b/vincepub/serializers.py @@ -232,7 +232,7 @@ def get_csafdocument(self,vr): if ven.addendum: addinfo = {"category": "other", "text": ven.addendum, - "title": f"{settings.ORG_NAME} comment on {ven.vendor} notes"} + "title": f"settings.ORG_NAME comment on {ven.vendor} notes"} csafdoc["notes"] += [addinfo] return csafdoc @@ -259,9 +259,7 @@ def get_csafvuls(self, vr): "vuid": vr.vuid, "cve": cve, "title": json.dumps(casevul.description.split(".")[0]+"."), - "description": json.dumps(casevul.description), - "ORG_NAME": settings.ORG_NAME - } + "description": json.dumps(casevul.description) } csafvulj = json.loads(csafvul,strict=False) if cve is None: del csafvulj['cve'] diff --git a/vincepub/static/vincepub/js/vulsearch.js b/vincepub/static/vincepub/js/vulsearch.js index a5f86ed..42b77da 100644 --- a/vincepub/static/vincepub/js/vulsearch.js +++ b/vincepub/static/vincepub/js/vulsearch.js @@ -64,13 +64,13 @@ function searchNotes(e) { } $("#id_page").val("1"); var url = "/vuls/results/"; - + $("#searchresults").css({opacity: 0.5}); $.ajax({ url: url, type: "POST", data: $('#searchform').serialize(), success: function(data) { - $("#searchresults").html(data); + $("#searchresults").html(data).css({opacity: 1}); } }); } @@ -78,12 +78,22 @@ function searchNotes(e) { $(document).ready(function() { function vend_auto(data) { - var vendor_input=$('input[id="id_vendor"]'); + var vendor_input=$('#id_vendor'); vendor_input.autocomplete({ - source: data, - minLength: 2, - select: function( event, ui) { $("#id_vendor").val(ui.item.value); searchNotes(); } - + source: data, + minLength: 2, + select: function( event, ui) { + $("#id_vendor").val(ui.item.value); + searchNotes(); + }, + response: function(event, ui) { + $('#noresults_vendor').remove(); + if (ui.content.length === 0) { + console.log("No results"); + if($('#noresults_vendor').length == 0) + $('#id_vendor').after('

No matches found

'); + } + } }); } diff --git a/vincepub/views.py b/vincepub/views.py index 417ced1..d116cf3 100644 --- a/vincepub/views.py +++ b/vincepub/views.py @@ -640,6 +640,7 @@ def post(self, request, *args, **kwargs): if 'years' in self.request.POST: yearlist = self.request.POST.getlist('years') for year in yearlist: + year = re.sub('[^\d]','',year) if year != "": datefilter.append(Q(datefirstpublished__year=year)) @@ -1113,15 +1114,15 @@ def get_view_name(self): return "Vulnerability Notes Published by Month" def get_queryset(self): - year = self.kwargs['year'] - month = self.kwargs['month'] + year = re.sub('[^\d]','',self.kwargs['year']) + month = re.sub('[^\d]','',self.kwargs['month']) return VUReport.objects.filter(datefirstpublished__year=year, datefirstpublished__month=month) class VUNoteViewByYear(generics.ListAPIView): serializer_class = serializers.VUReportSerializer def get_queryset(self): - year = self.kwargs['year'] + year = re.sub('[^\d]','',self.kwargs['year']) return VUReport.objects.filter(datefirstpublished__year=year) class VUNoteViewByMonthSummary(VUNoteViewByMonth): @@ -1167,14 +1168,14 @@ def get_view_name(self): return "Vendors By Month" def get_queryset(self): - year = self.kwargs['year'] - month = self.kwargs['month'] + year = re.sub('[^\d]','',self.kwargs['year']) + month = re.sub('[^\d]','',self.kwargs['month']) reports = VUReport.objects.filter(datefirstpublished__year=year, datefirstpublished__month=month).values_list('vuid', flat=True) return VendorRecord.objects.filter(vuid__in=reports) def get(self, request, *args, **kwargs): - year = self.kwargs['year'] - month = self.kwargs['month'] + year = re.sub('[^\d]','',self.kwargs['year']) + month = re.sub('[^\d]','',self.kwargs['month']) reports = VUReport.objects.filter(datefirstpublished__year=year, datefirstpublished__month=month).values_list('idnumber', flat=True) oldrecs = VendorRecord.objects.filter(idnumber__in=reports) x = serializers.VendorRecordSerializer(oldrecs, many=True) @@ -1186,7 +1187,7 @@ class VendorViewByYear(generics.ListAPIView): serializer_class = serializers.VendorRecordSerializer def get_queryset(self): - year = self.kwargs['year'] + year = re.sub('[^\d]','',self.kwargs['year']) reports = VUReport.objects.filter(datefirstpublished__year=year).values_list('vuid', flat=True) return VendorRecord.objects.filter(vuid__in=reports) @@ -1197,8 +1198,8 @@ def get_view_name(self): def summarize(self, request, *args, **kwargs): # make sure the filters of the parent class get applied - year = self.kwargs['year'] - month = self.kwargs['month'] + year = re.sub('[^\d]','',self.kwargs['year']) + month = re.sub('[^\d]','',self.kwargs['month']) reports = VUReport.objects.filter(datefirstpublished__year=year, datefirstpublished__month=month).values_list('idnumber', flat=True) oldrecs = VendorRecord.objects.filter(idnumber__in=reports).distinct('vendor') vendor = Vendor.objects.filter(note__vuid__in=reports).distinct('vendor') @@ -1277,8 +1278,12 @@ def get(self, request, *args, **kwargs): class CVEVulViewAPI(generics.GenericAPIView): def get(self, request, *args, **kwargs): - cve = f"CVE-{self.kwargs['year']}-{self.kwargs['pk']}" - cvewo = f"{self.kwargs['year']}-{self.kwargs['pk']}" + #Be safe and remove all alpha character if this view + #is accessed some other way than URL regex map + year = re.sub('[^\d]','',self.kwargs['year']) + pk = re.sub('[^\d]','',self.kwargs['pk']) + cve = f"CVE-{year}-{pk}" + cvewo = f"{year}-{pk}" report = None old_report = VUReport.objects.raw(f"SELECT * from vincepub_vureport where cveids::text like '%%{cve}%%'") for x in old_report: @@ -1356,4 +1361,9 @@ def get_object(self): svuid = re.sub('[^\d]','',self.kwargs['vuid']) vr = get_object_or_404(VUReport, idnumber=svuid) return vr + def finalize_response(self, request, response, *args, **kwargs): + response = super().finalize_response(request, response, *args, **kwargs) + if request.headers.get('Origin') and request.headers.get('Origin').find("https://") > -1: + response["Access-Control-Allow-Origin"] = request.headers.get('Origin') + return response diff --git a/vinny/forms.py b/vinny/forms.py index f902e3b..d6b12ea 100644 --- a/vinny/forms.py +++ b/vinny/forms.py @@ -674,7 +674,7 @@ class StatementForm(forms.Form): disabled=True, widget = forms.Textarea(), label = _('Coordinator Addendum'), - help_text=_('Coordination team may add additional text about the vendor statements and status.'), + help_text=_('The coordination team may add additional text about the vendor statements and status.'), required=False ) @@ -934,7 +934,7 @@ def __init__(self, *args, **kwargs): super(PreferencesForm, self).__init__(*args, **kwargs) #if setting is not set for this user, set to default for x,y in DEFAULT_USER_SETTINGS.items(): - if self.initial.get(x) is None: + if self.initial.get(x) is None and x in self.fields: self.fields[x].initial=y diff --git a/vinny/models.py b/vinny/models.py index d9935f5..633e8fb 100644 --- a/vinny/models.py +++ b/vinny/models.py @@ -56,6 +56,7 @@ import traceback import mimetypes from django.dispatch import Signal +import io logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) @@ -217,6 +218,10 @@ def _get_modified(self): def _set_settings(self, data): # data should always be a Python dictionary. + if not isinstance(data,dict): + print("Non dictionary item sent to pickle %s" % str(data)) + logger.warn("Non dictionary item sent to pickle %s" % str(data)) + data = {} try: import pickle except ImportError: @@ -230,14 +235,26 @@ def _get_settings(self): import pickle except ImportError: import cPickle as pickle - + class RestrictedUnpickler(pickle.Unpickler): + def find_class(self, module, name): + """ If find_class gets called then return error """ + raise pickle.UnpicklingError("global '%s.%s' is forbidden" % + (module, name)) try: from base64 import decodebytes as b64decode if self.settings_pickled: - return pickle.loads(b64decode(self.settings_pickled.encode('utf-8'))) + s = b64decode(self.settings_pickled.encode('utf-8')) + #replacement for pickle.loads() + return RestrictedUnpickler(io.BytesIO(s)).load() else: return {} except (pickle.UnpicklingError, AttributeError) as e: + print("Error when trying to unpickle data %s " %(str(e))) + logger.warn("Error when trying to unpickle data %s " %(str(e))) + return {} + except Exception as e: + print("Generic error when trying to unpickle data %s " %(str(e))) + logger.warn("Generic error when trying to unpickle data %s " %(str(e))) return {} settings = property(_get_settings, _set_settings) diff --git a/vinny/static/vinny/js/case_search.js b/vinny/static/vinny/js/case_search.js index b0cc289..9b7ea28 100644 --- a/vinny/static/vinny/js/case_search.js +++ b/vinny/static/vinny/js/case_search.js @@ -56,19 +56,33 @@ function nextTickets(page) { }); } -function searchTickets(e) { + +function searchTickets(e,noalert) { if (e) { e.preventDefault(); } $("#id_page").val("1"); var url = $("#searchform").attr("action"); - $.ajax({ + lockunlock(true,'div.mainbody,div.vtmainbody','#searchresults'); + window.txhr = $.ajax({ url: url, type: "POST", data: $('#searchform').serialize(), - success: function(data) { - $("#searchresults").html(data); - } + success: function(data) { + lockunlock(false,'div.mainbody,div.vtmainbody','#searchresults'); + $("#searchresults").html(data); + }, + error: function() { + lockunlock(false,'div.mainbody,div.vtmainbody','#searchresults'); + console.log(arguments); + if(noalert != true) + alert("Search failed or canceled! See console log for details."); + }, + complete: function() { + /* Just safety net */ + lockunlock(false,'div.mainbody,div.vtmainbody','#searchresults'); + window.txhr = null; + } }); } @@ -86,7 +100,7 @@ $(document).ready(function() { var input = document.getElementById("id_wordSearch"); input.addEventListener("keyup", function(event) { - searchTickets(event); + searchTickets(event,true); }); var form = document.getElementById('searchform'); diff --git a/vinny/static/vinny/js/inbox.js b/vinny/static/vinny/js/inbox.js index e32e177..f08fd95 100644 --- a/vinny/static/vinny/js/inbox.js +++ b/vinny/static/vinny/js/inbox.js @@ -46,7 +46,6 @@ function nextThreads(page) { }); } - function searchThreads(e) { if (e) { e.preventDefault(); @@ -54,13 +53,25 @@ function searchThreads(e) { $("#id_page").val("1"); var url = $("#filterform").attr("action"); - $.ajax({ + lockunlock(true,'div.mainbody,div.vtmainbody','#inbox'); + window.txhr = $.ajax({ url : url, type: "POST", data: $('#filterform').serialize(), success: function(data) { + lockunlock(false,'div.mainbody,div.vtmainbody','#inbox'); $("#inbox").html(data); - } + }, + error: function() { + lockunlock(false,'div.mainbody,div.vtmainbody','#inbox'); + console.log(arguments); + alert("Search failed or canceled! See console log for details."); + }, + complete: function() { + /* Just safety net */ + lockunlock(false,'div.mainbody,div.vtmainbody','#inbox'); + window.txhr = null; + } }); } @@ -78,7 +89,6 @@ function nextSent(page) { $(document).ready(function() { - $(document).on("click", '.search_page', function(event) { var page = $(this).attr('next'); nextPage(page); @@ -99,9 +109,9 @@ $(document).ready(function() { var filter_msg = document.getElementById("id_keyword"); if (filter_msg) { - filter_msg.addEventListener("keyup", function(event) { - searchThreads(event); - }); + filter_msg.addEventListener("keyup", delaySearch(function(event) { + searchThreads(event); + },1000)); } var modal = $("#deletemodal"); diff --git a/vinny/static/vinny/js/vincecomm.js b/vinny/static/vinny/js/vincecomm.js index 8214597..299d128 100644 --- a/vinny/static/vinny/js/vincecomm.js +++ b/vinny/static/vinny/js/vincecomm.js @@ -1,31 +1,31 @@ /*######################################################################### -# VINCE -# -# Copyright 2022 Carnegie Mellon University. -# -# NO WARRANTY. THIS CARNEGIE MELLON UNIVERSITY AND SOFTWARE ENGINEERING -# INSTITUTE MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON -# UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, -# AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR -# PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE -# MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND -# WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT. -# -# Released under a MIT (SEI)-style license, please see license.txt or contact -# permission@sei.cmu.edu for full terms. -# -# [DISTRIBUTION STATEMENT A] This material has been approved for public -# release and unlimited distribution. Please see Copyright notice for non-US -# Government use and distribution. -# -# Carnegie Mellon®, CERT® and CERT Coordination Center® are registered in the -# U.S. Patent and Trademark Office by Carnegie Mellon University. -# -# This Software includes and/or makes use of Third-Party Software each subject -# to its own license. -# -# DM21-1126 -######################################################################## + # VINCE + # + # Copyright 2022 Carnegie Mellon University. + # + # NO WARRANTY. THIS CARNEGIE MELLON UNIVERSITY AND SOFTWARE ENGINEERING + # INSTITUTE MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON + # UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, + # AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR + # PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE + # MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND + # WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT. + # + # Released under a MIT (SEI)-style license, please see license.txt or contact + # permission@sei.cmu.edu for full terms. + # + # [DISTRIBUTION STATEMENT A] This material has been approved for public + # release and unlimited distribution. Please see Copyright notice for non-US + # Government use and distribution. + # + # Carnegie Mellon®, CERT® and CERT Coordination Center® are registered in the + # U.S. Patent and Trademark Office by Carnegie Mellon University. + # + # This Software includes and/or makes use of Third-Party Software each subject + # to its own license. + # + # DM21-1126 + ######################################################################## */ function getCookie(name) { var cookieValue = null; @@ -34,7 +34,7 @@ function getCookie(name) { for (var i = 0; i < cookies.length; i++) { var cookie = jQuery.trim(cookies[i]); // Does this cookie string begin with the name we want? \ - + if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; @@ -44,6 +44,28 @@ function getCookie(name) { return cookieValue; } +function lockunlock(f,divmain,divhtml) { + if(f) { + /* Show search is in progress */ + $(divmain).css({opacity:0.5}); + if($(divhtml + ' > .loading').length < 1) + $(divhtml).prepend($('#hiddenloading').html()); + } else { + /* Back to normal */ + $(divmain).css({opacity:1}); + $(divhtml + ' > .loading').remove(); + } +} +function delaySearch(callfun,wait) { + var timeout; + return (...args) => { + clearTimeout(timeout); + timeout = setTimeout( + function () { + callfun.apply(this, args); + }, wait); + }; +} $(function () { $('span[title]').qtip({ @@ -63,5 +85,14 @@ $(function () { nav.toggleClass('less_padding', scrollTop > prev); prev = scrollTop; }); - + + $(document).keyup(function(e) { + if (e.key === "Escape") { + if(window.txhr && 'abort' in window.txhr) { + console.log("Aborting search because user hit Escape"); + window.txhr.abort(); + window.txhr = null; + } + } + }); }); diff --git a/vinny/static/vinny/js/vinny_dashboard.js b/vinny/static/vinny/js/vinny_dashboard.js index d0245e1..82758de 100644 --- a/vinny/static/vinny/js/vinny_dashboard.js +++ b/vinny/static/vinny/js/vinny_dashboard.js @@ -28,8 +28,6 @@ ######################################################################## */ - - function searchThreads(e, newpage) { var csrftoken = getCookie('csrftoken'); @@ -43,7 +41,8 @@ function searchThreads(e, newpage) { var url = $("#filter_threads").attr("href"); var owner = $("input[id^='id_owner_']:checked"); - $.ajax({ + lockunlock(true,'div.mainbody,div.vtmainbody','#casecontainer'); + window.txhr = $.ajax({ url : url, type: "POST", data: {"keyword": $("#filter_threads").val(), @@ -52,7 +51,20 @@ function searchThreads(e, newpage) { "csrfmiddlewaretoken": csrftoken }, success: function(data) { + lockunlock(false,'div.mainbody,div.vtmainbody','#casecontainer'); $("#casecontainer").html(data); + }, + error: function() { + lockunlock(false,'div.mainbody,div.vtmainbody','#casecontainer'); + console.log(arguments); + /* + alert("Search failed or canceled! See console log for details."); + */ + }, + complete: function() { + /* Just safety net */ + lockunlock(false,'div.mainbody,div.vtmainbody','#casecontainer'); + window.txhr = null; } }); } @@ -71,7 +83,7 @@ function searchReports(e, newpage) { var idSelector = function() { return this.value; }; var url = $("#filter_reports").attr("href"); var status = $("#id_status input[type=checkbox]:checked").map(idSelector).get(); - $.ajax({ + window.txhr = $.ajax({ url : url, type: "POST", data: {"keyword": $("#filter_reports").val(), @@ -80,8 +92,21 @@ function searchReports(e, newpage) { "csrfmiddlewaretoken": csrftoken }, success: function(data) { + lockunlock(false,'div.mainbody,div.vtmainbody','#casecontainer'); $("#casecontainer").html(data); - } + }, + error: function() { + lockunlock(false,'div.mainbody,div.vtmainbody','#casecontainer'); + console.log(arguments); + /* + alert("Search failed or canceled! See console log for details."); + */ + }, + complete: function() { + /* Just safety net */ + lockunlock(false,'div.mainbody,div.vtmainbody','#casecontainer'); + window.txhr = null; + } }); } @@ -90,16 +115,16 @@ $(document).ready(function() { var filter_msg = document.getElementById("filter_threads"); if (filter_msg) { - filter_msg.addEventListener("keyup", function(event) { + filter_msg.addEventListener("keyup", delaySearch(function(event) { searchThreads(event); - }); + },1000)); } var filter_report = document.getElementById("filter_reports"); if (filter_report) { - filter_report.addEventListener("keyup", function(event) { + filter_report.addEventListener("keyup", delaySearch(function(event) { searchReports(event); - }); + },1000)); } $("input[id^='id_owner_']").change(function() {