aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/orm/fixtures/common.xml100
-rw-r--r--lib/orm/fixtures/nist.xml31
-rw-r--r--lib/orm/fixtures/samples.xml117
-rw-r--r--lib/orm/fixtures/yp.xml65
-rw-r--r--lib/orm/management/commands/checksettings.py110
-rw-r--r--lib/orm/management/commands/lsupdates.py327
-rw-r--r--lib/orm/migrations/0001_initial.py68
-rw-r--r--lib/orm/models.py363
-rw-r--r--lib/srtgui/api.py146
-rw-r--r--lib/srtgui/reports.py1326
-rw-r--r--lib/srtgui/tables.py861
-rw-r--r--lib/srtgui/templates/base.html32
-rw-r--r--lib/srtgui/templates/cpes-toastertable.html3
-rw-r--r--lib/srtgui/templates/cve.html713
-rw-r--r--lib/srtgui/templates/cves-select-toastertable.html14
-rw-r--r--lib/srtgui/templates/cves-toastertable.html14
-rw-r--r--lib/srtgui/templates/cwes-toastertable.html14
-rw-r--r--lib/srtgui/templates/defect.html86
-rw-r--r--lib/srtgui/templates/defects-toastertable.html14
-rw-r--r--lib/srtgui/templates/guided_tour.html8
-rw-r--r--lib/srtgui/templates/investigation.html439
-rw-r--r--lib/srtgui/templates/investigations-toastertable.html14
-rw-r--r--lib/srtgui/templates/landing.html10
-rw-r--r--lib/srtgui/templates/login.html40
-rw-r--r--lib/srtgui/templates/manage-cpes-toastertable.html14
-rw-r--r--lib/srtgui/templates/management.html14
-rw-r--r--lib/srtgui/templates/product.html84
-rw-r--r--lib/srtgui/templates/products-toastertable.html14
-rw-r--r--lib/srtgui/templates/publish-select-toastertable.html248
-rw-r--r--lib/srtgui/templates/publish.html33
-rw-r--r--lib/srtgui/templates/published-select-toastertable.html247
-rw-r--r--lib/srtgui/templates/report.html73
-rw-r--r--lib/srtgui/templates/sources-toastertable.html72
-rw-r--r--lib/srtgui/templates/triage_cves.html10
-rw-r--r--lib/srtgui/templates/users.html20
-rw-r--r--lib/srtgui/templates/vulnerabilities-toastertable.html17
-rw-r--r--lib/srtgui/templates/vulnerability.html604
-rw-r--r--lib/srtgui/templatetags/projecttags.py6
-rw-r--r--lib/srtgui/urls.py107
-rw-r--r--lib/srtgui/views.py790
-rw-r--r--lib/srtgui/widgets.py16
-rw-r--r--lib/srtmain/settings.py6
42 files changed, 5716 insertions, 1574 deletions
diff --git a/lib/orm/fixtures/common.xml b/lib/orm/fixtures/common.xml
index 5f095372..97bbd8e9 100644
--- a/lib/orm/fixtures/common.xml
+++ b/lib/orm/fixtures/common.xml
@@ -1,27 +1,107 @@
<?xml version="1.0" encoding="utf-8"?>
<django-objects version="1.0">
- <!-- Set the common data sources (starts at 1) -->
+
+<!-- Set the common data settings (starts at 1) -->
+
+ <object model="orm.srtsetting" pk="1">
+ <field type="CharField" name="name">SRTOOL_FIXTURE_LIST_FALLBACK</field>
+ <field type="CharField" name="value">yp,nist</field>
+ </object>
+
+ <object model="orm.srtsetting" pk="10">
+ <field type="CharField" name="name">SRTOOL_DEFECT_UPDATE_FALLBACK</field>
+ <field type="CharField" name="value">bin/srtool_defect.py --update</field>
+ </object>
+ <object model="orm.srtsetting" pk="11">
+ <field type="CharField" name="name">SRTOOL_DEFECT_ADD_FALLBACK</field>
+ <field type="CharField" name="value">bin/srtool_defect.py --add</field>
+ </object>
+ <object model="orm.srtsetting" pk="12">
+ <field type="CharField" name="name">SRTOOL_DEFECT_DEL_FALLBACK</field>
+ <field type="CharField" name="value">bin/srtool_defect.py --del</field>
+ </object>
+ <object model="orm.srtsetting" pk="13">
+ <field type="CharField" name="name">SRTOOL_DEFECT_NEW_FALLBACK</field>
+ <field type="CharField" name="value">bin/srtool_defect.py --new</field>
+ </object>
+ <object model="orm.srtsetting" pk="14">
+ <field type="CharField" name="name">SRTOOL_DEFECT_SAMPLENAME_FALLBACK</field>
+ <field type="CharField" name="value">54321</field>
+ </object>
+
+<!-- Set the common data sources (starts at 1) -->
+
+<!-- Full production size keyword list
<object model="orm.datasource" pk="1">
<field type="CharField" name="data">triage_keywords</field>
<field type="CharField" name="source">common</field>
<field type="CharField" name="type">csv</field>
<field type="TextField" name="description">Table of keyword filters</field>
- <field type="FilePathField" name="file_path">data/keyword_filters.csv</field>
+ <field type="FilePathField" name="file_path">data/keyword_filters_full.csv</field>
<field type="TextField" name="url"></field>
+ <field type="CharField" name="lastModifiedDate">2018-03-01 01:01:01</field>
+ <field type="IntegerField" name="update_frequency">3</field>
+ <field type="CharField" name="update_time">02:00:00</field>
</object>
-
- <!-- TEST DATA SOURCES -->
+-->
-<!--
- <object model="orm.datasource" pk="10">
- <field type="CharField" name="data">test</field>
+<!-- Debug size keyword list -->
+ <object model="orm.datasource" pk="1">
+ <field type="CharField" name="data">triage_keywords</field>
<field type="CharField" name="source">common</field>
<field type="CharField" name="type">csv</field>
- <field type="TextField" name="description">TEST: CVE composite status charts</field>
- <field type="FilePathField" name="file_path">data/test_data.csv</field>
+ <field type="TextField" name="description">Table of keyword filters</field>
+ <field type="FilePathField" name="file_path">data/keyword_filters.csv</field>
<field type="TextField" name="url"></field>
+ <field type="CharField" name="lastModifiedDate">2018-03-01 01:01:01</field>
+ <field type="IntegerField" name="update_frequency">3</field>
+ <field type="CharField" name="update_time">02:00:00</field>
+ </object>
+<!-- -->
+
+ <object model="orm.datasource" pk="2">
+ <field type="CharField" name="data">backup_weekly</field>
+ <field type="CharField" name="source">common</field>
+ <field type="CharField" name="type">script</field>
+ <field type="TextField" name="description">Weekly archive database backup</field>
+ <field type="FilePathField" name="file_path"></field>
+ <field type="TextField" name="url"></field>
+ <field type="CharField" name="lastModifiedDate">0001-01-01 01:01:01</field>
+ <field type="IntegerField" name="update_frequency">3</field>
+ <field type="CharField" name="update_time">02:00:00</field>
+ <field type="TextField" name="command">bin/srtool_utils.py --backup-db-json</field>
+ </object>
+
+ <object model="orm.datasource" pk="3">
+ <field type="CharField" name="data">backup_daily</field>
+ <field type="CharField" name="source">common</field>
+ <field type="CharField" name="type">script</field>
+ <field type="TextField" name="description">Daily database backup (wheel)</field>
+ <field type="FilePathField" name="file_path"></field>
+ <field type="TextField" name="url"></field>
+ <field type="CharField" name="lastModifiedDate">0001-01-01 01:01:01</field>
+ <field type="IntegerField" name="update_frequency">2</field>
+ <field type="CharField" name="update_time">02:00:00</field>
+ <field type="TextField" name="command">bin/srtool_utils.py --backup-db-json-daily</field>
+ </object>
+
+<!-- Built-in Users : first user is default log-on user -->
+
+ <object model="orm.user" pk="1">
+ <field type="TextField" name="name">Guest</field>
+ <field type="TextField" name="email"></field>
+ <field type="TextField" name="role">Guest</field>
+ <field type="IntegerField" name="access">0</field>
+ <field type="TextField" name="password"></field>
+ </object>
+
+ <object model="orm.user" pk="2">
+ <field type="TextField" name="name">SRTool</field>
+ <field type="TextField" name="email"></field>
+ <field type="TextField" name="role">SRTool automation scripts</field>
+ <field type="IntegerField" name="access">3</field>
+ <field type="TextField" name="password"></field>
</object>
--->
</django-objects>
diff --git a/lib/orm/fixtures/nist.xml b/lib/orm/fixtures/nist.xml
index 3b65f2e5..b392e57b 100644
--- a/lib/orm/fixtures/nist.xml
+++ b/lib/orm/fixtures/nist.xml
@@ -9,27 +9,43 @@
<field type="TextField" name="description">NIST Common Weakness Enumeration Data</field>
<field type="FilePathField" name="file_path">data/nist-cwe-summary.html</field>
<field type="TextField" name="url">https://nvd.nist.gov/vuln/categories</field>
+ <field type="CharField" name="lastModifiedDate">0001-01-01 01:01:01</field>
+ <field type="IntegerField" name="update_frequency">3</field>
+ <field type="CharField" name="update_time">02:00:00</field>
+ <field type="TextField" name="command"></field>
</object>
- <!-- NIST data feeds: https://nvd.nist.gov/vuln/data-feeds#JSON_FEED -->
+
<object model="orm.datasource" pk="23">
<field type="CharField" name="data">cve</field>
<field type="CharField" name="source">nist</field>
- <field type="CharField" name="type">json</field>
+ <field type="CharField" name="type">script</field>
<field type="TextField" name="description">NIST JSON Data 2017</field>
<field type="FilePathField" name="file_path">data/nvdcve-1.0-2017.json</field>
<field type="TextField" name="url">https://static.nvd.nist.gov/feeds/json/cve/1.0/nvdcve-1.0-2017.json.gz</field>
+ <field type="TextField" name="meta_url">https://nvd.nist.gov/feeds/json/cve/1.0/nvdcve-1.0-2017.meta</field>
+ <field type="CharField" name="lastModifiedDate">0001-01-01 01:01:01</field>
+ <field type="IntegerField" name="update_frequency">3</field>
+ <field type="CharField" name="update_time">02:00:00</field>
+ <field type="TextField" name="command">bin/srtool_cve.py -n "NIST JSON Data 2017"</field>
</object>
+
<object model="orm.datasource" pk="24">
<field type="CharField" name="data">cve</field>
<field type="CharField" name="source">nist</field>
- <field type="CharField" name="type">json</field>
+ <field type="CharField" name="type">script</field>
<field type="TextField" name="description">NIST JSON Data 2018</field>
<field type="FilePathField" name="file_path">data/nvdcve-1.0-2018.json</field>
<field type="TextField" name="url">https://static.nvd.nist.gov/feeds/json/cve/1.0/nvdcve-1.0-2018.json.gz</field>
+ <field type="TextField" name="meta_url">https://nvd.nist.gov/feeds/json/cve/1.0/nvdcve-1.0-2018.meta</field>
+ <field type="CharField" name="lastModifiedDate">0001-01-01 01:01:01</field>
+ <field type="IntegerField" name="update_frequency">3</field>
+ <field type="CharField" name="update_time">02:00:00</field>
+ <field type="TextField" name="command">bin/srtool_cve.py -n "NIST JSON Data 2018"</field>
</object>
+
<!--
<object model="orm.datasource" pk="25">
<field type="CharField" name="data">cve</field>
@@ -44,10 +60,15 @@
<object model="orm.datasource" pk="26">
<field type="CharField" name="data">cve</field>
<field type="CharField" name="source">nist</field>
- <field type="CharField" name="type">json</field>
- <field type="TextField" name="description">NIST JSON Modified Data 2017</field>
+ <field type="CharField" name="type">script</field>
+ <field type="TextField" name="description">NIST JSON Modified Data</field>
<field type="FilePathField" name="file_path">data/nvdcve-1.0-modified.json</field>
<field type="TextField" name="url">https://static.nvd.nist.gov/feeds/json/cve/1.0/nvdcve-1.0-modified.json.gz</field>
+ <field type="TextField" name="meta_url">https://nvd.nist.gov/feeds/json/cve/1.0/nvdcve-1.0-modified.meta</field>
+ <field type="CharField" name="lastModifiedDate">0001-01-01 01:01:01</field>
+ <field type="IntegerField" name="update_frequency">2</field>
+ <field type="CharField" name="update_time">02:00:00</field>
+ <field type="TextField" name="command">bin/srtool_cve.py -n "NIST JSON Modified Data"</field>
</object>
</django-objects>
diff --git a/lib/orm/fixtures/samples.xml b/lib/orm/fixtures/samples.xml
index 0d22770a..04b865b0 100644
--- a/lib/orm/fixtures/samples.xml
+++ b/lib/orm/fixtures/samples.xml
@@ -1,25 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<django-objects version="1.0">
- <!-- Set up test data for Products -->
-
- <object model="orm.product" pk="1">
- <field type="CharField" name="name">Yocto Project</field>
- <field type="CharField" name="version">2.5 (Sumo)</field>
- <field type="CharField" name="profile"></field>
- </object>
- <object model="orm.product" pk="2">
- <field type="CharField" name="name">Yocto Project</field>
- <field type="CharField" name="version">2.4 (Rocko)</field>
- <field type="CharField" name="profile"></field>
- </object>
- <object model="orm.product" pk="3">
- <field type="CharField" name="name">Yocto Project</field>
- <field type="CharField" name="version">2.3 (Pyro)</field>
- <field type="CharField" name="profile"></field>
- </object>
-
-
<object model="orm.cve" pk="1">
<field type="CharField" name="name">CVE-2017-0000</field>
<field type="BooleanField" name="public">False</field>
@@ -94,12 +75,6 @@
<field type="DateField" name="date">2017-12-14</field>
<field type="TextField" name="author">Mark Hatle</field>
</object>
- <object model="orm.vulnerabilitycomments" pk="2">
- <field type="ForeignKey" name="vulnerability">1</field>
- <field type="TextField" name="comment">ACTION: User 'Paul Gortmaker' 'Bruce Ashfield' added</field>
- <field type="DateField" name="date">2017-12-14</field>
- <field type="TextField" name="author">Mark Hatle</field>
- </object>
<object model="orm.vulnerabilitycomments" pk="3">
<field type="ForeignKey" name="vulnerability">1</field>
<field type="TextField" name="comment">ACTION: Attachment 'PowerDNS Security Advisories 2018-02'</field>
@@ -166,7 +141,7 @@
<field type="IntegerField" name="priority">3</field>
<field type="IntegerField" name="status">5</field>
<field type="IntegerField" name="resolution">1</field>
- <field type="IntegerField" name="publishOLS">Reviewed - Publish</field>
+ <field type="IntegerField" name="publish">Reviewed - Publish</field>
<field type="CharField" name="release_version">2.5.1</field>
<field type="ForeignKey" name="product">1</field>
</object>
@@ -176,7 +151,7 @@
<field type="CharField" name="summary">(TEST) This is another defect</field>
<field type="IntegerField" name="priority">2</field>
<field type="IntegerField" name="status">0</field>
- <field type="IntegerField" name="publishOLS">Not Reviewed</field>
+ <field type="IntegerField" name="publish">Not Reviewed</field>
<field type="CharField" name="release_version"></field>
<field type="ForeignKey" name="product">1</field>
</object>
@@ -206,112 +181,38 @@
<field type="ForeignKey" name="defect">2</field>
</object>
- <!-- Set up default users -->
-
- <object model="orm.user" pk="1">
- <field type="TextField" name="name">Guest</field>
- <field type="TextField" name="email"></field>
- <field type="TextField" name="role">Guest</field>
- <field type="IntegerField" name="access">0</field>
- <field type="TextField" name="password"></field>
- </object>
-
- <object model="orm.user" pk="2">
- <field type="TextField" name="name">All</field>
- <field type="TextField" name="email"></field>
- <field type="TextField" name="role">internal all access placeholder</field>
- <field type="IntegerField" name="access">0</field>
- <field type="TextField" name="password"></field>
- </object>
-
- <object model="orm.user" pk="3">
- <field type="TextField" name="name">Ross Burton</field>
- <field type="TextField" name="email"></field>
- <field type="TextField" name="role">Security Manager Yocto Project</field>
- <field type="IntegerField" name="access">1</field>
- <field type="TextField" name="password"></field>
- </object>
-
- <object model="orm.user" pk="4">
- <field type="TextField" name="name">Richard Purtie</field>
- <field type="TextField" name="email"></field>
- <field type="TextField" name="role">Security Manager Yocto Project (backup)</field>
- <field type="IntegerField" name="access">1</field>
- <field type="TextField" name="password"></field>
- </object>
-
- <object model="orm.user" pk="5">
- <field type="TextField" name="name">Mark Hatle</field>
- <field type="TextField" name="email"></field>
- <field type="TextField" name="role">Product Security Expert Wind River</field>
- <field type="IntegerField" name="access">2</field>
- <field type="TextField" name="password"></field>
- </object>
-
- <object model="orm.user" pk="6">
- <field type="TextField" name="name">Jason Wessel</field>
- <field type="TextField" name="email"></field>
- <field type="TextField" name="role">Product Security Expert WRLinux (backup)</field>
- <field type="IntegerField" name="access">2</field>
- <field type="TextField" name="password"></field>
- </object>
-
- <object model="orm.user" pk="7">
- <field type="TextField" name="name">Jefro Osier-Mixon</field>
- <field type="TextField" name="email"></field>
- <field type="TextField" name="role">Product Owner Yocto Project</field>
- <field type="IntegerField" name="access">1</field>
- <field type="TextField" name="password"></field>
- </object>
-
- <object model="orm.user" pk="8">
- <field type="TextField" name="name">Stephen Jolley</field>
- <field type="TextField" name="email"></field>
- <field type="TextField" name="role">Product Owner Yocto Project (backup)</field>
- <field type="IntegerField" name="access">1</field>
- <field type="TextField" name="password"></field>
- </object>
-
- <object model="orm.user" pk="9">
- <field type="TextField" name="name">David Reyna</field>
- <field type="TextField" name="email">david.reyna@windriver.com</field>
- <field type="TextField" name="role">Developer Wind River</field>
- <field type="IntegerField" name="access">1</field>
- <field type="TextField" name="password"></field>
- </object>
-
<!-- Set up default users to investigations -->
<object model="orm.investigationaccess" pk="1">
<field type="ForeignKey" name="investigation">1</field>
- <field type="ForeignKey" name="user">1</field>
+ <field type="ForeignKey" name="user">10</field>
</object>
<object model="orm.investigationaccess" pk="2">
<field type="ForeignKey" name="investigation">1</field>
- <field type="ForeignKey" name="user">2</field>
+ <field type="ForeignKey" name="user">11</field>
</object>
<object model="orm.investigationaccess" pk="3">
<field type="ForeignKey" name="investigation">1</field>
- <field type="ForeignKey" name="user">3</field>
+ <field type="ForeignKey" name="user">12</field>
</object>
<object model="orm.vulnerabilityaccess" pk="4">
<field type="ForeignKey" name="vulnerability">1</field>
- <field type="ForeignKey" name="user">2</field>
+ <field type="ForeignKey" name="user">10</field>
</object>
<object model="orm.vulnerabilityaccess" pk="5">
<field type="ForeignKey" name="vulnerability">1</field>
- <field type="ForeignKey" name="user">4</field>
+ <field type="ForeignKey" name="user">11</field>
</object>
<object model="orm.investigationnotification" pk="1">
<field type="ForeignKey" name="investigation">1</field>
- <field type="ForeignKey" name="user">5</field>
+ <field type="ForeignKey" name="user">12</field>
</object>
<object model="orm.vulnerabilitynotification" pk="2">
<field type="ForeignKey" name="vulnerability">1</field>
- <field type="ForeignKey" name="user">6</field>
+ <field type="ForeignKey" name="user">10</field>
</object>
</django-objects>
diff --git a/lib/orm/fixtures/yp.xml b/lib/orm/fixtures/yp.xml
new file mode 100644
index 00000000..38e0f875
--- /dev/null
+++ b/lib/orm/fixtures/yp.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<django-objects version="1.0">
+
+ <!-- Set up test data for Products -->
+
+ <object model="orm.product" pk="1">
+ <field type="CharField" name="name">Yocto Project</field>
+ <field type="CharField" name="version">2.5 (Sumo)</field>
+ <field type="CharField" name="profile"></field>
+ </object>
+ <object model="orm.product" pk="2">
+ <field type="CharField" name="name">Yocto Project</field>
+ <field type="CharField" name="version">2.4 (Rocko)</field>
+ <field type="CharField" name="profile"></field>
+ </object>
+ <object model="orm.product" pk="3">
+ <field type="CharField" name="name">Yocto Project</field>
+ <field type="CharField" name="version">2.3 (Pyro)</field>
+ <field type="CharField" name="profile"></field>
+ </object>
+
+ <!-- Set up default users -->
+
+ <object model="orm.user" pk="10">
+ <field type="TextField" name="name">Ross Burton</field>
+ <field type="TextField" name="email"></field>
+ <field type="TextField" name="role">Security Manager Yocto Project</field>
+ <field type="IntegerField" name="access">3</field>
+ <field type="TextField" name="password"></field>
+ </object>
+
+ <object model="orm.user" pk="11">
+ <field type="TextField" name="name">Richard Purtie</field>
+ <field type="TextField" name="email"></field>
+ <field type="TextField" name="role">Security Manager Yocto Project (backup)</field>
+ <field type="IntegerField" name="access">3</field>
+ <field type="TextField" name="password"></field>
+ </object>
+
+ <object model="orm.user" pk="12">
+ <field type="TextField" name="name">Mark Hatle</field>
+ <field type="TextField" name="email"></field>
+ <field type="TextField" name="role">Product Security Expert Wind River</field>
+ <field type="IntegerField" name="access">2</field>
+ <field type="TextField" name="password"></field>
+ </object>
+
+ <object model="orm.user" pk="13">
+ <field type="TextField" name="name">Stephen Jolley</field>
+ <field type="TextField" name="email"></field>
+ <field type="TextField" name="role">Product Owner Yocto Project</field>
+ <field type="IntegerField" name="access">1</field>
+ <field type="TextField" name="password"></field>
+ </object>
+
+ <object model="orm.user" pk="14">
+ <field type="TextField" name="name">David Reyna</field>
+ <field type="TextField" name="email">david.reyna@windriver.com</field>
+ <field type="TextField" name="role">Developer Wind River</field>
+ <field type="IntegerField" name="access">1</field>
+ <field type="TextField" name="password"></field>
+ </object>
+
+</django-objects>
+
diff --git a/lib/orm/management/commands/checksettings.py b/lib/orm/management/commands/checksettings.py
index 65e9ab8a..e65d16ac 100644
--- a/lib/orm/management/commands/checksettings.py
+++ b/lib/orm/management/commands/checksettings.py
@@ -29,7 +29,7 @@ class Command(BaseCommand):
def _verify_srt_source(self):
ds_loaded = {}
-
+
needs_import = False
if 0 == DataSource.objects.all().count():
needs_import = True
@@ -46,7 +46,7 @@ class Command(BaseCommand):
print("Loading default settings")
call_command("loaddata", "settings")
- # Import the Common fixture if it's present
+ # Import the common fixture
with warnings.catch_warnings():
warnings.filterwarnings(
action="ignore",
@@ -54,41 +54,57 @@ class Command(BaseCommand):
print("Importing Common settings if present")
try:
call_command("loaddata", "common")
- except:
- print("NOTE: optional fixture 'common' not found")
-
- # Import the Mitre fixture if it's present
- with warnings.catch_warnings():
- warnings.filterwarnings(
- action="ignore",
- message="^.*No fixture named.*$")
- print("Importing Mitre settings if present")
- try:
- call_command("loaddata", "mitre")
- except:
- print("NOTE: optional fixture 'mitre' not found")
+ except Exception as e:
+ print("NOTE: optional fixture 'common' not found (%s)" % e)
- # Import the NIST fixture if it's present
+ # Import the 'custom' fixture to allow local custom overrides
with warnings.catch_warnings():
warnings.filterwarnings(
action="ignore",
message="^.*No fixture named.*$")
- print("Importing NIST settings if present")
- try:
- call_command("loaddata", "nist")
- except:
- print("NOTE: optional fixture 'nist' not found")
-
- # Import the Sample_Test fixture if it's present
- with warnings.catch_warnings():
- warnings.filterwarnings(
- action="ignore",
- message="^.*No fixture named.*$")
- print("Importing Sample Test settings if present")
+ print("Importing Common settings if present")
try:
- call_command("loaddata", "samples")
- except:
- print("NOTE: optional fixture 'samples' not found")
+ call_command("loaddata", "custom")
+ except Exception as e:
+ print("NOTE: optional fixture 'custom' not found (%s)" % e)
+
+ # Promote fallback values to missing configure defines
+ for setting in SrtSetting.objects.all():
+ if '_fallback' in setting.name:
+ name = setting.name.replace('_fallback','')
+ s,create = SrtSetting.objects.get_or_create(name=key)
+ if create:
+ s.value = setting.value
+ s.save
+
+ # Import the requested source fixture list
+ try:
+ fixture_list = SrtSetting.objects.get(name='SRTOOL_FIXTURE_LIST').value
+ except:
+ fixture_list = 'yp,nist'
+ for fixture in fixture_list.split(','):
+ fixture = fixture.strip()
+ with warnings.catch_warnings():
+ warnings.filterwarnings(
+ action="ignore",
+ message="^.*No fixture named.*$")
+ print("Importing %s fixture if present" % fixture)
+ try:
+ call_command("loaddata", fixture)
+ except Exception as e:
+ print("NOTE: optional fixture '%s' not found (%s)" % (fixture,e))
+
+ # Import the Sample_Test fixture if it's requested and present
+ if self._test_settings_get('SRTDBG_SAMPLES'):
+ with warnings.catch_warnings():
+ warnings.filterwarnings(
+ action="ignore",
+ message="^.*No fixture named.*$")
+ print("Importing Sample Test settings if present")
+ try:
+ call_command("loaddata", "samples")
+ except Exception as e:
+ print("NOTE: optional fixture 'samples' not found (%s)" % e)
# restore data source loaded flags
for source in DataSource.objects.all():
@@ -109,8 +125,20 @@ class Command(BaseCommand):
traceback.print_exc()
return 0
-
- def _test_settings(self,key):
+
+ def _test_settings_get(self,key):
+ try:
+ key_record = SrtSetting.objects.get(name=key)
+ if 'yes' == key_record.value:
+ return True
+ elif 'no' == key_record.value:
+ return False
+ else:
+ return key_record.value
+ except:
+ return False
+
+ def _test_settings_set(self,key):
key_record,create = SrtSetting.objects.get_or_create(name=key)
if key in os.environ.keys():
key_record.value = 'yes' if os.environ[key].startswith('1') else 'no'
@@ -127,12 +155,16 @@ class Command(BaseCommand):
SrtSetting.objects.get_or_create(name='DEFAULT_RELEASE', value='')
# TEST: set up the test flags based on ENVIRONMENT values
- # * export TEST_SKIP_NIST_IMPORT=1: we already have NIST data in the DB
- # * export TEST_SKIP_CPE_IMPORT=1: we do not need to (re-)scan the CPEs for vulnerable CVEs
- # * export TEST_MINIMAL_DB=1: only load the minimal database items for fast GUI tests
- self._test_settings('TEST_SKIP_NIST_IMPORT')
- self._test_settings('TEST_SKIP_CPE_IMPORT')
- self._test_settings('TEST_MINIMAL_DB')
+ # * export SRTDBG_SKIP_CVE_IMPORT=1: we do not need to (re-)scan the CVE data
+ # * export SRTDBG_SKIP_CPE_IMPORT=1: we do not need to (re-)scan the CPE data
+ # * export SRTDBG_SKIP_DEFECT_IMPORT=1: we do not need to (re-)scan the CPE data
+ # * export SRTDBG_MINIMAL_DB=1: only load the minimal database items for fast GUI tests
+ # * export SRTDBG_SAMPLES=1: load sample fixture (if any) database items for fast GUI tests
+ self._test_settings_set('SRTDBG_SKIP_CVE_IMPORT')
+ self._test_settings_set('SRTDBG_SKIP_CPE_IMPORT')
+ self._test_settings_set('SRTDBG_SKIP_DEFECT_IMPORT')
+ self._test_settings_set('SRTDBG_MINIMAL_DB')
+ self._test_settings_set('SRTDBG_SAMPLES')
# TEMP: set up default user info
current_user = SrtSetting.objects.get_or_create(name='current_user')[0]
diff --git a/lib/orm/management/commands/lsupdates.py b/lib/orm/management/commands/lsupdates.py
index 32548ddb..d72d732a 100644
--- a/lib/orm/management/commands/lsupdates.py
+++ b/lib/orm/management/commands/lsupdates.py
@@ -33,22 +33,21 @@ from orm.models import Keywords
import os
import sys
import re
+import subprocess
+import time
+from datetime import datetime, date
import json
import xml.etree.ElementTree as ET
import csv
import logging
import threading
-import time
-logger = logging.getLogger("srt")
import urllib
+logger = logging.getLogger("srt")
-def _log(msg):
- f1=open('/tmp/srt.log', 'a')
- f1.write("|" + msg + "|\n" )
- f1.close()
-
+# quick development/debugging support
+from srtgui.api import _log
# === Debugging limited database loading support ===
debug_cve_list = [] # empty list for any
@@ -112,6 +111,27 @@ class Command(BaseCommand):
sys.stdout.flush()
+ # Execute a shell script to import data, relative the SRT base
+ def execute_script(self,command):
+ SRT_BASE_DIR = os.environ.get('SRT_BASE_DIR')
+ CWD = os.getcwd()
+ os.chdir(SRT_BASE_DIR)
+ script = os.path.join(SRT_BASE_DIR,command)
+ print("====vvv Executing script '%s' vvv====" % script)
+ os.system(script)
+ os.chdir(CWD)
+ print("====^^^ Script Done ^^^====")
+
+ # Mark database as loaded
+ def source_loaded(self,id,update_modified=True):
+ # Re-fetch record in case external script updates
+ updated_source=DataSource.objects.get(id=id)
+ updated_source.loaded = True
+ if update_modified:
+ updated_source.update_time = datetime.today().strftime('%Y-%m-%d %H:%M:%S')
+ updated_source.lastModifiedDate = updated_source.update_time
+ updated_source.save()
+
def nist_scan_configuration_or(self, cve, cpe_or_node, name, and_enum):
cpe_list = '<or>|'
for cpe in cpe_or_node['cpe']:
@@ -128,207 +148,6 @@ class Command(BaseCommand):
cpe_list += '</or>|'
return cpe_list
- def nist_jason(self, dct):
- CVE_Items = dct['CVE_Items']
- total = len(CVE_Items)
- for i, CVE_Item in enumerate(CVE_Items):
- cve = CVE_Item['cve']
- references = cve['references']['reference_data']
- CVE_data_meta = cve['CVE_data_meta']['ID']
-
- # DEBUGGING SUPPORT !!! TODO
- scan = True
- status = Cve.NOT_VULNERABLE
- if (Command.debug_cve_count or len(debug_cve_list)) and not CVE_data_meta.startswith(Command.debug_include_id_prefix):
- scan = False
- if Command.debug_cve_count:
- if i < Command.debug_cve_count:
- scan = True
- if len(debug_cve_list):
- for debug_cve in debug_cve_list:
- if cve['CVE_data_meta']['ID'].startswith(debug_cve):
- scan = True
- status = Cve.INVESTIGATE
- if not scan:
- continue
-
- if False:
- print(" publishedDate: %s" % CVE_Item['publishedDate'])
- print(" lastModifiedDate: %s" % CVE_Item['lastModifiedDate'])
-
- print(" publishedDate: %s" % re.sub('T.*','',CVE_Item['publishedDate']))
- print(" lastModifiedDate: %s" % re.sub('T.*','',CVE_Item['lastModifiedDate']))
-
- print(" data_type: %s" % cve['data_type'])
- print(" data_format: %s" % cve['data_format'])
- print(" CVE_data_meta: %s" % cve['CVE_data_meta']['ID'])
- print(" problemtype: %s" % cve['problemtype']['problemtype_data'][0]['description'][0]['value'])
- print(" description: '%s'" % cve['description']['description_data'][0]['value'])
- references = cve['references']['reference_data']
- print(" References = %d" % len(references))
- for ref in references:
- print(" reference: %s" % ref['url'])
- if CVE_Item['impact'] and CVE_Item['impact']['baseMetricV3']:
- baseMetricV3 = CVE_Item['impact']['baseMetricV3']
- print(" cvssV3 : %s,%s" % (baseMetricV3['exploitabilityScore'],baseMetricV3['impactScore']))
- print(" vectorString = %s" % baseMetricV3['cvssV3']['vectorString'])
- print(" attackVector = %s" % baseMetricV3['cvssV3']['attackVector'])
- print(" attackComplexity = %s" % baseMetricV3['cvssV3']['attackComplexity'])
- print(" privilegesRequired = %s" % baseMetricV3['cvssV3']['privilegesRequired'])
- print(" userInteraction = %s" % baseMetricV3['cvssV3']['userInteraction'])
- print(" scope = %s" % baseMetricV3['cvssV3']['scope'])
- print(" confidentialityImpact = %s" % baseMetricV3['cvssV3']['confidentialityImpact'])
- print(" integrityImpact = %s" % baseMetricV3['cvssV3']['integrityImpact'])
- print(" availabilityImpact = %s" % baseMetricV3['cvssV3']['availabilityImpact'])
- print(" baseScore = %s" % baseMetricV3['cvssV3']['baseScore'])
- print(" baseSeverity = %s" % baseMetricV3['cvssV3']['baseSeverity'])
- if CVE_Item['impact'] and CVE_Item['impact']['baseMetricV2']:
- baseMetricV2 = CVE_Item['impact']['baseMetricV2']
- print(" cvssV2 : %s,%s" % (baseMetricV2['exploitabilityScore'],baseMetricV2['exploitabilityScore']))
- print(" vectorString = %s" % baseMetricV2['cvssV2']['vectorString'])
- print(" accessVector = %s" % baseMetricV2['cvssV2']['accessVector'])
- print(" accessComplexity = %s" % baseMetricV2['cvssV2']['accessComplexity'])
- print(" authentication = %s" % baseMetricV2['cvssV2']['authentication'])
- print(" confidentialityImpact = %s" % baseMetricV2['cvssV2']['confidentialityImpact'])
- print(" integrityImpact = %s" % baseMetricV2['cvssV2']['integrityImpact'])
- print(" availabilityImpact = %s" % baseMetricV2['cvssV2']['availabilityImpact'])
- print(" baseScore = %s" % baseMetricV2['cvssV2']['baseScore'])
- print(" severity = %s" % baseMetricV2['severity'])
-
- try:
- CVE_data_meta = cve['CVE_data_meta']['ID']
- v, created = Cve.objects.get_or_create(name=CVE_data_meta)
-
- v.name = CVE_data_meta
- v.source = 'NIST'
- status = Cve.NOT_VULNERABLE
-
- # Debugging support
-# if v.name.startswith("CVE-2018"):
-# status = Cve.NEW
-# v.status = status
- v.tags = ''
- v.tags_private = ''
-
- v.cve_data_type = cve['data_type']
- v.cve_data_format = cve['data_format']
- v.cve_data_version = cve['data_version']
-
- v.description = cve['description']['description_data'][0]['value']
- v.publishedDate = re.sub('T.*','',CVE_Item['publishedDate'])
- v.lastModifiedDate = re.sub('T.*','',CVE_Item['lastModifiedDate'])
-
- v.public = True
- v.publish = Cve.PUBLISH_PUBLISHED
- v.publish_date = v.publishedDate
-
- #v.problemtype = cve['problemtype']['problemtype_data'][0]['description'][0]['value']
- problem_list = cve['problemtype']['problemtype_data']
- CveToCwe.objects.filter(cve=v).delete()
- for problem_Item in problem_list:
- description_list = problem_Item['description']
- for description_Item in description_list:
- value = description_Item['value']
- cwe, created = CweTable.objects.get_or_create(name=value)
- if created:
- print("WARNING Missing CWE = '%s'"% value)
- cwe.save()
- cve2cwe, created = CveToCwe.objects.get_or_create(cve=v,cwe=cwe)
- if created:
- cve2cwe.save()
-
-# if CVE_Item['impact'] and CVE_Item['impact']['baseMetricV3']:
- if ('impact' in CVE_Item) and ('baseMetricV3' in CVE_Item['impact']):
- baseMetricV3 = CVE_Item['impact']['baseMetricV3']
- v.cvssV3_baseScore = baseMetricV3['cvssV3']['baseScore']
- v.cvssV3_baseSeverity = baseMetricV3['cvssV3']['baseSeverity']
- v.cvssV3_vectorString = baseMetricV3['cvssV3']['vectorString']
- v.cvssV3_exploitabilityScore = baseMetricV3['exploitabilityScore']
- v.cvssV3_impactScore = baseMetricV3['impactScore']
- v.cvssV3_attackVector = baseMetricV3['cvssV3']['attackVector']
- v.cvssV3_attackComplexity = baseMetricV3['cvssV3']['attackComplexity']
- v.cvssV3_privilegesRequired = baseMetricV3['cvssV3']['privilegesRequired']
- v.cvssV3_userInteraction = baseMetricV3['cvssV3']['userInteraction']
- v.cvssV3_scope = baseMetricV3['cvssV3']['scope']
- v.cvssV3_confidentialityImpact = baseMetricV3['cvssV3']['confidentialityImpact']
- v.cvssV3_integrityImpact = baseMetricV3['cvssV3']['integrityImpact']
- v.cvssV3_availabilityImpact = baseMetricV3['cvssV3']['availabilityImpact']
- if ('impact' in CVE_Item) and ('baseMetricV2' in CVE_Item['impact']):
- baseMetricV2 = CVE_Item['impact']['baseMetricV2']
- v.cvssV2_baseScore = baseMetricV2['cvssV2']['baseScore']
- v.cvssV2_severity = baseMetricV2['severity']
- v.cvssV2_vectorString = baseMetricV2['cvssV2']['vectorString']
- v.cvssV2_exploitabilityScore = baseMetricV2['exploitabilityScore']
- v.cvssV2_impactScore = baseMetricV2['exploitabilityScore']
- v.cvssV2_accessVector = baseMetricV2['cvssV2']['accessVector']
- v.cvssV2_accessComplexity = baseMetricV2['cvssV2']['accessComplexity']
- v.cvssV2_authentication = baseMetricV2['cvssV2']['authentication']
- v.cvssV2_confidentialityImpact = baseMetricV2['cvssV2']['confidentialityImpact']
- v.cvssV2_integrityImpact = baseMetricV2['cvssV2']['integrityImpact']
-
-## v.save()
-
- CveReference.objects.filter(cve=v).delete()
- for ref in references:
- r, created = CveReference.objects.get_or_create(cve=v,
- hyperlink=ref['url'])
- r.resource = ''
- r.type = ''
- r.source = ''
- r.name = ''
- r.save()
-# print(" reference: %s,%s" % (ref['url'],created))
-
-
- configurations = CVE_Item['configurations']
- v.cpe_list = ''
- is_first_and = True
- for i, config in enumerate(configurations['nodes']):
- v.cpe_list += '<config>|'
- v.cpe_list += '<and>|'
- if "AND" == config['operator']:
- # create AND record
- if not is_first_and:
- v.cpe_list += '</and>|'
- v.cpe_list += '<and>|'
- for j, cpe_or_node in enumerate(config['children']):
- if "OR" == cpe_or_node['operator']:
- v.cpe_list += self.nist_scan_configuration_or(v,cpe_or_node, CVE_data_meta, j)
- else:
- print("ERROR CONFIGURE:OR_OP?:%s" % cpe_or_node['operator'])
- elif "OR" == config['operator']:
- v.cpe_list += self.nist_scan_configuration_or(v,config, CVE_data_meta, 0)
- else:
- print("ERROR CONFIGURE:OP?:%s" % config_rec['operator'])
- v.cpe_list += '</and>|'
- v.cpe_list += '</config>|'
-
-# # create a parent CveSet if needed
-# cve_set, created = CveSet.objects.get_or_create(name=v.name)
-# if created:
-# cve_set.name = v.name
-# cve_set.description = v.description
-# cve_set.cvssV3_baseScore = v.cvssV3_baseScore
-# cve_set.cvssV3_baseSeverity = v.cvssV3_baseSeverity
-# cve_set.publishedDate = v.publishedDate
-# cve_set.lastModifiedDate = v.lastModifiedDate
-# cve_set.save()
-#
-# # connect the Cve with the CveSet
-# cve2cveset, created = CveToCveSet.objects.get_or_create(cve=v, cveset=cve_set)
-# cve2cveset.save()
-
- # save the final CVE content
- v.recommend = v.recommendation()
- v.save()
-
- except Exception as e:
- logger.warning("Failed saving CVE %s (%s)", (cve['CVE_data_meta']['ID'],e))
- return
-
- self.mini_progress("CVE's", i, total)
-
-
def nist_cwe(self, content):
# <td nowrap><span id="cweIdEntry-CWE-123">CWE-123</span></td>
# <td nowrap><a href="http://cwe.mitre.org/data/definitions/123.html" target="_blank"> Write-what-where Condition</a></td>
@@ -473,7 +292,8 @@ class Command(BaseCommand):
# print("[%d]cpe23Uri=%s,%s" % (i,company,product))
- def cve_keywords_old(self, csvfile_name):
+ # Obsolete (slow) table-based keyword management
+ def cve_keywords_table(self, csvfile_name):
# mode,type,keyword,weight
# y,key,abiword,
@@ -566,26 +386,6 @@ class Command(BaseCommand):
setting = SrtSetting.objects.get_or_create(name='keywords_against')[0]
setting.value = keywords_against[1:]
setting.save()
-
- S = SrtSetting.objects.get(name='keywords_for')
- #print("FOO_FOR:[%s]='%s'" % (S.name,S.value[0:30]))
- S = SrtSetting.objects.get(name='keywords_against')
- #print("FOO_NOT:[%s]='%s'" % (S.name,S.value[0:30]))
-
-
- def debug_set_cve(self,key,public,vulnerability,comments,comments_private):
- try:
- c = Cve.objects.get(name=key)
- c.public = public
- c.comments = comments
- c.comments_private = comments_private
- c.save()
- if vulnerability:
- v = Vulnerability.objects.get(name=vulnerability)
- cv, created = CveToVulnerablility.objects.get_or_create(vulnerability=v,cve=c)
- cv.save()
- except ObjectDoesNotExist:
- print("Cve %s not found" % key)
def update(self):
"""
@@ -607,11 +407,11 @@ class Command(BaseCommand):
if source.loaded:
logger.info("Skipping source data from %s",source.file_path)
- print("Skipping CVE data for %s (already loaded)" % (source.description))
+ print("Skipping CVE data from %s (already loaded)" % (source.description))
continue
else:
- logger.info("Fetching source data from %s",source.file_path)
- print("Fetching source data for '%s'" % (source.description))
+ logger.info("Fetching source data from %s:%s" % (source.source,source.file_path))
+ print("Fetching source data from '%s:%s:%s'" % (source.source,source.description,source.file_path))
file_path = source.file_path
url_path = source.url
@@ -619,14 +419,17 @@ class Command(BaseCommand):
root = None
content = None
source_doc = None
- # prefer the file path before the url
- if file_path:
+ # precedence: (1) script, (2) local file path, (3) url
+ if 'script' == source.type:
+ if not source.command:
+ # no script to run
+ logger.error("Data source is script but no script provided '%s'" % (source.description))
+ continue
+ elif file_path:
# load the file
source_doc = source.file_path
if not source.file_path.startswith('/'):
file_path = os.path.join(os.getenv('SRT_BASE_DIR'), source.file_path)
- source.loaded = True
- source.save()
if not os.path.isfile(file_path):
logger.error("Data file not found '%s'" % (file_path))
continue
@@ -643,7 +446,7 @@ class Command(BaseCommand):
content = text_data.read()
elif url_path:
# load the HTML page
- source_doc = source.url
+ href = source.url
try:
f = urlopen(href)
content = f.read().decode('UTF-8')
@@ -653,66 +456,64 @@ class Command(BaseCommand):
continue
else:
# no data source path to load
- logger.error("Unknown data source path for '%s' (%s,%s) " % (source.source.description,source.file_path,source.url))
+ logger.error("Unknown data source path for '%s' (%s,%s,%s) " % (source.description,source.type,source.file_path,source.url))
continue
# testing shortcut
- if ('nist' == source.source) and ('yes' == SrtSetting.objects.get(name='TEST_SKIP_NIST_IMPORT').value):
+ if ('cve' == source.data) and ('yes' == SrtSetting.objects.get(name='SRTDBG_SKIP_CVE_IMPORT').value):
+ continue
+ if ('cpe' == source.data) and ('yes' == SrtSetting.objects.get(name='SRTDBG_SKIP_CPE_IMPORT').value):
+ continue
+ if ('defect' == source.data) and ('yes' == SrtSetting.objects.get(name='SRTDBG_SKIP_DEFECT_IMPORT').value):
continue
-
+
+ # Script-based update?
+ if 'script' == source.type and source.command:
+ # do not perform backups for brand new databases
+ if source.data in ['backup_weekly','backup_daily']:
+ pass
+ else:
+ self.execute_script(source.command)
+ self.source_loaded(source.id,False)
+ continue
+
# Common data sources
if 'common' == source.source:
if 'triage_keywords' == source.data:
self.cve_keywords(csvfile_name)
- source.loaded = True
- source.save()
+ self.source_loaded(source.id)
continue
# Common Vulnerabilities and Exposures
- if 'cve' == source.data:
- if 'nist' == source.source and 'json' == source.type:
- self.nist_jason(dct)
- source.loaded = True
- source.save()
- continue
+ # Handled by "srtool_cve.py"
+
# Common Weakness Enumeration
if 'cwe' == source.data:
if 'nist' == source.source and 'html' == source.type:
self.nist_cwe(content)
- source.loaded = True
- source.save()
+ self.source_loaded(source.id)
continue
# Common Product Enumeration
if 'cpe' == source.data:
if 'nist' == source.source and 'xml' == source.type:
self.nist_cpe(root)
- source.loaded = True
- source.save()
+ self.source_loaded(source.id)
continue
if 'nist' == source.source and 'csv' == source.type:
self.nist_cpe_csv(csvfile_name)
- source.loaded = True
- source.save()
+ self.source_loaded(source.id)
continue
-
# data source not handled
logger.error("Unknown data source type for '%s' (%s,%s,%s) " % (source.file_path,source.data,source.source,source.type))
- # TEST DEBUG
-# self.debug_set_cve('CVE-2017-0002',False,'','','')
-# self.debug_set_cve('CVE-2017-0010',False,'','','')
- self.debug_set_cve('CVE-2017-5753',True,'V0000','Spectre Variant 1: Bounds check bypass','community calling this "spectre"')
- self.debug_set_cve('CVE-2017-5715',True,'V0000','Spectre Variant 2: Branch target injection','see if this will required compiler changes')
- self.debug_set_cve('CVE-2017-5754',True,'V0000','Meltdown: Rogue data cache load, memory access permission check performed after kernel memory read','mostly for Intel parts')
-
os.system('setterm -cursor on')
def handle(self, **options):
# testing shortcuts
- if 'yes' == SrtSetting.objects.get(name='TEST_MINIMAL_DB').value:
+ if 'yes' == SrtSetting.objects.get(name='SRTDBG_MINIMAL_DB').value:
print("TEST: MINIMAL DATABASE LOADING")
Command.debug_cve_count = 10 # 0 for any
Command.debug_include_id_prefix = 'XXX' # always include CVEs with this prefix
diff --git a/lib/orm/migrations/0001_initial.py b/lib/orm/migrations/0001_initial.py
index 6d8b9472..764b27df 100644
--- a/lib/orm/migrations/0001_initial.py
+++ b/lib/orm/migrations/0001_initial.py
@@ -42,6 +42,11 @@ class Migration(migrations.Migration):
('file_path', models.FilePathField()),
('url', models.TextField(blank=True)),
('loaded', models.BooleanField(default=False)),
+ ('meta_url', models.TextField(blank=True)),
+ ('lastModifiedDate', models.CharField(max_length=50, blank=True)),
+ ('update_frequency', models.IntegerField(default=2)),
+ ('update_time', models.CharField(max_length=50, blank=True)),
+ ('command', models.TextField(blank=True)),
],
),
@@ -58,14 +63,17 @@ class Migration(migrations.Migration):
('found', models.BooleanField(default=False)),
],
),
+
migrations.CreateModel(
name='Cve',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=50)),
- ('source', models.CharField(max_length=50)),
+ ('datasource', models.ForeignKey(default=None, to='orm.datasource',null=True)),
+ ('source', models.CharField(max_length=50)),
+ ('priority', models.IntegerField(default=0)),
('status', models.IntegerField(default=0)),
('comments', models.TextField(blank=True)),
('comments_private', models.TextField(blank=True)),
@@ -75,44 +83,21 @@ class Migration(migrations.Migration):
('cve_data_version', models.CharField(max_length=50, blank=True)),
('public', models.BooleanField(default=False)),
- ('publish', models.IntegerField(default=0)),
+ ('publish_state', models.IntegerField(default=0)),
('publish_date', models.CharField(max_length=50, blank=True)),
('description', models.TextField(blank=True)),
('publishedDate', models.CharField(max_length=50, blank=True)),
('lastModifiedDate', models.CharField(max_length=50, blank=True)),
-# ('problemtype', models.CharField(max_length=40, blank=True)),
-# ('problemtype', models.ForeignKey(CweTable, related_name='cwe')),
-
('recommend', models.IntegerField(default=0)),
-
- ('cpe_list', models.TextField(blank=True)),
+ ('recommend_list', models.TextField(blank=True)),
('cvssV3_baseScore', models.CharField(max_length=50, blank=True)),
('cvssV3_baseSeverity', models.CharField(max_length=50, blank=True)),
- ('cvssV3_vectorString', models.TextField(blank=True)),
- ('cvssV3_exploitabilityScore', models.CharField(max_length=50, blank=True)),
- ('cvssV3_impactScore', models.CharField(max_length=50, blank=True)),
- ('cvssV3_attackVector', models.CharField(max_length=5, blank=True)),
- ('cvssV3_attackComplexity', models.CharField(max_length=50, blank=True)),
- ('cvssV3_privilegesRequired', models.CharField(max_length=50, blank=True)),
- ('cvssV3_userInteraction', models.CharField(max_length=50, blank=True)),
- ('cvssV3_scope', models.CharField(max_length=50, blank=True)),
- ('cvssV3_confidentialityImpact', models.CharField(max_length=50, blank=True)),
- ('cvssV3_integrityImpact', models.CharField(max_length=50, blank=True)),
- ('cvssV3_availabilityImpact', models.CharField(max_length=50, blank=True)),
('cvssV2_baseScore',models.CharField(max_length=50, blank=True)),
('cvssV2_severity', models.CharField(max_length=50, blank=True)),
- ('cvssV2_vectorString', models.TextField(blank=True)),
- ('cvssV2_exploitabilityScore', models.CharField(max_length=50, blank=True)),
- ('cvssV2_impactScore', models.CharField(max_length=50, blank=True)),
- ('cvssV2_accessVector', models.CharField(max_length=50, blank=True)),
- ('cvssV2_accessComplexity', models.CharField(max_length=50, blank=True)),
- ('cvssV2_authentication', models.CharField(max_length=50, blank=True)),
- ('cvssV2_confidentialityImpact', models.CharField(max_length=50, blank=True)),
- ('cvssV2_integrityImpact', models.CharField(max_length=50, blank=True)),
],
),
@@ -190,11 +175,11 @@ class Migration(migrations.Migration):
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=50)),
- ('description', models.TextField(blank=True)),
- ('cve_primary_name', models.CharField(max_length=50)),
+ ('description', models.TextField(blank=True, default='')),
+ ('cve_primary_name', models.CharField(max_length=50, default='')),
('public', models.BooleanField(default=False)),
- ('comments', models.TextField(blank=True)),
- ('comments_private', models.TextField(blank=True)),
+ ('comments', models.TextField(blank=True, default='')),
+ ('comments_private', models.TextField(blank=True, default='')),
('status', models.IntegerField(default=0)),
('outcome', models.IntegerField(default=0)),
('severity', models.IntegerField(default=0)),
@@ -251,10 +236,11 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=50)),
('summary', models.TextField(blank=True)),
+ ('url', models.TextField(blank=True)),
('priority', models.IntegerField(default=0)),
('status', models.IntegerField(default=0)),
('resolution', models.IntegerField(default=0)),
- ('publishOLS', models.TextField(blank=True)),
+ ('publish', models.TextField(blank=True)),
('release_version', models.CharField(max_length=50)),
('product', models.ForeignKey(default=None, to='orm.product', null=True)),
('date_created', models.CharField(max_length=50)),
@@ -421,13 +407,15 @@ class Migration(migrations.Migration):
],
),
-# migrations.AddField(
-# model_name='project',
-# name='release',
-# field=models.ForeignKey(to='orm.Release', null=True),
-# ),
-# migrations.AlterUniqueTogether(
-# name='layersource',
-# unique_together=set([('sourcetype', 'apiurl')]),
-# ),
+ migrations.CreateModel(
+ name='PublishPending',
+ fields=[
+ ('cve', models.ForeignKey(default=None, to='orm.cve',blank=True,null=True)),
+ ('vulnerability', models.ForeignKey(default=None, to='orm.vulnerability',blank=True,null=True)),
+ ('investigation', models.ForeignKey(default=None, to='orm.investigation',blank=True,null=True)),
+ ('date', models.DateField(null=True, blank=True)),
+ ('note', models.TextField()),
+ ],
+ ),
+
]
diff --git a/lib/orm/models.py b/lib/orm/models.py
index 3a4a39a7..0d287bb4 100644
--- a/lib/orm/models.py
+++ b/lib/orm/models.py
@@ -42,10 +42,8 @@ from signal import SIGUSR1
import logging
logger = logging.getLogger("srt")
-def _log(msg):
- f1=open('/tmp/srt.log', 'a')
- f1.write("|" + msg + "|\n" )
- f1.close()
+# quick development/debugging support
+from srtgui.api import _log
# Sqlite support
@@ -127,7 +125,6 @@ class SrtSetting(models.Model):
def __unicode__(self):
return "Setting %s = %s" % (self.name, self.value)
-
class HelpText(models.Model):
VARIABLE = 0
HELPTEXT_AREA = ((VARIABLE, 'variable'), )
@@ -136,7 +133,25 @@ class HelpText(models.Model):
key = models.CharField(max_length=100)
text = models.TextField()
+
+#UPDATE_FREQUENCY: 0 = every minute, 1 = every hour, 2 = every day, 3 = every week, 4 = every month, 5 = every year
class DataSource(models.Model):
+ #UPDATE FREQUENCT
+ MINUTELY = 0
+ HOURLY = 1
+ DAILY = 2
+ WEEKLY = 3
+ MONTHLY = 4
+ ONDEMAND = 5
+ FREQUENCY = (
+ (MINUTELY, 'New'),
+ (HOURLY, 'Hourly'),
+ (DAILY, 'Daily'),
+ (WEEKLY, 'Weekly'),
+ (MONTHLY, 'Monthly'),
+ (ONDEMAND, 'OnDemand'),
+ )
+
data = models.CharField(max_length=20)
source = models.CharField(max_length=20)
type = models.CharField(max_length=20)
@@ -144,6 +159,15 @@ class DataSource(models.Model):
file_path = models.FilePathField()
url = models.TextField(blank=True)
loaded = models.BooleanField(default=False)
+ meta_url = models.TextField(blank=True)
+ lastModifiedDate = models.CharField(max_length=50, blank=True)
+ update_frequency = models.IntegerField(choices=FREQUENCY, default=DAILY)
+ update_time = models.CharField(max_length=50, blank=True)
+ command = models.TextField(blank=True)
+
+
+ def get_frequency_text(self):
+ return DataSource.FREQUENCY[int(self.update_frequency)][1]
class CweTable(models.Model):
search_allowed_fields = ['name', 'href', 'description', 'summary']
@@ -155,9 +179,25 @@ class CweTable(models.Model):
vulnerable_count = models.IntegerField(default=0)
found = models.BooleanField(default=False)
+
class Cve(models.Model):
search_allowed_fields = ['name', 'description', 'publishedDate',
'lastModifiedDate', 'comments', 'comments_private']
+
+ # SRTool Priority
+ UNDEFINED = 0
+ MINOR = 1
+ LOW = 2
+ MEDIUM = 3
+ HIGH = 4
+ PRIORITY = (
+ (UNDEFINED, ''),
+ (MINOR, 'Minor'),
+ (LOW, 'Low'),
+ (MEDIUM, 'Medium'),
+ (HIGH, 'High'),
+ )
+
# WR Status
NEW = 0
INVESTIGATE = 1
@@ -170,18 +210,20 @@ class Cve(models.Model):
(NOT_VULNERABLE, 'Not Vulnerable'),
)
- # Publish options
- PUBLISH_UNDEF = 0
- PUBLISH_AUTO = 1
- PUBLISH_REQUEST = 2
- PUBLISH_PUBLISHED = 3
- PUBLISH_NOPUBLISH = 4
- PUBLISH = (
- (PUBLISH_UNDEF, 'Undetermined'),
- (PUBLISH_AUTO, 'Automatic Publish Date'),
- (PUBLISH_REQUEST, 'Request Publish Date'),
+ # Publish state
+ PUBLISH_UNPUBLISHED = 0
+ PUBLISH_NOPUBLISH = 1
+ PUBLISH_PUBLISHED = 2
+ PUBLISH_REQUEST = 3
+ PUBLISH_UPDATE = 4
+ PUBLISH_SUBMITTED = 5
+ PUBLISH_STATE = (
+ (PUBLISH_UNPUBLISHED, 'Unpublished'),
+ (PUBLISH_NOPUBLISH, 'Not to be Published'),
(PUBLISH_PUBLISHED, 'Published'),
- (PUBLISH_NOPUBLISH, 'Do Not Published'),
+ (PUBLISH_REQUEST, 'Publish Request (New)'),
+ (PUBLISH_UPDATE, 'Publish Request (Update)'),
+ (PUBLISH_SUBMITTED, 'Publish Submitted'),
)
# CPE item list
@@ -193,69 +235,44 @@ class Cve(models.Model):
name = models.CharField(max_length=50)
source = models.CharField(max_length=50)
+ datasource = models.ForeignKey(DataSource,related_name="cve_datasource")
+ priority = models.IntegerField(default=0)
status = models.IntegerField(choices=STATUS, default=NEW)
comments = models.TextField(blank=True)
comments_private = models.TextField(blank=True)
-
+
cve_data_type = models.CharField(max_length=100, blank=True)
cve_data_format = models.CharField(max_length=50, blank=True)
cve_data_version = models.CharField(max_length=50, blank=True)
public = models.BooleanField(default=True)
- publish = models.IntegerField(choices=PUBLISH, default=PUBLISH_UNDEF)
+ publish_state = models.IntegerField(choices=PUBLISH_STATE, default=PUBLISH_UNPUBLISHED)
publish_date = models.CharField(max_length=50, blank=True)
description = models.TextField(blank=True)
publishedDate = models.CharField(max_length=50, blank=True)
lastModifiedDate = models.CharField(max_length=50, blank=True)
-# problemtype = models.CharField(max_length=40, blank=True)
-# problemtype = models.ForeignKey(CweTable, related_name='cwe')
recommend = models.IntegerField(default=0)
-
- cpe_list= models.TextField(blank=True)
+ recommend_list = models.TextField(blank=True)
cvssV3_baseScore = models.CharField(max_length=50, blank=True)
cvssV3_baseSeverity = models.CharField(max_length=50, blank=True)
- cvssV3_vectorString = models.TextField(blank=True)
- cvssV3_exploitabilityScore = models.CharField(max_length=50, blank=True)
- cvssV3_impactScore = models.CharField(max_length=50, blank=True)
- cvssV3_attackVector = models.CharField(max_length=50, blank=True)
- cvssV3_attackComplexity = models.CharField(max_length=50, blank=True)
- cvssV3_privilegesRequired = models.CharField(max_length=50, blank=True)
- cvssV3_userInteraction = models.CharField(max_length=50, blank=True)
- cvssV3_scope = models.CharField(max_length=50, blank=True)
- cvssV3_confidentialityImpact = models.CharField(max_length=50, blank=True)
- cvssV3_integrityImpact = models.CharField(max_length=50, blank=True)
- cvssV3_availabilityImpact = models.CharField(max_length=50, blank=True)
cvssV2_baseScore = models.CharField(max_length=50, blank=True)
cvssV2_severity = models.CharField(max_length=50, blank=True)
- cvssV2_vectorString = models.TextField(blank=True)
- cvssV2_exploitabilityScore = models.CharField(max_length=50, blank=True)
- cvssV2_impactScore = models.CharField(max_length=50, blank=True)
- cvssV2_accessVector = models.CharField(max_length=50, blank=True)
- cvssV2_accessComplexity = models.CharField(max_length=50, blank=True)
- cvssV2_authentication = models.CharField(max_length=50, blank=True)
- cvssV2_confidentialityImpact = models.CharField(max_length=50, blank=True)
- cvssV2_integrityImpact = models.CharField(max_length=50, blank=True)
class Meta:
unique_together = ('name', 'source' )
@property
- def problemtype_summary(self):
- """ Return the summary of the CWE """
- summary = '?'
- try:
- r = CweTable.objects.get(name=self.problemtype)
- summary = r.summary
- except Exception as e:
- logger.warning("ERROR: could not find CWE %s" % self.problemtype)
- return summary
+ def get_priority_text(self):
+ return Cve.PRIORITY[int(self.priority)][1]
+ @property
def get_publish_text(self):
- return Cve.PUBLISH[int(self.publish)][1]
+ return Cve.PUBLISH_STATE[int(self.publish_state)][1]
+ @property
def get_status_text(self):
return Cve.STATUS[int(self.status)][1]
def get_cpe_list(self):
@@ -264,31 +281,54 @@ class Cve(models.Model):
cpe_array.append(cpe.split(','))
return cpe_array
- FOR_LIST = ['linux','openjpeg','libtiff','libav','tcp','binutil ','ssl','ssh','glibc']
- AGAINST_LIST = ['cisco','microsoft','windows','ibm','oracle','sun','java','peoplesoft','hancom','zyxel','wordpress','sugarcrm','cobham',
- 'juniper']
-
- def recommendation(self):
- recommendation = 0
- for s in Cve.FOR_LIST:
- if 0 <= self.description.lower().find(s):
- recommendation += 1
- for s in Cve.AGAINST_LIST:
- if 0 <= self.description.lower().find(s):
- recommendation -= 1
- return recommendation
- def reasons_for(self):
- reason = ''
- for s in Cve.FOR_LIST:
- if 0 <= self.description.lower().find(s):
- reason += '%s ' % s
- return reason
- def reasons_against(self):
- reason = ''
- for s in Cve.AGAINST_LIST:
- if 0 <= self.description.lower().find(s):
- reason += '%s ' % s
- return reason
+
+class CveDetail():
+ # CPE item list
+ CPE_LIST_KEY = 0 # entry is <[/]component|and|or> tag or '|' delimited list
+ CPE_LIST_VULNERABLE = 0
+ CPE_LIST_CPE23 = 1
+ CPE_LIST_CPE22 = 2
+ CPE_LIST_VERSIONEND = 3
+
+ name = ''
+# problemtype = ''
+
+ recommend = ''
+ recommend_list = ''
+
+ cpe_list= ''
+
+ cvssV3_baseScore = ''
+ cvssV3_baseSeverity = ''
+ cvssV3_vectorString = ''
+ cvssV3_exploitabilityScore = ''
+ cvssV3_impactScore = ''
+ cvssV3_attackVector = ''
+ cvssV3_attackComplexity = ''
+ cvssV3_privilegesRequired = ''
+ cvssV3_userInteraction = ''
+ cvssV3_scope = ''
+ cvssV3_confidentialityImpact = ''
+ cvssV3_integrityImpact = ''
+ cvssV3_availabilityImpact = ''
+
+ cvssV2_baseScore = ''
+ cvssV2_severity = ''
+ cvssV2_vectorString = ''
+ cvssV2_exploitabilityScore = ''
+ cvssV2_impactScore = ''
+ cvssV2_accessVector = ''
+ cvssV2_accessComplexity = ''
+ cvssV2_authentication = ''
+ cvssV2_confidentialityImpact = ''
+ cvssV2_integrityImpact = ''
+
+ def get_cpe_list(self):
+ cpe_array = []
+ for cpe in self.cpe_list.split('|'):
+ cpe_array.append(cpe.split(','))
+ return cpe_array
+
# Same CVE from multiple sources and/or revisions
class CveSet(models.Model):
@@ -319,7 +359,7 @@ class CpeTable(models.Model):
cpeMatchString = models.TextField(blank=True)
cpe23Uri = models.TextField(blank=True)
versionEndIncluding = models.TextField(blank=True)
-
+
class CpeToCve(models.Model):
cpe = models.ForeignKey(CpeTable,related_name="cpe2cve")
cve = models.ForeignKey(Cve,related_name="cve2cpe")
@@ -353,7 +393,7 @@ class CpeFilter(models.Model):
@property
def get_status_text(self):
return CpeFilter.STATUS[int(self.status)][1]
-
+
# CVE/CWE Mapping
@@ -373,6 +413,8 @@ class CveReference(models.Model):
# PRODUCT
class Product(models.Model):
+ search_allowed_fields = ['name', 'version', 'profile']
+
name = models.CharField(max_length=40)
version = models.CharField(max_length=40)
profile = models.CharField(max_length=40)
@@ -382,13 +424,14 @@ class Product(models.Model):
class Meta:
unique_together = ('name', 'version', 'profile', )
+ @property
def long_name(self):
return '%s %s %s' % (self.name,self.version,self.profile)
# VULNERABILITY
-# Company-level Vulnerablility Record
+# Company-level Vulnerablility Record
class Vulnerability(models.Model):
search_allowed_fields = ['name', 'comments', 'comments_private']
@@ -410,22 +453,27 @@ class Vulnerability(models.Model):
(FIXED, 'Closed (Fixed)'),
(NOT_FIX, "Closed (Won't Fix)"),
)
- LOW = 0
- MEDIUM = 1
- HIGH = 2
+ # SRTool Severity, matched with Cve/Defect Priority with placeholder for 'minor'
+ UNDEFINED = 0
+ MINOR = 1
+ LOW = 2
+ MEDIUM = 3
+ HIGH = 4
SEVERITY = (
+ (UNDEFINED, ''),
+ (MINOR, 'Minor'),
(LOW, 'Low'),
(MEDIUM, 'Medium'),
(HIGH, 'High'),
)
name = models.CharField(max_length=50)
- cve_primary_name = models.CharField(max_length=50)
- description = models.TextField(blank=True)
+ cve_primary_name = models.CharField(max_length=50, default='')
+ description = models.TextField(blank=True, default='')
- public = models.BooleanField(default=False)
- comments = models.TextField(blank=True)
- comments_private = models.TextField(blank=True)
+ public = models.BooleanField(default=True)
+ comments = models.TextField(blank=True, default='')
+ comments_private = models.TextField(blank=True, default='')
status = models.IntegerField(choices=STATUS, default=INVESTIGATE)
outcome = models.IntegerField(choices=OUTCOME, default=OPEN)
@@ -485,7 +533,7 @@ class Vulnerability(models.Model):
except IntegrityError:
print("Error in new_vulnerability_name")
raise
- return "V%04d" % index
+ return "V%05d" % index
class VulnerabilityComments(models.Model):
vulnerability = models.ForeignKey(Vulnerability,related_name="vulnerability_comments")
@@ -513,7 +561,7 @@ class CveToVulnerablility(models.Model):
# Defects
-# Defect Record
+# Defect Record
class Defect(models.Model):
search_allowed_fields = ['name', 'summary', 'release_version'] #, 'product']
@@ -521,11 +569,13 @@ class Defect(models.Model):
#Issue Type,Key,Summary,Priority,Status,Resolution,Publish To OLS,Fix Version
#Bug,LIN10-2031,Security Advisory - libvorbis - CVE-2017-14633,P3,Closed,Fixed,Reviewed - Publish,10.17.41.3
- MINOR = 0
- LOW = 1
- MEDIUM = 2
- HIGH = 3
+ NONE = 0
+ MINOR = 1
+ LOW = 2
+ MEDIUM = 3
+ HIGH = 4
Priority = (
+ (NONE, 'None'),
(MINOR, 'P4'),
(LOW, 'P3'),
(MEDIUM, 'P2'),
@@ -546,35 +596,49 @@ class Defect(models.Model):
(CLOSED, 'Closed'),
)
UNRESOLVED = 0
- FIXED = 1
- WILL_NOT_FIX = 2
- WITHDRAWN = 3
- REJECTED = 4
- DUPLICATE = 5
+ RESOLVED = 1
+ FIXED = 2
+ WILL_NOT_FIX = 3
+ WITHDRAWN = 4
+ REJECTED = 5
+ DUPLICATE = 6
+ NOT_APPLICABLE = 7
+ REPLACED_BY_REQUIREMENT = 8
+ CANNOT_REPRODUCE = 9
+ DONE = 10
Resolution = (
(UNRESOLVED, 'Unresolved'),
+ (RESOLVED, 'Resolved'),
(FIXED, 'Fixed'),
(WILL_NOT_FIX, 'Won\'t Fix'),
(WITHDRAWN, 'Withdrawn'),
(REJECTED, 'Rejected'),
(DUPLICATE, 'Duplicate'),
+ (NOT_APPLICABLE, 'Not Applicable'),
+ (REPLACED_BY_REQUIREMENT, 'Replaced By Requirement'),
+ (CANNOT_REPRODUCE, 'Cannot Reproduce'),
+ (DONE, 'Done'),
)
name = models.CharField(max_length=50)
summary = models.TextField(blank=True)
+ url = models.TextField(blank=True)
priority = models.IntegerField(choices=Priority, default=MINOR)
status = models.IntegerField(choices=Status, default=OPEN)
resolution = models.IntegerField(choices=Resolution, default=UNRESOLVED)
- publishOLS = models.TextField(blank=True)
+ publish = models.TextField(blank=True)
release_version = models.CharField(max_length=50)
product = models.ForeignKey(Product,related_name="product_defect")
date_created = models.CharField(max_length=50)
date_updated = models.CharField(max_length=50)
# Methods
+ @property
def get_priority_text(self):
return Defect.Priority[int(self.priority)][1]
+ @property
def get_status_text(self):
return Defect.Status[int(self.status)][1]
+ @property
def get_resolution_text(self):
return Defect.Resolution[int(self.resolution)][1]
def get_long_name(self):
@@ -585,7 +649,7 @@ class Defect(models.Model):
# INVESTIGATION
-# Product-level Vulnerablility Investigation Record
+# Product-level Vulnerablility Investigation Record
class Investigation(models.Model):
search_allowed_fields = ['name', 'comments', 'comments_private']
@@ -607,10 +671,15 @@ class Investigation(models.Model):
(FIXED, 'Fixed'),
(NOT_FIX, "Won't Fix"),
)
- LOW = 0
- MEDIUM = 1
- HIGH = 2
+ # SRTool Severity, matched with Cve/Defect Priority with placeholder for 'minor'
+ UNDEFINED = 0
+ MINOR = 1
+ LOW = 2
+ MEDIUM = 3
+ HIGH = 4
SEVERITY = (
+ (UNDEFINED, ''),
+ (MINOR, 'Minor'),
(LOW, 'Low'),
(MEDIUM, 'Medium'),
(HIGH, 'High'),
@@ -650,7 +719,7 @@ class Investigation(models.Model):
index = int(current_investigation_index.value) + 1
current_investigation_index.value = str(index)
current_investigation_index.save()
- return "I%04d" % index
+ return "I%05d" % index
class InvestigationToDefect(models.Model):
investigation = models.ForeignKey(Investigation,related_name="investigation_to_defect")
@@ -700,7 +769,7 @@ class User(models.Model):
# the default guest user account is ID=1
USER_GUEST = 1
- # Access model
+ # Access model
READER = 0
CONTRIBUTOR = 1
CREATOR = 2
@@ -720,6 +789,32 @@ class User(models.Model):
def get_access_text(self):
return User.ACCESS[int(self.access)][1]
+ @property
+ def builtin(self):
+ return( ('Guest' == self.name) or ('SRTool' == self.name))
+
+# Minimal and safe User object to pass to web pages (no passwords)
+class UserSafe():
+ def __init__(self, pk, name, email):
+ self.pk = pk
+ self.name = name
+ self.email = email
+
+ def __str__(self):
+ return "UserSafeStr=%d,%s,%s" % (self.pk, self.name, self.email)
+
+ @staticmethod
+ def get_safe_userlist(allow_assignment=True):
+ user_list = []
+ for user in User.objects.all():
+ if 'SRTool' == user.name:
+ continue
+ if allow_assignment and ('Guest' == user.name):
+ continue
+ u = UserSafe(user.id,user.name,user.email)
+ user_list.append(u)
+ return user_list
+
class VulnerabilityAccess(models.Model):
vulnerability = models.ForeignKey(Vulnerability,related_name="vulnerability_users")
user = models.ForeignKey(User,related_name="vulnerability_user")
@@ -759,47 +854,59 @@ class Keywords(models.Model):
def get_keytype_text(self):
return Keywords.KeyType[int(self.key_type)][1]
-
-
-# ====
+# Items waiting for SRTool external publishing
+class PublishPending(models.Model):
+ cve = models.ForeignKey(Cve,related_name="publish_pending_cves",blank=True,null=True)
+ vulnerability = models.ForeignKey(Vulnerability,related_name="publish_pending_vulnerabilities",blank=True,null=True)
+ investigation = models.ForeignKey(Investigation,related_name="publish_pending_investigations",blank=True,null=True)
+ date = models.DateField(null=True, blank=True)
+ note = models.TextField(blank=True)
+
+# ==== Support clases, meta classes ====
+
+def _log_args(msg, *args, **kwargs):
+ s = '%s:(' % msg
+ if args:
+ for a in args:
+ s += '%s,' % a
+ s += '),('
+ if kwargs:
+ for key, value in kwargs.iteritems():
+ s += '(%s=%s),' % (key,value)
+ s += ')'
+ _log(s)
class Access():
# default user is "Guest"
-
- def read_values(self):
- v, created = SrtSetting.objects.get_or_create(name='current_user')
- if created:
- v.value = User.USER_GUEST
- v.save()
- self.current_user = int(v.value)
+
+ def __init__(self, *args, **kwargs):
+ _log_args("ACCESS:", *args, **kwargs)
+ srt_user_id = args[0]
+
+ # default to "Guest"
+ if 0 == srt_user_id:
+ srt_user_id = 1
+
+ self.current_user = srt_user_id
try:
- self.current_user_name = User.objects.get(pk=self.current_user).name
+ user = User.objects.get(pk=self.current_user)
+ self.current_user_name = user.name
+ self.current_user_access = user.access
except:
self.current_user_name = '<not_found>'
-
- v, created = SrtSetting.objects.get_or_create(name='current_user_access')
- if created:
- v.value = User.READER
- v.save()
- self.current_user_access = int(v.value)
+ self.current_user_access = User.READER
def is_guest(self):
- self.read_values()
return self.current_user == User.USER_GUEST
def is_reader(self):
- self.read_values()
return self.current_user_access >= User.READER
def is_contributor(self):
- self.read_values()
return self.current_user_access >= User.CONTRIBUTOR
def is_creator(self):
- self.read_values()
return self.current_user_access >= User.CREATOR
def is_admin(self):
- self.read_values()
return self.current_user_access >= User.ADMIN
def user_name(self):
- self.read_values()
return self.current_user_name
# Database Cache Support
diff --git a/lib/srtgui/api.py b/lib/srtgui/api.py
index b2c15b97..68aedb5d 100644
--- a/lib/srtgui/api.py
+++ b/lib/srtgui/api.py
@@ -1,7 +1,7 @@
#
# BitBake Toaster Implementation
#
-# Copyright (C) 2016 Intel Corporation
+# Copyright (C) 2016-2018 Intel Corporation
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
@@ -24,13 +24,12 @@ import logging
import json
from collections import Counter
-from orm.models import Vulnerability
-
from django.http import HttpResponse, JsonResponse
from django.views.generic import View
from django.core.urlresolvers import reverse
from django.db.models import Q, F
from django.db import Error
+
from srtgui.templatetags.projecttags import filtered_filesizeformat
logger = logging.getLogger("srt")
@@ -40,3 +39,144 @@ def error_response(error):
return JsonResponse({"error": error})
+# quick development/debugging support
+def _log(msg):
+ DBG_LVL = os.environ['SRTDBG_LVL'] if ('SRTDBG_LVL' in os.environ) else 2
+ DBG_LOG = os.environ['SRTDBG_LOG'] if ('SRTDBG_LOG' in os.environ) else '/tmp/toaster.log'
+ if 1 == DBG_LVL:
+ print(msg)
+ elif 2 == DBG_LVL:
+ f1=open(DBG_LOG, 'a')
+ f1.write("|" + msg + "|\n" )
+ f1.close()
+
+
+## add os.makedirs(cache_path) just to be safe?
+def readCveDetails(cve):
+ from orm.models import CveDetail, DataSource
+ cve_name = cve.name
+ cve_datasource = cve.datasource
+
+ # Initialize and populate CveDetail object to return
+ v = CveDetail()
+ v.name = cve_name
+
+ # Fetch cached data, else extract data from datasource file
+ cache_path = os.path.join(os.environ['SRT_BASE_DIR'], "data/cache")
+ cve_path = os.path.join(cache_path, cve_name + ".json")
+
+ #check if in cache, and use if exists. Else fetch from appropriate CVE JSON feed file
+ if (os.path.isfile(cve_path)):
+ try:
+ f = open(cve_path, 'r')
+ CVE_Item = json.load(f)
+ except Exception as e:
+ _log("| error reading json file %s: %s |\n" % (cve_path,e,))
+ return v
+ else:
+ try:
+ SRT_BASE_DIR= os.environ['SRT_BASE_DIR']
+ f = open(os.path.join(SRT_BASE_DIR, cve_datasource.file_path), 'r')
+ source_dct = json.load(f)
+ for item in source_dct["CVE_Items"]:
+ if not 'cve' in item:
+ continue
+ if not 'CVE_data_meta' in item['cve']:
+ continue
+ if not 'ID' in item['cve']['CVE_data_meta']:
+ continue
+ if (item['cve']['CVE_data_meta']['ID'] == cve_name):
+ CVE_Item = item
+ cve_cache_file = open(os.path.join(SRT_BASE_DIR, "data", "cache", cve_name + ".json"), "w+") #write the cve to json file in cache
+ cve_cache_file.write(json.dumps(CVE_Item))
+ break
+ except Exception as e:
+ _log("| error reading json file: %s |\n" % os.path.join(SRT_BASE_DIR, cve_datasource.file_path) )
+ return v
+
+ #initialize and populate CveDetail object to return
+ v = CveDetail()
+ v.name = cve_name
+
+ if ('impact' in CVE_Item) and ('baseMetricV3' in CVE_Item['impact']):
+ baseMetricV3 = CVE_Item['impact']['baseMetricV3']
+ v.cvssV3_baseScore = baseMetricV3['cvssV3']['baseScore']
+ v.cvssV3_baseSeverity = baseMetricV3['cvssV3']['baseSeverity']
+ v.cvssV3_vectorString = baseMetricV3['cvssV3']['vectorString']
+ v.cvssV3_exploitabilityScore = baseMetricV3['exploitabilityScore']
+ v.cvssV3_impactScore = baseMetricV3['impactScore']
+ v.cvssV3_attackVector = baseMetricV3['cvssV3']['attackVector']
+ v.cvssV3_attackComplexity = baseMetricV3['cvssV3']['attackComplexity']
+ v.cvssV3_privilegesRequired = baseMetricV3['cvssV3']['privilegesRequired']
+ v.cvssV3_userInteraction = baseMetricV3['cvssV3']['userInteraction']
+ v.cvssV3_scope = baseMetricV3['cvssV3']['scope']
+ v.cvssV3_confidentialityImpact = baseMetricV3['cvssV3']['confidentialityImpact']
+ v.cvssV3_integrityImpact = baseMetricV3['cvssV3']['integrityImpact']
+ v.cvssV3_availabilityImpact = baseMetricV3['cvssV3']['availabilityImpact']
+ if ('impact' in CVE_Item) and ('baseMetricV2' in CVE_Item['impact']):
+ baseMetricV2 = CVE_Item['impact']['baseMetricV2']
+ v.cvssV2_baseScore = baseMetricV2['cvssV2']['baseScore']
+ v.cvssV2_severity = baseMetricV2['severity']
+ v.cvssV2_vectorString = baseMetricV2['cvssV2']['vectorString']
+ v.cvssV2_exploitabilityScore = baseMetricV2['exploitabilityScore']
+ v.cvssV2_impactScore = baseMetricV2['exploitabilityScore']
+ v.cvssV2_accessVector = baseMetricV2['cvssV2']['accessVector']
+ v.cvssV2_accessComplexity = baseMetricV2['cvssV2']['accessComplexity']
+ v.cvssV2_authentication = baseMetricV2['cvssV2']['authentication']
+ v.cvssV2_confidentialityImpact = baseMetricV2['cvssV2']['confidentialityImpact']
+ v.cvssV2_integrityImpact = baseMetricV2['cvssV2']['integrityImpact']
+
+ configurations = CVE_Item['configurations']
+ is_first_and = True
+ for i, config in enumerate(configurations['nodes']):
+ v.cpe_list += '[config]|'
+ v.cpe_list += '[and]|'
+ if "AND" == config['operator']:
+ # create AND record
+ if not is_first_and:
+ v.cpe_list += '[/and]|'
+ v.cpe_list += '[and]|'
+ #is_first_and = False
+ if 'children' in config:
+ for j, cpe_or_node in enumerate(config['children']):
+ if "OR" == cpe_or_node['operator']:
+ v.cpe_list += nist_scan_configuration_or(v,cpe_or_node, cve_name, j)
+ else:
+ print("ERROR CONFIGURE:OR_OP?:%s" % cpe_or_node['operator'])
+ elif "OR" == config['operator']:
+ v.cpe_list += nist_scan_configuration_or(v,config, cve_name, 0)
+ else:
+ print("ERROR CONFIGURE:OP?:%s" % config_rec['operator'])
+ v.cpe_list += '[/and]|'
+ v.cpe_list += '[/config]|'
+
+ return v
+
+def nist_scan_configuration_or(cve, cpe_or_node, name, and_enum):
+ cpe_list = '[or]|'
+ for cpe in cpe_or_node['cpe']:
+ cpe23Uri = cpe['cpe23Uri']
+ if 'cpeMatchString' in cpe:
+ cpeMatchString = cpe['cpeMatchString']
+ else:
+ cpeMatchString = ''
+ if 'versionEndIncluding' in cpe:
+ versionEndIncluding = cpe['versionEndIncluding']
+ else:
+ versionEndIncluding = ''
+ cpe_list += '%s,%s,%s,%s|' % (cpe['vulnerable'],cpe23Uri,cpeMatchString,versionEndIncluding)
+ cpe_list += '[/or]|'
+ return cpe_list
+
+def saveCveToCache(cve):
+ #Encode cve to json and save into cache
+ path = os.path.join(os.environ['SRT_BASE_DIR'], "data/cache")
+ # Catch the post against this page
+ try:
+ os.makedirs(path)
+ except:
+ pass
+
+ cve_name = cve['CVE_data_meta']['ID']
+ file = open(os.path.join(path, cve_name + ".json" ), 'w+')
+ file.write(json.dumps(cve))
diff --git a/lib/srtgui/reports.py b/lib/srtgui/reports.py
new file mode 100644
index 00000000..f27beb34
--- /dev/null
+++ b/lib/srtgui/reports.py
@@ -0,0 +1,1326 @@
+#
+# Security Response Tool Implementation
+#
+# Copyright (C) 2017-2018 Wind River Systems
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# Please run flake8 on this file before sending patches
+
+import os
+import re
+import logging
+import json
+from collections import Counter
+from datetime import datetime, date
+
+from orm.models import Cve, Vulnerability, Investigation, Defect, Product
+from orm.models import SrtSetting, Access, Keywords
+
+from django.db.models import Q, F
+from django.db import Error
+from srtgui.templatetags.projecttags import filtered_filesizeformat
+
+logger = logging.getLogger("srt")
+
+SRT_BASE_DIR = os.environ['SRT_BASE_DIR']
+SRT_REPORT_DIR = '%s/reports' % SRT_BASE_DIR
+
+# quick development/debugging support
+from srtgui.api import _log
+
+def _log_args(msg, *args, **kwargs):
+ s = '%s:(' % msg
+ if args:
+ for a in args:
+ s += '%s,' % a
+ s += '),('
+ if kwargs:
+ for key, value in kwargs.items():
+ s += '(%s=%s),' % (key,value)
+ s += ')'
+ _log(s)
+
+class Report():
+ def __init__(self, parent_page, *args, **kwargs):
+ self.parent_page = parent_page
+ self.report_name = '%s%s' % (parent_page[0].upper(),parent_page[1:])
+ self.title = self.report_name
+ self.request = kwargs['request']
+
+ def get_context_data(self, *args, **kwargs):
+ context = {}
+ context['title'] = self.title
+ context['parent_page'] = self.parent_page
+ context['report_name'] = self.report_name
+ context['report_enable_submit'] = '1'
+ # global variables
+ context['access'] = Access(int(self.request.session.get('srt_user_id', '0')))
+
+ return context
+
+ def exec_report(self, *args, **kwargs):
+ return None
+
+
+class ManagementReport(Report):
+ """Report for the Management Page"""
+
+ def __init__(self, parent_page, *args, **kwargs):
+ _log_args("REPORT_MANAGEMENT_INIT(%s)" % parent_page, *args, **kwargs)
+ super(ManagementReport, self).__init__(parent_page, *args, **kwargs)
+
+ def get_context_data(self, *args, **kwargs):
+ _log_args("REPORT_MANAGEMENT_CONTEXT", *args, **kwargs)
+ context = super(ManagementReport, self).get_context_data(*args, **kwargs)
+
+ context['report_type_list'] = '\
+ <option value="status">Overall Status</option> \
+ <option value="vulnerabilities">Open Vulnerabilities</option> \
+ <option value="investigations">Open Investigations</option> \
+ '
+ context['report_get_title'] = '1'
+ context['report_recordrange_list'] = '\
+ <input type="radio" name="records" value="selected" checked> Selected<br> \
+ '
+ context['report_columnrange_list'] = ''
+ context['report_format_list'] = '\
+ <input type="radio" name="format" value="txt" checked> Text<br> \
+ <input type="radio" name="format" value="csv"> CSV<br> \
+ '
+ return context
+
+ def exec_report(self, *args, **kwargs):
+ _log_args("REPORT_MANAGEMENT_EXEC", *args, **kwargs)
+ super(ManagementReport, self).exec_report(*args, **kwargs)
+
+ request_POST = self.request.POST
+
+ records = request_POST.get('records', '')
+ format = request_POST.get('format', '')
+ title = request_POST.get('title', '')
+ report_type = request_POST.get('report_type', '')
+
+ report_name = '%s/management_%s_%s.%s' % (SRT_REPORT_DIR,report_type,datetime.today().strftime('%Y%m%d%H%M'),format)
+ with open(report_name, 'w') as file:
+
+ if 'csv' == format:
+ tab = "\t"
+ else:
+ tab = " = "
+
+ if 'status' == report_type:
+ if 'txt' == format:
+ file.write("Report : Management - Summary\n")
+ file.write("\n")
+ file.write("%s%s%s\n" % ('cve_total',tab,Cve.objects.all().count()))
+ file.write("%s%s%s\n" % ('cve_new',tab,Cve.objects.filter(status=Cve.NEW).count()))
+ file.write("%s%s%s\n" % ('cve_open',tab,Cve.objects.filter( Q(status=Cve.INVESTIGATE) & Q(status=Cve.VULNERABLE) ).count()))
+ file.write("%s%s%s\n" % ('vulnerability_total',tab,Vulnerability.objects.all().count()))
+ file.write("%s%s%s\n" % ('vulnerability_open',tab,Vulnerability.objects.filter(outcome=Vulnerability.OPEN).count()))
+ file.write("%s%s%s\n" % ('vulnerability_high',tab,Vulnerability.objects.filter(severity=Vulnerability.HIGH).count()))
+ file.write("%s%s%s\n" % ('vulnerability_medium',tab,Vulnerability.objects.filter(severity=Vulnerability.MEDIUM).count()))
+ file.write("%s%s%s\n" % ('vulnerability_low',tab,Vulnerability.objects.filter(severity=Vulnerability.HIGH).count()))
+ file.write("%s%s%s\n" % ('investigation_total',tab,Investigation.objects.all().count()))
+ file.write("%s%s%s\n" % ('investigation_open',tab,Investigation.objects.filter(outcome=Investigation.OPEN).count()))
+ file.write("%s%s%s\n" % ('investigation_high',tab,Investigation.objects.filter(severity=Investigation.HIGH).count()))
+ file.write("%s%s%s\n" % ('investigation_medium',tab,Investigation.objects.filter(severity=Investigation.MEDIUM).count()))
+ file.write("%s%s%s\n" % ('investigation_low',tab,Investigation.objects.filter(severity=Investigation.LOW).count()))
+ file.write("%s%s%s\n" % ('defect_total',tab,Defect.objects.all().count()))
+
+ if 'vulnerabilities' == report_type:
+ if 'txt' == format:
+ file.write("Report : Management - Open Vulnerabilities\n")
+ file.write("\n")
+ else:
+ file.write("Name\tStatus\tOutcome\tSeverity\tComments\tCVEs\tInvestigations\n")
+ for v in Vulnerability.objects.filter(outcome=Vulnerability.OPEN):
+ if 'txt' == format:
+ file.write("Name: %s\n" % v.name)
+ file.write(" Status: %s\n" % v.get_status_text)
+ file.write(" Outcome: %s\n" % v.get_outcome_text)
+ file.write(" Severity: %s\n" % v.get_severity_text)
+ file.write(" Comments: %s\n" % v.comments)
+ file.write(" CVEs: ")
+ for i,vc in enumerate(v.vulnerability_to_cve.all()):
+ if i > 0:
+ file.write(",")
+ file.write("%s" % vc.cve.name)
+ file.write("\n")
+ file.write(" Investigations: ")
+ for i,investigation in enumerate(Investigation.objects.filter(vulnerability=v)):
+ if i > 0:
+ file.write(",")
+ file.write("%s" % investigation.name)
+ file.write("\n")
+ file.write("\n")
+ else:
+ file.write("%s\t%s\t%s\t%s\t%s\t" % (v.name,v.get_status_text,v.get_outcome_text,v.get_severity_text,v.comments))
+ for i,vc in enumerate(v.vulnerability_to_cve.all()):
+ if i > 0:
+ file.write(",")
+ file.write("%s" % vc.cve.name)
+ file.write("\t")
+ for i,investigation in enumerate(Investigation.objects.filter(vulnerability=v)):
+ if i > 0:
+ file.write(",")
+ file.write("%s" % investigation.name)
+ file.write("\n")
+
+ if 'investigations' == report_type:
+ if 'txt' == format:
+ file.write("Report : Management - Open Vulnerabilities\n")
+ file.write("\n")
+ else:
+ file.write("Name\tStatus\tOutcome\tSeverity\tComments\tDefects\n")
+ for investigation in Investigation.objects.filter(outcome=Vulnerability.OPEN):
+ if 'txt' == format:
+ file.write("Name: %s\n" % investigation.name)
+ file.write(" Status: %s\n" % investigation.get_status_text)
+ file.write(" Outcome: %s\n" % investigation.get_outcome_text)
+ file.write(" Severity: %s\n" % investigation.get_severity_text)
+ file.write(" Comments: %s\n" % investigation.comments)
+ file.write(" Defects: ")
+ for i,id in enumerate(investigation.investigation_to_defect.filter(investigation=investigation)):
+ if i > 0:
+ file.write(",")
+ file.write("%s" % id.defect.name)
+ file.write("\n")
+ file.write("\n")
+ else:
+ file.write("%s\t%s\t%s\t%s\t%s\t" % (investigation.name,investigation.get_status_text,
+ investigation.get_outcome_text,investigation.get_severity_text,investigation.comments))
+ for i,id in enumerate(investigation.investigation_to_defect.filter(investigation=investigation)):
+ if i > 0:
+ file.write(",")
+ file.write("%s" % id.defect.name)
+ file.write("\n")
+
+ return report_name,os.path.basename(report_name)
+
+class CveReport(Report):
+ """Report for the CVE Page"""
+
+ def __init__(self, parent_page, *args, **kwargs):
+ _log_args("REPORT_CVE_INIT(%s)" % parent_page, *args, **kwargs)
+ super(CveReport, self).__init__(parent_page, *args, **kwargs)
+
+ def get_context_data(self, *args, **kwargs):
+ _log_args("REPORT_CVE_CONTEXT", *args, **kwargs)
+ context = super(CveReport, self).get_context_data(*args, **kwargs)
+
+ context['report_type_list'] = '\
+ <option value="summary">CVE Summary</option> \
+ <option value="audit">CVE Audit</option> \
+ '
+ context['report_get_title'] = '1'
+ context['report_recordrange_list'] = '\
+ <input type="radio" name="records" value="selected" checked> Selected<br> \
+ '
+ context['report_columnrange_list'] = ''
+ context['report_format_list'] = '\
+ <input type="radio" name="format" value="txt" checked> Text<br> \
+ '
+ context['report_custom_list'] = '\
+ <input type="checkbox" class="checkbox-options" name="cvss_v2" value="cvss_v2"> CVSS_v2<br> \
+ <input type="checkbox" class="checkbox-options" name="ref" type="ref"> References<br> \
+ <input type="checkbox" class="checkbox-options" name="cpe" type="cpe"> CPE list<br> \
+ '
+ return context
+
+ def exec_report(self, *args, **kwargs):
+ _log_args("REPORT_CVE_EXEC", *args, **kwargs)
+ super(CveReport, self).exec_report(*args, **kwargs)
+
+ request_POST = self.request.POST
+
+ records = request_POST.get('records', '')
+ format = request_POST.get('format', '')
+ title = request_POST.get('title', '')
+ report_type = request_POST.get('report_type', '')
+ record_list = request_POST.get('record_list', '')
+
+ cvss_v2 = request_POST.get('cvss_v2', '')
+ ref_list = request_POST.get('ref', '')
+ cpe = request_POST.get('cpe', '')
+
+ cve = Cve.objects.get(id=record_list)
+
+ report_name = '%s/cve_%s_%s.%s' % (SRT_REPORT_DIR,report_type,datetime.today().strftime('%Y%m%d%H%M'),format)
+ with open(report_name, 'w') as file:
+
+ if 'csv' == format:
+ tab = "\t"
+ else:
+ tab = " = "
+
+ if ('summary' == report_type) or ('audit' == report_type):
+ if 'txt' == format:
+ file.write("Report : CVE %s - Summary\n" % cve.name)
+ file.write("\n")
+ file.write("%s%s%s\n" % ('source',tab,cve.source))
+ file.write("%s%s%s\n" % ('status',tab,cve.status))
+ file.write("%s%s%s\n" % ('cve_data_type',tab,cve.cve_data_type))
+ file.write("%s%s%s\n" % ('cve_data_format',tab,cve.cve_data_format))
+ file.write("%s%s%s\n" % ('cve_data_version',tab,cve.cve_data_version))
+ file.write("%s%s%s\n" % ('description',tab,cve.description))
+ file.write("\n")
+
+ file.write("CVSS Version 3:\n")
+ file.write(" %s%s%s\n" % ('cvssV3_baseScore',tab,cve.cvssV3_baseScore))
+ file.write(" %s%s%s\n" % ('cvssV3_baseSeverity',tab,cve.cvssV3_baseSeverity))
+ file.write(" %s%s%s\n" % ('cvssV3_vectorString',tab,cve.cvssV3_vectorString))
+ file.write(" %s%s%s\n" % ('cvssV3_exploitabilityScore',tab,cve.cvssV3_exploitabilityScore))
+ file.write(" %s%s%s\n" % ('cvssV3_impactScore',tab,cve.cvssV3_impactScore))
+ file.write(" %s%s%s\n" % ('cvssV3_attackVector',tab,cve.cvssV3_attackVector))
+ file.write(" %s%s%s\n" % ('cvssV3_attackComplexity',tab,cve.cvssV3_attackComplexity))
+ file.write(" %s%s%s\n" % ('cvssV3_privilegesRequired',tab,cve.cvssV3_privilegesRequired))
+ file.write(" %s%s%s\n" % ('cvssV3_userInteraction',tab,cve.cvssV3_userInteraction))
+ file.write(" %s%s%s\n" % ('cvssV3_scope',tab,cve.cvssV3_scope))
+ file.write(" %s%s%s\n" % ('cvssV3_confidentialityImpact',tab,cve.cvssV3_confidentialityImpact))
+ file.write(" %s%s%s\n" % ('cvssV3_integrityImpact',tab,cve.cvssV3_integrityImpact))
+ file.write(" %s%s%s\n" % ('cvssV3_availabilityImpact',tab,cve.cvssV3_availabilityImpact))
+
+ if (cvss_v2):
+ file.write("\n")
+ file.write("CVSS Version 2:\n")
+ file.write(" %s%s%s\n" % ('cvssV2_baseScore',tab,cve.cvssV2_baseScore))
+ file.write(" %s%s%s\n" % ('cvssV2_severity',tab,cve.cvssV2_severity))
+ file.write(" %s%s%s\n" % ('cvssV2_vectorString',tab,cve.cvssV2_vectorString))
+ file.write(" %s%s%s\n" % ('cvssV2_exploitabilityScore',tab,cve.cvssV2_exploitabilityScore))
+ file.write(" %s%s%s\n" % ('cvssV2_impactScore',tab,cve.cvssV2_impactScore))
+ file.write(" %s%s%s\n" % ('cvssV2_accessVector',tab,cve.cvssV2_accessVector))
+ file.write(" %s%s%s\n" % ('cvssV2_accessComplexity',tab,cve.cvssV2_accessComplexity))
+ file.write(" %s%s%s\n" % ('cvssV2_authentication',tab,cve.cvssV2_authentication))
+ file.write(" %s%s%s\n" % ('cvssV2_confidentialityImpact',tab,cve.cvssV2_confidentialityImpact))
+ file.write(" %s%s%s\n" % ('cvssV2_integrityImpact',tab,cve.cvssV2_integrityImpact))
+
+ if (ref_list):
+ file.write("\n")
+ file.write("References:\n")
+ for i,ref in enumerate(cve.references.all()):
+ file.write(" %s\n" % ref.hyperlink)
+
+ if (cpe):
+ file.write("\n")
+ file.write("CPE Table:\n")
+ for cpe in cve.cpe_list.split("|"):
+ if '<config>' == cpe:
+ file.write(" Configation:\n")
+ elif '<and>' == cpe:
+ file.write(" * AND\n")
+ elif '<or>' == cpe:
+ file.write(" * OR\n")
+ else :
+ file.write(" %s\n" % cpe)
+
+ if 'audit' == report_type:
+
+ for cv in cve.cve_to_vulnerability.all():
+ v = cv.vulnerability
+ file.write("\n")
+ file.write("-------------------------------------------\n")
+ file.write("Vulnerability: %s\n" % v.name)
+ file.write(" Status: %s\n" % v.get_status_text)
+ file.write(" Outcome: %s\n" % v.get_outcome_text)
+ file.write(" Severity: %s\n" % v.get_severity_text)
+ file.write(" Comments: %s\n" % v.comments)
+ file.write("\n")
+ file.write(" Investigations:\n")
+ for investigation in Investigation.objects.filter(vulnerability=v):
+ file.write(" Name: %s\n" % investigation.name)
+ file.write(" Status: %s\n" % investigation.get_status_text)
+ file.write(" Outcome: %s\n" % investigation.get_outcome_text)
+ file.write(" Severity: %s\n" % investigation.get_severity_text)
+ file.write(" Defects: ")
+ for i,id in enumerate(investigation.investigation_to_defect.all()):
+ if i > 0:
+ file.write(",")
+ file.write("%s (%s)" % (id.defect.name,id.defect.get_status_text))
+ file.write("\n")
+
+ file.write("\n")
+ file.write(" Comments:\n")
+ for i,vc in enumerate(v.vulnerability_comments.all()):
+ file.write(" %s (%s): %s\n" % (vc.date,vc.author,vc.comment))
+
+ file.write("\n")
+ file.write(" Audit Trail:\n")
+ for i,vh in enumerate(v.vulnerability_history.all()):
+ file.write(" %s (%s): %s\n" % (vh.date,vh.author,vh.comment))
+
+ file.write("\n")
+ else:
+ file.write("Investigations: no attached investigations as this time\n")
+
+ return report_name,os.path.basename(report_name)
+
+class VulnerabilityReport(Report):
+ """Report for the Vulnerability Page"""
+
+ def __init__(self, parent_page, *args, **kwargs):
+ _log_args("REPORT_VULNERABILITY_INIT(%s)" % parent_page, *args, **kwargs)
+ super(VulnerabilityReport, self).__init__(parent_page, *args, **kwargs)
+
+ def get_context_data(self, *args, **kwargs):
+ _log_args("REPORT_VULNERABILITY_CONTEXT", *args, **kwargs)
+ context = super(VulnerabilityReport, self).get_context_data(*args, **kwargs)
+
+ context['report_type_list'] = '\
+ <option value="summary">Vulnerability Summary</option> \
+ <option value="audit">Vulnerability Audit</option> \
+ '
+ context['report_get_title'] = '1'
+ context['report_recordrange_list'] = '\
+ <input type="radio" name="records" value="selected" checked> Selected<br> \
+ '
+ context['report_columnrange_list'] = ''
+ context['report_format_list'] = '\
+ <input type="radio" name="format" value="txt" checked> Text<br> \
+ '
+ return context
+
+ def exec_report(self, *args, **kwargs):
+ _log_args("REPORT_VULNERABILITY_EXEC", *args, **kwargs)
+ super(VulnerabilityReport, self).exec_report(*args, **kwargs)
+
+ request_POST = self.request.POST
+
+ records = request_POST.get('records', '')
+ format = request_POST.get('format', '')
+ title = request_POST.get('title', '')
+ report_type = request_POST.get('report_type', '')
+ record_list = request_POST.get('record_list', '')
+
+ v = Vulnerability.objects.get(id=record_list)
+
+ report_name = '%s/vulnerability_%s_%s.%s' % (SRT_REPORT_DIR,report_type,datetime.today().strftime('%Y%m%d%H%M'),format)
+ with open(report_name, 'w') as file:
+
+ if 'csv' == format:
+ tab = "\t"
+ else:
+ tab = " = "
+
+ if ('summary' == report_type) or ('audit' == report_type):
+ if 'txt' == format:
+ file.write("Report : Vulnerability %s - Summary\n" % v.name)
+ file.write("\n")
+
+ file.write("Vulnerability: %s\n" % v.name)
+ file.write(" Status: %s\n" % v.get_status_text)
+ file.write(" Outcome: %s\n" % v.get_outcome_text)
+ file.write(" Severity: %s\n" % v.get_severity_text)
+ file.write(" Comments: %s\n" % v.comments)
+
+ file.write("\n")
+ file.write("Affected Products:\n")
+ found_p = False
+ for i,p in enumerate(v.get_affected_list):
+ found_p = True
+ file.write("%2d) Product: %s\n" % (i,p.product.long_name))
+ found_i = False
+ for investigation in Investigation.objects.filter(vulnerability=v,product=p.product):
+ found_i = True
+ file.write(" Investigation: %s\n" % investigation.name)
+ file.write(" Status: %s\n" % investigation.get_status_text)
+ file.write(" Outcome: %s\n" % investigation.get_outcome_text)
+ file.write(" Severity: %s\n" % investigation.get_severity_text)
+ file.write(" Defects: ")
+ for j,id in enumerate(investigation.investigation_to_defect.all()):
+ if j > 0:
+ file.write(",")
+ file.write("%s (%s)" % (id.defect.name,id.defect.get_status_text))
+ file.write("\n")
+ if not found_i:
+ file.write(" No investigations found\n")
+ if not found_p:
+ file.write(" No affected products found\n")
+
+ file.write("\n")
+ file.write("Related Products:\n")
+ found_p = False
+ for i,p in enumerate(v.get_related_list):
+ found_p = True
+ file.write("%2d) Product: %s\n" % (i,p.product.long_name))
+ if not found_p:
+ file.write(" No related products found\n")
+
+ file.write("\n")
+ file.write("Comments:\n")
+ found_c = False
+ for i,vc in enumerate(v.vulnerability_comments.all()):
+ found_c = True
+ file.write(" %2d) %s (%s): %s\n" % (i,vc.date,vc.author,vc.comment))
+ if not found_c:
+ file.write(" No comments found\n")
+
+ if 'audit' == report_type:
+ file.write("\n")
+ file.write("Audit Trail:\n")
+ for i,vh in enumerate(v.vulnerability_history.all()):
+ file.write(" %2d) %s (%s): %s\n" % (i,vh.date,vh.author,vh.comment))
+
+ file.write("\n")
+
+ return report_name,os.path.basename(report_name)
+
+class InvestigationReport(Report):
+ """Report for the Investigation Page"""
+
+ def __init__(self, parent_page, *args, **kwargs):
+ _log_args("REPORT_INVESTIGATION_INIT(%s)" % parent_page, *args, **kwargs)
+ super(InvestigationReport, self).__init__(parent_page, *args, **kwargs)
+
+ def get_context_data(self, *args, **kwargs):
+ _log_args("REPORT_INVESTIGATION_CONTEXT", *args, **kwargs)
+ context = super(InvestigationReport, self).get_context_data(*args, **kwargs)
+
+ context['report_type_list'] = '\
+ <option value="summary">Investigation Summary</option> \
+ <option value="audit">Investigation Audit</option> \
+ '
+ context['report_get_title'] = '1'
+ context['report_recordrange_list'] = '\
+ <input type="radio" name="records" value="selected" checked> Selected<br> \
+ '
+ context['report_columnrange_list'] = ''
+ context['report_format_list'] = '\
+ <input type="radio" name="format" value="txt" checked> Text<br> \
+ '
+ return context
+
+ def exec_report(self, *args, **kwargs):
+ _log_args("REPORT_INVESTIGATION_EXEC", *args, **kwargs)
+ super(InvestigationReport, self).exec_report(*args, **kwargs)
+
+ request_POST = self.request.POST
+
+ records = request_POST.get('records', '')
+ format = request_POST.get('format', '')
+ title = request_POST.get('title', '')
+ report_type = request_POST.get('report_type', '')
+ record_list = request_POST.get('record_list', '')
+
+ investigation = Investigation.objects.get(id=record_list)
+
+ report_name = '%s/investigation_%s_%s.%s' % (SRT_REPORT_DIR,report_type,datetime.today().strftime('%Y%m%d%H%M'),format)
+ with open(report_name, 'w') as file:
+
+ if 'csv' == format:
+ tab = "\t"
+ else:
+ tab = " = "
+
+ if ('summary' == report_type) or ('audit' == report_type):
+ if 'txt' == format:
+ file.write("Report : Investigation %s - Summary\n" % investigation.name)
+ file.write("\n")
+
+ file.write("Name: %s\n" % investigation.name)
+ file.write(" Status: %s\n" % investigation.get_status_text)
+ file.write(" Outcome: %s\n" % investigation.get_outcome_text)
+ file.write(" Severity: %s\n" % investigation.get_severity_text)
+ file.write(" Defects: ")
+ for i,id in enumerate(investigation.investigation_to_defect.all()):
+ if i > 0:
+ file.write(",")
+ file.write("%s (%s)" % (id.defect.name,id.defect.get_status_text))
+ file.write("\n")
+
+ file.write("\n")
+ file.write("Comments:\n")
+ found_c = False
+ for i,vc in enumerate(investigation.investigation_comments.all()):
+ found_c = True
+ file.write(" %s (%s): %s\n" % (ic.date,ic.author,ic.comment))
+ if not found_c:
+ file.write(" No comments found\n")
+
+ if 'audit' == report_type:
+ file.write("\n")
+ file.write(" Audit Trail:\n")
+ for i,ih in enumerate(investigation.investigation_history.all()):
+ file.write(" %s (%s): %s\n" % (ih.date,ih.author,ih.comment))
+
+ file.write("\n")
+
+ return report_name,os.path.basename(report_name)
+
+class DefectReport(Report):
+ """Report for the Defect Page"""
+
+ def __init__(self, parent_page, *args, **kwargs):
+ _log_args("REPORT_DEFECT_INIT(%s)" % parent_page, *args, **kwargs)
+ super(DefectReport, self).__init__(parent_page, *args, **kwargs)
+
+ def get_context_data(self, *args, **kwargs):
+ _log_args("REPORT_DEFECT_CONTEXT", *args, **kwargs)
+ context = super(DefectReport, self).get_context_data(*args, **kwargs)
+
+ context['report_type_list'] = '\
+ <option value="summary">Defect Summary</option> \
+ '
+ context['report_get_title'] = '1'
+ context['report_recordrange_list'] = '\
+ <input type="radio" name="records" value="selected" checked> Selected<br> \
+ '
+ context['report_columnrange_list'] = ''
+ context['report_format_list'] = '\
+ <input type="radio" name="format" value="txt" checked> Text<br> \
+ <input type="radio" name="format" value="csv"> CSV<br> \
+ '
+ return context
+
+ def exec_report(self, *args, **kwargs):
+ _log_args("REPORT_DEFECT_EXEC", *args, **kwargs)
+ super(DefectReport, self).exec_report(*args, **kwargs)
+
+ request_POST = self.request.POST
+
+ records = request_POST.get('records', '')
+ format = request_POST.get('format', '')
+ title = request_POST.get('title', '')
+ report_type = request_POST.get('report_type', '')
+ record_list = request_POST.get('record_list', '')
+
+ report_name = '%s/defect_%s_%s.%s' % (SRT_REPORT_DIR,report_type,datetime.today().strftime('%Y%m%d%H%M'),format)
+ with open(report_name, 'w') as file:
+
+ if 'csv' == format:
+ tab = "\t"
+ else:
+ tab = ","
+
+ if ('summary' == report_type):
+ if 'csv' == format:
+ file.write("Name\tSummary\tPriority\tStatus\tResolution\tReleased Version\tURL\tInvestigations\tProduct\n")
+ if 'txt' == format:
+ file.write("Report : Defects Table\n")
+ file.write("\n")
+ file.write("Name,Summary,Priority,Status,Resolution,Released Version,URL,Investigations,Product\n")
+
+ defect = Defect.objects.get(id=record_list)
+ file.write("%s%s" % (defect.name,tab))
+ file.write("%s%s" % (defect.summary,tab))
+ file.write("%s%s" % (defect.get_priority_text,tab))
+ file.write("%s%s" % (defect.get_status_text,tab))
+ file.write("%s%s" % (defect.get_resolution_text,tab))
+ file.write("%s%s" % (defect.release_version,tab))
+ file.write("%s%s" % (defect.publish,tab))
+ file.write("%s%s" % (defect.url,tab))
+ for i,di in enumerate(defect.defect_to_investigation.all()):
+ if i > 0:
+ file.write(" ")
+ file.write("%s" % (di.investigation.name))
+ file.write("%s" % tab)
+ tab='' # EOL
+ file.write("%s%s" % (defect.product.long_name,tab))
+ file.write("\n")
+
+ return report_name,os.path.basename(report_name)
+
+
+class CvesReport(Report):
+ """Report for the CVEs Page"""
+
+ def __init__(self, parent_page, *args, **kwargs):
+ _log_args("REPORT_CVES_INIT(%s)" % parent_page, *args, **kwargs)
+ super(CvesReport, self).__init__(parent_page, *args, **kwargs)
+
+ def get_context_data(self, *args, **kwargs):
+ _log_args("REPORT_CVES_CONTEXT", *args, **kwargs)
+ context = super(CvesReport, self).get_context_data(*args, **kwargs)
+
+ context['report_type_list'] = '\
+ <option value="summary">CVEs Table</option> \
+ '
+ context['report_get_title'] = '1'
+ context['report_recordrange_list'] = '\
+ <input type="radio" name="records" value="selected" checked> Selected<br> \
+ '
+ context['report_columnrange_list'] = ''
+ context['report_format_list'] = '\
+ <input type="radio" name="format" value="txt" checked> Text<br> \
+ <input type="radio" name="format" value="csv"> CSV<br> \
+ '
+ return context
+
+ def exec_report(self, *args, **kwargs):
+ _log_args("REPORT_CVES_EXEC", *args, **kwargs)
+ super(CvesReport, self).exec_report(*args, **kwargs)
+
+ request_POST = self.request.POST
+
+ records = request_POST.get('records', '')
+ format = request_POST.get('format', '')
+ title = request_POST.get('title', '')
+ report_type = request_POST.get('report_type', '')
+ record_list = request_POST.get('record_list', '')
+
+ report_name = '%s/cves_%s_%s.%s' % (SRT_REPORT_DIR,report_type,datetime.today().strftime('%Y%m%d%H%M'),format)
+ with open(report_name, 'w') as file:
+
+ if 'csv' == format:
+ tab = "\t"
+ else:
+ tab = ","
+
+ if ('summary' == report_type):
+ if 'csv' == format:
+ file.write("Name\tStatus\tType\tFormat\tVersion\tVulnerabilities\tDescription\n")
+ if 'txt' == format:
+ file.write("Report : CVEs Table\n")
+ file.write("\n")
+ file.write("Name,Status,Type,Format,Version,Vulnerabilities,Description\n")
+
+ for id in record_list.split(','):
+ if not id:
+ continue
+ cve = Cve.objects.get(id=id)
+ file.write("%s%s" % (cve.name,tab))
+ file.write("%s%s" % (cve.get_status_text,tab))
+ file.write("%s%s" % (cve.cve_data_type,tab))
+ file.write("%s%s" % (cve.cve_data_format,tab))
+ file.write("%s%s" % (cve.cve_data_version,tab))
+
+ for i,cv in enumerate(cve.cve_to_vulnerability.all()):
+ if i > 0:
+ file.write(" ")
+ file.write("%s" % cv.vulnerability.name)
+ file.write("%s" % tab)
+
+ file.write("%s%s" % (cve.description,tab))
+ file.write("\n")
+
+ return report_name,os.path.basename(report_name)
+
+class SelectCvesReport(Report):
+ """Report for the Select CVEs Page"""
+
+ def __init__(self, parent_page, *args, **kwargs):
+ _log_args("REPORT_SELECTCVES_INIT(%s)" % parent_page, *args, **kwargs)
+ super(SelectCvesReport, self).__init__(parent_page, *args, **kwargs)
+
+ def get_context_data(self, *args, **kwargs):
+ _log_args("REPORT_SELECTCVES_CONTEXT", *args, **kwargs)
+ context = super(SelectCvesReport, self).get_context_data(*args, **kwargs)
+
+ context['report_type_list'] = '\
+ <option value="summary">CVEs Table</option> \
+ '
+ context['report_get_title'] = '1'
+ context['report_recordrange_list'] = '\
+ <input type="radio" name="records" value="selected" checked> Selected<br> \
+ '
+ context['report_columnrange_list'] = ''
+ context['report_format_list'] = '\
+ <input type="radio" name="format" value="txt" checked> Text<br> \
+ <input type="radio" name="format" value="csv"> CSV<br> \
+ '
+ return context
+
+ def exec_report(self, *args, **kwargs):
+ _log_args("REPORT_SELECTCVES_EXEC", *args, **kwargs)
+ super(SelectCvesReport, self).exec_report(*args, **kwargs)
+
+ request_POST = self.request.POST
+
+ records = request_POST.get('records', '')
+ format = request_POST.get('format', '')
+ title = request_POST.get('title', '')
+ report_type = request_POST.get('report_type', '')
+ record_list = request_POST.get('record_list', '')
+
+ report_name = '%s/select_cves_%s_%s.%s' % (SRT_REPORT_DIR,report_type,datetime.today().strftime('%Y%m%d%H%M'),format)
+ with open(report_name, 'w') as file:
+
+ if 'csv' == format:
+ tab = "\t"
+ else:
+ tab = ","
+
+ if ('summary' == report_type):
+ if 'csv' == format:
+ file.write("Name\tStatus\tType\tFormat\tVersion\tVulnerabilities\tDescription\n")
+ if 'txt' == format:
+ file.write("Report : CVEs Table\n")
+ file.write("\n")
+ file.write("Name,Status,Type,Format,Version,Vulnerabilities,Description\n")
+
+ for id in record_list.split(','):
+ if not id:
+ continue
+ cve = Cve.objects.get(id=id)
+ file.write("%s%s" % (cve.name,tab))
+ file.write("%s%s" % (cve.get_status_text,tab))
+ file.write("%s%s" % (cve.cve_data_type,tab))
+ file.write("%s%s" % (cve.cve_data_format,tab))
+ file.write("%s%s" % (cve.cve_data_version,tab))
+
+ for i,cv in enumerate(cve.cve_to_vulnerability.all()):
+ if i > 0:
+ file.write(" ")
+ file.write("%s" % cv.vulnerability.name)
+ file.write("%s" % tab)
+
+ file.write("%s%s" % (cve.description,tab))
+ file.write("\n")
+
+ return report_name,os.path.basename(report_name)
+
+class VulnerabilitiesReport(Report):
+ """Report for the Vulnerabilities Page"""
+
+ def __init__(self, parent_page, *args, **kwargs):
+ _log_args("REPORT_VULNERABILITIES_INIT(%s)" % parent_page, *args, **kwargs)
+ super(VulnerabilitiesReport, self).__init__(parent_page, *args, **kwargs)
+
+ def get_context_data(self, *args, **kwargs):
+ _log_args("REPORT_VULNERABILITIES_CONTEXT", *args, **kwargs)
+ context = super(VulnerabilitiesReport, self).get_context_data(*args, **kwargs)
+
+ context['report_type_list'] = '\
+ <option value="summary">Vulnerabilities Table</option> \
+ '
+ context['report_get_title'] = '1'
+ context['report_recordrange_list'] = '\
+ <input type="radio" name="records" value="selected" checked> Selected<br> \
+ '
+ context['report_columnrange_list'] = ''
+ context['report_format_list'] = '\
+ <input type="radio" name="format" value="txt" checked> Text<br> \
+ <input type="radio" name="format" value="csv"> CSV<br> \
+ '
+ return context
+
+ def exec_report(self, *args, **kwargs):
+ _log_args("REPORT_VULNERABILITIES_EXEC", *args, **kwargs)
+ super(VulnerabilitiesReport, self).exec_report(*args, **kwargs)
+
+ request_POST = self.request.POST
+
+ records = request_POST.get('records', '')
+ format = request_POST.get('format', '')
+ title = request_POST.get('title', '')
+ report_type = request_POST.get('report_type', '')
+ record_list = request_POST.get('record_list', '')
+
+ report_name = '%s/vulnerabilities_%s_%s.%s' % (SRT_REPORT_DIR,report_type,datetime.today().strftime('%Y%m%d%H%M'),format)
+ with open(report_name, 'w') as file:
+
+ if 'csv' == format:
+ tab = "\t"
+ else:
+ tab = ","
+
+ if ('summary' == report_type):
+ if 'csv' == format:
+ file.write("Name\tStatus\tOutcome\tSeverity\tCVEs\tInvestigations\n")
+ if 'txt' == format:
+ file.write("Report : Investigations Table\n")
+ file.write("\n")
+ file.write("Name,Status,Outcome,Severity,CVEs,Investigations\n")
+
+ for id in record_list.split(','):
+ if not id:
+ continue
+ v = Vulnerability.objects.get(id=id)
+ file.write("%s%s" % (v.name,tab))
+ file.write("%s%s" % (v.get_status_text,tab))
+ file.write("%s%s" % (v.get_outcome_text,tab))
+ file.write("%s%s" % (v.get_severity_text,tab))
+ for i,vc in enumerate(v.vulnerability_to_cve.all()):
+ if i > 0:
+ file.write(" ")
+ file.write("%s" % vc.cve.name)
+ file.write("%s" % tab)
+ for i,investigation in enumerate(Investigation.objects.filter(vulnerability=v)):
+ if i > 0:
+ file.write(" ")
+ file.write("%s" % investigation.name)
+ #file.write("%s" % tab)
+ file.write("\n")
+
+ return report_name,os.path.basename(report_name)
+
+class InvestigationsReport(Report):
+ """Report for the Investigations Page"""
+
+ def __init__(self, parent_page, *args, **kwargs):
+ _log_args("REPORT_INVESTIGATIONS_INIT(%s)" % parent_page, *args, **kwargs)
+ super(InvestigationsReport, self).__init__(parent_page, *args, **kwargs)
+
+ def get_context_data(self, *args, **kwargs):
+ _log_args("REPORT_INVESTIGATIONS_CONTEXT", *args, **kwargs)
+ context = super(InvestigationsReport, self).get_context_data(*args, **kwargs)
+
+ context['report_type_list'] = '\
+ <option value="summary">Investigations Table</option> \
+ '
+ context['report_get_title'] = '1'
+ context['report_recordrange_list'] = '\
+ <input type="radio" name="records" value="selected" checked> Selected<br> \
+ '
+ context['report_columnrange_list'] = ''
+ context['report_format_list'] = '\
+ <input type="radio" name="format" value="txt" checked> Text<br> \
+ <input type="radio" name="format" value="csv"> CSV<br> \
+ '
+ return context
+
+ def exec_report(self, *args, **kwargs):
+ _log_args("REPORT_INVESTIGATIONS_EXEC", *args, **kwargs)
+ super(InvestigationsReport, self).exec_report(*args, **kwargs)
+
+ request_POST = self.request.POST
+
+ records = request_POST.get('records', '')
+ format = request_POST.get('format', '')
+ title = request_POST.get('title', '')
+ report_type = request_POST.get('report_type', '')
+ record_list = request_POST.get('record_list', '')
+
+ report_name = '%s/investigations_%s_%s.%s' % (SRT_REPORT_DIR,report_type,datetime.today().strftime('%Y%m%d%H%M'),format)
+ with open(report_name, 'w') as file:
+
+ if 'csv' == format:
+ tab = "\t"
+ else:
+ tab = ","
+
+ if ('summary' == report_type):
+ if 'csv' == format:
+ file.write("Name\tStatus\tOutcome\tSeverity\tProduct\tDefects\n")
+ if 'txt' == format:
+ file.write("Report : Investigations Table\n")
+ file.write("\n")
+ file.write("Name,Status,Outcome,Severity,Product,Defects\n")
+
+ for id in record_list.split(','):
+ if not id:
+ continue
+ investigation = Investigation.objects.get(id=id)
+ file.write("%s%s" % (investigation.name,tab))
+ file.write("%s%s" % (investigation.get_status_text,tab))
+ file.write("%s%s" % (investigation.get_outcome_text,tab))
+ file.write("%s%s" % (investigation.get_severity_text,tab))
+ file.write("%s%s" % (investigation.product.long_name,tab))
+ for i,id in enumerate(investigation.investigation_to_defect.all()):
+ if i > 0:
+ file.write(" ")
+ file.write("%s (%s)" % (id.defect.name,id.defect.get_status_text))
+ #file.write("%s" % tab)
+ file.write("\n")
+
+ return report_name,os.path.basename(report_name)
+
+class DefectsReport(Report):
+ """Report for the Defects Page"""
+
+ def __init__(self, parent_page, *args, **kwargs):
+ _log_args("REPORT_DEFECTS_INIT(%s)" % parent_page, *args, **kwargs)
+ super(DefectsReport, self).__init__(parent_page, *args, **kwargs)
+
+ def get_context_data(self, *args, **kwargs):
+ _log_args("REPORT_DEFECTS_CONTEXT", *args, **kwargs)
+ context = super(DefectsReport, self).get_context_data(*args, **kwargs)
+
+ context['report_type_list'] = '\
+ <option value="summary">Defects Table</option> \
+ '
+ context['report_get_title'] = '1'
+ context['report_recordrange_list'] = '\
+ <input type="radio" name="records" value="selected" checked> Selected<br> \
+ '
+ context['report_columnrange_list'] = ''
+ context['report_format_list'] = '\
+ <input type="radio" name="format" value="txt" checked> Text<br> \
+ <input type="radio" name="format" value="csv"> CSV<br> \
+ '
+ return context
+
+ def exec_report(self, *args, **kwargs):
+ _log_args("REPORT_DEFECTS_EXEC", *args, **kwargs)
+ super(DefectsReport, self).exec_report(*args, **kwargs)
+
+ request_POST = self.request.POST
+
+ records = request_POST.get('records', '')
+ format = request_POST.get('format', '')
+ title = request_POST.get('title', '')
+ report_type = request_POST.get('report_type', '')
+ record_list = request_POST.get('record_list', '')
+
+ report_name = '%s/defects_%s_%s.%s' % (SRT_REPORT_DIR,report_type,datetime.today().strftime('%Y%m%d%H%M'),format)
+ with open(report_name, 'w') as file:
+
+ if 'csv' == format:
+ tab = "\t"
+ else:
+ tab = ","
+
+ if ('summary' == report_type):
+ if 'csv' == format:
+ file.write("Name\tSummary\tPriority\tStatus\tResolution\tReleased Version\tURL\tInvestigations\tProduct\n")
+ if 'txt' == format:
+ file.write("Report : Defects Table\n")
+ file.write("\n")
+ file.write("Name,Summary,Priority,Status,Resolution,Released Version,URL,Investigations,Product\n")
+
+ for id in record_list.split(','):
+ if not id:
+ continue
+ defect = Defect.objects.get(id=id)
+ file.write("%s%s" % (defect.name,tab))
+ file.write("%s%s" % (defect.summary,tab))
+ file.write("%s%s" % (defect.get_priority_text,tab))
+ file.write("%s%s" % (defect.get_status_text,tab))
+ file.write("%s%s" % (defect.get_resolution_text,tab))
+ file.write("%s%s" % (defect.release_version,tab))
+ file.write("%s%s" % (defect.publish,tab))
+ file.write("%s%s" % (defect.url,tab))
+ for i,di in enumerate(defect.defect_to_investigation.all()):
+ if i > 0:
+ file.write(" ")
+ file.write("%s" % (di.investigation.name))
+ file.write("%s" % tab)
+ tab='' # EOL
+ file.write("%s%s" % (defect.product.long_name,tab))
+ file.write("\n")
+
+ return report_name,os.path.basename(report_name)
+
+class ProductsReport(Report):
+ """Report for the Products Page"""
+
+ def __init__(self, parent_page, *args, **kwargs):
+ _log_args("REPORT_PRODUCTS_INIT(%s)" % parent_page, *args, **kwargs)
+ super(ProductsReport, self).__init__(parent_page, *args, **kwargs)
+
+ def get_context_data(self, *args, **kwargs):
+ _log_args("REPORT_PRODUCTS_CONTEXT", *args, **kwargs)
+ context = super(ProductsReport, self).get_context_data(*args, **kwargs)
+
+ context['report_type_list'] = '\
+ <option value="summary">Products Table</option> \
+ '
+ context['report_get_title'] = '1'
+ context['report_recordrange_list'] = '\
+ <input type="radio" name="records" value="selected" checked> Selected<br> \
+ '
+ context['report_columnrange_list'] = ''
+ context['report_format_list'] = '\
+ <input type="radio" name="format" value="txt" checked> Text<br> \
+ <input type="radio" name="format" value="csv"> CSV<br> \
+ '
+ return context
+
+ def exec_report(self, *args, **kwargs):
+ _log_args("REPORT_PRODUCTS_EXEC", *args, **kwargs)
+ super(ProductsReport, self).exec_report(*args, **kwargs)
+
+ request_POST = self.request.POST
+
+ records = request_POST.get('records', '')
+ format = request_POST.get('format', '')
+ title = request_POST.get('title', '')
+ report_type = request_POST.get('report_type', '')
+ record_list = request_POST.get('record_list', '')
+
+ report_name = '%s/products_%s_%s.%s' % (SRT_REPORT_DIR,report_type,datetime.today().strftime('%Y%m%d%H%M'),format)
+ with open(report_name, 'w') as file:
+
+ if 'csv' == format:
+ tab = "\t"
+ else:
+ tab = ","
+
+ if ('summary' == report_type):
+ if 'csv' == format:
+ file.write("Name\tVersion\tProfile\tCPE\tSRT SPE\tInvestigations\tDefects\n")
+ if 'txt' == format:
+ file.write("Report : Investigations Table\n")
+ file.write("\n")
+ file.write("Name,Version,Profile,CPE,SRT SPE,Investigations,Defects\n")
+
+ for id in record_list.split(','):
+ if not id:
+ continue
+ product = Product.objects.get(id=id)
+ file.write("%s%s" % (product.name,tab))
+ file.write("%s%s" % (product.version,tab))
+ file.write("%s%s" % (product.profile,tab))
+ file.write("%s%s" % (product.cpe,tab))
+ file.write("%s%s" % (product.srt_cpe,tab))
+ file.write("%s%s" % (product.defect_prefix,tab))
+ for i,pi in enumerate(product.product_investigation.all()):
+ if i > 0:
+ file.write(" ")
+ file.write("%s" % (pi.name))
+ file.write("%s" % tab)
+ for i,pd in enumerate(product.product_defect.all()):
+ if i > 0:
+ file.write(" ")
+ file.write("%s" % (pd.name))
+ #file.write("%s" % tab)
+ file.write("\n")
+
+ return report_name,os.path.basename(report_name)
+
+class PublishCveReport(Report):
+ """Report for the Publish Cve Page"""
+
+ def __init__(self, parent_page, *args, **kwargs):
+ _log_args("REPORT_PUBLISHCVE_INIT(%s)" % parent_page, *args, **kwargs)
+ super(PublishCveReport, self).__init__(parent_page, *args, **kwargs)
+
+ def get_context_data(self, *args, **kwargs):
+ _log_args("REPORT_PUBLISHCVE_CONTEXT", *args, **kwargs)
+ context = super(PublishCveReport, self).get_context_data(*args, **kwargs)
+
+ context['report_type_list'] = '\
+ <option value="summary">CVE Publish Request Table</option> \
+ '
+ context['report_get_title'] = '1'
+ context['report_recordrange_list'] = '\
+ <input type="radio" name="records" value="selected" checked> Selected<br> \
+ '
+ context['report_columnrange_list'] = ''
+ context['report_format_list'] = '\
+ <input type="radio" name="format" value="txt" checked> Text<br> \
+ <input type="radio" name="format" value="csv"> CSV<br> \
+ '
+ return context
+
+ def exec_report(self, *args, **kwargs):
+ _log_args("REPORT_PUBLISHCVE_EXEC", *args, **kwargs)
+ super(PublishCveReport, self).exec_report(*args, **kwargs)
+
+ _log("FOO1")
+ request_POST = self.request.POST
+
+ records = request_POST.get('records', '')
+ format = request_POST.get('format', '')
+ title = request_POST.get('title', '')
+ report_type = request_POST.get('report_type', '')
+ record_list = request_POST.get('record_list', '')
+
+ _log("FOO2 (%s,%s,%s" % (record_list,format,report_type))
+ report_name = '%s/cve_publish_%s_%s.%s' % (SRT_REPORT_DIR,report_type,datetime.today().strftime('%Y%m%d%H%M'),format)
+ with open(report_name, 'w') as file:
+
+ _log("FOO3")
+ if 'csv' == format:
+ tab = "\t"
+ else:
+ tab = ","
+
+ if ('summary' == report_type):
+ if 'csv' == format:
+ file.write("Name\tStatus\tType\tFormat\tVersion\tVulnerabilities\tDescription\n")
+ if 'txt' == format:
+ file.write("Report : CVEs Table\n")
+ file.write("\n")
+ file.write("Name,Status,Type,Format,Version,Vulnerabilities,Description\n")
+
+ _log("FOO4")
+ for id in record_list.split(','):
+ _log("FOO5:%s" % id)
+ if not id:
+ continue
+ try:
+ cve = Cve.objects.get(id=id)
+ file.write("%s%s" % (cve.name,tab))
+ file.write("%s%s" % (cve.get_status_text,tab))
+ file.write("%s%s" % (cve.cve_data_type,tab))
+ file.write("%s%s" % (cve.cve_data_format,tab))
+ file.write("%s%s" % (cve.cve_data_version,tab))
+
+ for i,cv in enumerate(cve.cve_to_vulnerability.all()):
+ if i > 0:
+ file.write(" ")
+ file.write("%s" % cv.vulnerability.name)
+ file.write("%s" % tab)
+
+ file.write("%s" % (cve.description))
+ file.write("\n")
+ except Exception as e:
+ _log("FOOX:%s" % e)
+
+ _log("FOO9:%s" % (report_name))
+ return report_name,os.path.basename(report_name)
+
+class PublishPendingCveReport(Report):
+ """Report for the Publish Cve Page"""
+
+ def __init__(self, parent_page, *args, **kwargs):
+ _log_args("REPORT_PUBLISHPENDINGCVE_INIT(%s)" % parent_page, *args, **kwargs)
+ super(PublishPendingCveReport, self).__init__(parent_page, *args, **kwargs)
+
+ def get_context_data(self, *args, **kwargs):
+ _log_args("REPORT_PUBLISHPENDINGCVE_CONTEXT", *args, **kwargs)
+ context = super(PublishPendingCveReport, self).get_context_data(*args, **kwargs)
+ context['report_type_list'] = '\
+ <option value="summary">CVE Publish Request Table</option> \
+ '
+ context['report_get_title'] = '1'
+ context['report_recordrange_list'] = '\
+ <input type="radio" name="records" value="selected" checked> Selected<br> \
+ '
+ context['report_columnrange_list'] = ''
+ context['report_format_list'] = '\
+ <input type="radio" name="format" value="txt" checked> Text<br> \
+ <input type="radio" name="format" value="csv"> CSV<br> \
+ '
+ return context
+
+ def exec_report(self, *args, **kwargs):
+ _log_args("REPORT_PUBLISHPENDINGCVE_EXEC", *args, **kwargs)
+ super(PublishPendingCveReport, self).exec_report(*args, **kwargs)
+
+ _log("FOO1")
+ request_POST = self.request.POST
+
+ records = request_POST.get('records', '')
+ format = request_POST.get('format', '')
+ title = request_POST.get('title', '')
+ report_type = request_POST.get('report_type', '')
+ record_list = request_POST.get('record_list', '')
+
+ _log("FOO2 (%s,%s,%s" % (record_list,format,report_type))
+ report_name = '%s/cve_publish_%s_%s.%s' % (SRT_REPORT_DIR,report_type,datetime.today().strftime('%Y%m%d%H%M'),format)
+ with open(report_name, 'w') as file:
+
+ _log("FOO3")
+ if 'csv' == format:
+ tab = "\t"
+ else:
+ tab = ","
+
+ if ('summary' == report_type):
+ if 'csv' == format:
+ file.write("Name\tStatus\tType\tFormat\tVersion\tVulnerabilities\tDescription\n")
+ if 'txt' == format:
+ file.write("Report : CVEs Table\n")
+ file.write("\n")
+ file.write("Name,Status,Type,Format,Version,Vulnerabilities,Description\n")
+
+ _log("FOO4")
+ for id in record_list.split(','):
+ if not id:
+ continue
+ _log("FOO5:%s" % id)
+ try:
+ cve = Cve.objects.get(id=id)
+ file.write("%s%s" % (cve.name,tab))
+ file.write("%s%s" % (cve.get_status_text,tab))
+ file.write("%s%s" % (cve.cve_data_type,tab))
+ file.write("%s%s" % (cve.cve_data_format,tab))
+ file.write("%s%s" % (cve.cve_data_version,tab))
+
+ for i,cv in enumerate(cve.cve_to_vulnerability.all()):
+ if i > 0:
+ file.write(" ")
+ file.write("%s" % cv.vulnerability.name)
+ file.write("%s" % tab)
+
+ file.write("%s" % (cve.description))
+ file.write("\n")
+ except Exception as e:
+ _log("FOOX:%s" % e)
+
+ _log("FOO9:%s" % (report_name))
+ return report_name,os.path.basename(report_name)
+
+class DefaultReport(Report):
+ """Report for the Default Page"""
+
+ def __init__(self, parent_page, *args, **kwargs):
+ _log_args("REPORT_GENERIC_INIT(%s)" % parent_page, *args, **kwargs)
+ super(DefaultReport, self).__init__(parent_page, *args, **kwargs)
+ self.default_orderby = "name"
+
+ def get_context_data(self, *args, **kwargs):
+ _log_args("REPORT_GENERIC_CONTEXT", *args, **kwargs)
+ context = super(DefaultReport, self).get_context_data(*args, **kwargs)
+ context['report_enable_submit'] = ''
+
+ #context['report_recordrange_list'] = '\
+ # <input type="radio" name="records" value="selected" checked> Selected<br> \
+ # <input type="radio" name="records" value="all"> all<br> \
+ #context['report_columnrange_list'] = ''
+ # <input type="radio" name="columns" value="selected" checked> Selected<br>
+ # <input type="radio" name="columns" value="all"> All<br>
+ #context['report_format_list'] = '\
+ # <input type="radio" name="format" value="txt" checked> Text<br> \
+ # <input type="radio" name="format" value="csv"> CSV<br> \
+ # <input type="radio" name="format" value="rtf"> RTF<br>
+ # <input type="radio" name="format" value="xml"> XML<br>
+ # <input type="radio" name="format" value="json"> CVE NIST JSON<br>
+
+ return context
+
+ def exec_report(self, *args, **kwargs):
+ _log_args("REPORT_GENERIC_EXEC", *args, **kwargs)
+ super(ManagementReport, self).exec_report(*args, **kwargs)
+ return None
+
+
+class ReportManager():
+ @staticmethod
+ def get_report_class(parent_page, *args, **kwargs):
+ if ('management' == parent_page) or ('manage' == parent_page):
+ return ManagementReport(parent_page, *args, **kwargs)
+
+ elif 'cve' == parent_page:
+ return CveReport(parent_page, *args, **kwargs)
+ elif 'vulnerability' == parent_page:
+ return VulnerabilityReport(parent_page, *args, **kwargs)
+ elif 'investigation' == parent_page:
+ return InvestigationReport(parent_page, *args, **kwargs)
+ elif 'defect' == parent_page:
+ return DefectReport(parent_page, *args, **kwargs)
+
+ elif 'cves' == parent_page:
+ return CvesReport(parent_page, *args, **kwargs)
+ elif 'select-cves' == parent_page:
+ return SelectCvesReport(parent_page, *args, **kwargs)
+ elif 'vulnerabilities' == parent_page:
+ return VulnerabilitiesReport(parent_page, *args, **kwargs)
+ elif 'investigations' == parent_page:
+ return InvestigationsReport(parent_page, *args, **kwargs)
+ elif 'defects' == parent_page:
+ return DefectsReport(parent_page, *args, **kwargs)
+ elif 'products' == parent_page:
+ return ProductsReport(parent_page, *args, **kwargs)
+
+ elif 'select-publish' == parent_page:
+ return PublishCveReport(parent_page, *args, **kwargs)
+ elif 'update-published' == parent_page:
+ return PublishPendingCveReport(parent_page, *args, **kwargs)
+
+
+ else:
+ return DefaultReport(parent_page, *args, **kwargs)
+
+ @staticmethod
+ def get_context_data(parent_page, *args, **kwargs):
+ reporter = ReportManager.get_report_class(parent_page, *args, **kwargs)
+ return reporter.get_context_data(*args, **kwargs)
+
+ @staticmethod
+ def exec_report(parent_page, *args, **kwargs):
+ reporter = ReportManager.get_report_class(parent_page, *args, **kwargs)
+ return reporter.exec_report(*args, **kwargs)
diff --git a/lib/srtgui/tables.py b/lib/srtgui/tables.py
index 798855d6..643dd34d 100644
--- a/lib/srtgui/tables.py
+++ b/lib/srtgui/tables.py
@@ -22,7 +22,8 @@
from srtgui.widgets import ToasterTable
from orm.models import SrtSetting
from orm.models import Cve, Vulnerability, Investigation, CweTable, Product
-from orm.models import CpeTable, Access, CpeFilter, Defect, Keywords
+from orm.models import CpeTable, Access, CpeFilter, Defect, Keywords, DataSource
+from orm.models import PublishPending
from django.db.models import Q, Max, Sum, Count, When, Case, Value, IntegerField
from django.conf.urls import url
@@ -35,47 +36,46 @@ from srtgui.tablefilter import TableFilterActionToggle
from srtgui.tablefilter import TableFilterActionDateRange
from srtgui.tablefilter import TableFilterActionDay
-def _log(msg):
- f1=open('/tmp/srt.log', 'a')
- f1.write("|" + msg + "|\n" )
- f1.close()
+import os
+# quick development/debugging support
+from srtgui.api import _log
-class AllCveTable(ToasterTable):
+class CvesTable(ToasterTable):
"""Table of All CVE's in SRTool"""
def __init__(self, *args, **kwargs):
- super(AllCveTable, self).__init__(*args, **kwargs)
+ super(CvesTable, self).__init__(*args, **kwargs)
self.default_orderby = "name"
def get_context_data(self, **kwargs):
- context = super(AllCveTable, self).get_context_data(**kwargs)
+ context = super(CvesTable, self).get_context_data(**kwargs)
return context
def setup_filters(self, *args, **kwargs):
- # Is Vulnerable filter
+ # Is Status filter
is_status = TableFilter(name="is_status",
title="Filter CVE's by 'Status")
- exec_is_new = TableFilterActionToggle(
+ is_status.add_action(TableFilterActionToggle(
"new",
"New",
Q(status=Cve.NEW))
- exec_is_investigate = TableFilterActionToggle(
+ )
+ is_status.add_action(TableFilterActionToggle(
"investigate",
"Investigate",
Q(status=Cve.INVESTIGATE))
- exec_is_vulnerable = TableFilterActionToggle(
+ )
+ is_status.add_action(TableFilterActionToggle(
"vulnerable",
"Is Vulnerable",
Q(status=Cve.VULNERABLE))
- exec_is_not_vulnerable = TableFilterActionToggle(
+ )
+ is_status.add_action(TableFilterActionToggle(
"not_vulnerable",
"Not Vulnerable",
Q(status=Cve.NOT_VULNERABLE))
- is_status.add_action(exec_is_new)
- is_status.add_action(exec_is_investigate)
- is_status.add_action(exec_is_vulnerable)
- is_status.add_action(exec_is_not_vulnerable)
+ )
self.add_filter(is_status)
# Recommends filter
@@ -123,38 +123,37 @@ class AllCveTable(ToasterTable):
Cve.objects.all()
# filter out hidden records
- userAccess = Access()
+ userAccess = Access(self.request.session.get('srt_user_id', '0'))
if not userAccess.is_admin():
self.queryset = self.queryset.exclude(public = False)
self.queryset = self.queryset.order_by(self.default_orderby)
-# self.static_context_extra['in_prj'] = ProjectLayer.objects.filter(Q(project=kwargs['pid']) & Q(layercommit=kwargs['layerid'])).count()
+
def setup_columns(self, *args, **kwargs):
id_link_template = '''
- <a href="{% url 'cve' data.id %}">
- {{data.name}}
- </a>
+ <a href="{% url 'cve' data.id %}" id="dataid_{{data.id}}">{{data.name}}</a>
'''
- self.add_column(title="ID",
+ self.add_column(title="Name",
hideable=False,
orderable=True,
field_name="name",
static_data_name="name",
- static_data_template=id_link_template)
+ static_data_template=id_link_template,
+ )
self.add_column(title="Status",
field_name="status",
hideable=True,
orderable=True,
- filter_name="is_status",
+# filter_name="is_status",
static_data_name="status",
static_data_template="{{data.get_status_text}}"
)
score_link_template = '''
- {% if 0 == data.recommend %}0{% else %}{{data.recommend}}{% endif %}
+ {% if 0 == data.recommend %}0{% else %}{{data.recommend}}{% endif %}
'''
self.add_column(title="Score",
field_name="recommend",
@@ -189,17 +188,18 @@ class AllCveTable(ToasterTable):
)
severity_v3_template = '''
- {{data.cvssV3_baseScore}} {{data.cvssV3_baseSeverity}}
+ {{data.cvssV3_baseScore}} {{data.cvssV3_baseSeverity}}
'''
self.add_column(title="Severity (V3)",
help_text="Severity of the CVE (v3)",
hideable=False,
orderable=False,
static_data_name='severity_v3',
- static_data_template=severity_v3_template)
+ static_data_template=severity_v3_template,
+ )
severity_v2_template = '''
- {{data.cvssV2_baseScore}} {{data.cvssV2_severity}}
+ {{data.cvssV2_baseScore}} {{data.cvssV2_severity}}
'''
self.add_column(title="Severity (V2)",
help_text="Severity of the CVE (v2)",
@@ -207,19 +207,22 @@ class AllCveTable(ToasterTable):
hidden=True,
orderable=False,
static_data_name='severity_v2',
- static_data_template=severity_v2_template)
+ static_data_template=severity_v2_template,
+ )
self.add_column(title="Published",
help_text="Initial publish date of the CVE",
hideable=False,
orderable=True,
- field_name="publishedDate")
+ field_name="publishedDate",
+ )
self.add_column(title="Modified",
help_text="Last modification date of the CVE",
hideable=True,
orderable=True,
- field_name="lastModifiedDate")
+ field_name="lastModifiedDate",
+ )
self.add_column(title="Comments",
field_name="comments",
@@ -227,7 +230,25 @@ class AllCveTable(ToasterTable):
orderable=True,
)
- userAccess = Access()
+ self.add_column(title="Publish Request",
+ help_text="SRT Publish Request State",
+ hideable=True,
+ hidden=True,
+ orderable=True,
+ field_name="publish_state",
+ static_data_name="publish_state",
+ static_data_template='{{data.get_publish_text}}',
+ )
+
+ self.add_column(title="Publish Date",
+ help_text="SRT Publish date of the CVE",
+ hideable=True,
+ hidden=True,
+ orderable=True,
+ field_name="publish_date"
+ )
+
+ userAccess = Access(self.request.session.get('srt_user_id', '0'))
if userAccess.is_admin():
self.add_column(title="Comments Private",
field_name="comments_private",
@@ -235,27 +256,32 @@ class AllCveTable(ToasterTable):
)
vulnerability_link_template = '''
- {% if data.cve_to_vulnerability.all %}
- {% for cv in data.cve_to_vulnerability.all %}
- {% if not forloop.first %}| {% endif %}<a href="{% url 'vulnerability' cv.vulnerability.pk %}">{{cv.vulnerability.name}}</a>
- {% endfor %}
- {% endif %}
+ {% for cv in data.cve_to_vulnerability.all %}
+ {% if not forloop.first %}| {% endif %}<a href="{% url 'vulnerability' cv.vulnerability.pk %}">{{cv.vulnerability.name}}</a>
+ {% endfor %}
'''
self.add_column(title="Vulnerability",
static_data_name="vulnerability",
static_data_template=vulnerability_link_template,
- hidden=False)
-
- if False:
- defect_template = '''
+# static_data_template='',
+ hidden=False,
+ )
- '''
- self.add_column(title="Defect",
- help_text="Associated Defects",
- hideable=True,
- orderable=True,
- static_data_name='defect',
- static_data_template=defect_template)
+ defect_link_template = '''
+ {% for cv in data.cve_to_vulnerability.all %}
+ {% for investigation in cv.vulnerability.vulnerability_investigation.all %}
+ {% for id in investigation.investigation_to_defect.all %}
+ {% if not forloop.first %}| {% endif %}<a href="{% url 'defect' id.defect.pk %}">{{id.defect.name}}</a>
+ {% endfor %}
+ {% endfor %}
+ {% endfor %}
+ '''
+ self.add_column(title="Defect",
+ static_data_name="defect",
+ static_data_template=defect_link_template,
+# static_data_template='',
+ hidden=False,
+ )
class SelectCveTable(ToasterTable):
@@ -274,27 +300,15 @@ class SelectCveTable(ToasterTable):
data = super(SelectCveTable, self).apply_row_customization(data)
# data:dict_keys(['rows', 'total', 'default_orderby', 'error', 'columns'])
- if False:
- # TEST
- KeywordsFor = SrtSetting.objects.get(name='keywords_for').value.split('|')
- KeywordsAgainst = SrtSetting.objects.get(name='keywords_against').value.split('|')
- qq = 0
- for i in range(len(data['rows'])):
- data['rows'][i]['for'] = 'Y:%s%d' % (KeywordsFor[qq],i)
- data['rows'][i]['against'] = 'N:%s%d' % (KeywordsAgainst[qq],i)
- qq += 1
- if 10<qq:
- qq = 0
-
- if True:
- for i in range(len(data['rows'])):
- data['rows'][i]['for'] = ''
- data['rows'][i]['against'] = ''
- for key in data['rows'][i]['comments_private'].split(','):
- if key.startswith('+'):
- data['rows'][i]['for'] += '%s ' % key[1:]
- elif key.startswith('-'):
- data['rows'][i]['against'] += '%s ' % key[1:]
+ # comments_private -> recommend_list
+ for i in range(len(data['rows'])):
+ data['rows'][i]['for'] = ''
+ data['rows'][i]['against'] = ''
+ for key in data['rows'][i]['recommend_list'].split(','):
+ if key.startswith('+'):
+ data['rows'][i]['for'] += '%s ' % key[1:]
+ elif key.startswith('-'):
+ data['rows'][i]['against'] += '%s ' % key[1:]
return data
@@ -365,14 +379,12 @@ class SelectCveTable(ToasterTable):
Cve.objects.filter(status = Cve.NEW,name__startswith = 'CVE-2018')
# filter out hidden records !!! ALL NEW ONES SHOULD BE PUBLIC
-# userAccess = Access()
+# userAccess = Access(self.request.session.get('srt_user_id', '0'))
# if not userAccess.is_admin():
# self.queryset = self.queryset.exclude(public = False)
self.queryset = self.queryset.order_by(self.default_orderby)
-# self.static_context_extra['in_prj'] = ProjectLayer.objects.filter(Q(project=kwargs['pid']) & Q(layercommit=kwargs['layerid'])).count()
-
def setup_columns(self, *args, **kwargs):
@@ -380,7 +392,7 @@ class SelectCveTable(ToasterTable):
field_name="Select",
hideable=False,
static_data_name="select",
- static_data_template='<input type="checkbox" name="{{data.name}}" />'
+ static_data_template='<input type="checkbox" name="{{data.name}}" />',
)
self.add_column(title="Status",
@@ -389,18 +401,17 @@ class SelectCveTable(ToasterTable):
orderable=True,
filter_name="is_status",
static_data_name="status",
- static_data_template="{{data.get_status_text}}"
+ static_data_template="{{data.get_status_text}}",
)
- self.add_column(title="Comments",
- field_name="comments_private",
+ self.add_column(title="Recommend List",
+ field_name="recommend_list",
hideable=True,
hidden=True,
)
-# {% if 0 == data.recommend %}0{% else %}{{data.recommend}}{% endif %}
recommend_link_template = '''
- {% load projecttags %}{{data.recommend|recommend_display}}
+ {% load projecttags %}{{data.recommend|recommend_display}}
'''
self.add_column(title="Recommendation",
hideable=False,
@@ -412,16 +423,15 @@ class SelectCveTable(ToasterTable):
)
id_link_template = '''
- <a href="{% url 'cve' data.id %}" target="_blank">
- {{data.name}}
- </a>
+ <a href="{% url 'cve' data.id %}" id="dataid_{{data.id}}" target="_blank">{{data.name}}</a>
'''
self.add_column(title="Name",
hideable=False,
orderable=True,
field_name="name",
static_data_name="name",
- static_data_template=id_link_template)
+ static_data_template=id_link_template,
+ )
self.add_column(title="Description",
field_name="description",
@@ -429,17 +439,18 @@ class SelectCveTable(ToasterTable):
)
severity_v3_template = '''
- {{data.cvssV3_baseScore}} {{data.cvssV3_baseSeverity}}
+ {{data.cvssV3_baseScore}} {{data.cvssV3_baseSeverity}}
'''
self.add_column(title="Severity (V3)",
help_text="Severity of the CVE (v3)",
hideable=False,
orderable=False,
static_data_name='severity_v3',
- static_data_template=severity_v3_template)
+ static_data_template=severity_v3_template,
+ )
severity_v2_template = '''
- {{data.cvssV2_baseScore}} {{data.cvssV2_severity}}
+ {{data.cvssV2_baseScore}} {{data.cvssV2_severity}}
'''
self.add_column(title="Severity (V2)",
help_text="Severity of the CVE (v2)",
@@ -447,15 +458,11 @@ class SelectCveTable(ToasterTable):
hidden=True,
orderable=False,
static_data_name='severity_v2',
- static_data_template=severity_v2_template)
-
-
-#{{keyscore|get_dict_value:data.name}}
-#{{keysfor|get_dict_value:data.name}}
-#{{keysagainst|get_dict_value:data.name}}
+ static_data_template=severity_v2_template,
+ )
for_template = '''
- {{keysfor|get_dict_value:data.name}}
+ {{keysfor|get_dict_value:data.name}}
'''
self.add_column(title="Reasons For",
help_text="Keywords for accepting this CVE",
@@ -466,7 +473,7 @@ class SelectCveTable(ToasterTable):
)
against_template = '''
- {{keysagainst|get_dict_value:data.name}}
+ {{keysagainst|get_dict_value:data.name}}
'''
self.add_column(title="Reasons Against",
help_text="Keywords for not accepting this CVE",
@@ -477,15 +484,15 @@ class SelectCveTable(ToasterTable):
)
-class AllDefectTable(ToasterTable):
- """Table of All Defects's in SRTool"""
+class DefectsTable(ToasterTable):
+ """Table of All Defects in SRTool"""
def __init__(self, *args, **kwargs):
- super(AllDefectTable, self).__init__(*args, **kwargs)
+ super(DefectsTable, self).__init__(*args, **kwargs)
self.default_orderby = "name"
def get_context_data(self, **kwargs):
- context = super(AllDefectTable, self).get_context_data(**kwargs)
+ context = super(DefectsTable, self).get_context_data(**kwargs)
return context
@@ -493,102 +500,47 @@ class AllDefectTable(ToasterTable):
# Priority filter
is_priority = TableFilter(name="is_priority",
title="Filter defects by 'Priority'")
- exec_is_low = TableFilterActionToggle(
- "low",
- "Low",
- Q(priority=Defect.LOW))
- exec_is_medium = TableFilterActionToggle(
- "medium",
- "Medium",
- Q(priority=Defect.MEDIUM))
- exec_is_high = TableFilterActionToggle(
- "high",
- "High",
- Q(priority=Defect.HIGH))
- is_priority.add_action(exec_is_low)
- is_priority.add_action(exec_is_medium)
- is_priority.add_action(exec_is_high)
+ for priority in range(len(Defect.Priority)):
+ is_priority.add_action(TableFilterActionToggle(
+ Defect.Priority[priority][1].lower().replace(' ','_'),
+ Defect.Priority[priority][1],
+ Q(resolution=Defect.Priority[priority][0]))
+ )
self.add_filter(is_priority)
# Status filter
is_status = TableFilter(name="is_status",
title="Filter defects by 'Status'")
- exec_is_open = TableFilterActionToggle(
- "open",
- "Open",
- Q(status=Defect.OPEN))
- exec_is_in_progress = TableFilterActionToggle(
- "in_progress",
- "In progress",
- Q(status=Defect.IN_PROGRESS))
- exec_is_on_hold = TableFilterActionToggle(
- "on_hold",
- "On Hold",
- Q(status=Defect.ON_HOLD))
- exec_is_checked_in = TableFilterActionToggle(
- "checked_in",
- "Checked In",
- Q(status=Defect.CHECKED_IN))
- exec_is_resolved = TableFilterActionToggle(
- "resolved",
- "Resolved",
- Q(status=Defect.RESOLVED))
- exec_is_closed = TableFilterActionToggle(
- "closed",
- "Closed",
- Q(status=Defect.CLOSED))
- is_status.add_action(exec_is_open)
- is_status.add_action(exec_is_in_progress)
- is_status.add_action(exec_is_on_hold)
- is_status.add_action(exec_is_checked_in)
- is_status.add_action(exec_is_resolved)
- is_status.add_action(exec_is_closed)
+ for status in range(len(Defect.Status)):
+ is_status.add_action(TableFilterActionToggle(
+ Defect.Status[status][1].lower().replace(' ','_'),
+ Defect.Status[status][1],
+ Q(resolution=Defect.Status[status][0]))
+ )
self.add_filter(is_status)
# Resolution filter
is_resolution = TableFilter(name="is_resolution",
title="Filter defects by 'Resolution'")
- exec_is_unresolved = TableFilterActionToggle(
- "unresolved",
- "Unresolved",
- Q(resolution=Defect.UNRESOLVED))
- exec_is_fixed = TableFilterActionToggle(
- "fixed",
- "Fixed",
- Q(resolution=Defect.FIXED))
- exec_is_will_not_fix = TableFilterActionToggle(
- "will_not_fix",
- "Will Not Fix",
- Q(resolution=Defect.WILL_NOT_FIX))
- exec_is_withdrawn = TableFilterActionToggle(
- "withdrawn",
- "Withdrawn",
- Q(resolution=Defect.WITHDRAWN))
- exec_is_rejected = TableFilterActionToggle(
- "rejected",
- "Rejected",
- Q(resolution=Defect.REJECTED))
- exec_is_duplicate = TableFilterActionToggle(
- "duplicate",
- "Duplicate",
- Q(resolution=Defect.DUPLICATE))
- is_resolution.add_action(exec_is_unresolved)
- is_resolution.add_action(exec_is_fixed)
- is_resolution.add_action(exec_is_will_not_fix)
- is_resolution.add_action(exec_is_withdrawn)
- is_resolution.add_action(exec_is_rejected)
- is_resolution.add_action(exec_is_duplicate)
+ for resolution in range(len(Defect.Resolution)):
+ is_resolution.add_action(TableFilterActionToggle(
+ Defect.Resolution[resolution][1].lower().replace(' ','_'),
+ Defect.Resolution[resolution][1],
+ Q(resolution=Defect.Resolution[resolution][0]))
+ )
self.add_filter(is_resolution)
# Product filter
#(name="Wind River Linux",version="LTS-17")
is_product = TableFilter(name="is_product",
title="Filter defects by 'Product'")
- for p in Product.objects.all():
+ for product in Product.objects.all():
+ _log("PRODUCTS:%s,%s"% (product.defect_prefix,product.long_name))
is_product.add_action( TableFilterActionToggle(
- p.defect_prefix,
- p.long_name(),
- Q(product=p)) )
+ product.defect_prefix,
+ product.long_name,
+ Q(product=product))
+ )
self.add_filter(is_product)
@@ -601,16 +553,15 @@ class AllDefectTable(ToasterTable):
def setup_columns(self, *args, **kwargs):
name_link_template = '''
- <a href="http://defect.wrs.com/browse/{{data.name}}" target="_blank">
- {{data.name}}
- </a>
+ <a href="{% url 'defect' data.id %}" id="dataid_{{data.id}}">{{data.name}}</a>
'''
self.add_column(title="Name",
hideable=False,
orderable=True,
field_name="name",
static_data_name="name",
- static_data_template=name_link_template)
+ static_data_template=name_link_template,
+ )
self.add_column(title="Summary",
field_name="summary",
@@ -622,25 +573,25 @@ class AllDefectTable(ToasterTable):
orderable=True,
filter_name="is_priority",
static_data_name="priority",
- static_data_template='{{data.get_priority_text}}'
+ static_data_template='{{data.get_priority_text}}',
)
-
+
self.add_column(title="Status",
hideable=False,
field_name="status",
orderable=True,
filter_name="is_status",
static_data_name="status",
- static_data_template='{{data.get_status_text}}'
+ static_data_template='{{data.get_status_text}}',
)
-
- self.add_column(title="resolution",
+
+ self.add_column(title="Resolution",
hideable=False,
field_name="resolution",
orderable=True,
filter_name="is_resolution",
static_data_name="resolution",
- static_data_template='{{data.get_resolution_text}}'
+ static_data_template='{{data.get_resolution_text}}',
)
self.add_column(title="Release Version",
@@ -649,53 +600,64 @@ class AllDefectTable(ToasterTable):
field_name="release_version",
)
- self.add_column(title="Publish OLS",
+ self.add_column(title="Publish",
hideable=True,
orderable=True,
- field_name="publishOLS",
+ field_name="publish",
+ )
+
+ url_link_template = '''
+ <a href="{{data.url}}" target="_blank">{{data.url}}</a>
+ '''
+ self.add_column(title="URL",
+ field_name="url",
+ hideable=True,
+ hidden=True,
+ static_data_name="url",
+ static_data_template=url_link_template,
)
#date_created = models.DateField(null=True, blank=True)
#date_updated = models.DateField(null=True, blank=True)
investigations_link_template = '''
- {% for ji in data.defect_to_investigation.all %}
- {% if not forloop.first %}| {% endif %}<a href="{% url 'investigation' ji.investigation.id %}" target="_blank">{{ji.investigation.name}} </a>
- {% endfor %}
+ {% for ji in data.defect_to_investigation.all %}
+ {% if not forloop.first %}| {% endif %}<a href="{% url 'investigation' ji.investigation.id %}" target="_blank">{{ji.investigation.name}} </a>
+ {% endfor %}
'''
self.add_column(title="Investigation",
hideable=True,
# orderable=True, # multiple investigations
static_data_name="investigation",
- static_data_template=investigations_link_template
+ static_data_template=investigations_link_template,
)
# !!! HACK: 'data.product' is returning '%s' when it is supposed to be null !!!
product_link_template = '''
- {% if data.product != '%s' %}
- <a href="{% url 'products'%}">
- {{data.product.long_name}}
- </a>
- {% endif %}
+ {% if data.product != '%s' %}
+ <a href="{% url 'product' data.product.id %}">
+ {{data.product.long_name}}
+ </a>
+ {% endif %}
'''
self.add_column(title="Product",
hideable=True,
orderable=True,
filter_name="is_product",
static_data_name="product",
- static_data_template=product_link_template
+ static_data_template=product_link_template,
)
-class AllCweTable(ToasterTable):
+class CwesTable(ToasterTable):
"""Table of All CWE's in SRTool"""
def __init__(self, *args, **kwargs):
- super(AllCweTable, self).__init__(*args, **kwargs)
+ super(CwesTable, self).__init__(*args, **kwargs)
self.default_orderby = "name_sort"
def get_context_data(self, **kwargs):
- context = super(AllCweTable, self).get_context_data(**kwargs)
+ context = super(CwesTable, self).get_context_data(**kwargs)
return context
@@ -719,28 +681,22 @@ class AllCweTable(ToasterTable):
def setup_columns(self, *args, **kwargs):
- name_link_template = '''
- <a href="cwelink_{{data.name}}"></a>
- {{data.name}}
- '''
self.add_column(title="Name",
+ field_name="name",
hideable=False,
orderable=True,
- field_name="name_sort",
- static_data_name="name_sort",
- static_data_template=name_link_template)
+ )
href_link_template = '''
- <a href="{{data.href}}" target="_blank">
- {{data.href}}
- </a>
+ <a href="{{data.href}}" id="dataid_{{data.id}} target="_blank">{{data.href}}</a>
'''
self.add_column(title="Link",
hideable=False,
orderable=False,
field_name="href",
static_data_name="href",
- static_data_template=href_link_template)
+ static_data_template=href_link_template,
+ )
self.add_column(title="Summary",
field_name="summary",
@@ -758,23 +714,23 @@ class AllCweTable(ToasterTable):
static_data_name="cves",
static_data_template='{{data.vulnerable_count}}',
)
-
+
# self.add_column(title="CVE's",
# hidden=False,
# static_data_name="cves",
# static_data_template='{{data.cwe2cve.all.count}}',
# )
-
-class AllCpeTable(ToasterTable):
+
+class CpesTable(ToasterTable):
"""Table of All CPE's in SRTool"""
def __init__(self, *args, **kwargs):
- super(AllCpeTable, self).__init__(*args, **kwargs)
+ super(CpesTable, self).__init__(*args, **kwargs)
self.default_orderby = "vulnerable"
def get_context_data(self, **kwargs):
- context = super(AllCpeTable, self).get_context_data(**kwargs)
+ context = super(CpesTable, self).get_context_data(**kwargs)
return context
def setup_filters(self, *args, **kwargs):
@@ -808,20 +764,13 @@ class AllCpeTable(ToasterTable):
# cpeMatchString = models.TextField(blank=True)
# cpe23Uri = models.TextField(blank=True)
- vulnerable_link_template = '''
- {% if data.vulnerable %}
- Yes
- {% else %}
- No
- {% endif %}
- '''
self.add_column(title="Vulnerable",
field_name="vulnerable",
hideable=False,
orderable=True,
filter_name="is_vulnerable",
static_data_name="vulnerable",
- static_data_template=vulnerable_link_template
+ static_data_template="{% if data.vulnerable %}Yes{% else %}No{% endif %}",
)
self.add_column(title="CPE 2.3",
@@ -845,16 +794,17 @@ class AllCpeTable(ToasterTable):
)
cve_link_template = '''
- {% for pv in data.cpe2cve.all %}
- {% if not forloop.first %}| {% endif %}<a href="{% url 'cve' pv.cve.id %}">{{pv.cve.name}} </a>
- {% endfor %}
+ {% for pv in data.cpe2cve.all %}
+ {% if not forloop.first %}| {% endif %}<a href="{% url 'cve' pv.cve.id %}">{{pv.cve.name}} </a>
+ {% endfor %}
'''
self.add_column(title="CVE",
hideable=False,
orderable=True,
field_name="cveName",
static_data_name="cveName",
- static_data_template=cve_link_template)
+ static_data_template=cve_link_template,
+ )
class ManageCpeTable(ToasterTable):
@@ -918,7 +868,7 @@ class ManageCpeTable(ToasterTable):
field_name="Select",
hideable=False,
static_data_name="select",
- static_data_template='<input type="checkbox" name="check_{{data.key_prime}}_{{data.key_sub}}" />'
+ static_data_template='<input type="checkbox" name="check_{{data.key_prime}}_{{data.key_sub}}" />',
)
@@ -928,7 +878,7 @@ class ManageCpeTable(ToasterTable):
orderable=True,
filter_name="is_status",
static_data_name="status",
- static_data_template="{{data.get_status_text}}"
+ static_data_template="{{data.get_status_text}}",
)
self.add_column(title="Company",
@@ -943,22 +893,15 @@ class ManageCpeTable(ToasterTable):
hideable=False,
orderable=True,
static_data_name="key_sub",
- static_data_template="{% if data.key_sub %}{{data.key_sub}}{% else %}(company){% endif %}"
+ static_data_template="{% if data.key_sub %}{{data.key_sub}}{% else %}(company){% endif %}",
)
- automatic_link_template = '''
- {% if data.automatic %}
- Yes
- {% else %}
- No
- {% endif %}
- '''
self.add_column(title="Automatic",
field_name="automatic",
hideable=False,
orderable=True,
static_data_name="automatic",
- static_data_template=automatic_link_template
+ static_data_template="{% if data.automatic %}Yes{% else %}No{% endif %}",
)
manage_link_template = '''
@@ -970,7 +913,7 @@ class ManageCpeTable(ToasterTable):
hideable=False,
orderable=True,
static_data_name="manage",
- static_data_template=manage_link_template
+ static_data_template=manage_link_template,
)
@@ -1015,14 +958,15 @@ class ProductsTable(ToasterTable):
def setup_columns(self, *args, **kwargs):
name_link_template = '''
- {{data.name}}
+ <a href="{% url 'product' data.id %}" id="dataid_{{data.id}}">{{data.name}}<a>
'''
self.add_column(title="Name",
hideable=False,
orderable=True,
field_name="name",
static_data_name="name",
- static_data_template=name_link_template)
+ static_data_template=name_link_template,
+ )
self.add_column(title="Version",
field_name="version",
@@ -1042,8 +986,8 @@ class ProductsTable(ToasterTable):
self.add_column(title="SRT CPE",
field_name="srt_cpe",
- hideable=False,
- )
+ hideable=True,
+ )
self.add_column(title="Defect Prefix",
field_name="defect_prefix",
@@ -1052,25 +996,25 @@ class ProductsTable(ToasterTable):
investigations_link_template = '''
- {% if data.product_investigation.all.count %}
- <a href="{% url 'investigations' %}?filter=is_product:{{data.defect_prefix}}&">
- {{data.product_investigation.all.count}}
- </a>
- {% else %}0{% endif %}
+ {% if data.product_investigation.all.count %}
+ <a href="{% url 'investigations' %}?filter=is_product:{{data.defect_prefix}}&">
+ {{data.product_investigation.all.count}}
+ </a>
+ {% else %}0{% endif %}
'''
self.add_column(title="Investigations",
field_name="investigations",
hidden=False,
static_data_name="investigations",
- static_data_template=investigations_link_template
+ static_data_template=investigations_link_template,
)
defects_link_template = '''
- {% if data.product_defect.all.count %}
- <a href="{% url 'all-defects' %}?filter=is_product:{{data.defect_prefix}}&">
- {{data.product_defect.all.count}}
- </a>
- {% else %}0{% endif %}
+ {% if data.product_defect.all.count %}
+ <a href="{% url 'defects' %}?filter=is_product:{{data.defect_prefix}}&">
+ {{data.product_defect.all.count}}
+ </a>
+ {% else %}0{% endif %}
'''
self.add_column(title="Defects",
field_name="defects",
@@ -1080,15 +1024,15 @@ class ProductsTable(ToasterTable):
)
-class AllVulnerabilitiesTable(ToasterTable):
+class VulnerabilitiesTable(ToasterTable):
"""Table of All Vulnerabilities in SRTool"""
def __init__(self, *args, **kwargs):
- super(AllVulnerabilitiesTable, self).__init__(*args, **kwargs)
+ super(VulnerabilitiesTable, self).__init__(*args, **kwargs)
self.default_orderby = "name"
def get_context_data(self, **kwargs):
- context = super(AllVulnerabilitiesTable, self).get_context_data(**kwargs)
+ context = super(VulnerabilitiesTable, self).get_context_data(**kwargs)
return context
@@ -1163,7 +1107,7 @@ class AllVulnerabilitiesTable(ToasterTable):
Vulnerability.objects.all()
# filter out hidden records
- userAccess = Access()
+ userAccess = Access(self.request.session.get('srt_user_id', '0'))
if not userAccess.is_admin():
self.queryset = self.queryset.exclude(public = False)
@@ -1172,37 +1116,37 @@ class AllVulnerabilitiesTable(ToasterTable):
def setup_columns(self, *args, **kwargs):
id_link_template = '''
- <a href="{% url 'vulnerability' data.id %}">
- {{data.name}}
- </a>
+ <a href="{% url 'vulnerability' data.id %}" id="dataid_{{data.id}}">{{data.name}}</a>
'''
self.add_column(title="ID",
hideable=False,
orderable=True,
field_name="name",
static_data_name="name",
- static_data_template=id_link_template)
+ static_data_template=id_link_template,
+ )
cve_link_template = '''
- {% for vc in data.vulnerability_to_cve.all %}
- {% if not forloop.first %}| {% endif %} <a href="{% url 'cve' vc.cve.pk %}">
- {{vc.cve.name}}
- </a>
- {% endfor %}
+ {% for vc in data.vulnerability_to_cve.all %}
+ {% if not forloop.first %}| {% endif %} <a href="{% url 'cve' vc.cve.pk %}">
+ {{vc.cve.name}}
+ </a>
+ {% endfor %}
'''
self.add_column(title="CVE",
hideable=False,
orderable=False,
field_name="cve__name",
static_data_name="cve__name",
- static_data_template=cve_link_template)
+ static_data_template=cve_link_template,
+ )
self.add_column(title="Status",
field_name="status",
hideable=False,
filter_name="is_status",
static_data_name="status",
- static_data_template="{{data.get_status_text}}"
+ static_data_template="{{data.get_status_text}}",
)
self.add_column(title="Outcome",
@@ -1210,7 +1154,7 @@ class AllVulnerabilitiesTable(ToasterTable):
hideable=False,
filter_name="is_outcome",
static_data_name="outcome",
- static_data_template="{{data.get_outcome_text}}"
+ static_data_template="{{data.get_outcome_text}}",
)
self.add_column(title="Severity",
@@ -1218,7 +1162,7 @@ class AllVulnerabilitiesTable(ToasterTable):
hideable=False,
filter_name="is_severity",
static_data_name="severity",
- static_data_template="{{data.get_severity_text}}"
+ static_data_template="{{data.get_severity_text}}",
)
self.add_column(title="Comments",
@@ -1226,62 +1170,82 @@ class AllVulnerabilitiesTable(ToasterTable):
hideable=True,
)
- userAccess = Access()
+ userAccess = Access(self.request.session.get('srt_user_id', '0'))
if userAccess.is_admin():
self.add_column(title="Comments Private",
field_name="comments_private",
hideable=True,
)
+ investigate_link_template = '''
+ {% for investigation in data.vulnerability_investigation.all %}
+ {% if not forloop.first %}| {% endif %}<a href="{% url 'investigation' investigation.id %}" target="_blank">{{investigation.name}}</a>
+ {% endfor %}
+ '''
+ self.add_column(title="Investigations",
+ static_data_name="vulnerability_investigation",
+ static_data_template=investigate_link_template,
+ hidden=False,
+ )
+
+ defect_link_template = '''
+ {% for investigation in data.vulnerability_investigation.all %}
+ {% for id in investigation.investigation_to_defect.all %}
+ {% if forloop.counter == 1 %}| {% endif %}<a href="{% url 'defect' id.defect.id %}" target="_blank">{{id.defect.name}}</a>
+ {% endfor %}
+ {% endfor %}
+ '''
+ self.add_column(title="Defects",
+ static_data_name="investigation_to_defect",
+ static_data_template=defect_link_template,
+ hidden=False,
+ )
+
+ # VulnerabilityProduct.AFFECTED = 0
product_link_template = '''
{% for vp in data.affected_products.all %}
- {% if vp.relation = 0 %}{% if not forloop.first %}| {% endif %}<a href="{% url 'products'%}" target="_blank">{{vp.product.defect_prefix}}</a>{% endif %}
- {% endfor %}
+ {% if vp.product != '%s' %}
+ {% if vp.relation == 0 %}{% if not forloop.first %}| {% endif %}<a href="{% url 'product' vp.product.id %}" target="_blank">{{vp.product.defect_prefix}}</a>{% endif %}
+ {% endfor %}
+ {% endif %}
'''
self.add_column(title="Products",
static_data_name="investigation_products",
static_data_template=product_link_template,
hidden=False,
)
- if False:
- self.add_column(title="Defects",
- static_data_name="investigation_defects",
- static_data_template='\
- 0',
- hidden=False,
- )
-class AllInvestigationsTable(ToasterTable):
+class InvestigationsTable(ToasterTable):
"""Table of All Investigations in SRTool"""
def __init__(self, *args, **kwargs):
- super(AllInvestigationsTable, self).__init__(*args, **kwargs)
+ super(InvestigationsTable, self).__init__(*args, **kwargs)
self.default_orderby = "name"
def get_context_data(self, **kwargs):
- context = super(AllInvestigationsTable, self).get_context_data(**kwargs)
+ context = super(InvestigationsTable, self).get_context_data(**kwargs)
return context
def setup_filters(self, *args, **kwargs):
# Status filter
is_status = TableFilter(name="is_status",
title="Filter Investigations by 'Status'")
- exec_is_investigate = TableFilterActionToggle(
+ is_status.add_action(TableFilterActionToggle(
"investigate",
"Investigate",
Q(status=Investigation.INVESTIGATE))
- exec_is_vulnerable = TableFilterActionToggle(
+ )
+ is_status.add_action(TableFilterActionToggle(
"vulnerable",
"Is Vulnerable",
Q(status=Investigation.VULNERABLE))
- exec_is_not_vulnerable = TableFilterActionToggle(
+ )
+ is_status.add_action(TableFilterActionToggle(
"not_vulnerable",
"Not Vulnerable",
Q(status=Investigation.NOT_VULNERABLE))
- is_status.add_action(exec_is_investigate)
- is_status.add_action(exec_is_vulnerable)
- is_status.add_action(exec_is_not_vulnerable)
+ )
self.add_filter(is_status)
# Outcome filter
@@ -1335,7 +1299,7 @@ class AllInvestigationsTable(ToasterTable):
for p in Product.objects.all():
is_product.add_action( TableFilterActionToggle(
p.defect_prefix,
- p.long_name(),
+ p.long_name,
Q(product=p)) )
self.add_filter(is_product)
@@ -1345,7 +1309,7 @@ class AllInvestigationsTable(ToasterTable):
Investigation.objects.all()
# filter out hidden records
- userAccess = Access()
+ userAccess = Access(self.request.session.get('srt_user_id', '0'))
if not userAccess.is_admin():
self.queryset = self.queryset.exclude(public = False)
@@ -1354,27 +1318,26 @@ class AllInvestigationsTable(ToasterTable):
def setup_columns(self, *args, **kwargs):
id_link_template = '''
- <a href="{% url 'investigation' data.id %}">
- {{data.name}}
- </a>
+ <a href="{% url 'investigation' data.id %}" id="dataid_{{data.id}}">{{data.name}}</a>
'''
self.add_column(title="ID",
hideable=False,
orderable=True,
field_name="name",
static_data_name="name",
- static_data_template=id_link_template)
+ static_data_template=id_link_template,
+ )
defect_link_template = '''
{% for ij in data.investigation_to_defect.all %}
- {% if not forloop.first %}| {% endif %}<a href="http://defect.wrs.com/browse/{{ij.defect.name}}" target="_blank">{{ij.defect.name}} </a>
+ {% if not forloop.first %}| {% endif %}<a href="{% url 'defect' ij.defect.id %}">{{ij.defect.name}} </a>
{% endfor %}
'''
self.add_column(title="Defects",
field_name="defect",
hideable=False,
static_data_name="defect",
- static_data_template=defect_link_template
+ static_data_template=defect_link_template,
)
self.add_column(title="Status",
@@ -1382,7 +1345,7 @@ class AllInvestigationsTable(ToasterTable):
hideable=True,
filter_name="is_status",
static_data_name="status",
- static_data_template="{{data.get_status_text}}"
+ static_data_template="{{data.get_status_text}}",
)
self.add_column(title="Outcome",
@@ -1390,15 +1353,20 @@ class AllInvestigationsTable(ToasterTable):
hideable=False,
filter_name="is_outcome",
static_data_name="outcome",
- static_data_template="{{data.get_outcome_text}}"
+ static_data_template="{{data.get_outcome_text}}",
)
+ release_version_template = '''
+ {% for ij in data.investigation_to_defect.all %}
+ {% if not forloop.first %}| {% endif %}<a href="{{ij.defect.url}}" target="_blank">{{ij.defect.release_version}} </a>
+ {% endfor %}
+ '''
self.add_column(title="Release Version",
# field_name="release_version",
orderable=True,
hideable=False,
- static_data_name="outcome",
- static_data_template="{{data.defect.release_version}}"
+ static_data_name="release_version",
+ static_data_template=release_version_template,
)
self.add_column(title="Severity",
@@ -1406,7 +1374,7 @@ class AllInvestigationsTable(ToasterTable):
filter_name="is_severity",
hideable=False,
static_data_name="severity",
- static_data_template="{{data.get_severity_text}}"
+ static_data_template="{{data.get_severity_text}}",
)
self.add_column(title="Comments",
@@ -1414,7 +1382,7 @@ class AllInvestigationsTable(ToasterTable):
hideable=True,
)
- userAccess = Access()
+ userAccess = Access(self.request.session.get('srt_user_id', '0'))
if userAccess.is_admin():
self.add_column(title="Comments Private",
field_name="comments_private",
@@ -1432,7 +1400,7 @@ class AllInvestigationsTable(ToasterTable):
# orderable=True,
filter_name="is_product",
static_data_name="investigation_products",
- static_data_template="<a href=\"{% url 'products' %}\">{{data.product.long_name}}</a>",
+ static_data_template="<a href=\"{% url 'product' data.product.id %}\">{{data.product.long_name}}</a>",
)
@@ -1468,7 +1436,7 @@ class KeywordsTable(ToasterTable):
Keywords.objects.all()
# # filter out hidden records
-# userAccess = Access()
+# userAccess = Access(self.request.session.get('srt_user_id', '0'))
# if not userAccess.is_admin():
# self.queryset = self.queryset.exclude(public = False)
@@ -1504,5 +1472,278 @@ class KeywordsTable(ToasterTable):
hideable=False,
orderable=False,
static_data_name="manage",
- static_data_template=manage_link_template)
+ static_data_template=manage_link_template,
+ )
+
+
+class SourcesTable(ToasterTable):
+ """Table of All Data Sources in SRTool"""
+
+ def __init__(self, *args, **kwargs):
+ super(SourcesTable, self).__init__(*args, **kwargs)
+ self.default_orderby = "data"
+
+ def get_context_data(self, **kwargs):
+ context = super(SourcesTable, self).get_context_data(**kwargs)
+ return context
+
+ def setup_queryset(self, *args, **kwargs):
+ self.queryset = \
+ DataSource.objects.all()
+
+ self.queryset = self.queryset.order_by(self.default_orderby)
+
+ def setup_columns(self, *args, **kwargs):
+
+ self.add_column(title="Data",
+ hideable=False,
+ orderable=True,
+ field_name="data",
+ static_data_name="data",
+ static_data_template='<span id="dataid_{{data.id}}">{{data.data}}</span>',
+ )
+
+ self.add_column(title="Source",
+ hideable=False,
+ orderable=True,
+ field_name="source",
+ )
+
+ self.add_column(title="Type",
+ hideable=False,
+ orderable=True,
+ field_name="type",
+ )
+
+ self.add_column(title="Description",
+ hideable=False,
+ orderable=False,
+ field_name="description",
+ )
+
+ self.add_column(title="File Path",
+ hideable=True,
+ hidden=True,
+ orderable=False,
+ field_name="file_path",
+ )
+
+ self.add_column(title="URL",
+ hideable=True,
+ hidden=True,
+ orderable=False,
+ field_name="url",
+ )
+
+ self.add_column(title="Meta URL",
+ hideable=True,
+ hidden=True,
+ orderable=False,
+ field_name="meta_url",
+ )
+
+ self.add_column(title="Data Modified",
+ hideable=False,
+ orderable=True,
+ field_name="lastModifiedDate",
+ )
+
+ self.add_column(title="Updates",
+ hideable=False,
+ orderable=True,
+ field_name="update_frequency",
+ static_data_name="update_frequency",
+ static_data_template="{{data.get_frequency_text}}",
+ )
+
+ self.add_column(title="Updated",
+ hideable=False,
+ orderable=True,
+ field_name="update_time",
+ )
+
+ self.add_column(title="Command",
+ hideable=True,
+ orderable=False,
+ field_name="command",
+ )
+
+
+class SelectPublishTable(ToasterTable):
+ """Table of Publishable CVE's in SRTool"""
+
+ def __init__(self, *args, **kwargs):
+ super(SelectPublishTable, self).__init__(*args, **kwargs)
+ self.default_orderby = "name"
+ _log("SelectPublishTable:__init")
+
+ def get_context_data(self,**kwargs):
+ _log("SelectPublishTable:get_context_data")
+ context = super(SelectPublishTable, self).get_context_data(**kwargs)
+ return context
+
+ def setup_filters(self, *args, **kwargs):
+ _log("SelectPublishTable:setup_filters")
+ # Status filter
+ is_status = TableFilter(name="is_status",
+ title="Filter CVE's by 'Status")
+ is_status.add_action(TableFilterActionToggle(
+ "new",
+ "New",
+ Q(status=Cve.NEW))
+ )
+ is_status.add_action(TableFilterActionToggle(
+ "investigate",
+ "Investigate",
+ Q(status=Cve.INVESTIGATE))
+ )
+ is_status.add_action(TableFilterActionToggle(
+ "vulnerable",
+ "Is Vulnerable",
+ Q(status=Cve.VULNERABLE))
+ )
+ is_status.add_action(TableFilterActionToggle(
+ "not_vulnerable",
+ "Not Vulnerable",
+ Q(status=Cve.NOT_VULNERABLE))
+ )
+ self.add_filter(is_status)
+
+ def setup_queryset(self, *args, **kwargs):
+ _log("SelectPublishTable:setup_queryset")
+ self.queryset = \
+ Cve.objects.filter(publish_state = Cve.PUBLISH_REQUEST) | \
+ Cve.objects.filter(publish_state = Cve.PUBLISH_UPDATE)
+
+ _log("SelectPublishTable1:%s" % len(self.queryset))
+
+ # filter out hidden records !!! ALL NEW ONES SHOULD BE PUBLIC
+# userAccess = Access(self.request.session.get('srt_user_id', '0'))
+# if not userAccess.is_admin():
+# self.queryset = self.queryset.exclude(public = False)
+
+ self.queryset = self.queryset.order_by(self.default_orderby)
+
+ def setup_columns(self, *args, **kwargs):
+
+ _log("SelectPublishTable:setup_columns")
+
+ self.add_column(title="Select",
+ field_name="Select",
+ hideable=False,
+ static_data_name="select",
+ static_data_template='<input type="checkbox" name="{{data.name}}" />',
+ )
+
+ self.add_column(title="Status",
+ field_name="status",
+ hideable=False,
+ orderable=True,
+ filter_name="is_status",
+ static_data_name="status",
+ static_data_template="{{data.get_status_text}}",
+ )
+
+ id_link_template = '''
+ <a href="{% url 'cve' data.id %}" id="dataid_{{data.id}}" target="_blank">{{data.name}}</a>
+ '''
+ self.add_column(title="Name",
+ hideable=False,
+ orderable=True,
+ field_name="name",
+ static_data_name="name",
+ static_data_template=id_link_template,
+ )
+
+ self.add_column(title="Publish Request",
+ field_name="publish_state",
+ hideable=False,
+ static_data_name="publish_state",
+ static_data_template="{{data.get_publish_text}}",
+ )
+
+ self.add_column(title="Request Date",
+ field_name="publish_date",
+ hideable=False,
+ static_data_name="publish_date",
+ static_data_template="{% if data.publish_date %}{{data.publish_date}}{% else %}ASAP{% endif %}",
+ )
+
+ severity_v3_template = '''
+ {{data.cvssV3_baseScore}} {{data.cvssV3_baseSeverity}}
+ '''
+ self.add_column(title="Severity (V3)",
+ help_text="Severity of the CVE (v3)",
+ hideable=False,
+ orderable=False,
+ static_data_name='severity_v3',
+ static_data_template=severity_v3_template,
+ )
+
+ self.add_column(title="Description",
+ field_name="description",
+ hideable=False,
+ )
+
+class UpdatePublishedTable(ToasterTable):
+ """Table of Publish requested CVE's in SRTool"""
+
+ def __init__(self, *args, **kwargs):
+ super(UpdatePublishedTable, self).__init__(*args, **kwargs)
+ self.default_orderby = "date"
+
+ def get_context_data(self,**kwargs):
+ context = super(UpdatePublishedTable, self).get_context_data(**kwargs)
+ return context
+
+ def setup_queryset(self, *args, **kwargs):
+ self.queryset = PublishPending.objects.all()
+ self.queryset = self.queryset.order_by(self.default_orderby)
+
+ def setup_columns(self, *args, **kwargs):
+
+ self.add_column(title="Select",
+ field_name="Select",
+ hideable=False,
+ static_data_name="select",
+ static_data_template='<input type="checkbox" name="{{data.cve.name}}" />',
+ )
+
+ self.add_column(title="Status",
+ field_name="status",
+ hideable=False,
+ orderable=True,
+ static_data_name="status",
+ static_data_template="{{data.cve.get_status_text}}",
+ )
+
+ id_link_template = '''
+ <a href="{% url 'cve' data.cve.id %}" id="dataid_{{data.cve.id}}" target="_blank">{{data.cve.name}}</a>
+ '''
+ self.add_column(title="Name",
+ hideable=False,
+ orderable=True,
+ field_name="name",
+ static_data_name="name",
+ static_data_template=id_link_template,
+ )
+
+ self.add_column(title="Publish Request",
+ field_name="publish_state",
+ hideable=False,
+ static_data_name="publish_state",
+ static_data_template="{{data.cve.get_publish_text}}",
+ )
+
+ self.add_column(title="Publish Request Date",
+ field_name="date",
+ hideable=False,
+ orderable=True,
+ )
+
+ if False:
+ self.add_column(title="Note",
+ field_name="note",
+ hideable=False,
+ )
diff --git a/lib/srtgui/templates/base.html b/lib/srtgui/templates/base.html
index 3cc98a49..527d6b9b 100644
--- a/lib/srtgui/templates/base.html
+++ b/lib/srtgui/templates/base.html
@@ -148,9 +148,15 @@ window.onclick = function(event) {
</div>
<div class="collapse navbar-collapse" id="global-nav">
<ul class="nav navbar-nav">
+ <li id="navbar-home" {% if request.resolver_match.url_name == 'landing' %}class="active"{% endif %}>
+ <a href="{% url 'landing' %}">
+ <i class="glyphicon glyphicon-tasks"></i>
+ Home
+ </a>
+ </li>
{% if access.is_guest %}
{% else %}
- <li id="navbar-manage" class="active">
+ <li id="navbar-manage" {% if request.resolver_match.url_name == 'manage' %}class="active"{% endif %}>
<a href="{% url 'manage' %}">
<i class="glyphicon glyphicon-tasks"></i>
Management
@@ -158,18 +164,18 @@ window.onclick = function(event) {
</li>
{% endif %}
{% if request.resolver_match.url_name != 'landing' %}
- <li id="navbar-all-builds"
- {% if request.resolver_match.url_name == 'all-cves' %}
+ <li id="navbar-all-cves"
+ {% if request.resolver_match.url_name == 'cves' %}
class="active"
{% endif %}>
- <a href="{% url 'all-cves' %}">
+ <a href="{% url 'cves' %}">
<i class="glyphicon glyphicon-tasks"></i>
All CVE's
</a>
</li>
{% endif %}
<li id="navbar-docs">
- <a href="{% url 'guided_tour' %}"> <i class="glyphicon glyphicon-book"></i> Documentation </a>
+ <a href="{% url 'guided_tour' %}"> <i class="glyphicon glyphicon-book"></i> Documentation ({{srt_user_id}},{{access.current_user_access}})</a>
<!--
<a target="_blank" href="https://knowledge.windriver.com/en-us/000_Products/000/010/050">
<i class="glyphicon glyphicon-book"></i>
@@ -180,7 +186,7 @@ window.onclick = function(event) {
</ul>
{% if access.is_guest %}
- <a class="btn btn-default navbar-btn navbar-right" id="login-button" href="{% url 'login_admin' %}">Login (Guest)</a>
+ <a class="btn btn-default navbar-btn navbar-right" id="login-button" href="{% url 'login' %}">Login (Guest)</a>
{% else %}
<a class="btn btn-default navbar-btn navbar-right" id="login-button" href="{% url 'login_guest' %}">Logout ({{access.user_name}})</a>
{% endif %}
@@ -189,19 +195,9 @@ window.onclick = function(event) {
<button onclick="myFunction()" class="dropbtn ">Tools</button>
<div id="myDropdown" class="dropdown-content">
{% if request.resolver_match.url_name == 'landing' %}
- {% if access.is_creator %}
- <a href="{% url 'users' %}">Users</a>
- <a href="{% url 'sources' %}">Sources</a>
- <a href="{% url 'manage' %}">Management</a>
- {% endif %}
- <a href="{% url 'export' request.resolver_match.url_name %}">Report ...</a>
- <a href="{% url 'export' request.resolver_match.url_name %}">Export ...</a>
+ <a href="{% url 'report' request.resolver_match.url_name %}">Report/Export ...</a>
{% else %}
- {% if access.is_creator %}
- <a href="">Edit ...</a>
- {% endif %}
- <a href="{% url 'export' request.resolver_match.url_name %}">Report ...</a>
- <a href="{% url 'export' request.resolver_match.url_name %}">Export ...</a>
+ <a id="report_link" href="{% url 'report' request.resolver_match.url_name %}">Report/Export ...</a>
{% endif %}
</div>
</div>
diff --git a/lib/srtgui/templates/cpes-toastertable.html b/lib/srtgui/templates/cpes-toastertable.html
index 58101e2a..8c92c012 100644
--- a/lib/srtgui/templates/cpes-toastertable.html
+++ b/lib/srtgui/templates/cpes-toastertable.html
@@ -29,7 +29,8 @@
<h1 class="top-air" data-role="page-title"></h1>
</div>
- {% url 'cpes' as xhr_table_url %}
+ {# xhr_table_url is just the current url so leave it blank #}
+ {% url '' as xhr_table_url %}
{% include 'toastertable.html' %}
</div>
</div>
diff --git a/lib/srtgui/templates/cve.html b/lib/srtgui/templates/cve.html
index b1df1819..a70448f8 100644
--- a/lib/srtgui/templates/cve.html
+++ b/lib/srtgui/templates/cve.html
@@ -8,357 +8,452 @@
<div class="row">
<!-- Breadcrumbs -->
- <div class="col-md-12">
- <ul class="breadcrumb" id="breadcrumb">
- <li><a href="{% url 'landing' %}">Home</a></li><span class="divider">&rarr;</span>
- <li><a href="{% url 'all-cves' %}">CVE's</a></li><span class="divider">&rarr;</span>
- <li>{{cve_list_table.0.0.name}}</li>
- <li><a class="btn btn-default navbar-btn " id="cve-prev" href="{% url 'cve' cve_prev %}">Prev</a></li>
- <li><a class="btn btn-default navbar-btn " id="cve-next" href="{% url 'cve' cve_next %}">Next</a></li>
- </ul>
- </div>
+ <div class="col-md-12">
+ <ul class="breadcrumb" id="breadcrumb">
+ <li><a href="{% url 'landing' %}">Home</a></li><span class="divider">&rarr;</span>
+ <li><a href="{% url 'cves' %}">CVE's</a></li><span class="divider">&rarr;</span>
+ <li>{{cve_list_table.0.0.name}}</li>
+ <li><a class="btn btn-default navbar-btn " id="cve-prev" href="{% url 'cve' cve_prev %}">Prev</a></li>
+ <li><a class="btn btn-default navbar-btn " id="cve-next" href="{% url 'cve' cve_next %}">Next</a></li>
+ </ul>
+ </div>
</div>
<!-- Begin container -->
+
<div class="row">
<div class="col-md-12">
<div class="page-header build-data">
- <h1>{{cve_list_table.0.0.name}} Detail {% if not cve_list_table.0.0.public %} <font color="red">[PRIVATE]</font> {% endif %}</h1>
+ <h1 style="display:inline-block;vertical-align: middle;">{{cve_list_table.0.0.name}} Detail {% if not cve_list_table.0.0.public %} <font color="red">[PRIVATE]</font> {% endif %}</h1>
+ {% if access.is_creator %}
+ <span style="padding-left:30px;"><button id="select-quickedit" class="btn btn-default" type="button">Edit SRTool Status...</button></span>
+ <!--<span style="padding-left:30px;"><button id="select-quickedit" class="btn btn-default" type="button">Edit CVE Data ...</button></span>-->
+ {% endif %}
</div>
</div>
</div>
+
<div class="row" style="padding-left: 25px;">
<UL>
- <LI>
+ <LI>
+ <i>SRTool Priority:</i> {{cve_list_table.0.0.get_priority_text}}
+ </LI>
+ <LI>
<i>SRTool Status:</i> {{cve_list_table.0.0.get_status_text}}
- </LI>
- <LI>
+ </LI>
+ <LI>
<i>SRTool Notes:</i> '{{cve_list_table.0.0.comments}}'
- {% if access.is_creator %}
- </LI>
- <LI>
- <i>SRTool Private Notes:</i> '{{cve_list_table.0.0.comments_private}}'
- {% endif %}
- </LI>
- <LI>
- {% if access.is_creator %}
- <i>Publish</i> =
- <select name="Publish">
- <option value="Undetermined">Undetermined</option>
- <option value="Automatic Publish Date">Automatic Publish Date</option>
- <option value="Request Publish Date">Request Publish Date</option>
- <option value="Published">Published</option>
- <option value="Do Not Published">Do Not Published</option>
- </select>
- <i>Publish Date</i> = {{cve_list_table.0.0.publish_date}}
- <a class="btn btn-default " id="login-button" href="">Publish Now</a>
- <!--<a class="btn btn-default navbar-btn " id="login-button" href="">Publish Now</a> -->
- {% else %}
- <i>Publish</i> = {{cve_list_table.0.0.get_publish_text}}, <i>Publish Date</i> = {{cve_list_table.0.0.publish_date}}
- {% endif %}
- </LI>
+ {% if access.is_creator %}
+ </LI>
+ <LI>
+ <i>SRTool Private Notes:</i> '{{cve_list_table.0.0.comments_private}}'
+ {% endif %}
+ </LI>
+ <LI>
+ {% if access.is_creator %}
+ <i>Publish = {{cve_list_table.0.0.get_publish_text}}</i>
+ <!--<a class="btn btn-default navbar-btn " id="login-button" href="">Publish Now</a> -->
+ {% else %}
+ <i>Publish</i> = {{cve_list_table.0.0.get_publish_text}}, <i>Publish Date</i> = {{cve_list_table.0.0.publish_date}}
+ {% endif %}
+ </LI>
</UL>
+
+
+</div>
+<!-- Quick Edit -->
+<div id="details-quickedit" style="display:none;">
+ <p><p>
+ <button class="execute" id="submit-quickedit"> Submit Changes </button>
+ <p><i>Priority</i> =
+ <select name="Priority" id="select-priority-state">
+ <option value="0" {% if 0 == cve_list_table.0.0.priority %}selected{% endif %}></option>
+ <option value="1" {% if 1 == cve_list_table.0.0.priority %}selected{% endif %}>Minor</option>
+ <option value="2" {% if 2 == cve_list_table.0.0.priority %}selected{% endif %}>Low</option>
+ <option value="3" {% if 3 == cve_list_table.0.0.priority %}selected{% endif %}>Medium</option>
+ <option value="4" {% if 4 == cve_list_table.0.0.priority %}selected{% endif %}>High</option>
+ </select>
+ <p><input type="text" placeholder="Edit Note" id="text-note" size="40" value="{{cve_list_table.0.0.comments}}"></p>
+ <p><input type="text" placeholder="Edit Private Note" id="text-private-note" size="40" value="{{cve_list_table.0.0.comments_private}}"></p>
+ <i>Publish</i> =
+ <select name="Publish" id="select-publish-state">
+ <option value="0" {% if 0 == cve_list_table.0.0.publish_state %}selected{% endif %}>Unpublished</option>
+ <option value="1" {% if 1 == cve_list_table.0.0.publish_state %}selected{% endif %}>Not to be Published</option>
+ <option value="2" {% if 2 == cve_list_table.0.0.publish_state %}selected{% endif %}>Published</option>
+ <option value="3" {% if 3 == cve_list_table.0.0.publish_state %}selected{% endif %}>Publish Request (New)</option>
+ <option value="4" {% if 4 == cve_list_table.0.0.publish_state %}selected{% endif %}>Publish Request (Update)</option>
+ <option value="5" {% if 5 == cve_list_table.0.0.publish_state %}selected{% endif %}>Publish Submitted</option>
+ </select>
+ <i>Publish Date</i> = <input type="text" placeholder="Auto Publish Date" id="select-publish-date" size="40" value="{{cve_list_table.0.0.publish_date}}"><p>
+ <p><p>
</div>
<div class="row">
<div class="col-md-8 tabbable">
<ul class="nav nav-tabs">
- {% for object,state,id in cve_list_table %}
+ {% for object,details,state,id in cve_list_table %}
<li class="{{state}}">
<a href="#{{id}}" data-toggle="tab">
<span class="glyphicon glyphicon-question-sign get-help" title="{{id}}"></span>
{{id}}
</a>
</li>
- {% endfor %}
+ {% endfor %}
</ul>
<div class="tab-content">
- {% for object,state,id in cve_list_table %}
- <div class="tab-pane {{state}}" id="{{id}}">
+ {% for object,details,state,id in cve_list_table %}
+ <div class="tab-pane {{state}}" id="{{id}}">
<!-- vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv -->
- <div class="row">
- <div class="col-md-5">
- <div>
- <h3>Decription</h3>
- {{object.description}}
- </div>
- <p/>
- <div>
- <B>Source:</B> {{object.cve_data_format}} <B>Last Modified:</B> {{object.lastModifiedDate}}
- </div>
- </div>
- <div class="col-md-5">
- <div class="well">
- <h2>Quick Info</h2>
-
-
- <dl class="dl-horizontal">
- <dt>CVE Dictionary Entry:</dt>
- <dd>{{object.name}}</dd>
-
- <dt>Original release date:</dt>
- <dd>{{object.publishedDate}}</dd>
-
- <dt>Last revised:</dt>
- <dd>{{object.lastModifiedDate}}</dd>
-
- <dt>Source:</dt>
- <dd>{{object.cve_data_format}}</dd>
-
- {% if id == "Summary" %}
- <dt>SRTool Vulnerability:</dt>
- <dd>
- {% if object.cve_to_vulnerability.all %}
- {% for cv in object.cve_to_vulnerability.all %}
- {% if not forloop.first %}| {% endif %}<a href="{% url 'vulnerability' cv.vulnerability.pk %}">{{cv.vulnerability.name}}</a>
- {% endfor %}
- {% else %}
- No vulnerability record found
- {% endif %}
- {% endif %}
- </dd>
- </dl>
- </div>
- </div>
- </div>
-
- <div class="row">
- <h3>Impact</h3>
- <div class="col-md-4">
- <h3>CVSS Severity (version 3.0):</h3>
- <dl class="dl-horizontal">
- <dt>CVSS v3 Base Score:</dt>
- <dd>{{object.cvssV3_baseScore}} {{object.cvssV3_baseSeverity}}</dd>
-
- <dt>Vector:</dt>
- <dd>{{object.cvssV3_vectorString}}</dd>
-
- <dt>Impact Score:</dt>
- <dd>{{object.cvssV3_impactScore}}</dd>
-
- <dt>Exploitability Score:</dt>
- <dd>{{object.cvssV3_exploitabilityScore}}</dd>
- </dl>
- <h3>CVSS Version 3 Metrics:</h3>
- <dl class="dl-horizontal">
- <dt>Attack Vector (AV):</dt>
- <dd>{{object.cvssV3_attackVector}}</dd>
-
- <dt>Attack Complexity (AC):</dt>
- <dd>{{object.cvssV3_attackComplexity}}</dd>
-
- <dt>Privileges Required (PR):</dt>
- <dd>{{object.cvssV3_privilegesRequired}}</dd>
-
- <dt>User Interaction (UI):</dt>
- <dd>{{object.cvssV3_userInteraction}}</dd>
-
- <dt>Scope (S):</dt>
- <dd>{{object.cvssV3_scope}}</dd>
-
- <dt>Confidentiality (C):</dt>
- <dd>{{object.cvssV3_confidentialityImpact}}</dd>
-
- <dt>Integrity (I):</dt>
- <dd>{{object.cvssV3_integrityImpact}}</dd>
-
- <dt>Availability (A):</dt>
- <dd>{{object.cvssV3_availabilityImpact}}</dd>
- </dl>
- </div>
- <div class="col-md-4">
- <h3>CVSS Severity (version 2.0):</h3>
- <dl class="dl-horizontal">
- <dt>CVSS v2 Base Score:</dt>
- <dd>{{object.cvssV2_baseScore}} {{object.cvssV2_severity}}</dd>
-
- <dt>Vector:</dt>
- <dd>{{object.cvssV2_vectorString}}</dd>
-
- <dt>Impact Subscore:</dt>
- <dd>{{object.cvssV2_impactScore}}</dd>
-
- <dt>Exploitability Subscore:</dt>
- <dd>{{object.cvssV2_exploitabilityScore}}</dd>
-
- </dl>
- <h3>CVSS Version 2 Metrics:</h3>
- <dl class="dl-horizontal">
- <dt>Access Vector (AV):</dt>
- <dd>{{object.cvssV2_accessVector}}</dd>
-
- <dt>Access Complexity (AC):</dt>
- <dd>{{object.cvssV2_accessComplexity}}</dd>
-
- <dt>Authentication:</dt>
- <dd>{{object.cvssV2_authentication}}</dd>
-
- <dt>Impact Type:</dt>
- <dd>???</dd>
-
- </dl>
- </div>
- </div>
-
- <div class="row">
- <h3>References to Advisories, Solutions, and Tools</h3>
- <p>
- By selecting these links, you will be leaving NIST webspace. We have provided these links to other web sites
- because they may have information that would be of interest to you. No inferences should be drawn on account
- of other sites being referenced, or not, from this page. There may be other web sites that are more appropriate
- for your purpose. NIST does not necessarily endorse the views expressed, or concur with the facts presented on
- these sites. Further, NIST does not endorse any commercial products that may be mentioned on these sites. Please
- address comments about this page to nvd@nist.gov.
- </p>
- <table class="table table-striped table-condensed" data-testid="vuln-hyperlinks-table">
- <thead>
- <tr>
- <th>Hyperlink</th>
- <th>Resource</th>
- <th>Type</th>
- <th>Source</th>
- <th>Name</th>
- </tr>
- </thead>
- {% if object.references.all %}
- {% for ref in object.references.all %}
- <tr>
- <td><a href="{{ref.hyperlink}}" target="_blank">{{ ref.hyperlink }}</a></td>
- <td>{{ ref.resource }}</td>
- <td>{{ ref.type }}</td>
- <td>{{ ref.source }}</td>
- <td>{{ ref.name }}</td>
- </tr>
- {% endfor %}
- {% else %}
- <tr>
- <td>No references</td>
- </tr>
- {% endif %}
- </table>
- </div>
-
- <div class="row">
- <h3>Technical Details</h3>
- <p>
- <h4>Vulnerability Type<a href="{% url 'all-cwes' %}"> (View All)</a></h4>
- <p>
- <table class="table table-striped table-condensed" data-testid="cve2cwe-hyperlinks-table">
- <thead>
- <tr>
- <th>Name</th>
- <th>Summary</th>
- </tr>
- </thead>
- {% if object.cve2cwe.all %}
- {% for ref in object.cve2cwe.all %}
- <tr>
- <td>{{ ref.cwe.name }}</td>
- <td>{{ ref.cwe.summary }}</td>
- </tr>
- {% endfor %}
- {% else %}
- <tr>
- <td>No CWE references</td>
- </tr>
- {% endif %}
- </table>
- </div>
-
- <div class="row">
- <h3>Vulnerable software and versions</h3>
- <div > <!--style="padding-left: 25px;" -->
- {% if object.get_cpe_list %}
- {% for cpe in object.get_cpe_list %}
- {% if not cpe %}
- {% elif not cpe.0 %}
- {% elif '<config' in cpe.0 %}
- <div style="padding-left: 25px;">
- <h4>&bull; Configuration </h3>
- {% elif '<and>' == cpe.0 %}
- <div style="padding-left: 25px;">
- <h4>&bull; AND</h3>
- {% elif '<or>' == cpe.0 %}
- <div style="padding-left: 25px;">
- <h4>&bull; OR</h3>
- <table class="table table-striped table-condensed" data-testid="configs-hyperlinks-table">
- <thead>
- <tr>
- <th>Vulnerable</th>
- <th>CPE 2.3</th>
- <th>CPE 2.2</th>
- <th><!--<span class="glyphicon glyphicon-question-sign get-help" title="Version End Including"></span>-->Version End</th>
- </tr>
- </thead>
- {% elif '</or>' == cpe.0 %}
- </table>
- </div>
- {% elif '</and>' == cpe.0 %}
- </div>
- {% elif '</config>' == cpe.0 %}
- </div>
- {% else %}
- <tr>
- <td>{{ cpe.0 }}</td>
- <td>{{ cpe.1 }}</td>
- <td>{{ cpe.2 }}</td>
- <td>{{ cpe.3 }}</td>
- </tr>
- {% endif %}
- {% endfor %}
- {% else %}
- No CPE configurations
- {% endif %}
- </div>
- <p/>
- </div>
-
-
- <div class="row">
- <h3>History
- </h3>
-
- <table class="table table-striped table-condensed" data-testid="vuln-hyperlinks-table">
- <thead>
- <tr>
- <th>Comment</th>
- <th>Date</th>
- <th>Author</th>
- </tr>
- </thead>
-
- {% if object.cve_history.all %}
- {% for c in object.cve_history.all %}
- <tr>
- <td>{{ c.comment }}</td>
- <td>{{ c.date }}</td>
- <td>{{ c.author }}</td>
- </tr>
- {% endfor %}
- {% else %}
- <tr>
- <td>No history found</td>
- </tr>
- {% endif %}
- </table>
-
- </div>
+ <!-- Row: Description and Quick Info -->
+ <div class="row">
+ <div class="col-md-5">
+ <div>
+ <h3>Decription</h3>
+ {{object.description}}
+ </div>
+ <p/>
+ <div>
+ <B>Source:</B> {{object.cve_data_format}} <B>Last Modified:</B> {{object.lastModifiedDate}}
+ </div>
+ </div>
+ <div class="col-md-5">
+ <div class="well">
+ <h2>Quick Info</h2>
+
+
+ <dl class="dl-horizontal">
+ <dt>CVE Dictionary Entry:</dt>
+ <dd>{{object.name}}</dd>
+
+ <dt>Original release date:</dt>
+ <dd>{{object.publishedDate}}</dd>
+
+ <dt>Last revised:</dt>
+ <dd>{{object.lastModifiedDate}}</dd>
+
+ <dt>Source:</dt>
+ <dd>{{object.cve_data_format}}</dd>
+
+ {% if id == "Summary" %}
+ <dt>SRTool Vulnerability:</dt>
+ <dd>
+ {% if object.cve_to_vulnerability.all %}
+ {% for cv in object.cve_to_vulnerability.all %}
+ {% if not forloop.first %}| {% endif %}<a href="{% url 'vulnerability' cv.vulnerability.pk %}">{{cv.vulnerability.name}}</a>
+ {% endfor %}
+ {% else %}
+ No vulnerability record found
+ {% endif %}
+ {% endif %}
+ </dd>
+
+ <dt>NIST Link:</dt>
+ <dd><a href="https://nvd.nist.gov/vuln/detail/{{object.name}}" target="_blank">{{object.name}}</a></dd>
+
+ </dl>
+ </div>
+ </div>
+ </div> <!-- /Description -->
+
+ <!-- Row: CVSS -->
+ <div class="row" style="padding-left: 25px;">
+ <h3>Impact</h3>
+ <div class="col-md-4">
+ <h3>CVSS Severity (version 3.0):</h3>
+ <dl class="dl-horizontal">
+ <dt>CVSS v3 Base Score:</dt>
+ <dd>{{object.cvssV3_baseScore}} {{object.cvssV3_baseSeverity}}</dd>
+
+ <dt>Vector:</dt>
+ <dd>{{details.cvssV3_vectorString}}</dd>
+
+ <dt>Impact Score:</dt>
+ <dd>{{details.cvssV3_impactScore}}</dd>
+
+ <dt>Exploitability Score:</dt>
+ <dd>{{details.cvssV3_exploitabilityScore}}</dd>
+ </dl>
+ <h3>CVSS Version 3 Metrics:</h3>
+ <dl class="dl-horizontal">
+ <dt>Attack Vector (AV):</dt>
+ <dd>{{details.cvssV3_attackVector}}</dd>
+
+ <dt>Attack Complexity (AC):</dt>
+ <dd>{{details.cvssV3_attackComplexity}}</dd>
+
+ <dt>Privileges Required (PR):</dt>
+ <dd>{{details.cvssV3_privilegesRequired}}</dd>
+
+ <dt>User Interaction (UI):</dt>
+ <dd>{{details.cvssV3_userInteraction}}</dd>
+
+ <dt>Scope (S):</dt>
+ <dd>{{details.cvssV3_scope}}</dd>
+
+ <dt>Confidentiality (C):</dt>
+ <dd>{{details.cvssV3_confidentialityImpact}}</dd>
+
+ <dt>Integrity (I):</dt>
+ <dd>{{details.cvssV3_integrityImpact}}</dd>
+
+ <dt>Availability (A):</dt>
+ <dd>{{details.cvssV3_availabilityImpact}}</dd>
+ </dl>
+ </div>
+ <div class="col-md-4">
+ <h3>CVSS Severity (version 2.0):</h3>
+ <dl class="dl-horizontal">
+ <dt>CVSS v2 Base Score:</dt>
+ <dd>{{object.cvssV2_baseScore}} {{details.cvssV2_severity}}</dd>
+
+ <dt>Vector:</dt>
+ <dd>{{details.cvssV2_vectorString}}</dd>
+
+ <dt>Impact Subscore:</dt>
+ <dd>{{details.cvssV2_impactScore}}</dd>
+
+ <dt>Exploitability Subscore:</dt>
+ <dd>{{details.cvssV2_exploitabilityScore}}</dd>
+
+ </dl>
+ <h3>CVSS Version 2 Metrics:</h3>
+ <dl class="dl-horizontal">
+ <dt>Access Vector (AV):</dt>
+ <dd>{{details.cvssV2_accessVector}}</dd>
+
+ <dt>Access Complexity (AC):</dt>
+ <dd>{{details.cvssV2_accessComplexity}}</dd>
+
+ <dt>Authentication:</dt>
+ <dd>{{details.cvssV2_authentication}}</dd>
+
+ <dt>Impact Type:</dt>
+ <dd>???</dd>
+
+ </dl>
+ </div>
+ </div> <!-- /CVSS -->
+
+ <!-- Row: References -->
+ <div class="row" style="padding-left: 25px;">
+ <h3>References to Advisories, Solutions, and Tools</h3>
+ <p>
+ By selecting these links, you will be leaving NIST webspace. We have provided these links to other web sites
+ because they may have information that would be of interest to you. No inferences should be drawn on account
+ of other sites being referenced, or not, from this page. There may be other web sites that are more appropriate
+ for your purpose. NIST does not necessarily endorse the views expressed, or concur with the facts presented on
+ these sites. Further, NIST does not endorse any commercial products that may be mentioned on these sites. Please
+ address comments about this page to nvd@nist.gov.
+ </p>
+ <table class="table table-striped table-condensed" data-testid="vuln-hyperlinks-table">
+ <thead>
+ <tr>
+ <th>Hyperlink</th>
+ <th>Resource</th>
+ </tr>
+ </thead>
+ {% if object.references.all %}
+ {% for ref in object.references.all %}
+ <tr>
+ <td><a href="{{ref.hyperlink}}" target="_blank">{{ ref.hyperlink }}</a></td>
+ <td>{{ ref.resource }}</td>
+ </tr>
+ {% endfor %}
+ {% else %}
+ <tr>
+ <td>No references</td>
+ </tr>
+ {% endif %}
+ </table>
+ </div> <!-- /References -->
+
+ <!-- Row: CWE -->
+ <div class="row" style="padding-left: 25px;">
+ <h3>Technical Details</h3>
+ <p>
+ <h4>Vulnerability Type<a href="{% url 'cwes' %}"> (View All)</a></h4>
+ <p>
+ <table class="table table-striped table-condensed" data-testid="cve2cwe-hyperlinks-table">
+ <thead>
+ <tr>
+ <th>Name</th>
+ <th>Summary</th>
+ </tr>
+ </thead>
+ {% if object.cve2cwe.all %}
+ {% for ref in object.cve2cwe.all %}
+ <tr>
+ <td>{{ ref.cwe.name }}</td>
+ <td>{{ ref.cwe.summary }}</td>
+ </tr>
+ {% endfor %}
+ {% else %}
+ <tr>
+ <td>No CWE references</td>
+ </tr>
+ {% endif %}
+ </table>
+ </div> <!-- /CWE -->
+
+ <!-- Row: CPE -->
+ <div class="row" style="padding-left: 25px;">
+ <h3>Vulnerable software and versions</h3>
+ <div > <!--style="padding-left: 25px;" -->
+ {% if details.get_cpe_list %}
+ {% for cpe in details.get_cpe_list %}
+ {% if not cpe %}
+ {% elif not cpe.0 %}
+ {% elif '[config' in cpe.0 %}
+ <div style="padding-left: 25px;">
+ <h4>&bull; Configuration </h3>
+ {% elif '[and]' == cpe.0 %}
+ <div style="padding-left: 25px;">
+ <h4>&bull; AND</h3>
+ {% elif '[or]' == cpe.0 %}
+ <div style="padding-left: 25px;">
+ <h4>&bull; OR</h3>
+ <table class="table table-striped table-condensed" data-testid="configs-hyperlinks-table">
+ <thead>
+ <tr>
+ <th>Vulnerable</th>
+ <th>CPE 2.3</th>
+ <th>CPE 2.2</th>
+ <th><!--<span class="glyphicon glyphicon-question-sign get-help" title="Version End Including"></span>-->Version End</th>
+ </tr>
+ </thead>
+ {% elif '[/or]' == cpe.0 %}
+ </table>
+ </div>
+ {% elif '[/and]' == cpe.0 %}
+ </div>
+ {% elif '[/config]' == cpe.0 %}
+ </div>
+ {% else %}
+ <tr>
+ <td>{{ cpe.0 }}</td>
+ <td>{{ cpe.1 }}</td>
+ <td>{{ cpe.2 }}</td>
+ <td>{{ cpe.3 }}</td>
+ </tr>
+ {% endif %}
+ {% endfor %}
+ {% else %}
+ No CPE configurations
+ {% endif %}
+ </div>
+ <p>
+ </div> <!-- /CPE -->
+
<!-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -->
- </div> <!-- end tab-pane -->
+ </div> <!-- end tab-pane -->
{% endfor %}
</div> <!-- end tab-content -->
</div> <!-- end tabbable -->
</div> <!-- end row -->
+<div class="row" style="padding-left: 25px;">
+ <h3>History</h3>
+
+ <table class="table table-striped table-condensed" data-testid="vuln-hyperlinks-table">
+ <thead>
+ <tr>
+ <th>Comment</th>
+ <th>Date</th>
+ <th>Author</th>
+ </tr>
+ </thead>
+
+ {% if cve_list_table.1.0.cve_history.all %}
+ {% for c in cve_list_table.1.0.cve_history.all %}
+ <tr>
+ <td>{{ c.comment }}</td>
+ <td>{{ c.date }}</td>
+ <td>{{ c.author }}</td>
+ </tr>
+ {% endfor %}
+ {% else %}
+ <tr>
+ <td>No history found</td>
+ </tr>
+ {% endif %}
+ </table>
+</div>
+
<HR ALIGN="center" WIDTH="100%">
+<script>
+ var selected_quickedit=false;
+
+ $(document).ready(function() {
+ function onCommitAjaxSuccess(data, textstatus) {
+ if (window.console && window.console.log) {
+ console.log("XHR returned:", data, "(" + textstatus + ")");
+ } else {
+ alert("NO CONSOLE:\n");
+ return;
+ }
+ if (data.error != "ok") {
+ alert("error on request:\n" + data.error);
+ return;
+ }
+ // reload the page with the updated tables
+ location.reload(true);
+ }
+
+ function onCommitAjaxError(jqXHR, textstatus, error) {
+ console.log("ERROR:"+error+"|"+textstatus);
+ alert("XHR errored1:\n" + error + "\n(" + textstatus + ")");
+ }
+
+ /* ensure cookie exists {% csrf_token %} */
+ function postCommitAjaxRequest(reqdata) {
+ reqdata['cve_id'] = {{ object.id }};
+ var ajax = $.ajax({
+ type:"POST",
+ data: reqdata,
+ url:"{% url 'xhr_cve_commit' %}",
+ headers: { 'X-CSRFToken': $.cookie("csrftoken")},
+ success: onCommitAjaxSuccess,
+ error: onCommitAjaxError,
+ })
+ }
+
+ $('#select-quickedit').click(function(){
+ if (selected_quickedit) {
+ selected_quickedit=false;
+ $("#details-quickedit").slideUp();
+ } else {
+ selected_quickedit=true;
+ $("#details-quickedit").slideDown();
+ }
+ });
+
+ $('#submit-quickedit').click(function(){
+ var note=$('#text-note').val().trim();
+ var private_note=$('#text-private-note').val().trim();
+ var priority=$('#select-priority-state').val();
+ var publish_state=$('#select-publish-state').val();
+ var publish_date=$('#select-publish-date').val();
+ postCommitAjaxRequest({
+ "action" : 'submit-quickedit',
+ "priority" : priority,
+ "note" : note,
+ "private_note" : private_note,
+ "publish_state" : publish_state,
+ "publish_date" : publish_date,
+ });
+ });
+
+ /* Set the report link */
+ $('#report_link').attr('href',"{% url 'report' request.resolver_match.url_name %}?record_list={{cve_list_table.0.0.id}}");
+ });
+</script>
{% endblock %}
-
diff --git a/lib/srtgui/templates/cves-select-toastertable.html b/lib/srtgui/templates/cves-select-toastertable.html
index 8e2445b0..3399332e 100644
--- a/lib/srtgui/templates/cves-select-toastertable.html
+++ b/lib/srtgui/templates/cves-select-toastertable.html
@@ -111,7 +111,8 @@
<h1 class="top-air" data-role="page-title"></h1>
</div>
- {% url 'cpes' as xhr_table_url %}
+ {# xhr_table_url is just the current url so leave it blank #}
+ {% url '' as xhr_table_url %}
{% include 'toastertable.html' %}
</div>
</div>
@@ -338,6 +339,17 @@
titleElt.text(title);
cve_total = total;
update_vulnerable_status();
+
+ /* Set the report link */
+ var record_list=""
+ $(".name > a").each(function(){
+ var this_id=$(this).prop('id');
+ if (this_id.startsWith("dataid_")) {
+ record_list +=this_id.replace(/dataid_/,"") + ",";
+ }
+ });
+ $('#report_link').attr('href',"{% url 'report' request.resolver_match.url_name %}?record_list="+record_list);
+
});
});
</script>
diff --git a/lib/srtgui/templates/cves-toastertable.html b/lib/srtgui/templates/cves-toastertable.html
index fa83e5df..5fc37fdf 100644
--- a/lib/srtgui/templates/cves-toastertable.html
+++ b/lib/srtgui/templates/cves-toastertable.html
@@ -30,7 +30,8 @@
<h1 class="top-air" data-role="page-title"></h1>
</div>
- {% url 'cves' as xhr_table_url %}
+ {# xhr_table_url is just the current url so leave it blank #}
+ {% url '' as xhr_table_url %}
{% include 'toastertable.html' %}
</div>
</div>
@@ -53,6 +54,17 @@
}
titleElt.text(title);
+
+ /* Set the report link */
+ var record_list=""
+ $(".name > a").each(function(){
+ var this_id=$(this).prop('id');
+ if (this_id.startsWith("dataid_")) {
+ record_list +=this_id.replace(/dataid_/,"") + ",";
+ }
+ });
+ $('#report_link').attr('href',"{% url 'report' request.resolver_match.url_name %}?record_list="+record_list);
+
});
});
</script>
diff --git a/lib/srtgui/templates/cwes-toastertable.html b/lib/srtgui/templates/cwes-toastertable.html
index 06369343..cbd62a90 100644
--- a/lib/srtgui/templates/cwes-toastertable.html
+++ b/lib/srtgui/templates/cwes-toastertable.html
@@ -29,7 +29,8 @@
<h1 class="top-air" data-role="page-title"></h1>
</div>
- {% url 'cwes' as xhr_table_url %}
+ {# xhr_table_url is just the current url so leave it blank #}
+ {% url '' as xhr_table_url %}
{% include 'toastertable.html' %}
</div>
</div>
@@ -52,6 +53,17 @@
}
titleElt.text(title);
+
+ /* Set the report link */
+ var record_list=""
+ $(".href > a").each(function(){
+ var this_id=$(this).prop('id');
+ if (this_id.startsWith("dataid_")) {
+ record_list +=this_id.replace(/dataid_/,"") + ",";
+ }
+ });
+ $('#report_link').attr('href',"{% url 'report' request.resolver_match.url_name %}?record_list="+record_list);
+
});
});
</script>
diff --git a/lib/srtgui/templates/defect.html b/lib/srtgui/templates/defect.html
new file mode 100644
index 00000000..aa13b0dd
--- /dev/null
+++ b/lib/srtgui/templates/defect.html
@@ -0,0 +1,86 @@
+{% extends "base.html" %}
+
+{% load projecttags %}
+
+{% block title %} {{object.name}} - SRTool {% endblock %}
+
+{% block pagecontent %}
+
+<div class="row">
+ <!-- Breadcrumbs -->
+ <div class="col-md-12">
+ <ul class="breadcrumb" id="breadcrumb">
+ <li><a href="{% url 'landing' %}">Home</a></li><span class="divider">&rarr;</span>
+ <li><a href="{% url 'defects' %}">Defects</a></li><span class="divider">&rarr;</span>
+ <li>{{object.name}}</li>
+ </ul>
+ </div>
+</div>
+
+<!-- Begin container -->
+
+<div class="row">
+ <div class="col-md-12">
+ <div class="page-header build-data">
+ <h1>Defect {{object.name}} Detail</h1>
+ </div>
+ </div>
+</div>
+
+<div class="row">
+ <div class="col-md-5">
+ <div class="well">
+ <h2>Quick Info</h2>
+ <dl class="dl-horizontal">
+ <dt>Summary:</dt>
+ <dd>{{object.summary}}</dd>
+
+ <dt>URL:</dt>
+ <dd><a href="{{object.url}}" id="dataid_{{object.id}}" target="_blank">{{object.url}}</a></dd>
+
+ <dt>Priority:</dt>
+ <dd>{{object.get_priority_text}}</dd>
+
+ <dt>Status:</dt>
+ <dd>{{object.get_status_text}}</dd>
+
+ <dt>Resolution:</dt>
+ <dd>{{object.get_resolution_text}}</dd>
+
+ <dt>Publish:</dt>
+ <dd>{{object.publish}}</dd>
+
+ <dt>Release Version:</dt>
+ <dd>{{object.release_version}}</dd>
+
+ <dt>Investigations:</dt>
+ <dd>
+ {% for ji in object.defect_to_investigation.all %}
+ {% if not forloop.first %}| {% endif %}<a href="{% url 'investigation' ji.investigation.id %}" target="_blank">{{ji.investigation.name}} </a>
+ {% endfor %}
+ </dd>
+
+ <dt>Product:</dt>
+ <dd><a href="{% url 'product' object.product.id %}">{{object.product.long_name}}</a></dd>
+
+ <dt>date_created:</dt>
+ <dd>{{object.date_created}}</dd>
+
+ <dt>date_updated:</dt>
+ <dd>{{object.date_updated}}</dd>
+
+ </dl>
+ </div>
+ </div>
+</div>
+
+
+<!-- Javascript support -->
+<script>
+ $(document).ready(function() {
+ /* Set the report link */
+ $('#report_link').attr('href',"{% url 'report' request.resolver_match.url_name %}?record_list={{object.id}}");
+ });
+</script>
+
+{% endblock %}
diff --git a/lib/srtgui/templates/defects-toastertable.html b/lib/srtgui/templates/defects-toastertable.html
index 82a6c5ee..1d699909 100644
--- a/lib/srtgui/templates/defects-toastertable.html
+++ b/lib/srtgui/templates/defects-toastertable.html
@@ -29,7 +29,8 @@
<h1 class="top-air" data-role="page-title"></h1>
</div>
- {% url 'cpes' as xhr_table_url %}
+ {# xhr_table_url is just the current url so leave it blank #}
+ {% url '' as xhr_table_url %}
{% include 'toastertable.html' %}
</div>
</div>
@@ -52,6 +53,17 @@
}
titleElt.text(title);
+
+ /* Set the report link */
+ var record_list=""
+ $(".name > a").each(function(){
+ var this_id=$(this).prop('id');
+ if (this_id.startsWith("dataid_")) {
+ record_list +=this_id.replace(/dataid_/,"") + ",";
+ }
+ });
+ $('#report_link').attr('href',"{% url 'report' request.resolver_match.url_name %}?record_list="+record_list);
+
});
});
</script>
diff --git a/lib/srtgui/templates/guided_tour.html b/lib/srtgui/templates/guided_tour.html
index 648bde14..fe5fd60e 100644
--- a/lib/srtgui/templates/guided_tour.html
+++ b/lib/srtgui/templates/guided_tour.html
@@ -74,7 +74,7 @@
<div class="row" style="padding-left: 25px;">
<h3><a id="public"></a>Public View</h3>
<ul>
- <li> <b><a href="{% url 'all-cves' %}">CVE's</a></b> </li>
+ <li> <b><a href="{% url 'cves' %}">CVE's</a></b> </li>
<ul>
<li> The CVE page is based on the NIST public page, and includes the V3 and V2 severities information, download links, and CPE's</li>
<li> There are tabs to see (a) the original source data and (b) the SRTool edits (if any)</li>
@@ -104,7 +104,7 @@
</ul>
</ul>
<ul>
- <li> <b><a href="{% url 'all-defects' %}">Defects</a></b> </li>
+ <li> <b><a href="{% url 'defects' %}">Defects</a></b> </li>
<ul>
<li> This table lists all of the Jira defects being tracked by the Vulnerabilities and Investigations </li>
<li> A quick status overview of the defects is provided </li>
@@ -118,14 +118,14 @@
</ul>
</ul>
<ul>
- <li> <b><a href="{% url 'all-cpes' %}">CPE's</a></b> </li>
+ <li> <b><a href="{% url 'cpes' %}">CPE's</a></b> </li>
<ul>
<li> The 'Common Product Enumerations' (CPE) found in the vulnerable CVE records </li>
<li> This data can help track CPE's that result in vulnerabilities, to help improve triaging CVE's </li>
</ul>
</ul>
<ul>
- <li> <b><a href="{% url 'all-cwes' %}">CWE's</a></b> </li>
+ <li> <b><a href="{% url 'cwes' %}">CWE's</a></b> </li>
<ul>
<li> The 'Common Weakness Enumerations' (CWE) found in the vulnerable CVE records </li>
</ul>
diff --git a/lib/srtgui/templates/investigation.html b/lib/srtgui/templates/investigation.html
index 77cb8fbd..bf0a5672 100644
--- a/lib/srtgui/templates/investigation.html
+++ b/lib/srtgui/templates/investigation.html
@@ -52,7 +52,7 @@
<h2>Quick Info</h2>
<dl class="dl-horizontal">
<dt>Product:</dt>
- <dd>{{object.product.name}} {{ object.product.version }} {{ object.product.profile }}</dd>
+ <dd><a href="{% url 'product' object.product.id %}">{{object.product.long_name}}</a></dd>
<dt>Investigation:</dt>
<dd><a href="{% url 'vulnerability' object.vulnerability.id %}">{{object.vulnerability.get_long_name}}</a></dd>
@@ -60,15 +60,42 @@
<dt>Defect:</dt>
<dd>
{% for ij in object.investigation_to_defect.all %}
- {% if not forloop.first %}| {% endif %}<a href="http://defect.wrs.com/browse/{{ij.defect.name}}" target="_blank">{{ij.defect.name}} </a>
+ {% if not forloop.first %}| {% endif %}<a href="{% url 'defect' ij.defect.id %}" target="_blank">{{ij.defect.name}} </a>
{% endfor %}
<p>
{% if access.is_creator %}
- <a class="btn btn-default navbar-btn " id="new-investigation-attachement" href="">Attach Defect</a>
- <a class="btn btn-default navbar-btn " id="new-investigation-attachement" href="">Create Defect</a>
+ <a class="btn btn-default navbar-btn " id="select-attachdefect">Attach Defect</a>
+ <a class="btn btn-default navbar-btn " id="select-createdefect">Create Defect</a>
+ <a class="btn btn-default navbar-btn " id="select-trashdefect">Detach Defect</a>
{% endif %}
</dd>
+ <div id="details-attachdefect" style="display:none; border: 1px solid; padding:20px; width:400px; margin-bottom:25px; margin-left:150px">
+ <p><b><label>Select Defect by Key:</label></b>
+ <div id="input-attachdefect" style="padding-left: 50px">
+ <p><input type="text" id="text-attachdefect" placeholder="Issue Key (ex. {{defect_example}})" size="20"> <button class="execute" id="submit-attachdefect"> Submit </button></p>
+ </div>
+ </div>
+
+ <div id="details-trashdefect" style="display:none; border: 1px solid; padding:20px; width:400px; margin-bottom:25px; margin-left:150px">
+ <p><b><label>Select Defect(s):</label></b>
+ <div id="select-trashdefectlist" style="padding-left: 50px">
+ <div class="row">
+ <div id="all-investigation-to-defects" class="scrolling" style="width: 300px;">
+ {% for obj in investigation_to_defect %}
+ <div class="checkbox">
+ <label>
+ <input class="checkbox-defects" name="{{obj.defect.pk}}" type="checkbox">{{obj.defect.name}}
+ </label>
+ <p>
+ </div>
+ {% endfor %}
+ </div>
+ <button class="execute" id="submit-trashdefect"> Detach </button>
+ </div>
+ </div>
+ </div>
+
<dt>Status:</dt>
<dd>{{object.get_status_text}}</dd>
@@ -81,7 +108,7 @@
<dt>Release Version:</dt>
<dd>
{% for ij in object.investigation_to_defect.all %}
- {% if not forloop.first %}| {% endif %}<a href="http://defect.wrs.com/browse/{{ij.defect.name}}" target="_blank">{{ij.defect.release_version}} </a>
+ {% if not forloop.first %}| {% endif %}<a href="{{ij.defect.url}}" target="_blank">{{ij.defect.release_version}} </a>
{% endfor %}
</dd>
</dl>
@@ -91,14 +118,18 @@
<hr>
-<div class="row">
+<div class="row" style="padding-left: 25px;">
<h3>Comments
- {% if access.is_creator %}
- <a class="btn btn-default navbar-btn " id="new-investigation-attachement" href="{% url 'login' %}">Add comment</a>
- {% endif %}
+ {% if access.is_creator %}
+ <button id="select-newcomment" class="btn btn-default" type="button">Add comment ...</button>
+ {% endif %}
</h3>
- <table class="table table-striped table-condensed" data-testid="inv-hyperlinks-table">
+ <div id="input-newcomment" style="padding-left: 50px; display:none;">
+ <p><input type="text" id="text-newcomment" size="40"> <button class="execute" id="submit-newcomment"> Submit </button></p>
+ </div>
+
+ <table class="table table-striped table-condensed" data-testid="vuln-hyperlinks-table">
<thead>
<tr>
<th>Comment</th>
@@ -116,11 +147,11 @@
<td>{{ c.comment }}</td>
<td>{{ c.date }}</td>
<td>{{ c.author }}</td>
- {% if access.is_creator %}
+ {% if access.is_creator or c.author == current_user %}
<td>
<span id="config_var_entry_'+configvars_sorted[i][2]+'" class="js-config-var-name"></span>
- <span class="glyphicon glyphicon-edit js-icon-pencil-config_var" id="affected_edit_'+{{c.id}}+'" x-data="'+{{c.id}}+'"></span>
- <span class="glyphicon glyphicon-trash js-icon-trash-config_var" id="comment_trash_'+{{c.id}}+'" x-data="'+{{c.id}}+'"></span>
+ <span class="glyphicon glyphicon-edit edit-comment" id="affected_edit_'+{{c.id}}+'" x-data="{{c.id}}"></span>
+ <span class="glyphicon glyphicon-trash trash-comment" id="comment_trash_'+{{c.id}}+'" x-data="{{c.id}}"></span>
</td>
{% endif %}
</tr>
@@ -134,13 +165,25 @@
</div>
-<div class="row">
+<div class="row" style="padding-left: 25px;">
<h3>Attachments
- {% if access.is_creator %}
- <a class="btn btn-default navbar-btn " id="new-investigation-attachement" href="{% url 'login' %}">Add attachment</a>
- {% endif %}
+ {% if access.is_creator %}
+ <a class="btn btn-default navbar-btn " id="select-addattachment">Add attachment ... </a>
+ {% endif %}
</h3>
+ <div id="details-addattachment" style="padding-left: 50px; display:none;">
+ <p><p>
+ <div class="row">
+ <form id="uploadbanner" enctype="multipart/form-data" method="post">{% csrf_token %}
+ <input id="fileDescription" name="fileDescription" type="text" placeholder="Enter Description" />
+ <input id="fileUpload" name="fileUpload" type="file" />
+ <input type="hidden" id="action" name="action" value="upload">
+ <input type="submit" value="submit file" id="submit-addattachment" />
+ </form>
+ </div>
+ </div>
+
<table class="table table-striped table-condensed" data-testid="vuln-hyperlinks-table">
<thead>
<tr>
@@ -157,17 +200,20 @@
{% for u in object.investigation_uploads.all %}
<tr>
<td>{{ u.description }}</td>
- <td>{{ u.path }}</td>
+ <td>{{ u.path|basename }}</td>
<td>{{ u.size }}</td>
<td>{{ u.date }}</td>
<td>{{ u.author }}</td>
<td>
<span id="attachment_entry_'+{{u.id}}+'" class="js-config-var-name"></span>
- <span class="glyphicon glyphicon-download-alt get-help" title="Download document"></span>
- {% if access.is_creator %}
- <span class="glyphicon glyphicon-edit js-icon-pencil-config_var" id="affected_edit_'+{{u.id}}+'" x-data="'+{{u.id}}+'"></span>
- <span class="glyphicon glyphicon-trash js-icon-trash-config_var" id="attachment_trash_'+{{u.id}}+'" x-data="'+{{u.id}}+'"></span>
- {% endif %}
+ <form id="downloadbanner" enctype="multipart/form-data" method="post" >{% csrf_token %}
+ <input type="hidden" id="action" name="action" value="download">
+ <input type="hidden" id="record_id" name="record_id" value={{u.id}}>
+ <span class="glyphicon glyphicon-download-alt submit-downloadattachment" id="attachment_download_'+{{u.id}}+'" x-data="{{u.id}}"></span>
+ {% if access.is_creator %}
+ <span class="glyphicon glyphicon-trash trash-attachment" id="attachment_trash_'+{{u.id}}+'" x-data="{{u.id}}"></span>
+ {% endif %}
+ </form>
</td>
</tr>
{% endfor %}
@@ -177,18 +223,37 @@
</tr>
{% endif %}
</table>
-
</div>
<br/>
<hr/>
{% if access.is_creator %}
- <div class="row">
+ <div class="row" style="padding-left: 25px;">
<h3>Change Notifications
- <a class="btn btn-default navbar-btn " id="new-investigation-notify" href="{% url 'login' %}">Add user notification</a>
+ {% if access.is_creator %}
+ <button id="select-addusernotify" class="btn btn-default" type="button">Add user notification ...</button>
+ {% endif %}
</h3>
+ <div id="details-addusernotify" style="padding-left: 50px; display:none;">
+ <p><p>
+ <button class="execute" id="submit-addusernotify"> Submit </button>
+ <div class="row">
+ <p>
+ <div id="all-users" class="scrolling" style="width: 300px;">
+ {% for user in users %}
+ <div class="checkbox">
+ <label>
+ <input class="checkbox-users" name="{{user.pk}}" type="checkbox">{{user.name}}
+ </label>
+ <p>
+ </div>
+ {% endfor %}
+ </div>
+ </div>
+ </div>
+
<table class="table table-striped table-condensed" data-testid="vuln-hyperlinks-table">
<thead>
<tr>
@@ -200,16 +265,16 @@
</tr>
</thead>
- {% if object.investigation_users.all %}
- {% for u in object.investigation_users.all %}
+ {% if object.investigation_notification.all %}
+ {% for u in object.investigation_notification.all %}
<tr>
<td>{{ u.user.name }}</td>
<td>{{ u.user.email }}</td>
- {% if access.is_creator %}
+ {% if access.is_creator or u.user.name == current_user %}
<td>
<span id="attachment_entry_'+{{u.id}}+'" class="js-config-var-name"></span>
- <span class="glyphicon glyphicon-edit js-icon-pencil-config_var" id="affected_edit_'+{{u.id}}+'" x-data="'+{{u.id}}+'"></span>
- <span class="glyphicon glyphicon-trash js-icon-trash-config_var" id="attachment_trash_'+{{u.id}}+'" x-data="'+{{u.id}}+'"></span>
+ <span class="glyphicon glyphicon-edit edit-usernotification" id="affected_edit_'+{{u.id}}+'" x-data="{{u.id}}"></span>
+ <span class="glyphicon glyphicon-trash trash-usernotification" id="attachment_trash_'+{{u.id}}+'" x-data="{{u.id}}"></span>
</td>
{% endif %}
</tr>
@@ -223,11 +288,31 @@
</div>
- <div class="row">
+ <div class="row" style="padding-left: 25px;">
<h3>User Access
- <a class="btn btn-default navbar-btn " id="new-investigation-access" href="{% url 'login' %}">Add user access</a>
+ {% if access.is_creator %}
+ <button id="select-adduseraccess" class="btn btn-default" type="button">Add user access ...</button>
+ {% endif %}
</h3>
+ <div id="details-adduseraccess" style="padding-left: 50px; display:none;">
+ <p><p>
+ <button class="execute" id="submit-adduseraccess"> Submit </button>
+ <div class="row">
+ <p>
+ <div id="all-users" class="scrolling" style="width: 300px;">
+ {% for user in users %}
+ <div class="checkbox">
+ <label>
+ <input class="checkbox-users" name="{{user.pk}}" type="checkbox">{{user.name}}
+ </label>
+ <p>
+ </div>
+ {% endfor %}
+ </div>
+ </div>
+ </div>
+
<table class="table table-striped table-condensed" data-testid="vuln-hyperlinks-table">
<thead>
<tr>
@@ -253,8 +338,8 @@
{% if access.is_creator %}
<td>
<span id="attachment_entry_'+{{u.id}}+'" class="js-config-var-name"></span>
- <span class="glyphicon glyphicon-edit js-icon-pencil-config_var" id="affected_edit_'+{{u.id}}+'" x-data="'+{{u.id}}+'"></span>
- <span class="glyphicon glyphicon-trash js-icon-trash-config_var" id="attachment_trash_'+{{u.id}}+'" x-data="'+{{u.id}}+'"></span>
+ <span class="glyphicon glyphicon-edit edit-useraccess" id="affected_edit_'+{{u.id}}+'" x-data="{{u.id}}"></span>
+ <span class="glyphicon glyphicon-trash trash-useraccess" id="attachment_trash_'+{{u.id}}+'" x-data="{{u.id}}"></span>
</td>
{% endif %}
</tr>
@@ -271,7 +356,7 @@
</div>
{% endif %}
-<div class="row">
+<div class="row" style="padding-left: 25px;">
<h3>History</h3>
<table class="table table-striped table-condensed" data-testid="vuln-hyperlinks-table">
<thead>
@@ -297,5 +382,287 @@
</table>
</div>
+<script>
+ var selected_newcomment=false;
+ var selected_addusernotify=false;
+ var selected_adduseraccess=false;
+ var selected_addattachment=false;
+ var selected_attachdefect=false;
+ var selected_trashdefect=false;
+
+ $(document).ready(function() {
+ function onCommitAjaxSuccess(data, textstatus) {
+ if (window.console && window.console.log) {
+ console.log("XHR returned:", data, "(" + textstatus + ")");
+ } else {
+ alert("NO CONSOLE:\n");
+ return;
+ }
+ if (data.error != "ok") {
+ alert("error on request:\n" + data.error);
+ return;
+ }
+ // reload the page with the updated tables
+ location.reload(true);
+ }
+
+ function onCommitAjaxError(jqXHR, textstatus, error) {
+ console.log("ERROR:"+error+"|"+textstatus);
+ alert("XHR errored1:\n" + error + "\n(" + textstatus + ")");
+ }
+
+ /* ensure cookie exists {% csrf_token %} */
+ function postCommitAjaxRequest(reqdata) {
+ reqdata["investigation_id"] = {{ object.id }}
+ var ajax = $.ajax({
+ type:"POST",
+ data: reqdata,
+ url:"{% url 'xhr_investigation_commit' %}",
+ headers: { 'X-CSRFToken': $.cookie("csrftoken")},
+ success: onCommitAjaxSuccess,
+ error: onCommitAjaxError,
+ });
+ }
+
+ /* (De-)Select management */
+
+ $('#select-these').click(function(){
+ $(':checkbox').each(function(){
+ $(this).prop('checked', true);
+ });
+ });
+
+ $('#unselect-these').click(function(){
+ $(':checkbox').each(function(){
+ $(this).prop('checked', false);
+ });
+ });
+
+ /* Defect management */
+
+ $('#select-attachdefect').click(function(){
+ if (selected_attachdefect) {
+ selected_attachdefect=false;
+ $("#details-attachdefect").slideUp();
+ } else {
+ if (selected_trashdefect) {
+ selected_trashdefect = false;
+ }
+ selected_attachdefect=true;
+ $("#details-trashdefect").slideUp();
+ $("#details-attachdefect").slideDown();
+ }
+ })
+
+ $('#select-trashdefect').click(function(){
+ if (selected_trashdefect) {
+ selected_trashdefect=false;
+ $("#details-trashdefect").slideUp();
+ } else {
+ if (selected_attachdefect) {
+ selected_attachdefect = false;
+ }
+ selected_trashdefect=true;
+ $("#details-trashdefect").slideDown();
+ $("#details-attachdefect").slideUp();
+ }
+ })
+
+ $('#submit-attachdefectlist').click(function(){
+ var defect_list=""
+ $(':checkbox').each(function(){
+ if ($(this).is(':checked')) {
+ defect_list += $(this).prop('name') + ",";
+ }
+ });
+ if ("" == defect_list) {
+ alert("No users were selected");
+ return;
+ }
+ postCommitAjaxRequest({
+ "action" : 'submit-attachdefectlist',
+ "defects" : defect_list,
+ });
+ });
+
+ $('#submit-attachdefect').click(function(){
+ var query=$('#text-attachdefect').val().trim()
+ if (query=="") {
+ alert("No query given");
+ return;
+ }
+ postCommitAjaxRequest({
+ "action" : 'submit-attachdefect',
+ "query" : query,
+ })
+ });
+
+ $('#submit-trashdefect').click(function(){
+ var defect_list=""
+ $(':checkbox').each(function(){
+ if ($(this).is(':checked')) {
+ defect_list += $(this).prop('name') + ",";
+ }
+ });
+ if ("" == defect_list) {
+ alert("No users were selected");
+ return;
+ }
+ postCommitAjaxRequest({
+ "action" : 'submit-trashdefect',
+ "defects" : defect_list,
+ });
+ });
+
+ /* Comment management */
+
+ $('#select-newcomment').click(function(){
+ if (selected_newcomment) {
+ selected_newcomment=false;
+ $("#input-newcomment").slideUp();
+ } else {
+ selected_newcomment=true;
+ $("#input-newcomment").slideDown();
+ }
+ });
+
+ $('#submit-newcomment').click(function(){
+ var comment=$('#text-newcomment').val().trim()
+ if (comment=="") {
+ alert("No comment was written");
+ return;
+ }
+ postCommitAjaxRequest({
+ "action" : 'submit-newcomment',
+ "comment" : comment,
+ })
+ });
+
+ $('.trash-comment').click(function(){
+ var result = confirm("Are you sure?");
+ if (result){
+ postCommitAjaxRequest({
+ "action" : 'submit-trashcomment',
+ "record_id" : $(this).attr('x-data'),
+ });
+ }
+ })
+
+ /* Attachement management */
+
+ $('#select-addattachment').click(function() {
+ if (selected_addattachment) {
+ selected_addattachment=false;
+ $("#details-addattachment").slideUp();
+ } else {
+ selected_addattachment=true;
+ $("#details-addattachment").slideDown();
+ }
+ });
+
+ $('.submit-downloadattachment').click(function() {
+ $("#downloadbanner").submit();
+ });
+
+ $('.trash-attachment').click(function() {
+ var result = confirm("Are you sure?");
+ if (result){
+ postCommitAjaxRequest({
+ "action" : 'submit-trashattachment',
+ "record_id" : $(this).attr('x-data'),
+ });
+ }
+ });
+
+ /* User notify management */
+
+ $('#select-addusernotify').click(function(){
+ if (selected_addusernotify) {
+ selected_addusernotify=false;
+ $("#select-these").removeAttr("disabled");
+ $("#unselect-these").removeAttr("disabled");
+ $("#details-addusernotify").slideUp();
+ } else {
+ selected_addusernotify=true;
+ $("#select-these").attr("disabled","disabled");
+ $("#unselect-these").attr("disabled","disabled");
+ $("#details-addusernotify").slideDown();
+ }
+ });
+
+ $('#submit-addusernotify').click(function(){
+ var user_list=""
+ $(':checkbox').each(function(){
+ if ($(this).is(':checked')) {
+ user_list += $(this).prop('name') + ",";
+ }
+ });
+ if ("" == user_list) {
+ alert("No users were selected");
+ return;
+ }
+ postCommitAjaxRequest({
+ "action" : 'submit-addusernotify',
+ "users" : user_list,
+ });
+ });
+
+ $('.trash-usernotification').click(function(){
+ var result = confirm("Are you sure?");
+ if (result){
+ postCommitAjaxRequest({
+ "action" : 'submit-trashusernotification',
+ "record_id" : $(this).attr('x-data'),
+ });
+ }
+ })
+
+ /* User access management */
+
+ $('#select-adduseraccess').click(function(){
+ if (selected_adduseraccess) {
+ selected_adduseraccess=false;
+ $("#select-these").removeAttr("disabled");
+ $("#unselect-these").removeAttr("disabled");
+ $("#details-adduseraccess").slideUp();
+ } else {
+ selected_adduseraccess=true;
+ $("#select-these").attr("disabled","disabled");
+ $("#unselect-these").attr("disabled","disabled");
+ $("#details-adduseraccess").slideDown();
+ }
+ });
+
+ $('#submit-adduseraccess').click(function(){
+ var user_list=""
+ $(':checkbox').each(function(){
+ if ($(this).is(':checked')) {
+ user_list += $(this).prop('name') + ",";
+ }
+ });
+ if ("" == user_list) {
+ alert("No users were selected");
+ return;
+ }
+ postCommitAjaxRequest({
+ "action" : 'submit-adduseraccess',
+ "users" : user_list,
+ });
+ });
+
+ $('.trash-useraccess').click(function(){
+ var result = confirm("Are you sure?");
+ if (result){
+ postCommitAjaxRequest({
+ "action" : 'submit-trashuseraccess',
+ "record_id" : $(this).attr('x-data'),
+ });
+ }
+ })
+
+ /* Set the report link */
+ $('#report_link').attr('href',"{% url 'report' request.resolver_match.url_name %}?record_list={{object.id}}");
+ });
+</script>
{% endblock %}
diff --git a/lib/srtgui/templates/investigations-toastertable.html b/lib/srtgui/templates/investigations-toastertable.html
index 2aee7f7e..384d7141 100644
--- a/lib/srtgui/templates/investigations-toastertable.html
+++ b/lib/srtgui/templates/investigations-toastertable.html
@@ -30,7 +30,8 @@
<h1 class="top-air" data-role="page-title"></h1>
</div>
- {% url 'cves' as xhr_table_url %}
+ {# xhr_table_url is just the current url so leave it blank #}
+ {% url '' as xhr_table_url %}
{% include 'toastertable.html' %}
</div>
</div>
@@ -53,6 +54,17 @@
}
titleElt.text(title);
+
+ /* Set the report link */
+ var record_list=""
+ $(".name > a").each(function(){
+ var this_id=$(this).prop('id');
+ if (this_id.startsWith("dataid_")) {
+ record_list +=this_id.replace(/dataid_/,"") + ",";
+ }
+ });
+ $('#report_link').attr('href',"{% url 'report' request.resolver_match.url_name %}?record_list="+record_list);
+
});
});
</script>
diff --git a/lib/srtgui/templates/landing.html b/lib/srtgui/templates/landing.html
index 52f24482..e0950bd8 100644
--- a/lib/srtgui/templates/landing.html
+++ b/lib/srtgui/templates/landing.html
@@ -25,7 +25,7 @@
</tr>
</thead>
- {% if access.is_admin %}
+ {% if access.is_creator %}
<tr>
<td><a class="btn btn-info btn-lg" href="{% url 'manage' %}">Management</a></td>
<td>Triage CVE's, Create Vulnerabilities, Manage Users</td>
@@ -33,7 +33,7 @@
{% endif %}
<tr>
- <td><a class="btn btn-info btn-lg" href="{% url 'all-cves' %}">CVE's</a></td>
+ <td><a class="btn btn-info btn-lg" href="{% url 'cves' %}">CVE's</a></td>
<td>Common Vulnerblility Enumeration</td>
</tr>
@@ -48,7 +48,7 @@
</tr>
<tr>
- <td><a class="btn btn-info btn-lg" href="{% url 'all-defects' %}">Defects</a></td>
+ <td><a class="btn btn-info btn-lg" href="{% url 'defects' %}">Defects</a></td>
<td>SRTool Defects</td>
</tr>
@@ -58,12 +58,12 @@
</tr>
<tr>
- <td><a class="btn btn-info btn-lg" href="{% url 'all-cpes' %}">CPE's</a></td>
+ <td><a class="btn btn-info btn-lg" href="{% url 'cpes' %}">CPE's</a></td>
<td>Common Platform Enumeration</td>
</tr>
<tr>
- <td><a class="btn btn-info btn-lg" href="{% url 'all-cwes' %}">CWE's</a></td>
+ <td><a class="btn btn-info btn-lg" href="{% url 'cwes' %}">CWE's</a></td>
<td>Common Weakness Enumeration</td>
</tr>
diff --git a/lib/srtgui/templates/login.html b/lib/srtgui/templates/login.html
new file mode 100644
index 00000000..be597992
--- /dev/null
+++ b/lib/srtgui/templates/login.html
@@ -0,0 +1,40 @@
+{% extends "base.html" %}
+
+{% load static %}
+{% load projecttags %}
+{% load humanize %}
+
+{% block title %} Login Page {% endblock %}
+{% block pagecontent %}
+ <div class="row">
+ <div class="col-md-7" style="padding-left: 50px;">
+ <h1>Login Page</h1>
+ </div>
+ </div>
+
+ <form method="POST">{% csrf_token %}
+ <div class="row" style="padding-left: 100px;">
+ <h2>Select User:</h2>
+ {% if object.all %}
+ <select name="username" size="10" required>
+ {% for user in object.all %}
+ <option>{{user.name}} ({{user.get_access_text}})</option>
+ {% endfor %}
+ </select>
+ {% else %}
+ <p>No Users Found</p>
+ {% endif%}
+ </div>
+
+ <div class="row" style="padding-left: 100px;">
+ <h2>Password:</h2>
+ <input type="password" class="form-control" style="width: 150px;" name="password" placeholder="(enter anything)">
+ </div>
+
+ <div class="top-air" style="padding-left: 100px;">
+ <input type="submit" id="login-button" class="btn btn-primary btn-lg" value="Submit"/>
+ <a class="btn btn-info btn-lg" href="{% url 'landing' %}">Cancel</a>
+ </div>
+ </form>
+
+{% endblock %}
diff --git a/lib/srtgui/templates/manage-cpes-toastertable.html b/lib/srtgui/templates/manage-cpes-toastertable.html
index dc4bb800..13fdff80 100644
--- a/lib/srtgui/templates/manage-cpes-toastertable.html
+++ b/lib/srtgui/templates/manage-cpes-toastertable.html
@@ -36,7 +36,8 @@
<h1 class="top-air" data-role="page-title"></h1>
</div>
- {% url 'cpes' as xhr_table_url %}
+ {# xhr_table_url is just the current url so leave it blank #}
+ {% url '' as xhr_table_url %}
{% include 'toastertable.html' %}
</div>
</div>
@@ -60,6 +61,17 @@
}
titleElt.text(title);
+
+ /* Set the report link */
+ var record_list=""
+ $(".name > a").each(function(){
+ var this_id=$(this).prop('id');
+ if (this_id.startsWith("dataid_")) {
+ record_list +=this_id.replace(/dataid_/,"") + ",";
+ }
+ });
+ $('#report_link').attr('href',"{% url 'report' request.resolver_match.url_name %}?record_list="+record_list);
+
});
});
</script>
diff --git a/lib/srtgui/templates/management.html b/lib/srtgui/templates/management.html
index 2e53ee88..cfdd10d4 100644
--- a/lib/srtgui/templates/management.html
+++ b/lib/srtgui/templates/management.html
@@ -35,8 +35,8 @@
</tr>
<tr>
- <td><a class="btn btn-info btn-lg" href="{% url 'publish' %}">Publish Vulnerabilities</a></td>
- <td>Process the items that are ready to be published</td>
+ <td><a class="btn btn-info btn-lg" href="{% url 'publish' %}">Publish Request</a></td>
+ <td>Process the items that are ready to be published from SRTool</td>
</tr>
<tr>
@@ -44,6 +44,7 @@
<td>Report on the over all response system status</td>
</tr>
+ {% if access.is_admin %}
<tr>
<td><a class="btn btn-info btn-lg" href="{% url 'users' %}">Manage Users</a></td>
<td>Add, edit, and remove users</td>
@@ -53,6 +54,7 @@
<td><a class="btn btn-info btn-lg" href="{% url 'sources' %}">Manage Sources</a></td>
<td>Manage source list, perform manual pulls</td>
</tr>
+ {% endif %}
</table>
</div>
@@ -65,16 +67,16 @@
<dl class="dl-horizontal">
<dt>CVE's: Total Count =</dt>
<dd>
- <a href="{% url 'all-cves' %}"> {{cve_total}} </a>
+ <a href="{% url 'cves' %}"> {{cve_total}} </a>
</dd>
<dt>Pending triaged =</dt>
<dd>
- <a href="{% url 'all-cves' %}?limit=25&page=1&orderby=name&filter=is_status:new&default_orderby=name&filter_value=on&"> {{cve_new}} </a>
+ <a href="{% url 'cves' %}?limit=25&page=1&orderby=name&filter=is_status:new&default_orderby=name&filter_value=on&"> {{cve_new}} </a>
</dd>
<!--
<dt>Open =</dt>
<dd>
- <a href="{% url 'all-cves' %}?limit=25&page=1&orderby=name&filter=is_status:open&default_orderby=name&filter_value=on&"> {{cve_open}} </a>
+ <a href="{% url 'cves' %}?limit=25&page=1&orderby=name&filter=is_status:open&default_orderby=name&filter_value=on&"> {{cve_open}} </a>
</dd>
-->
<dt>Vulnerabilities: Total Count =</dt>
@@ -125,7 +127,7 @@
<dt>Defects: Total Count =</dt>
<dd>
- <a href="{% url 'all-defects' %}" %}> {{defect_total}} </a>
+ <a href="{% url 'defects' %}" %}> {{defect_total}} </a>
</dd>
</dl>
diff --git a/lib/srtgui/templates/product.html b/lib/srtgui/templates/product.html
new file mode 100644
index 00000000..e26bb2fe
--- /dev/null
+++ b/lib/srtgui/templates/product.html
@@ -0,0 +1,84 @@
+{% extends "base.html" %}
+
+{% load projecttags %}
+
+{% block title %} {{object.name}} - SRTool {% endblock %}
+
+{% block pagecontent %}
+
+<div class="row">
+ <!-- Breadcrumbs -->
+ <div class="col-md-12">
+ <ul class="breadcrumb" id="breadcrumb">
+ <li><a href="{% url 'landing' %}">Home</a></li><span class="divider">&rarr;</span>
+ <li><a href="{% url 'products' %}">Products</a></li><span class="divider">&rarr;</span>
+ <li>{{object.name}}</li>
+ </ul>
+ </div>
+</div>
+
+<!-- Begin container -->
+
+<div class="row">
+ <div class="col-md-12">
+ <div class="page-header build-data">
+ <h1>Product {{object.long_name}}Detail</h1>
+ </div>
+ </div>
+</div>
+
+<div class="row">
+ <div class="col-md-5">
+ <div class="well">
+ <h2>Quick Info</h2>
+ <dl class="dl-horizontal">
+ <dt>Name:</dt>
+ <dd>{{object.name}}</dd>
+
+ <dt>Version:</dt>
+ <dd>{{object.version}}</dd>
+
+ <dt>Profile:</dt>
+ <dd>{{object.profile}}</dd>
+
+ <dt>Cpe:</dt>
+ <dd>{{object.cpe}}</dd>
+
+ <dt>Srt Cpe:</dt>
+ <dd>{{object.srt_cpe}}</dd>
+
+ <dt>Defect Prefix:</dt>
+ <dd>{{object.defect_prefix }}</dd>
+
+ <dt>Investigations Count/Link:</dt>
+ <dd>
+ {% if object.product_investigation.all.count %}
+ <a href="{% url 'investigations' %}?filter=is_product:{{object.defect_prefix}}&" class="btn btn-info" >
+ {{object.product_investigation.all.count}}
+ </a>
+ {% else %}0{% endif %}
+ </dd>
+
+ <dt>Defects Count/Link:</dt>
+ <dd>
+ {% if object.product_defect.all.count %}
+ <a href="{% url 'defects' %}?filter=is_product:{{object.defect_prefix}}&" class="btn btn-info" >
+ {{object.product_defect.all.count}}
+ </a>
+ {% else %}0{% endif %}
+ </dd>
+
+ </dl>
+ </div>
+ </div>
+</div>
+
+<!-- Javascript support -->
+<script>
+ $(document).ready(function() {
+ /* Set the report link */
+ $('#report_link').attr('href',"{% url 'report' request.resolver_match.url_name %}?record_list={{object.id}}");
+ });
+</script>
+
+{% endblock %}
diff --git a/lib/srtgui/templates/products-toastertable.html b/lib/srtgui/templates/products-toastertable.html
index 65602be7..7e12b96b 100644
--- a/lib/srtgui/templates/products-toastertable.html
+++ b/lib/srtgui/templates/products-toastertable.html
@@ -30,7 +30,8 @@
<h1 class="top-air" data-role="page-title"></h1>
</div>
- {% url 'cves' as xhr_table_url %}
+ {# xhr_table_url is just the current url so leave it blank #}
+ {% url '' as xhr_table_url %}
{% include 'toastertable.html' %}
</div>
</div>
@@ -53,6 +54,17 @@
}
titleElt.text(title);
+
+ /* Set the report link */
+ var record_list=""
+ $(".name > a").each(function(){
+ var this_id=$(this).prop('id');
+ if (this_id.startsWith("dataid_")) {
+ record_list +=this_id.replace(/dataid_/,"") + ",";
+ }
+ });
+ $('#report_link').attr('href',"{% url 'report' request.resolver_match.url_name %}?record_list="+record_list);
+
});
});
</script>
diff --git a/lib/srtgui/templates/publish-select-toastertable.html b/lib/srtgui/templates/publish-select-toastertable.html
new file mode 100644
index 00000000..5a439c63
--- /dev/null
+++ b/lib/srtgui/templates/publish-select-toastertable.html
@@ -0,0 +1,248 @@
+{% extends 'base.html' %}
+{% load static %}
+
+
+{% block extraheadcontent %}
+ <link rel="stylesheet" href="{% static 'css/jquery-ui.min.css' %}" type='text/css'>
+ <link rel="stylesheet" href="{% static 'css/jquery-ui.structure.min.css' %}" type='text/css'>
+ <link rel="stylesheet" href="{% static 'css/jquery-ui.theme.min.css' %}" type='text/css'>
+ <script src="{% static 'js/jquery-ui.min.js' %}">
+ </script>
+ {% if access.is_creator %}{% else %}<meta http-equiv="refresh" content="0; url=/" />{% endif %}
+
+ <style>
+ /* Style the execution buttons */
+ button.execute { height:50px;width:210px;background-color:#4CAF50;text-align:center; border:2px #f69c55;border-radius: 12px; }
+
+ button:disabled {
+ cursor: not-allowed;
+ }
+
+ /* Create two equal columns that floats next to each other */
+ .column {
+ float: left;
+ width: 350px;
+ padding: 10px;
+ }
+
+ /* Clear floats after the columns */
+ .row:after {
+ content: "";
+ display: table;
+ clear: both;
+ }
+ </style>
+
+{% endblock %}
+
+{% block title %} Publish CVE's - SRTool {% endblock %}
+
+{% block pagecontent %}
+
+ <div class="row">
+ <!-- Breadcrumbs -->
+ <div class="col-md-12">
+ <ul class="breadcrumb" id="breadcrumb">
+ <li><a href="{% url 'landing' %}">Home</a></li><span class="divider">&rarr;</span>
+ <li><a href="{% url 'manage' %}">Management</a></li><span class="divider">&rarr;</span>
+ <li><a href="{% url 'publish' %}">Publish</a></li><span class="divider">&rarr;</span>
+ <li>Publish CVE's</li>
+ </ul>
+ </div>
+ </div>
+
+ <div id="change-publish-state" > <!--class="form-inline" -->
+ <b><big>Actions: </big></b>
+ <button id="select-these" class="btn btn-default" type="button">Select these</button>
+ <button id="unselect-these" class="btn btn-default" type="button">Un-select these</button>
+ <button id="select-publish" class="btn btn-default" type="button">Update ...</button>
+ <!--<button id="collect-publish" class="btn btn-default" type="button">Collect Publishable CVEs</button> -->
+ </div>
+
+ <div id="details-publish" style="display:none;">
+ <p><p>
+ <button class="execute" id="submit-publish"> Update Publish CVE State </button>
+ <p><b><big>New Publish State: </big></b>
+ <select name="Publish" id="select-publish-state">
+ <option value="0" >Unpublished</option>
+ <option value="1" >Not to be Published</option>
+ <option value="2" >Published</option>
+ <option value="3" >Publish Request (New)</option>
+ <option value="4" >Publish Request (Update)</option>
+ <option value="5" selected>Publish Submitted</option>
+ </select>
+ </div>
+
+ <div class="row">
+ <div class="col-md-12">
+ <div class="page-header">
+ <h1 class="top-air" data-role="page-title"></h1>
+ </div>
+
+ {% url '' as xhr_table_url %}
+ {% include 'toastertable.html' %}
+ </div>
+ </div>
+
+ <!-- Javascript support -->
+ <script>
+
+ //# sourceURL=somename.js
+
+ // global variables
+ var selected_publish=false;
+ var cve_total=0;
+
+ $(document).ready(function() {
+
+ function onCommitAjaxSuccess(data, textstatus) {
+ if (window.console && window.console.log) {
+ console.log("XHR returned:", data, "(" + textstatus + ")");
+ } else {
+ alert("NO CONSOLE:\n");
+ return;
+ }
+ if (data.error != "ok") {
+ alert("error on request:\n" + data.error);
+ return;
+ }
+ // reload the page with the updated tables
+ location.reload(true);
+ }
+
+ function onCommitAjaxError(jqXHR, textstatus, error) {
+ console.log("ERROR:"+error+"|"+textstatus);
+ alert("XHR errored1:\n" + error + "\n(" + textstatus + ")");
+ }
+
+ /* ensure cookie exists {% csrf_token %} */
+ function postCommitAjaxRequest(reqdata) {
+ var ajax = $.ajax({
+ type:"POST",
+ data: reqdata,
+ url:"{% url 'xhr_cve_publish_commit'%}",
+ headers: { 'X-CSRFToken': $.cookie("csrftoken")},
+ success: onCommitAjaxSuccess,
+ error: onCommitAjaxError,
+ })
+ }
+
+ function update_publish_status() {
+ var cve_count = 0;
+ var cve_checked_count = 0;
+ $('#selectpublishtable input').each(function(){
+ cve_count = cve_count + 1;
+ if ($(this).is(':checked')) {
+ cve_checked_count = cve_checked_count + 1;
+ }
+ });
+ if (cve_total > cve_count) {
+ document.getElementById("select-these").innerText = "Select "+(cve_count-cve_checked_count)+" unchecked ("+(cve_total-cve_count)+" offpage)";
+ } else {
+ document.getElementById("select-these").innerText = "Select "+(cve_count-cve_checked_count)+" unchecked";
+ }
+ document.getElementById("unselect-these").innerText = "Un-select "+cve_checked_count+" checked";
+ if (0 == cve_checked_count) {
+ //$("#submit-publish").attr("disabled","disabled");
+ document.getElementById("submit-publish").disabled = true;
+ } else {
+ //$("#submit-publish").removeAttr("disabled");
+ document.getElementById("submit-publish").disabled = false;
+ }
+ }
+
+ $('#select-these').click(function(){
+ $('#selectpublishtable input').each(function(){
+ $(this).prop('checked', true);
+ });
+ update_publish_status();
+ });
+
+ $('#unselect-these').click(function(){
+ $('#selectpublishtable input').each(function(){
+ $(this).prop('checked', false);
+ });
+ update_publish_status();
+ });
+
+ // Open Publish Action
+ $('#select-publish').click(function(){
+ if (selected_publish) {
+ selected_publish=false;
+ $("#select-these").removeAttr("disabled");
+ $("#unselect-these").removeAttr("disabled");
+ $("#details-publish").slideUp();
+ } else {
+ selected_publish=true;
+ $("#select-these").attr("disabled","disabled");
+ $("#unselect-these").attr("disabled","disabled");
+ update_publish_status();
+ $("#details-publish").slideDown();
+ }
+ });
+
+ $('#submit-publish').click(function(){
+ var cve_list="";
+ $('#selectpublishtable input').each(function(){
+ if ($(this).is(':checked')) {
+ cve_list +=$(this).prop('name') + ",";
+ }
+ });
+ if ("" == cve_list) {
+ alert("No CVE's were selected");
+ return;
+ }
+ publish_state=$('#select-publish-state').val();
+ postCommitAjaxRequest({
+ "publish_state" : publish_state,
+ "cve_list" : cve_list,
+ });
+
+ });
+
+ // When change in product selections, update labels and enables
+ $(document).on("change", "#all-products :checkbox", function() {
+ update_publish_status();
+ });
+
+ // When change in CVE selections, update labels and enables
+ $(document).on("change", "#selectpublishtable :checkbox", function() {
+ update_publish_status();
+ });
+
+
+ // Standard Toaster Table enablement
+
+ var tableElt = $("#{{table_name}}");
+ var titleElt = $("[data-role='page-title']");
+
+ tableElt.on("table-done", function (e, total, tableParams) {
+ var title = "Publish CVE's";
+
+ if (tableParams.search || tableParams.filter) {
+ if (total === 0) {
+ title = "No CVE's found";
+ }
+ else if (total > 0) {
+ title = total + " CVE" + (total > 1 ? "'s" : '') + " found";
+ }
+ }
+
+ titleElt.text(title);
+ cve_total = total;
+ update_publish_status();
+
+ /* Set the report link */
+ var record_list=""
+ $(".name > a").each(function(){
+ var this_id=$(this).prop('id');
+ if (this_id.startsWith("dataid_")) {
+ record_list +=this_id.replace(/dataid_/,"") + ",";
+ }
+ });
+ $('#report_link').attr('href',"{% url 'report' request.resolver_match.url_name %}?record_list="+record_list);
+ });
+
+ });
+ </script>
+{% endblock %}
diff --git a/lib/srtgui/templates/publish.html b/lib/srtgui/templates/publish.html
index 2b65e81b..b1f3d83f 100644
--- a/lib/srtgui/templates/publish.html
+++ b/lib/srtgui/templates/publish.html
@@ -7,25 +7,38 @@
{% block title %} Publish Requests {% endblock %}
{% block pagecontent %}
- <div class="row">
- <div class="col-md-7" style="padding-left: 50px;">
+<div class="row">
+ <!-- Breadcrumbs -->
+ <div class="col-md-12">
+ <ul class="breadcrumb" id="breadcrumb">
<li><a href="{% url 'landing' %}">Home</a></li><span class="divider">&rarr;</span>
<li><a href="{% url 'manage' %}">Management</a></li><span class="divider">&rarr;</span>
- <h1>Publish (Proposals)</h1>
- </div>
- </div>
+ <li>Publish (Proposals)</li>
+ </ul>
+ </div>
+</div>
<h2> Manage Publish Requests</h2>
<ul>
- <li>This interface can review and accept the list of vulnerabilities that have readhed their publication date</li>
- <li>This is preferable over automatic publishing for when the defect and/or official publish date are not very certain</li>
+ <li>The SRTool supports an external publishing tool, for example a business table or the vendor's public website</li>
+ <li>These tools can be used to (a) submit CVEs to that tool, and (b) update the CVEs when they have been published</li>
</ul>
<h2> Publishing Actions</h2>
<ul>
- <li>Format (and hopefully automatically register) the Vulnerability information to the company website</li>
- <li>Format a notice for TechPubs</li>
- <li>Format a notice for the respective product leads</li>
+ <tr>
+ <td><a class="btn btn-info btn-lg" href="{% url 'select-publish' %}">Publish Request</a></td>
+ <td>Process the items that are ready to be published from SRTool</td>
+ </tr>
+
+ <br>
+ <br>
+ <br>
+
+ <tr>
+ <td><a class="btn btn-info btn-lg" href="{% url 'update-published' %}">Published Update</a></td>
+ <td>Process the items that have been published</td>
+ </tr>
</ul>
{% endblock %}
diff --git a/lib/srtgui/templates/published-select-toastertable.html b/lib/srtgui/templates/published-select-toastertable.html
new file mode 100644
index 00000000..df89d142
--- /dev/null
+++ b/lib/srtgui/templates/published-select-toastertable.html
@@ -0,0 +1,247 @@
+{% extends 'base.html' %}
+{% load static %}
+
+
+{% block extraheadcontent %}
+ <link rel="stylesheet" href="{% static 'css/jquery-ui.min.css' %}" type='text/css'>
+ <link rel="stylesheet" href="{% static 'css/jquery-ui.structure.min.css' %}" type='text/css'>
+ <link rel="stylesheet" href="{% static 'css/jquery-ui.theme.min.css' %}" type='text/css'>
+ <script src="{% static 'js/jquery-ui.min.js' %}">
+ </script>
+ {% if access.is_creator %}{% else %}<meta http-equiv="refresh" content="0; url=/" />{% endif %}
+
+ <style>
+ /* Style the execution buttons */
+ button.execute { height:50px;width:210px;background-color:#4CAF50;text-align:center; border:2px #f69c55;border-radius: 12px; }
+
+ button:disabled {
+ cursor: not-allowed;
+ }
+
+ /* Create two equal columns that floats next to each other */
+ .column {
+ float: left;
+ width: 350px;
+ padding: 10px;
+ }
+
+ /* Clear floats after the columns */
+ .row:after {
+ content: "";
+ display: table;
+ clear: both;
+ }
+ </style>
+
+{% endblock %}
+
+{% block title %} Publish Reqested CVE's - SRTool {% endblock %}
+
+{% block pagecontent %}
+
+ <div class="row">
+ <!-- Breadcrumbs -->
+ <div class="col-md-12">
+ <ul class="breadcrumb" id="breadcrumb">
+ <li><a href="{% url 'landing' %}">Home</a></li><span class="divider">&rarr;</span>
+ <li><a href="{% url 'manage' %}">Management</a></li><span class="divider">&rarr;</span>
+ <li><a href="{% url 'publish' %}">Publish</a></li><span class="divider">&rarr;</span>
+ <li>Publish Requested Update CVE's</li>
+ </ul>
+ </div>
+ </div>
+
+ <div id="change-publish-state" > <!--class="form-inline" -->
+ <b><big>Actions: </big></b>
+ <button id="select-these" class="btn btn-default" type="button">Select these</button>
+ <button id="unselect-these" class="btn btn-default" type="button">Un-select these</button>
+ <button id="select-publish" class="btn btn-default" type="button">Update ...</button>
+ <!--<button id="collect-publish" class="btn btn-default" type="button">Collect Publishable CVEs</button> -->
+ </div>
+
+ <div id="details-publish" style="display:none;">
+ <p><p>
+ <button class="execute" id="submit-publish"> Update Publish CVE State </button>
+ <p><b><big>New Publish State: </big></b>
+ <select name="Publish" id="select-publish-state">
+ <option value="0" >Unpublished</option>
+ <option value="1" >Not to be Published</option>
+ <option value="2" selected>Published</option>
+ <option value="3" >Publish Request (New)</option>
+ <option value="4" >Publish Request (Update)</option>
+ <option value="5" >Publish Submitted</option>
+ </select>
+ </div>
+
+ <div class="row">
+ <div class="col-md-12">
+ <div class="page-header">
+ <h1 class="top-air" data-role="page-title"></h1>
+ </div>
+
+ {% url '' as xhr_table_url %}
+ {% include 'toastertable.html' %}
+ </div>
+ </div>
+
+ <!-- Javascript support -->
+ <script>
+
+ //# sourceURL=somename.js
+
+ // global variables
+ var selected_publish=false;
+ var cve_total=0;
+
+ $(document).ready(function() {
+
+ function onCommitAjaxSuccess(data, textstatus) {
+ if (window.console && window.console.log) {
+ console.log("XHR returned:", data, "(" + textstatus + ")");
+ } else {
+ alert("NO CONSOLE:\n");
+ return;
+ }
+ if (data.error != "ok") {
+ alert("error on request:\n" + data.error);
+ return;
+ }
+ // reload the page with the updated tables
+ location.reload(true);
+ }
+
+ function onCommitAjaxError(jqXHR, textstatus, error) {
+ console.log("ERROR:"+error+"|"+textstatus);
+ alert("XHR errored1:\n" + error + "\n(" + textstatus + ")");
+ }
+
+ /* ensure cookie exists {% csrf_token %} */
+ function postCommitAjaxRequest(reqdata) {
+ var ajax = $.ajax({
+ type:"POST",
+ data: reqdata,
+ url:"{% url 'xhr_cve_publish_commit' %}",
+ headers: { 'X-CSRFToken': $.cookie("csrftoken")},
+ success: onCommitAjaxSuccess,
+ error: onCommitAjaxError,
+ })
+ }
+
+ function update_publish_status() {
+ var cve_count = 0;
+ var cve_checked_count = 0;
+ $('#updatepublishedtable input').each(function(){
+ cve_count = cve_count + 1;
+ if ($(this).is(':checked')) {
+ cve_checked_count = cve_checked_count + 1;
+ }
+ });
+ if (cve_total > cve_count) {
+ document.getElementById("select-these").innerText = "Select "+(cve_count-cve_checked_count)+" unchecked ("+(cve_total-cve_count)+" offpage)";
+ } else {
+ document.getElementById("select-these").innerText = "Select "+(cve_count-cve_checked_count)+" unchecked";
+ }
+ document.getElementById("unselect-these").innerText = "Un-select "+cve_checked_count+" checked";
+ if (0 == cve_checked_count) {
+ //$("#submit-publish").attr("disabled","disabled");
+ document.getElementById("submit-publish").disabled = true;
+ } else {
+ //$("#submit-publish").removeAttr("disabled");
+ document.getElementById("submit-publish").disabled = false;
+ }
+ }
+
+ $('#select-these').click(function(){
+ $('#updatepublishedtable input').each(function(){
+ $(this).prop('checked', true);
+ });
+ update_publish_status();
+ });
+
+ $('#unselect-these').click(function(){
+ $('#updatepublishedtable input').each(function(){
+ $(this).prop('checked', false);
+ });
+ update_publish_status();
+ });
+
+ // Open Publish Action
+ $('#select-publish').click(function(){
+ if (selected_publish) {
+ selected_publish=false;
+ $("#select-these").removeAttr("disabled");
+ $("#unselect-these").removeAttr("disabled");
+ $("#details-publish").slideUp();
+ } else {
+ selected_publish=true;
+ $("#select-these").attr("disabled","disabled");
+ $("#unselect-these").attr("disabled","disabled");
+ update_publish_status();
+ $("#details-publish").slideDown();
+ }
+ });
+
+ $('#submit-publish').click(function(){
+ var cve_list="";
+ $('#updatepublishedtable input').each(function(){
+ if ($(this).is(':checked')) {
+ cve_list +=$(this).prop('name') + ",";
+ }
+ });
+ if ("" == cve_list) {
+ alert("No CVE's were selected");
+ return;
+ }
+ publish_state=$('#select-publish-state').val();
+ postCommitAjaxRequest({
+ "publish_state" : publish_state,
+ "cve_list" : cve_list,
+ });
+
+// $.post("/srtgui/export/publish_cve", {parent_page:'publish_cve',cve_list:cve_list,report_type:$('#report_type').val(),report_format:$('#report_format').val(),csrfmiddlewaretoken:'{{ csrf_token }}'}, function(result){
+// alert(result);
+// });
+
+ });
+
+ // When change in CVE selections, update labels and enables
+ $(document).on("change", "#updatepublishedtable :checkbox", function() {
+ update_publish_status();
+ });
+
+
+ // Standard Toaster Table enablement
+
+ var tableElt = $("#{{table_name}}");
+ var titleElt = $("[data-role='page-title']");
+
+ tableElt.on("table-done", function (e, total, tableParams) {
+ var title = "Publish Requested CVE's";
+
+ if (tableParams.search || tableParams.filter) {
+ if (total === 0) {
+ title = "No CVE's found";
+ }
+ else if (total > 0) {
+ title = total + " CVE" + (total > 1 ? "'s" : '') + " found";
+ }
+ }
+
+ titleElt.text(title);
+ cve_total = total;
+ update_publish_status();
+
+ /* Set the report link */
+ var record_list=""
+ $(".name > a").each(function(){
+ var this_id=$(this).prop('id');
+ if (this_id.startsWith("dataid_")) {
+ record_list += this_id.replace(/dataid_/,"") + ",";
+ }
+ });
+ $('#report_link').attr('href',"{% url 'report' request.resolver_match.url_name %}?record_list="+record_list);
+
+ });
+ });
+ </script>
+{% endblock %}
diff --git a/lib/srtgui/templates/report.html b/lib/srtgui/templates/report.html
new file mode 100644
index 00000000..d4d27f76
--- /dev/null
+++ b/lib/srtgui/templates/report.html
@@ -0,0 +1,73 @@
+{% extends "base.html" %}
+
+{% load static %}
+{% load projecttags %}
+{% load humanize %}
+
+{% block title %} Report/Export {% endblock %}
+
+{% block pagecontent %}
+ <div class="row">
+ <div class="col-md-7" style="padding-left: 50px;">
+ <h1>Report/Export: {{title}}</h1>
+ </div>
+ </div>
+
+ <form method="POST">{% csrf_token %}
+ <input type="hidden" name="parent_page" value="{{parent_page}}">
+ <input type="hidden" name="record_list" value="{{record_list}}">
+
+ {% if report_type_list %}
+ <hr>
+ Report Type:<br>
+ <select name="report_type">
+ {{report_type_list|safe}}
+ </select>
+ {% else %}
+ <hr>
+ Note: There is no report defined for this page.<br>
+ {% endif %}
+
+ {% if report_get_title %}
+ <hr>
+ Title:<br>
+ <input type="text" name="title">
+ <br>
+ {% endif %}
+ <hr>
+
+ {% if report_recordrange_list %}
+ Record Range:<br>
+ {{report_recordrange_list|safe}}
+ <br>
+ {% endif %}
+ {% if report_columnrange_list %}
+ Column Range:<br>
+ {{report_columnrange_list|safe}}
+ {% endif %}
+ <hr>
+
+ {% if report_format_list %}
+ Export Format:<br>
+ {{report_format_list|safe}}
+ <hr>
+ {% endif %}
+
+ {% if report_custom_list %}
+ Page Specific Settings:<br>
+ {{report_custom_list|safe}}
+ <hr>
+ {% endif %}
+
+ {% if report_enable_submit %}
+ <input type="submit" id="submit-report-button" class="btn btn-primary btn-lg" value="Generate and Download Report"/>
+ <a class="btn btn-info btn-lg" id="report-done" href="{% url 'landing' %}">Done</a>
+ {% else %}
+ <a class="btn btn-info btn-lg" id="report-cancel" href="{% url 'landing' %}">Cancel</a>
+ {% endif %}
+
+ </form>
+
+<br>
+{% endblock %}
+
diff --git a/lib/srtgui/templates/sources-toastertable.html b/lib/srtgui/templates/sources-toastertable.html
new file mode 100644
index 00000000..1721e3b0
--- /dev/null
+++ b/lib/srtgui/templates/sources-toastertable.html
@@ -0,0 +1,72 @@
+{% extends 'base.html' %}
+{% load static %}
+
+{% block extraheadcontent %}
+ <link rel="stylesheet" href="{% static 'css/jquery-ui.min.css' %}" type='text/css'>
+ <link rel="stylesheet" href="{% static 'css/jquery-ui.structure.min.css' %}" type='text/css'>
+ <link rel="stylesheet" href="{% static 'css/jquery-ui.theme.min.css' %}" type='text/css'>
+ <script src="{% static 'js/jquery-ui.min.js' %}">
+ </script>
+{% endblock %}
+
+{% block title %} Data Sources - SRTool {% endblock %}
+
+{% block pagecontent %}
+
+<div class="row">
+ <!-- Breadcrumbs -->
+ <div class="col-md-12">
+ <ul class="breadcrumb" id="breadcrumb">
+ <li><a href="{% url 'landing' %}">Home</a></li><span class="divider">&rarr;</span>
+ <li><a href="{% url 'manage' %}">Management</a></li><span class="divider">&rarr;</span>
+ <li>Data Sources</li>
+ </ul>
+ </div>
+</div>
+
+
+<div class="row">
+ <div class="col-md-12">
+ <div class="page-header">
+ <h1 class="top-air" data-role="page-title"></h1>
+ </div>
+
+ {# xhr_table_url is just the current url so leave it blank #}
+ {% url '' as xhr_table_url %}
+ {% include 'toastertable.html' %}
+ </div>
+</div>
+
+ <script>
+ $(document).ready(function () {
+ var tableElt = $("#{{table_name}}");
+ var titleElt = $("[data-role='page-title']");
+
+ tableElt.on("table-done", function (e, total, tableParams) {
+ var title = "Data Sources";
+
+ if (tableParams.search || tableParams.filter) {
+ if (total === 0) {
+ title = "No Data Sources found";
+ }
+ else if (total > 0) {
+ title = total + " Data Source" + (total > 1 ? 's' : '') + " found";
+ }
+ }
+
+ titleElt.text(title);
+
+ /* Set the report link */
+ var record_list=""
+ $(".data > span").each(function(){
+ var this_id=$(this).prop('id');
+ if (this_id.startsWith("dataid_")) {
+ record_list +=this_id.replace(/dataid_/,"") + ",";
+ }
+ });
+ $('#report_link').attr('href',"{% url 'report' request.resolver_match.url_name %}?record_list="+record_list);
+
+ });
+ });
+ </script>
+{% endblock %}
diff --git a/lib/srtgui/templates/triage_cves.html b/lib/srtgui/templates/triage_cves.html
index 7325dce8..1df170ab 100644
--- a/lib/srtgui/templates/triage_cves.html
+++ b/lib/srtgui/templates/triage_cves.html
@@ -22,12 +22,18 @@
</ul>
<a class="btn btn-info btn-lg" href="{% url 'keywords' %}">Manage Keyword Filters</a></td>
-<h2> Guided Bulk Triage </h2>
+<h2> New CVEs Triage </h2>
<ul>
- <li>Select a range of similar CVE's via scoring, string matches, and filters</li>
+ <li>Select a range of similar new incoming CVE's via scoring, string matches, and filters</li>
<li>You can then (a) review/sample them, (b) select all or some, and then (c) click a button to bulk assign them</li>
</ul>
<a class="btn btn-info btn-lg" href="{% url 'select-cves' %}">Incoming CVE Triage Page</a>
+
+<h2> Updated CVEs Triage</h2>
+<ul>
+ <li>Select a range of similar updated CVE's via scoring, string matches, and filters</li>
+ <li>You can then (a) review/sample them, (b) select all or some, and then (c) click a button to bulk assign them</li>
+</ul>
<a class="btn btn-info btn-lg" href="{% url 'tbd' %}">Updated CVE Triage Page</a>
<h2> Guided Manual Triage </h2>
diff --git a/lib/srtgui/templates/users.html b/lib/srtgui/templates/users.html
index f934e552..3837b1fb 100644
--- a/lib/srtgui/templates/users.html
+++ b/lib/srtgui/templates/users.html
@@ -42,7 +42,7 @@
</div>
</div>
-<div class="row">
+<div class="row" style="padding-left: 25px;">
<h3>User List
<a class="btn btn-default navbar-btn " id="new-investigation-attachement" href="{% url 'login' %}">Add user</a>
</h3>
@@ -59,17 +59,17 @@
</thead>
{% if object.all %}
- {% for p in object.all %}
+ {% for user in object.all %}
<tr>
- <td>{{ p.name }} </td>
- <td>{{ p.email }} </td>
- <td>{{ p.role }} </td>
- <td>{{ p.get_access_text }} </td>
+ <td>{{ user.name }} </td>
+ <td>{{ user.email }} </td>
+ <td>{{ user.role }} </td>
+ <td>{{ user.get_access_text }} </td>
<td>
- {% if p.name != "Guest" %}
- <span id="user_'+{{p.id}}+'" class="js-user-name"></span>
- <span class="glyphicon glyphicon-edit js-icon-pencil-config_var" id="user_'+{{p.id}}+'" x-data="'+{{p.id}}+'"></span>
- <span class="glyphicon glyphicon-trash js-icon-trash-config_var" id="user_'+{{p.id}}+'" x-data="'+{{p.id}}+'"></span>
+ {% if not user.builtin %}
+ <span id="user_'+{{user.id}}+'" class="js-user-name"></span>
+ <span class="glyphicon glyphicon-edit js-icon-pencil-config_var" id="user_'+{{user.id}}+'" x-data="'+{{user.id}}+'"></span>
+ <span class="glyphicon glyphicon-trash js-icon-trash-config_var" id="user_'+{{user.id}}+'" x-data="'+{{user.id}}+'"></span>
{% endif %}
</td>
diff --git a/lib/srtgui/templates/vulnerabilities-toastertable.html b/lib/srtgui/templates/vulnerabilities-toastertable.html
index 27d8bea4..5a5bae50 100644
--- a/lib/srtgui/templates/vulnerabilities-toastertable.html
+++ b/lib/srtgui/templates/vulnerabilities-toastertable.html
@@ -30,7 +30,8 @@
<h1 class="top-air" data-role="page-title"></h1>
</div>
- {% url 'cves' as xhr_table_url %}
+ {# xhr_table_url is just the current url so leave it blank #}
+ {% url '' as xhr_table_url %}
{% include 'toastertable.html' %}
</div>
</div>
@@ -53,7 +54,21 @@
}
titleElt.text(title);
+
+ /* Set the report link */
+ var record_list=""
+ $(".name > a").each(function(){
+ /* if ('id' in $(this)) { */
+ var this_id=$(this).prop('id');
+ if (this_id.startsWith("dataid_")) {
+ record_list +=this_id.replace(/dataid_/,"") + ",";
+ }
+ /* } */
+ });
+ $('#report_link').attr('href',"{% url 'report' request.resolver_match.url_name %}?record_list="+record_list);
+
});
});
</script>
{% endblock %}
+
diff --git a/lib/srtgui/templates/vulnerability.html b/lib/srtgui/templates/vulnerability.html
index b238f7fc..ec0df78b 100644
--- a/lib/srtgui/templates/vulnerability.html
+++ b/lib/srtgui/templates/vulnerability.html
@@ -1,9 +1,32 @@
{% extends "base.html" %}
-
{% load projecttags %}
-{% block title %} {{object.name}} - SRTool {% endblock %}
+{% block extraheadcontent %}
+ <style>
+ /* Style the execution buttons */
+ /*button.execute { height:50px;width:210px;background-color:#4CAF50;text-align:center; border:2px #f69c55;border-radius: 12px; }*/
+
+ button:disabled {
+ cursor: not-allowed;
+ }
+
+ /* Create two equal columns that floats next to each other */
+ .column {
+ float: left;
+ width: 350px;
+ padding: 10px;
+ }
+
+ /* Clear floats after the columns */
+ .row:after {
+ content: "";
+ display: table;
+ clear: both;
+ }
+ </style>
+{% endblock %}
+{% block title %} {{object.name}} - SRTool {% endblock %}
{% block pagecontent %}
<div class="row">
@@ -56,9 +79,10 @@
</div>
<div class="col-md-5">
<div class="well">
- <h2>Quick Info</h2>
-
-
+ <h2>Quick Info
+ {% if access.is_creator %}
+ <button id="select-quickedit" class="btn btn-default" type="button">Edit ...</button>
+ {% endif %}</h2>
<dl class="dl-horizontal">
<dt>CVE Dictionary Entry:</dt>
<dd>
@@ -98,18 +122,104 @@
<dd>
{{object.get_severity_text}}
</dd>
+ <dt>Note:</dt>
+ <dd>
+ {{object.comments}}
+ </dd>
+ <dt>Private Note:</dt>
+ <dd>
+ {{object.comments_private}}
+ </dd>
+
+ <div id="details-quickedit" style="display:none;">
+ <p><p>
+ <button class="execute" id="submit-quickedit"> Submit Changes </button>
+ <p><input type="text" placeholder="Edit Note" id="text-note" size="40" value="{{object.comments}}"></p>
+ <p><input type="text" placeholder="Edit Private Note" id="text-private-note" size="40" value="{{object.comments_private}}"></p>
+ <p><p>
+ <div class="row">
+ <div class="column">
+ <p><b><label id="set_status">Set Status:</label></b>
+ <div id="status-list" class="scrolling" style="width: 300px;">
+ <div class="checkbox"> <label>
+ <input type="radio" name="status" value="2" type="checkbox" {%if 2 == object.status %}checked="checked"{% endif %}> Vulnerable
+ </label><p></div>
+ <div class="checkbox"> <label>
+ <input type="radio" name="status" value="1" type="checkbox" {%if 1 == object.status %}checked="checked"{% endif %}> Not Vulnerable
+ </label><p></div>
+ <div class="checkbox"> <label>
+ <input type="radio" name="status" value="0" type="checkbox" {%if 0 == object.status %}checked="checked"{% endif %}> Investiage
+ </label><p></div>
+ </div>
+ </div>
+ <div class="column">
+ <p><b><label id="set_outcome">Set Outcome:</label></b>
+ <div id="outcome-list" class="scrolling" style="width: 300px;">
+ <div class="checkbox"> <label>
+ <input type="radio" name="outcome" value="3" type="checkbox" {%if 3 == object.outcome %}checked="checked"{% endif %}> Not Fix
+ </label><p></div>
+ <div class="checkbox"> <label>
+ <input type="radio" name="outcome" value="2" type="checkbox" {%if 2 == object.outcome %}checked="checked"{% endif %}> Closed (Not Vulnerable)
+ </label><p></div>
+ <div class="checkbox"> <label>
+ <input type="radio" name="outcome" value="1" type="checkbox" {%if 1 == object.outcome %}checked="checked"{% endif %}> Closed (Fixed)
+ </label><p></div>
+ <div class="checkbox"> <label>
+ <input type="radio" name="outcome" value="0" type="checkbox" {%if 0 == object.outcome %}checked="checked"{% endif %}> Open
+ </label><p></div>
+ </div>
+ </div>
+ <div class="column">
+ <p><b><label id="set_severity">Set Severity:</label></b>
+ <div id="severity-list" class="scrolling" style="width: 300px;">
+ <div class="checkbox"> <label>
+ <input type="radio" name="severity" value="4" type="checkbox" {%if 4 == object.severity %}checked="checked"{% endif %}> High
+ </label><p></div>
+ <div class="checkbox"> <label>
+ <input type="radio" name="severity" value="3" type="checkbox" {%if 3 == object.severity %}checked="checked"{% endif %}> Medium
+ </label><p></div>
+ <div class="checkbox"> <label>
+ <input type="radio" name="severity" value="2" type="checkbox" {%if 2 == object.severity %}checked="checked"{% endif %}> Low
+ </label><p></div>
+ <div class="checkbox"> <label>
+ <input type="radio" name="severity" value="1" type="checkbox" {%if 0 == object.severity %}checked="checked"{% endif %}> Minor
+ </label><p></div>
+ <div class="checkbox"> <label>
+ <input type="radio" name="severity" value="0" type="checkbox" {%if 0 == object.severity %}checked="checked"{% endif %}> Undefined
+ </label><p></div>
+ </div>
+ </div>
+ </div>
+ </div>
</dl>
</div>
</div>
</div>
-<div class="row">
+<div class="row" style="padding-left: 25px;">
<h3>Affected Products
{% if access.is_creator %}
- <a class="btn btn-default navbar-btn " id="new-investigation-attachement" href="{% url 'login' %}">Add product</a>
+ <button id="select-addaffectedproduct" class="btn btn-default" type="button">Add product ...</button>
{% endif %}
</h3>
+ <div id="details-addaffectedproduct" style="padding-left: 50px; display:none;">
+ <p><p>
+ <button class="execute" id="submit-addaffectedproduct"> Submit </button>
+ <div class="row">
+ <div id="all-affectedproducts" class="scrolling" style="width: 300px;">
+ {% for product in products %}
+ <div class="checkbox">
+ <label>
+ <input class="checkbox-products" name="{{product.pk}}" type="checkbox">{{product.long_name}}
+ </label>
+ <p>
+ </div>
+ {% endfor %}
+ </div>
+ </div>
+ </div>
+
<table class="table table-striped table-condensed" data-testid="vuln-hyperlinks-table">
<thead>
<tr>
@@ -128,19 +238,20 @@
{% if object.get_affected_list.all %}
{% for p in object.get_affected_list.all %}
<tr>
- <td>{{ p.product.name }} {{ p.product.version }} {{ p.product.profile }} </td>
+ {% if p.product != '%s' %} <!-- hack for null records -->
+ <td><a href="{% url 'product' p.product.id %}">{{ p.product.long_name }}<a></td>
{% if p.investigation %}
<td><a href="{% url 'investigation' p.investigation.id %}">{{ p.investigation.name }}<a></td>
<td>{{ p.investigation.get_status_text }}</td>
<td>{{ p.investigation.get_outcome_text }}</td>
<td>
{% for ij in p.investigation.investigation_to_defect.all %}
- {% if not forloop.first %}| {% endif %}<a href="http://defect.wrs.com/browse/{{ij.defect.name}}" target="_blank">{{ij.defect.name}} </a>
+ {% if not forloop.first %}| {% endif %}<a href="{% url 'defect' ij.defect.id %}">{{ij.defect.name}} </a>
{% endfor %}
</td>
<td>
{% for ij in p.investigation.investigation_to_defect.all %}
- {% if not forloop.first %}| {% endif %}<a href="http://defect.wrs.com/browse/{{ij.defect.name}}" target="_blank">{{ij.defect.release_version}} </a>
+ {% if not forloop.first %}| {% endif %}<a href="{% url 'defect' ij.defect.id %}">{{ij.defect.release_version}} </a>
{% endfor %}
</td>
{% else %}
@@ -153,10 +264,10 @@
{% if access.is_creator %}
<td>
<span id="affected_entry_'+{{p.id}}+'" class="js-config-var-name"></span>
- <span class="glyphicon glyphicon-edit js-icon-pencil-config_var" id="affected_edit_'+{{p.id}}+'" x-data="'+{{p.id}}+'"></span>
- <span class="glyphicon glyphicon-trash js-icon-trash-config_var" id="affected_trash_'+{{p.id}}+'" x-data="'+{{p.id}}+'"></span>
+ <span class="glyphicon glyphicon-trash trash-affected" id="affected_trash_'+{{p.id}}+'" x-data="{{p.id}}"></span>
</td>
{% endif %}
+ {% endif %}
</tr>
{% endfor %}
{% else %}
@@ -168,13 +279,30 @@
</div>
-<div class="row">
+<div class="row" style="padding-left: 25px;">
<h3>Related Products
{% if access.is_creator %}
- <a class="btn btn-default navbar-btn " id="new-investigation-attachement" href="{% url 'login' %}">Add product</a>
+ <button id="select-addrelatedproduct" class="btn btn-default" type="button">Add product ...</button>
{% endif %}
</h3>
+ <div id="details-addrelatedproduct" style="padding-left: 50px; display:none;">
+ <p><p>
+ <button class="execute" id="submit-addrelatedproduct"> Submit </button>
+ <div class="row">
+ <div id="all-relatedproducts" class="scrolling" style="width: 300px;">
+ {% for product in products %}
+ <div class="checkbox">
+ <label>
+ <input class="checkbox-products" name="{{product.pk}}" type="checkbox">{{product.long_name}}
+ </label>
+ <p>
+ </div>
+ {% endfor %}
+ </div>
+ </div>
+ </div>
+
<table class="table table-striped table-condensed" data-testid="vuln-hyperlinks-table">
<thead>
<tr>
@@ -188,15 +316,16 @@
{% if object.get_related_list.all %}
{% for p in object.get_related_list.all %}
<tr>
- <td>{{ p.product.name }} {{ p.product.version }} {{ p.product.profile }} </td>
+ {% if p.product != '%s' %} <!-- hack for null records -->
+ <td><a href="{ % url 'product' p.product.id % }">{{p.product.long_name}}</a></td>
<td>Not vulnerable</td>
{% if access.is_creator %}
<td>
<span id="related_var_entry_'+{{p.id}}+'" class="js-config-var-name"></span>
- <span class="glyphicon glyphicon-edit js-icon-pencil-config_var" id="affected_edit_'+{{p.id}}+'" x-data="'+{{p.id}}+'"></span>
- <span class="glyphicon glyphicon-trash js-icon-trash-config_var" id="related_trash_'+{{p.id}}+'" x-data="'+{{p.id}}+'"></span>
+ <span class="glyphicon glyphicon-trash trash-related" id="related_trash_'+{{p.id}}+'" x-data="{{p.id}}"></span>
</td>
{% endif %}
+ {% endif %}
</tr>
{% endfor %}
{% else %}
@@ -209,13 +338,17 @@
</div>
-<div class="row">
+<div class="row" style="padding-left: 25px;">
<h3>Comments
{% if access.is_creator %}
- <a class="btn btn-default navbar-btn " id="new-investigation-comment" href="{% url 'login' %}">Add comment</a>
+ <button id="select-newcomment" class="btn btn-default" type="button">Add comment ...</button>
{% endif %}
</h3>
+<div id="input-newcomment" style="padding-left: 50px; display:none;">
+ <p><input type="text" id="text-newcomment" size="40"> <button class="execute" id="submit-newcomment"> Submit </button></p>
+</div>
+
<table class="table table-striped table-condensed" data-testid="vuln-hyperlinks-table">
<thead>
<tr>
@@ -234,11 +367,10 @@
<td>{{ c.comment }}</td>
<td>{{ c.date }}</td>
<td>{{ c.author }}</td>
- {% if access.is_creator %}
+ {% if access.is_creator or c.author == access.current_user_name %}
<td>
<span id="config_var_entry_'+configvars_sorted[i][2]+'" class="js-config-var-name"></span>
- <span class="glyphicon glyphicon-edit js-icon-pencil-config_var" id="comment_edit_'+{{c.id}}+'" x-data="'+{{c.id}}+'"></span>
- <span class="glyphicon glyphicon-trash js-icon-trash-config_var" id="comment_trash_'+{{c.id}}+'" x-data="'+{{c.id}}+'"></span>
+ <span class="glyphicon glyphicon-trash trash-comment" id="comment_trash_'+{{c.id}}+'" x-data="{{c.id}}"></span>
</td>
{% endif %}
</tr>
@@ -252,13 +384,25 @@
</div>
-<div class="row">
+<div class="row" style="padding-left: 25px;">
<h3>Attachments
{% if access.is_creator %}
- <a class="btn btn-default navbar-btn " id="new-investigation-attachement" href="{% url 'login' %}">Add attachment</a>
+ <a class="btn btn-default navbar-btn " id="select-addattachment">Add attachment ... </a>
{% endif %}
</h3>
+ <div id="details-addattachment" style="padding-left: 50px; display:none;">
+ <p><p>
+ <div class="row">
+ <form id="uploadbanner" enctype="multipart/form-data" method="post">{% csrf_token %}
+ <input id="fileDescription" name="fileDescription" type="text" placeholder="Enter Description" />
+ <input id="fileUpload" name="fileUpload" type="file" />
+ <input type="hidden" id="action" name="action" value="upload">
+ <input type="submit" value="submit file" id="submit-addattachment" />
+ </form>
+ </div>
+ </div>
+
<table class="table table-striped table-condensed" data-testid="vuln-hyperlinks-table">
<thead>
<tr>
@@ -275,17 +419,20 @@
{% for u in object.vulnerability_uploads.all %}
<tr>
<td>{{ u.description }}</td>
- <td>{{ u.path }}</td>
+ <td>{{ u.path|basename }}</td>
<td>{{ u.size }}</td>
<td>{{ u.date }}</td>
<td>{{ u.author }}</td>
<td>
<span id="attachment_entry_'+{{u.id}}+'" class="js-config-var-name"></span>
- <span class="glyphicon glyphicon-download-alt get-help" title="Download document"></span>
- {% if access.is_creator %}
- <span class="glyphicon glyphicon-edit js-icon-pencil-config_var" id="affected_edit_'+{{u.id}}+'" x-data="'+{{u.id}}+'"></span>
- <span class="glyphicon glyphicon-trash js-icon-trash-config_var" id="attachment_trash_'+{{u.id}}+'" x-data="'+{{u.id}}+'"></span>
- {% endif %}
+ <form id="downloadbanner" enctype="multipart/form-data" method="post" >{% csrf_token %}
+ <input type="hidden" id="action" name="action" value="download">
+ <input type="hidden" id="record_id" name="record_id" value={{u.id}}>
+ <span class="glyphicon glyphicon-download-alt submit-downloadattachment" id="attachment_download_'+{{u.id}}+'" x-data="{{u.id}}"></span>
+ {% if access.is_creator %}
+ <span class="glyphicon glyphicon-trash trash-attachment" id="attachment_trash_'+{{u.id}}+'" x-data="{{u.id}}"></span>
+ {% endif %}
+ </form>
</td>
</tr>
{% endfor %}
@@ -295,18 +442,35 @@
</tr>
{% endif %}
</table>
-
</div>
<br/>
-<div class="row">
+<div class="row" style="padding-left: 25px;">
<h3>Change Notifications
{% if access.is_creator %}
- <a class="btn btn-default navbar-btn " id="new-investigation-notify" href="{% url 'login' %}">Add user notification</a>
+ <button id="select-addusernotify" class="btn btn-default" type="button">Add user notification ...</button>
{% endif %}
</h3>
+ <div id="details-addusernotify" style="padding-left: 50px; display:none;">
+ <p><p>
+ <button class="execute" id="submit-addusernotify"> Submit </button>
+ <div class="row">
+ <p>
+ <div id="all-users" class="scrolling" style="width: 300px;">
+ {% for user in users %}
+ <div class="checkbox">
+ <label>
+ <input class="checkbox-users" name="{{user.pk}}" type="checkbox">{{user.name}}
+ </label>
+ <p>
+ </div>
+ {% endfor %}
+ </div>
+ </div>
+ </div>
+
<table class="table table-striped table-condensed" data-testid="vuln-hyperlinks-table">
<thead>
<tr>
@@ -318,16 +482,15 @@
</tr>
</thead>
- {% if object.vulnerability_users.all %}
- {% for u in object.vulnerability_users.all %}
+ {% if object.vulnerability_notification.all %}
+ {% for u in object.vulnerability_notification.all %}
<tr>
<td>{{ u.user.name }}</td>
<td>{{ u.user.email }}</td>
- {% if access.is_creator %}
+ {% if access.is_creator or u.user.name == access.current_user_name %}
<td>
<span id="attachment_entry_'+{{u.id}}+'" class="js-config-var-name"></span>
- <span class="glyphicon glyphicon-edit js-icon-pencil-config_var" id="affected_edit_'+{{u.id}}+'" x-data="'+{{u.id}}+'"></span>
- <span class="glyphicon glyphicon-trash js-icon-trash-config_var" id="attachment_trash_'+{{u.id}}+'" x-data="'+{{u.id}}+'"></span>
+ <span class="glyphicon glyphicon-trash trash-usernotification" id="attachment_trash_'+{{u.id}}+'" x-data="{{u.id}}"></span>
</td>
{% endif %}
</tr>
@@ -341,15 +504,34 @@
</div>
-{% if access.is_creator %}
+{% if not object.public %}
+ {% if access.is_creator %}
- <div class="row">
+ <div class="row" style="padding-left: 25px;">
<h3>User Access
{% if access.is_creator %}
- <a class="btn btn-default navbar-btn " id="new-investigation-access" href="{% url 'login' %}">Add user access</a>
+ <button id="select-adduseraccess" class="btn btn-default" type="button">Add user access ...</button>
{% endif %}
</h3>
+ <div id="details-adduseraccess" style="padding-left: 50px; display:none;">
+ <p><p>
+ <button class="execute" id="submit-adduseraccess"> Submit </button>
+ <div class="row">
+ <p>
+ <div id="all-users" class="scrolling" style="width: 300px;">
+ {% for user in users %}
+ <div class="checkbox">
+ <label>
+ <input class="checkbox-users" name="{{user.pk}}" type="checkbox">{{user.name}}
+ </label>
+ <p>
+ </div>
+ {% endfor %}
+ </div>
+ </div>
+ </div>
+
<table class="table table-striped table-condensed" data-testid="vuln-hyperlinks-table">
<thead>
<tr>
@@ -372,8 +554,7 @@
<td>{{ u.user.name }}</td>
<td>
<span id="attachment_entry_'+{{u.id}}+'" class="js-config-var-name"></span>
- <span class="glyphicon glyphicon-edit js-icon-pencil-config_var" id="affected_edit_'+{{u.id}}+'" x-data="'+{{u.id}}+'"></span>
- <span class="glyphicon glyphicon-trash js-icon-trash-config_var" id="attachment_trash_'+{{u.id}}+'" x-data="'+{{u.id}}+'"></span>
+ <span class="glyphicon glyphicon-trash trash-useraccess" id="attachment_trash_'+{{u.id}}+'" x-data="{{u.id}}"></span>
</td>
</tr>
{% endfor %}
@@ -387,9 +568,10 @@
</table>
</div>
+ {% endif %}
{% endif %}
-<div class="row">
+<div class="row" style="padding-left: 25px;">
<h3>History</h3>
<table class="table table-striped table-condensed" data-testid="vuln-hyperlinks-table">
<thead>
@@ -415,5 +597,339 @@
</table>
</div>
+<!-- Javascript support -->
+<script>
+ var selected_addrelatedproduct=false;
+ var selected_addaffectedproduct=false;
+ var selected_newcomment=false;
+ var selected_addusernotify=false;
+ var selected_adduseraccess=false;
+ var selected_quickedit=false;
+ var selected_addattachment=false;
+
+ window.onload = function() {
+ $("input[name=status][value=" + {{ object.status }} + "]").prop('checked', true);
+ $("input[name=outcome][value=" + {{ object.outcome }} + "]").prop('checked', true);
+ $("input[name=severity][value=" + {{ object.severity }} + "]").prop('checked', true);
+ }
+
+ $(document).ready(function() {
+ function onCommitAjaxSuccess(data, textstatus) {
+ if (window.console && window.console.log) {
+ console.log("XHR returned:", data, "(" + textstatus + ")");
+ } else {
+ alert("NO CONSOLE:\n");
+ return;
+ }
+ if (data.error != "ok") {
+ alert("error on request:\n" + data.error);
+ return;
+ }
+ // reload the page with the updated tables
+ location.reload(true);
+ }
+
+ function onCommitAjaxError(jqXHR, textstatus, error) {
+ console.log("ERROR:"+error+"|"+textstatus);
+ alert("XHR errored1:\n" + error + "\n(" + textstatus + ")");
+ }
+
+ /* ensure cookie exists {% csrf_token %} */
+ function postCommitAjaxRequest(reqdata) {
+ reqdata["vulnerability_id"] = {{ object.id }}
+ var ajax = $.ajax({
+ type:"POST",
+ data: reqdata,
+ url:"{% url 'xhr_vulnerability_commit' %}",
+ headers: { 'X-CSRFToken': $.cookie("csrftoken")},
+ success: onCommitAjaxSuccess,
+ error: onCommitAjaxError,
+ })
+ }
+
+ $('#select-these').click(function(){
+ $(':checkbox').each(function(){
+ $(this).prop('checked', true);
+ });
+ });
+
+ $('#unselect-these').click(function(){
+ $(':checkbox').each(function(){
+ $(this).prop('checked', false);
+ });
+ });
+
+ $('#select-quickedit').click(function(){
+ if (selected_quickedit) {
+ selected_quickedit=false;
+ $("#select-these").removeAttr("disabled");
+ $("#unselect-these").removeAttr("disabled");
+ $("#details-quickedit").slideUp();
+ } else {
+ selected_quickedit=true;
+ $("#select-these").attr("disabled","disabled");
+ $("#unselect-these").attr("disabled","disabled");
+ $("#details-quickedit").slideDown();
+ }
+ });
+
+ $('#submit-quickedit').click(function(){
+ var note=$('#text-note').val().trim()
+ var private_note=$('#text-private-note').val().trim()
+ var status=0
+ $('#status-list input').each(function(){
+ if ($(this).is(':checked')) {
+ status = $(this).prop('value');
+ }
+ });
+ var outcome=0
+ $('#outcome-list input').each(function(){
+ if ($(this).is(':checked')) {
+ outcome = $(this).prop('value');
+ }
+ });
+ var severity=0
+ $('#severity-list input').each(function(){
+ if ($(this).is(':checked')) {
+ severity = $(this).prop('value');
+ }
+ });
+
+ postCommitAjaxRequest({
+ "action" : 'submit-quickedit',
+ "note" : note,
+ "private_note" : private_note,
+ "status" : status,
+ "outcome" : outcome,
+ "severity" : severity,
+ });
+ });
+
+ $('#select-addrelatedproduct').click(function(){
+ if (selected_addrelatedproduct) {
+ selected_addrelatedproduct=false;
+ $("#select-these").removeAttr("disabled");
+ $("#unselect-these").removeAttr("disabled");
+ $("#details-addrelatedproduct").slideUp();
+ } else {
+ selected_addrelatedproduct=true;
+ $("#select-these").attr("disabled","disabled");
+ $("#unselect-these").attr("disabled","disabled");
+ $("#details-addrelatedproduct").slideDown();
+ }
+ });
+
+ $('#submit-addrelatedproduct').click(function(){
+ var product_list=""
+ $(':checkbox').each(function(){
+ if ($(this).is(':checked')) {
+ product_list += $(this).prop('name') + ",";
+ }
+ });
+ if ("" == product_list) {
+ alert("No products were selected");
+ return;
+ }
+ postCommitAjaxRequest({
+ "action" : 'submit-addrelatedproduct',
+ "products" : product_list,
+ });
+ });
+
+ $('.trash-related').click(function() {
+ var result = confirm("Are you sure?");
+ if (result){
+ postCommitAjaxRequest({
+ "action" : 'submit-trashrelated',
+ "record_id" : $(this).attr('x-data'),
+ });
+ }
+ });
+
+ $('#select-addaffectedproduct').click(function(){
+ if (selected_addaffectedproduct) {
+ selected_addaffectedproduct=false;
+ $("#select-these").removeAttr("disabled");
+ $("#unselect-these").removeAttr("disabled");
+ $("#details-addaffectedproduct").slideUp();
+ } else {
+ selected_addaffectedproduct=true;
+ $("#select-these").attr("disabled","disabled");
+ $("#unselect-these").attr("disabled","disabled");
+ $("#details-addaffectedproduct").slideDown();
+ }
+ });
+
+ $('#submit-addaffectedproduct').click(function(){
+ var product_list=""
+ $(':checkbox').each(function(){
+ if ($(this).is(':checked')) {
+ product_list += $(this).prop('name') + ",";
+ }
+ });
+ if ("" == product_list) {
+ alert("No products were selected");
+ return;
+ }
+ postCommitAjaxRequest({
+ "action" : 'submit-addaffectedproduct',
+ "products" : product_list,
+ });
+ });
+
+ $('.trash-affected').click(function() {
+ var result = confirm("Are you sure?");
+ if (result){
+ postCommitAjaxRequest({
+ "action" : 'submit-trashaffected',
+ "record_id" : $(this).attr('x-data'),
+ });
+ }
+ });
+
+ $('#select-newcomment').click(function(){
+ if (selected_newcomment) {
+ selected_newcomment=false;
+ $("#input-newcomment").slideUp();
+ } else {
+ selected_newcomment=true;
+ $("#input-newcomment").slideDown();
+ }
+ });
+
+ $('#submit-newcomment').click(function(){
+ var comment=$('#text-newcomment').val().trim()
+ if (comment=="") {
+ alert("No comment was written");
+ return;
+ }
+ postCommitAjaxRequest({
+ "action" : 'submit-newcomment',
+ "comment" : comment,
+ })
+ });
+
+ $('.trash-comment').click(function(){
+ var result = confirm("Are you sure?");
+ if (result){
+ postCommitAjaxRequest({
+ "action" : 'submit-trashcomment',
+ "record_id" : $(this).attr('x-data'),
+ });
+ }
+ })
+
+ $('#select-addattachment').click(function() {
+ if (selected_addattachment) {
+ selected_addattachment=false;
+ $("#details-addattachment").slideUp();
+ } else {
+ selected_addattachment=true;
+ $("#details-addattachment").slideDown();
+ }
+ });
+
+ $('.submit-downloadattachment').click(function() {
+ $("#downloadbanner").submit();
+ });
+
+ $('.trash-attachment').click(function() {
+ var result = confirm("Are you sure?");
+ if (result){
+ postCommitAjaxRequest({
+ "action" : 'submit-trashattachment',
+ "record_id" : $(this).attr('x-data'),
+ });
+ }
+ });
+
+ // Open AddUserNotify Action
+ $('#select-addusernotify').click(function(){
+ if (selected_addusernotify) {
+ selected_addusernotify=false;
+ $("#select-these").removeAttr("disabled");
+ $("#unselect-these").removeAttr("disabled");
+ $("#details-addusernotify").slideUp();
+ } else {
+ selected_addusernotify=true;
+ $("#select-these").attr("disabled","disabled");
+ $("#unselect-these").attr("disabled","disabled");
+ $("#details-addusernotify").slideDown();
+ }
+ });
+
+ $('#submit-addusernotify').click(function(){
+ var user_list=""
+ $(':checkbox').each(function(){
+ if ($(this).is(':checked')) {
+ user_list += $(this).prop('name') + ",";
+ }
+ });
+ if ("" == user_list) {
+ alert("No users were selected");
+ return;
+ }
+ postCommitAjaxRequest({
+ "action" : 'submit-addusernotify',
+ "users" : user_list,
+ });
+ });
+
+ $('.trash-usernotification').click(function(){
+ var result = confirm("Are you sure?");
+ if (result){
+ postCommitAjaxRequest({
+ "action" : 'submit-trashusernotification',
+ "record_id" : $(this).attr('x-data'),
+ });
+ }
+ })
+
+ $('#select-adduseraccess').click(function(){
+ if (selected_adduseraccess) {
+ selected_adduseraccess=false;
+ $("#select-these").removeAttr("disabled");
+ $("#unselect-these").removeAttr("disabled");
+ $("#details-adduseraccess").slideUp();
+ } else {
+ selected_adduseraccess=true;
+ $("#select-these").attr("disabled","disabled");
+ $("#unselect-these").attr("disabled","disabled");
+ $("#details-adduseraccess").slideDown();
+ }
+ });
+
+ $('#submit-adduseraccess').click(function(){
+ var user_list=""
+ $(':checkbox').each(function(){
+ if ($(this).is(':checked')) {
+ user_list += $(this).prop('name') + ",";
+ }
+ });
+ if ("" == user_list) {
+ alert("No users were selected");
+ return;
+ }
+ postCommitAjaxRequest({
+ "action" : 'submit-adduseraccess',
+ "users" : user_list,
+ });
+ });
+
+ $('.trash-useraccess').click(function(){
+ var result = confirm("Are you sure?");
+ if (result){
+ postCommitAjaxRequest({
+ "action" : 'submit-trashuseraccess',
+ "record_id" : $(this).attr('x-data'),
+ });
+ }
+ })
+
+ /* Set the report link */
+ $('#report_link').attr('href',"{% url 'report' request.resolver_match.url_name %}?record_list={{object.id}}");
+ });
+</script>
+
{% endblock %}
diff --git a/lib/srtgui/templatetags/projecttags.py b/lib/srtgui/templatetags/projecttags.py
index b9afebcd..ac35fa0a 100644
--- a/lib/srtgui/templatetags/projecttags.py
+++ b/lib/srtgui/templatetags/projecttags.py
@@ -27,6 +27,7 @@ from django.utils import timezone
from django.template.defaultfilters import filesizeformat
import json as JsonLib
from django.utils.safestring import mark_safe
+import os
register = template.Library()
@@ -308,3 +309,8 @@ def recommend_display(recommend):
return '>= 3'
else:
return '%s' % recommend
+
+@register.filter(name='basename')
+def basename(value):
+ return os.path.basename(value)
+
diff --git a/lib/srtgui/urls.py b/lib/srtgui/urls.py
index e86acbbc..e13939c9 100644
--- a/lib/srtgui/urls.py
+++ b/lib/srtgui/urls.py
@@ -1,7 +1,7 @@
#
-# BitBake Toaster Implementation
+# Security Response Tool Implementation
#
-# Copyright (C) 2013-2017 Intel Corporation
+# Copyright (C) 2017-2018 Wind River Systems
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
@@ -30,81 +30,100 @@ urlpatterns = [
# landing page
url(r'^landing/$', views.landing, name='landing'),
- url(r'^manage/$', views.management, name='manage'),
- url(r'^manage_cpes/$',
- tables.ManageCpeTable.as_view(template_name="manage-cpes-toastertable.html"),
- name='manage_cpes'),
- url(r'^triage_cves/$', views.triage_cves, name='triage_cves'),
- url(r'^create_vulnerability/$', views.create_vulnerability, name='create_vulnerability'),
- url(r'^publish/$', views.publish, name='publish'),
- url(r'^manage_report/$', views.manage_report, name='manage_report'),
-
url(r'^login/$', views.login, name='login'),
- url(r'^users/$', views.users, name='users'),
-
- # TEST CODE
url(r'^login_guest/$', views.login_guest, name='login_guest'),
- url(r'^login_admin/$', views.login_admin, name='login_admin'),
-
+ url(r'^cve/(?P<cve_pk>\d+)$', views.cve, name="cve"),
+ url(r'^cve/(?P<cve_pk>[^\d].+)$', views.cve),
+ url(r'^cve/(?P<cve_pk>\d+)/active_tab/(?P<active_tab>\d{1})$', views.cve, name="cve"),
url(r'^cves/$',
- tables.AllCveTable.as_view(template_name="cves-toastertable.html"),
- name='all-cves'),
-
- url(r'^start-select-cves/$', views.start_select_cves, name='start-select-cves'),
+ tables.CvesTable.as_view(template_name="cves-toastertable.html"),
+ name='cves'),
url(r'^select-cves/$',
tables.SelectCveTable.as_view(template_name="cves-select-toastertable.html"),
name='select-cves'),
- url(r'^cve/(?P<cve_pk>\d+)/active_tab/(?P<active_tab>\d{1})$', views.cve, name="cve"),
- url(r'^cve/(?P<cve_pk>\d+)$', views.cve, name="cve"),
-
+ url(r'^defect/(?P<defect_pk>\d+)$', views.defect, name="defect"),
+ url(r'^defect/(?P<defect_pk>[^\d].+)$', views.defect),
url(r'^defects/$',
- tables.AllDefectTable.as_view(template_name="defects-toastertable.html"),
- name='all-defects'),
+ tables.DefectsTable.as_view(template_name="defects-toastertable.html"),
+ name='defects'),
url(r'^cpes/$',
- tables.AllCpeTable.as_view(template_name="cpes-toastertable.html"),
- name='all-cpes'),
+ tables.CpesTable.as_view(template_name="cpes-toastertable.html"),
+ name='cpes'),
url(r'^cwes/$',
- tables.AllCweTable.as_view(template_name="cwes-toastertable.html"),
- name='all-cwes'),
+ tables.CwesTable.as_view(template_name="cwes-toastertable.html"),
+ name='cwes'),
+ url(r'^product/(?P<product_pk>\d+)$', views.product, name="product"),
url(r'^products/$',
tables.ProductsTable.as_view(template_name="products-toastertable.html"),
name='products'),
+ url(r'^vulnerability/(?P<vulnerability_pk>\d+)$', views.vulnerability, name="vulnerability"),
+ url(r'^vulnerability/(?P<vulnerability_pk>[^\d].+)$', views.vulnerability),
url(r'^vulnerabilities/$',
- tables.AllVulnerabilitiesTable.as_view(template_name="vulnerabilities-toastertable.html"),
+ tables.VulnerabilitiesTable.as_view(template_name="vulnerabilities-toastertable.html"),
name='vulnerabilities'),
- url(r'^vulnerability/(?P<vulnerability_pk>\d+)$', views.vulnerability, name="vulnerability"),
-
+ url(r'^investigation/(?P<investigation_pk>\d+)$', views.investigation, name="investigation"),
+ url(r'^investigation/(?P<investigation_pk>[^\d].+)$', views.investigation),
url(r'^investigations/$',
- tables.AllInvestigationsTable.as_view(template_name="investigations-toastertable.html"),
+ tables.InvestigationsTable.as_view(template_name="investigations-toastertable.html"),
name='investigations'),
- url(r'^investigation/(?P<investigation_pk>\d+)$', views.investigation, name="investigation"),
-
- url(r'^all-keywords/$',
- tables.KeywordsTable.as_view(template_name="keywords-toastertable.html"),
- name='all-keywords'),
-
url(r'^keywords/$', views.keywords, name='keywords'),
+ url(r'^keywords_table/$',
+ tables.KeywordsTable.as_view(template_name="keywords-toastertable.html"),
+ name='keywords_table'),
- url(r'^sources/$', views.sources, name='sources'),
+ url(r'^select-publish/$',
+ tables.SelectPublishTable.as_view(template_name="publish-select-toastertable.html"),
+ name='select-publish'),
- url(r'^export/(?P<page_name>\D+)$', views.export, name='export'),
-# url(r'^export/$', views.export_null, name='export'),
+ url(r'^update-published/$',
+ tables.UpdatePublishedTable.as_view(template_name="published-select-toastertable.html"),
+ name='update-published'),
- url(r'^guided_tour/$', views.guided_tour, name='guided_tour'),
+ url(r'^report/(?P<page_name>\D+)$', views.report, name='report'),
- url(r'^quicklink/$', views.quicklink, name='quicklink'),
url(r'^xhr_triage_commit/$', views.xhr_triage_commit,
name='xhr_triage_commit'),
+ url(r'^xhr_cve_commit/$', views.xhr_cve_commit,
+ name='xhr_cve_commit'),
+
+ url(r'^xhr_vulnerability_commit/$', views.xhr_vulnerability_commit,
+ name='xhr_vulnerability_commit'),
+
+ url(r'^xhr_investigation_commit/$', views.xhr_investigation_commit,
+ name='xhr_investigation_commit'),
+
+ url(r'^xhr_cve_publish_commit/$', views.xhr_cve_publish_commit,
+ name='xhr_cve_publish_commit'),
+
+
+ url(r'^manage/$', views.management, name='manage'),
+ url(r'^manage_cpes/$',
+ tables.ManageCpeTable.as_view(template_name="manage-cpes-toastertable.html"),
+ name='manage_cpes'),
+ url(r'^triage_cves/$', views.triage_cves, name='triage_cves'),
+ url(r'^create_vulnerability/$', views.create_vulnerability, name='create_vulnerability'),
+ url(r'^publish/$', views.publish, name='publish'),
+ url(r'^manage_report/$', views.manage_report, name='manage_report'),
+ url(r'^sources/$',
+ tables.SourcesTable.as_view(template_name="sources-toastertable.html"),
+ name='sources'),
+ url(r'^users/$', views.users, name='users'),
+
+
+ url(r'^guided_tour/$', views.guided_tour, name='guided_tour'),
+
+ url(r'^quicklink/$', views.quicklink, name='quicklink'),
+
url(r'^tbd/$', views.tbd, name='tbd'),
# default redirection
diff --git a/lib/srtgui/views.py b/lib/srtgui/views.py
index 48556b3b..6e215f33 100644
--- a/lib/srtgui/views.py
+++ b/lib/srtgui/views.py
@@ -2,9 +2,9 @@
# ex:ts=4:sw=4:sts=4:et
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
#
-# BitBake Toaster Implementation
+# Security Response Tool Implementation
#
-# Copyright (C) 2013 Intel Corporation
+# Copyright (C) 2017-2018 Wind River Systems
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
@@ -25,18 +25,24 @@ import re
from django.db.models import F, Q, Sum
from django.db import IntegrityError
from django.shortcuts import render, redirect, get_object_or_404
-from orm.models import Cve, CveHistory
-from orm.models import Vulnerability, VulnerabilityHistory, CveToVulnerablility, VulnerabilityProduct
-from orm.models import Investigation, InvestigationHistory, InvestigationToDefect
+from orm.models import Cve, CveDetail, CveHistory
+from orm.models import Vulnerability, VulnerabilityHistory, CveToVulnerablility, VulnerabilityProduct, VulnerabilityNotification, VulnerabilityAccess, VulnerabilityComments, VulnerabilityUploads
+from orm.models import Investigation, InvestigationHistory, InvestigationToDefect, InvestigationComments, InvestigationNotification, InvestigationAccess, InvestigationUploads
from orm.models import SrtSetting, CweTable, Product
-from orm.models import Investigation, DataSource, User, Access
-from orm.models import Defect
+from orm.models import Investigation, DataSource, User, UserSafe, Access
+from orm.models import Defect, PublishPending
+
+from srtgui.reports import ReportManager
+from srtgui.api import readCveDetails
from django.core.urlresolvers import reverse, resolve
from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
-from django.http import HttpResponse, HttpResponseNotFound, JsonResponse
+from django.core.files.uploadedfile import UploadedFile
+from django.http import HttpResponse, HttpResponseNotFound, JsonResponse, HttpResponseRedirect
from django.utils import timezone
+from django import forms
+
from datetime import timedelta, datetime
from srtgui.templatetags.projecttags import json as jsonfilter
from decimal import Decimal
@@ -44,16 +50,16 @@ import json
import os
from os.path import dirname
import mimetypes
-import datetime
+import subprocess
import logging
+SRT_BASE_DIR = os.environ['SRT_BASE_DIR']
+
logger = logging.getLogger("srt")
-def _log(msg):
- f1=open('/tmp/srt.log', 'a')
- f1.write("|" + msg + "|\n" )
- f1.close()
+# quick development/debugging support
+from srtgui.api import _log
class MimeTypeFinder(object):
# setting this to False enables additional non-standard mimetypes
@@ -72,25 +78,31 @@ class MimeTypeFinder(object):
# single point to add global values into the context before rendering
def toaster_render(request, page, context):
-# context['project_enable'] = project_enable
+ # Share session's user name
+ srt_user_id = int(request.session.get('srt_user_id', '0'))
+ if 0 == srt_user_id:
+ srt_user_id = User.USER_GUEST
+ request.session['srt_user_id'] = srt_user_id
+ request.session.modified = True
+ context['srt_user_id'] = srt_user_id ### REMOVE
+ # Set normal access rights unless pre-empted by page
+ if not 'access' in context:
+ context['access'] = Access(srt_user_id)
return render(request, page, context)
# a context processor which runs on every request; this provides the
# projects and non_cli_projects (i.e. projects created by the user)
# variables referred to in templates, which used to determine the
-# visibility of UI elements like the "New build" button
+# visibility of UI elements like the "Management" button
def managedcontextprocessor(request):
ret = {
# "non_cli_projects": projects.exclude(is_default=True),
# "DEBUG" : srtmain.settings.DEBUG,
# "TOASTER_BRANCH": srtmain.settings.TOASTER_BRANCH,
# "TOASTER_REVISION" : srtmain.settings.TOASTER_REVISION,
- 'access' : Access(),
}
return ret
-
-# all new sessions should come through the landing page;
# determine in which mode we are running in, and redirect appropriately
def landing(request):
@@ -99,9 +111,7 @@ def landing(request):
# user_projects = Project.objects.filter(is_default = False)
# has_user_project = user_projects.count() > 0
- context = {
- 'lvs_nos' : 0,
- }
+ context = {}
return toaster_render(request, 'landing.html', context)
@@ -447,19 +457,18 @@ def _add_daterange_context(queryset_all, request, daterange_list):
def management(request):
# does this user have permission to see this record?
- userAccess = Access()
- if not userAccess.is_admin():
+ userAccess = Access(int(request.session.get('srt_user_id', '0')))
+ if not userAccess.is_creator():
return redirect(landing)
context = {
- 'lvs_nos' : 0,
'cve_total' : Cve.objects.all().count(),
'cve_new' : Cve.objects.filter(status=Cve.NEW).count(),
'cve_open' : Cve.objects.filter( Q(status=Cve.INVESTIGATE) & Q(status=Cve.VULNERABLE) ).count(),
'vulnerability_total' : Vulnerability.objects.all().count(),
-
+
'vulnerability_open' : Vulnerability.objects.filter(outcome=Vulnerability.OPEN).count(),
'vulnerability_high' : Vulnerability.objects.filter(severity=Vulnerability.HIGH).count(),
'vulnerability_medium' : Vulnerability.objects.filter(severity=Vulnerability.MEDIUM).count(),
@@ -479,13 +488,19 @@ def management(request):
import copy
def cve(request, cve_pk, active_tab="1"):
template = "cve.html"
- if Cve.objects.filter(pk=cve_pk).count() == 0 :
- return redirect(landing)
- cve_object = Cve.objects.get(pk=cve_pk)
+ # CVE name or pk
+ try:
+ if cve_pk[0].isdigit():
+ cve_object = Cve.objects.get(pk=cve_pk)
+ else:
+ cve_object = Cve.objects.get(name=cve_pk)
+ cve_pk = cve_object.id
+ except:
+ return redirect(landing)
# does this user have permission to see this record?
- userAccess = Access()
+ userAccess = Access(int(request.session.get('srt_user_id', '0')))
if (not cve_object.public) and (not userAccess.is_admin()):
return redirect(landing)
@@ -500,61 +515,214 @@ def cve(request, cve_pk, active_tab="1"):
else:
response_link = str(investigation_records[0].pk)
+ # fetch CVE's detail information
+ cve_object_detail = readCveDetails(cve_object)
+ _log("FOO:%s" % cve_object_detail)
+
cve_summary = copy.copy(cve_object)
+ cve_summary_detail = copy.copy(cve_object_detail)
cve_summary.source = 'Summary'
-
- cve_local = Cve
+
+ cve_local = Cve()
+ cve_local_detail = CveDetail()
cve_local.source = 'Local'
-
+
context = {
- 'object' : { "name" : "CVE-1234"} ,
- 'cve_list_table' : [
- (cve_summary,tab_states['1'],"Summary"),
- (cve_object,tab_states['2'],"NIST"),
- (cve_local,tab_states['3'],"Local"),
+ 'object' : { "name" : "CVE-1234",
+ "id" : cve_object.id,
+ },
+ 'cve_list_table' : [
+ (cve_summary,cve_summary_detail,tab_states['1'],"Summary"),
+ (cve_object,cve_object_detail,tab_states['2'],"NIST"),
+ (cve_local,cve_local_detail,tab_states['3'],"Local"),
],
'tab_states' : tab_states,
'response_link' : response_link,
'cve_prev' : str(max(1,int(cve_pk)-1)),
'cve_next' : str(min(int(cve_pk)+1,Cve.objects.count()-1)),
}
- return render(request, template, context)
+ return toaster_render(request, template, context)
def vulnerability(request, vulnerability_pk):
- template = "vulnerability.html"
- if Vulnerability.objects.filter(pk=vulnerability_pk).count() == 0 :
- return redirect(landing)
+ if request.method == "GET":
+ template = "vulnerability.html"
- vulnerability_object = Vulnerability.objects.get(pk=vulnerability_pk)
+ # Defect name or pk
+ try:
+ if vulnerability_pk[0].isdigit():
+ vulnerability_object = Vulnerability.objects.get(pk=vulnerability_pk)
+ else:
+ vulnerability_object = Vulnerability.objects.get(name=vulnerability_pk)
+ vulnerability_pk = vulnerability_object.id
+ except:
+ return redirect(landing)
+
+ products = Product.objects.all()
+
+ # does this user have permission to see this record?
+ userAccess = Access(int(request.session.get('srt_user_id', '0')))
+ if (not vulnerability_object.public) and (not userAccess.is_admin()):
+ return redirect(landing)
+
+ context = {
+ 'object' : vulnerability_object,
+ 'users' : UserSafe.get_safe_userlist(True),
+ 'products': products,
+ }
+ return toaster_render(request, template, context)
+ elif request.method == "POST":
+ _log("EXPORT_POST:VULERNABILITY_POST: %s" % request)
+
+ if request.POST["action"] == "upload":
+ if vulnerability_pk[0].isdigit():
+ vulnerability_object = Vulnerability.objects.get(pk=vulnerability_pk)
+ else:
+ vulnerability_object = Vulnerability.objects.get(name=vulnerability_pk)
+ vulnerability_pk = vulnerability_object.id
+ path = os.path.join(SRT_BASE_DIR, "downloads/%s" % vulnerability_object.name)
+ # Catch the post against this page
+ try:
+ os.makedirs(path)
+ except:
+ pass
+
+ try:
+ file = request.FILES['fileUpload']
+ description = request.POST['fileDescription']
+ except Exception as e:
+ _log("EXPORT_POST:'fileupload' does not exist: %s" % e)
+
+ try:
+ with open(path + "/" + file.name, 'xb+') as destination:
+ for line in file:
+ destination.write(line)
+
+ userAccess = Access(int(request.session.get('srt_user_id', '0')))
+ 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=userAccess.current_user_name)
+ except Exception as e:
+ _log("EXPORT_POST:FILE ALREADY EXISTS: %s" % e)
+ return redirect(vulnerability,vulnerability_pk)
+ elif request.POST["action"] == "download":
+ record_id = request.POST['record_id']
+ upload = VulnerabilityUploads.objects.get(id=record_id)
+ file_path = upload.path
+ 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 toaster_render(request, "unavailable_artifact.html")
- # does this user have permission to see this record?
- userAccess = Access()
- if (not vulnerability_object.public) and (not userAccess.is_admin()):
+def investigation(request, investigation_pk):
+ if request.method == "GET":
+ template = "investigation.html"
+
+ # Investigation name or pk
+ try:
+ if investigation_pk[0].isdigit():
+ investigation_object = Investigation.objects.get(pk=investigation_pk)
+ else:
+ investigation_object = Investigation.objects.get(name=investigation_pk)
+ investigation_pk = investigation_object.id
+ except:
+ return redirect(landing)
+
+ defects = Defect.objects.all()
+ investigation_to_defect = investigation_object.investigation_to_defect.all()
+ context = {
+ 'object' : investigation_object,
+ 'users' : UserSafe.get_safe_userlist(True),
+ 'defects' : defects,
+ 'investigation_to_defect' : investigation_to_defect,
+ 'defect_example' : SrtSetting.objects.get(name='SRTOOL_DEFECT_SAMPLENAME').value,
+ }
+ return toaster_render(request, template, context)
+ elif request.method == "POST":
+ _log("EXPORT_POST:INVESTIGATION_POST: %s" % request)
+
+ if request.POST["action"] == "upload":
+ if investigation_pk[0].isdigit():
+ investigation_object = Investigation.objects.get(pk=investigation_pk)
+ else:
+ investigation_object = Investigation.objects.get(name=investigation_pk)
+ investigation_pk = investigation_object.id
+ path = os.path.join(SRT_BASE_DIR, "downloads/%s" % investigation_object.name)
+ # Catch the post against this page
+ try:
+ os.makedirs(path)
+ except:
+ pass
+
+ try:
+ file = request.FILES['fileUpload']
+ description = request.POST['fileDescription']
+ except Exception as e:
+ _log("EXPORT_POST:'fileupload' does not exist: %s" % e)
+
+ try:
+ with open(path + "/" + file.name, 'xb+') as destination:
+ for line in file:
+ destination.write(line)
+ userAccess = Access(int(request.session.get('srt_user_id', '0')))
+ 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=userAccess.current_user_name)
+ except Exception as e:
+ _log("EXPORT_POST:FILE ALREADY EXISTS: %s" % e)
+ return redirect(investigation,investigation_pk)
+ elif request.POST["action"] == "download":
+ record_id = request.POST['record_id']
+ upload = InvestigationUploads.objects.get(id=record_id)
+ file_path = upload.path
+ 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 toaster_render(request, "unavailable_artifact.html")
+
+
+def defect(request, defect_pk):
+ template = "defect.html"
+
+ # Defect name or pk
+ try:
+ if defect_pk[0].isdigit():
+ defect_object = Defect.objects.get(pk=defect_pk)
+ else:
+ defect_object = Defect.objects.get(name=defect_pk)
+ defect_pk = defect_object.id
+ except:
return redirect(landing)
context = {
- 'object' : vulnerability_object,
-# 'cwe_table' : CweTable.objects.all(),
+ 'object' : defect_object,
+ 'users' : users,
}
- return render(request, template, context)
+ return toaster_render(request, template, context)
-def investigation(request, investigation_pk):
- template = "investigation.html"
- if Investigation.objects.filter(pk=investigation_pk).count() == 0 :
+def product(request, product_pk):
+ template = "product.html"
+ if Product.objects.filter(pk=product_pk).count() == 0 :
return redirect(landing)
- investigation_object = Investigation.objects.get(pk=investigation_pk)
+ product_object = Product.objects.get(pk=product_pk)
context = {
- 'object' : investigation_object,
-# 'cwe_table' : CweTable.objects.all(),
+ 'object' : product_object,
}
- return render(request, template, context)
+ return toaster_render(request, template, context)
def sources(request):
# does this user have permission to see this record?
- userAccess = Access()
+ userAccess = Access(int(request.session.get('srt_user_id', '0')))
if not userAccess.is_admin():
return redirect(landing)
@@ -567,41 +735,46 @@ def sources(request):
context = {
'object' : object,
}
- return render(request, template, context)
+ return toaster_render(request, template, context)
def login(request):
- template = "login.html"
- context = {
- 'object' : object,
- }
- return render(request, template, context)
+ if request.method == "GET":
+ template = "login.html"
+ object = User.objects.all()
+ context = {
+ 'object' : object,
+ 'user_count' : len(object),
+ }
+ return toaster_render(request, template, context)
+ elif request.method == "POST":
+ user_name = request.POST.get('username', '_anonuser')
+ user_name = re.sub(r"\(.*","",user_name).strip()
+ password = request.POST.get('password', 'nopass')
+ _log("LOGIN_POST:%s,%s" % (user_name,password))
-def _log(msg):
- f1=open('/tmp/srt.log', 'a')
- f1.write("|" + msg + "|\n" )
- f1.close()
+ try:
+ ### USER CONTROL
+ user = User.objects.get(name=user_name)
+ request.session['srt_user_id'] = user.id
+ request.session.modified = True
+
+ except Exception as e:
+ _log("LOGIN_ERROR:%s,%s" % (user,e))
+ pass
+ return redirect(landing)
+ #return landing(request)
-# TEMP ACCESS TEST CODE
+ raise Exception("Invalid HTTP method for this page")
+
+# This is effectively the logout command
def login_guest(request):
- current_user = SrtSetting.objects.get_or_create(name='current_user')[0]
- current_user.value = 1
- current_user.save()
- current_user_access = SrtSetting.objects.get_or_create(name='current_user_access')[0]
- current_user_access.value = User.READER
- current_user_access.save()
- return redirect(landing)
-def login_admin(request):
- current_user = SrtSetting.objects.get_or_create(name='current_user')[0]
- current_user.value = 3
- current_user.save()
- current_user_access = SrtSetting.objects.get_or_create(name='current_user_access')[0]
- current_user_access.value = User.ADMIN
- current_user_access.save()
+ request.session['srt_user_id'] = User.USER_GUEST
+ request.session.modified = True
return redirect(landing)
def users(request):
# does this user have permission to see this record?
- userAccess = Access()
+ userAccess = Access(int(request.session.get('srt_user_id', '0')))
if not userAccess.is_admin():
return redirect(landing)
@@ -615,37 +788,55 @@ def users(request):
context = {
'object' : object,
}
- return render(request, template, context)
-
-def export(request,page_name):
- context = {
- 'lvs_nos' : 0,
- 'page' : '%s%s' % (page_name[0:1].upper(),page_name[1:])
- }
- return toaster_render(request, 'export.html', context)
+ return toaster_render(request, template, context)
+
+def report(request,page_name):
+ if request.method == "GET":
+ context = ReportManager.get_context_data(page_name,request=request)
+ record_list = request.GET.get('record_list', '')
+ _log("EXPORT_GET!:%s|%s|" % (request,record_list))
+ context['record_list'] = record_list
+ return toaster_render(request, 'report.html', context)
+ elif request.method == "POST":
+ _log("EXPORT_POST!:%s|%s" % (request,request.FILES))
+ parent_page = request.POST.get('parent_page', '')
+ file_name,response_file_name = ReportManager.exec_report(parent_page,request=request)
+
+ if file_name and response_file_name:
+ fsock = open(file_name, "rb")
+ content_type = MimeTypeFinder.get_mimetype(file_name)
+
+ response = HttpResponse(fsock, content_type = content_type)
+
+ disposition = "attachment; filename=" + response_file_name
+ response["Content-Disposition"] = disposition
+
+ _log("EXPORT_POST_Q{%s|" % (response))
+ return response
+ else:
+ return toaster_render(request, "unavailable_artifact.html", {})
-def export_null(request):
- return export(request,"NuLl")
+ return redirect(landing)
+ raise Exception("Invalid HTTP method for this page")
def triage_cves(request):
# does this user have permission to see this record?
- userAccess = Access()
- if not userAccess.is_admin():
+ userAccess = Access(int(request.session.get('srt_user_id', '0')))
+ if not userAccess.is_creator():
return redirect(landing)
- context = {'lvs_nos' : 0}
+ context = {}
return toaster_render(request, 'triage_cves.html', context)
-
def keywords(request):
# does this user have permission to see this record?
- userAccess = Access()
- if not userAccess.is_admin():
+ userAccess = Access(int(request.session.get('srt_user_id', '0')))
+ if not userAccess.is_creator():
return redirect(landing)
-
+
for_list = SrtSetting.objects.get(name='keywords_for').value.split('|')
against_list = SrtSetting.objects.get(name='keywords_against').value.split('|')
- context = {'lvs_nos' : 0,
+ context = {
'for_list' : for_list,
'for_list_count' : len(for_list),
'against_list' : against_list,
@@ -653,87 +844,36 @@ def keywords(request):
}
return toaster_render(request, 'keywords.html', context)
-
-def start_select_cves(request):
- # pre-calculate the recommend values
- queryset = \
- Cve.objects.filter(status = Cve.NEW,name__startswith = 'CVE-2018-')
-
- KeywordsFor = SrtSetting.objects.get(name='keywords_for').value.split('|')
- KeywordsAgainst = SrtSetting.objects.get(name='keywords_against').value.split('|')
-
- for cve in queryset:
- description = ' '+cve.description.lower()+' '
- total = 0
- list = ''
-
- for keypair in KeywordsFor:
- #print("keypair='%s'" % keypair)
- key,w = keypair.split(',')
- weight = 1
-# if w:
-# weight = int(w)
- #if ' '+key+' ' in description:
- if re.search(r'\b%s\b' % key, description):
- list += ",+%s" % key
- total += weight
-
- for keypair in KeywordsAgainst:
- #print("keypair='%s'" % keypair)
- key,w = keypair.split(',')
- weight = 1
-# if w:
-# weight = int(w)
- # re.search(r'\bis\b', your_string)
- #if ' '+key+' ' in description:
- #if re.search(re.escape(r'\b%s\b' % key), description):
- if re.search(r'\b%s\b' % key, description):
- list += ",-%s" % key
- total -= weight
-
- # set filter maximums
- if total < -3:
- total = -3
- if total > 3:
- total = 3
- cve.recommend = total
- cve.comments_private = list[1:]
- cve.save()
-
- #_log("%s[%d]=%s" % (cve.name,cve.recommend,cve.comments_private))
-
- return redirect("/srtgui/select-cves")
-
def create_vulnerability(request):
# does this user have permission to see this record?
- userAccess = Access()
- if not userAccess.is_admin():
+ userAccess = Access(int(request.session.get('srt_user_id', '0')))
+ if not userAccess.is_creator():
return redirect(landing)
- context = {'lvs_nos' : 0}
+ context = {}
return toaster_render(request, 'create_vulnerability.html', context)
def publish(request):
# does this user have permission to see this record?
- userAccess = Access()
- if not userAccess.is_admin():
+ userAccess = Access(int(request.session.get('srt_user_id', '0')))
+ if not userAccess.is_creator():
return redirect(landing)
- context = {'lvs_nos' : 0}
+ context = {}
return toaster_render(request, 'publish.html', context)
def manage_report(request):
# does this user have permission to see this record?
- userAccess = Access()
- if not userAccess.is_admin():
+ userAccess = Access(int(request.session.get('srt_user_id', '0')))
+ if not userAccess.is_creator():
return redirect(landing)
- return redirect(export,'management')
+ return redirect(report,'management')
def guided_tour(request):
- context = {'lvs_nos' : 0}
+ context = {}
return toaster_render(request, 'guided_tour.html', context)
-
+
def quicklink(request):
current_user = SrtSetting.objects.get_or_create(name='current_user')[0]
current_user.value = 16
@@ -741,7 +881,7 @@ def quicklink(request):
current_user_access = SrtSetting.objects.get_or_create(name='current_user_access')[0]
current_user_access.value = User.ADMIN
current_user_access.save()
- return redirect("/srtgui/start-select-cves")
+ return redirect("/srtgui/select-publish")
def xhr_triage_commit(request):
_log("xhr_triage_commit(%s)" % request.POST)
@@ -752,7 +892,7 @@ def xhr_triage_commit(request):
author_name = User.objects.get(pk=author_id).name
action = request.POST['action']
- today = datetime.datetime.today().strftime("%Y-%m-%d")
+ today = datetime.today().strftime("%Y-%m-%d")
if 'submit-notvulnerable' == action:
reason = request.POST['reason']
cves = request.POST['cves']
@@ -786,10 +926,11 @@ def xhr_triage_commit(request):
first_vulnerability = True
investigation_names = {}
for cve_name in cves[:-1].split(','):
-
+
# update CVE
cve = Cve.objects.get(name=cve_name)
cve.status = Cve.VULNERABLE
+ cve.priority = severity
if cve.comments:
cve.comments += ', ' + reason
else:
@@ -864,7 +1005,322 @@ def xhr_triage_commit(request):
_log("xhr_triage_commit:no(%s)" % e)
return HttpResponse(json.dumps({"error":str(e) + "\n" + traceback.format_exc()}), content_type = "application/json")
+def xhr_cve_commit(request):
+ _log("xhr_cve_commit(%s)" % request.POST)
+ if not 'action' in request.POST:
+ return HttpResponse(json.dumps({"error":"missing action\n"}), content_type = "application/json")
+ try:
+ cve = Cve.objects.get(id=request.POST['cve_id'])
+ action = request.POST['action']
+ history_comment = ''
+ if 'submit-quickedit' == action:
+ note = request.POST['note']
+ priority = int(request.POST['priority'])
+ private_note = request.POST['private_note']
+ publish_state = request.POST['publish_state']
+ publish_date = request.POST['publish_date']
+ if (priority != cve.priority):
+ cve.priority = priority
+ history_comment += "Priority, "
+ if (note != cve.comments):
+ cve.comments = note
+ history_comment += "Note, "
+ if (private_note != cve.comments_private):
+ cve.comments_private = private_note
+ history_comment += "Private Note, "
+ if (publish_state != cve.publish_state):
+ cve.publish_state = publish_state
+ history_comment += "Publish State, "
+ if (publish_date != cve.publish_date):
+ cve.publish_date = publish_date
+ history_comment += "Publish Date, "
+ cve.save()
+ return_data = {
+ "error": "ok",
+ }
+
+ access = Access(int(request.session.get('srt_user_id', '0')))
+ 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=access.current_user_name)
+ _log("xhr_cve_commit:SUCCESS")
+ return HttpResponse(json.dumps( return_data ), content_type = "application/json")
+
+ except Exception as e:
+ _log("xhr_cve_commit:no(%s)" % e)
+ return HttpResponse(json.dumps({"error":str(e) + "\n" + traceback.format_exc()}), content_type = "application/json")
+
+def xhr_cve_publish_commit(request):
+ _log("xhr_cve_publish_commit(%s)" % request.POST)
+ cve_list = request.POST['cve_list']
+ publish_state = int(request.POST['publish_state'])
+ _log("xhr_cve_publish_commit2")
+ try:
+ for name in cve_list.split(','):
+ _log("xhr_cve_publish_commit3:%s" % name)
+ if name:
+ _log("xhr_cve_publish_commit4")
+ cve = Cve.objects.get(name=name)
+ cve.publish_state = publish_state
+ cve.save()
+ _log("xhr_cve_publish_commit5")
+ # Add to publish pending queue?
+ if Cve.PUBLISH_SUBMITTED == publish_state:
+ _log("xhr_cve_publish_commit5a")
+ pub_req,created = PublishPending.objects.get_or_create(cve=cve)
+ pub_req.date=datetime.today().strftime('%Y-%m-%d')
+ pub_req.save()
+ _log("xhr_cve_publish_commit5b")
+ # Remove from publish pending queue?
+ if Cve.PUBLISH_PUBLISHED == publish_state:
+ _log("xhr_cve_publish_commit5c")
+ try:
+ pub_req = PublishPending.objects.get(cve=cve)
+ pub_req.delete()
+ except:
+ pass
+ _log("xhr_cve_publish_commit5d")
+ _log("xhr_cve_publish_commit6")
+ return_data = {
+ "error": "ok",
+ }
+ return HttpResponse(json.dumps( return_data ), content_type = "application/json")
+ except Exception as e:
+ _log("xhr_cve_publish_commit:no(%s)" % e)
+ return HttpResponse(json.dumps({"error":str(e) + "\n" + traceback.format_exc()}), content_type = "application/json")
+
+def xhr_vulnerability_commit(request):
+ _log("xhr_vulnerability_commit(%s)" % request.POST)
+ if not 'action' in request.POST:
+ return HttpResponse(json.dumps({"error":"missing action\n"}), content_type = "application/json")
+
+ action = request.POST['action']
+ v_id = request.POST['vulnerability_id']
+ access = Access(int(request.session.get('srt_user_id', '0')))
+ history_comment = ''
+ try:
+ if 'submit-quickedit' == action:
+ note = request.POST['note']
+ private_note = request.POST['private_note']
+ v = Vulnerability.objects.get(id=v_id)
+ if (v.comments != note):
+ v.comments = note
+ history_comment += "Note, "
+ if (v.comments_private != 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.severity != request.POST['severity']):
+ v.severity = request.POST['severity']
+ history_comment += "Severity, "
+ if (history_comment != ''):
+ history_comment = history_comment[:-2]
+ history_comment += " edited"
+ v.save()
+
+ if 'submit-addrelatedproduct' == action:
+ products = request.POST['products']
+ product_names = ''
+ for product_id in products[:-1].split(','):
+ tmp = Product.objects.get(pk=product_id)
+ product_names += tmp.name + ' ' + tmp.version + ', '
+ VulnerabilityProduct.objects.get_or_create(vulnerability_id=v_id, product_id=product_id, relation=1)
+ product_names = product_names[:-2]
+ history_comment = product_names + " added to related products"
+ if 'submit-trashrelated' == action:
+ record_id = request.POST['record_id']
+ record = VulnerabilityProduct.objects.get(id=record_id)
+ product = Product.objects.get(id=record.product_id)
+ history_comment = product.name + ' ' + product.version + " removed from related products"
+ record.delete()
+ if 'submit-addaffectedproduct' == action:
+ products = request.POST['products']
+ product_names = ''
+ for product_id in products[:-1].split(','):
+ tmp = Product.objects.get(pk=product_id)
+ product_names += tmp.name + ' ' + tmp.version + ', '
+ VulnerabilityProduct.objects.get_or_create(vulnerability_id=v_id, product_id=product_id, relation=0)
+ product_names = product_names[:-2]
+ history_comment = product_names + " added to affected products"
+ if 'submit-trashaffected' == action:
+ record_id = request.POST['record_id']
+ record = VulnerabilityProduct.objects.get(id=record_id)
+ product = Product.objects.get(id=record.product_id)
+ history_comment = product.name + ' ' + product.version + " removed from afftected products"
+ record.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=access.current_user_name)
+ history_comment = "New comment submitted"
+ 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()
+ 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
+ upload.delete()
+ if 'submit-addusernotify' == action:
+ users = request.POST['users']
+ usernames = ''
+ for user_id in users[:-1].split(','):
+ usernames += User.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"
+ if 'submit-trashusernotification' == action:
+ record_id = request.POST['record_id']
+ notification_record = VulnerabilityNotification.objects.get(id=record_id)
+ removed_user = User.objects.get(pk=notification_record.user_id).name
+ history_comment = removed_user + " removed from notifications"
+ notification_record.delete()
+ if 'submit-adduseraccess' == action:
+ users = request.POST['users']
+ usernames = ''
+ for user_id in users[:-1].split(','):
+ usernames += User.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"
+ if 'submit-trashuseraccess' == action:
+ record_id = request.POST['record_id']
+ access_record = VulnerabilityAccess.objects.get(id=record_id)
+ removed_user = User.objects.get(pk=access_record.user_id).name
+ history_comment = removed_user + "'s access removed"
+ access_record.delete()
+ if (history_comment != ''):
+ VulnerabilityHistory.objects.create(vulnerability_id=v_id, comment=history_comment, date=datetime.now().strftime('%Y-%m-%d'), author=access.current_user_name)
+ return_data = {
+ "error": "ok",
+ }
+ return HttpResponse(json.dumps( return_data ), content_type = "application/json")
+ except Exception as e:
+ _log("xhr_vulnerability_commit:no(%s)" % e)
+ return HttpResponse(json.dumps({"error":str(e) + "\n" + traceback.format_exc()}), content_type = "application/json")
+
+def xhr_investigation_commit(request):
+ _log("xhr_investigation_commit(%s)" % request.POST)
+ if not 'action' in request.POST:
+ return HttpResponse(json.dumps({"error":"missing action\n"}), content_type = "application/json")
+
+ action = request.POST['action']
+ invst_id = request.POST['investigation_id']
+ access = Access(int(request.session.get('srt_user_id', '0')))
+ history_comment = "Nothing happened."
+ try:
+ if 'submit-attachdefectlist' == action:
+ defects = request.POST['defects']
+ product_id = Investigation.objects.get(id=invst_id).product_id
+ defect_names = ""
+ for defect_id in defects[:-1].split(','):
+ defect_names += 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"
+ if 'submit-attachdefect' == action:
+ query = request.POST['query'].upper()
+ product_id = Investigation.objects.get(id=invst_id).product_id
+ #check if defect already in SRTool data
+ try:
+ defect = Defect.objects.get(name=query)
+ except Defect.DoesNotExist:
+ defect = None
+
+ #If defect not in SRTool, import data from Defect database and create record
+ if defect is None:
+ #try connecting to defect management tool
+ try:
+ cmd_list = SrtSetting.objects.get(name='SRTOOL_DEFECT_ADD').value.split(' ')
+ cmd_list.append(query)
+ result = subprocess.run(cmd_list, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ if 0 == result.returncode:
+ defect = Defect.objects.get(name=query)
+ else:
+ defect = None
+ return HttpResponse(json.dumps({"error":str(e) + "\n"}), content_type = "application/json")
+ except Exception as e:
+ _log("xhr_investigation_commit:Error in defect attach query:(%s)\n" % e)
+ return HttpResponse(json.dumps({"error":str(e) + "\n"}), 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
+ if 'submit-trashdefect' == action:
+ defects = request.POST['defects']
+ product_id = Investigation.objects.get(id=invst_id).product_id
+ defect_names = ""
+ for defect_id in defects[:-1].split(','):
+ defect_names += Defect.objects.get(pk=defect_id).name + ", "
+ InvestigationToDefect.objects.get(investigation_id=invst_id, defect_id=defect_id).delete()
+ defect_names = defect_names[:-2]
+ history_comment = defect_names + " deleted from defects"
+ 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=access.current_user_name)
+ history_comment = "New comment submitted"
+ 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()
+ 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
+ upload.delete()
+ if 'submit-addusernotify' == action:
+ users = request.POST['users']
+ usernames = ""
+ for user_id in users[:-1].split(','):
+ usernames += User.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"
+ if 'submit-trashusernotification' == action:
+ record_id = request.POST['record_id']
+ notification_record = InvestigationNotification.objects.get(id=record_id)
+ removed_user = User.objects.get(pk=notification_record.user_id).name
+ history_comment = removed_user + " removed from notifications"
+ notification_record.delete()
+ if 'submit-adduseraccess' == action:
+ users = request.POST['users']
+ usernames = ""
+ for user_id in users[:-1].split(','):
+ usernames += User.objects.get(pk=user_id).name + ", "
+ InvestigationAccess.objects.get_or_create(investigation_id=invst_id, user_id=user_id)
+ history_comment = usernames + " granted access"
+ if 'submit-trashuseraccess' == action:
+ record_id = request.POST['record_id']
+ access_record = InvestigationAccess.objects.get(id=record_id)
+ removed_user = User.objects.get(pk=access_record.user_id).name
+ history_comment = removed_user + "'s access removed"
+ access_record.delete()
+ InvestigationHistory.objects.create(investigation_id=invst_id, comment=history_comment, date=datetime.now().strftime('%Y-%m-%d'), author=access.current_user_name)
+ return_data = {
+ "error": "ok",
+ }
+
+ return HttpResponse(json.dumps( return_data ), content_type = "application/json")
+ except Exception as e:
+ _log("xhr_investigation_commit:no(%s)" % e)
+ return HttpResponse(json.dumps({"error":str(e) + "\n"}), content_type = "application/json")
+
+
def tbd(request):
- context = {'lvs_nos' : 0}
+ context = {}
return toaster_render(request, 'tbd.html', context)
-
diff --git a/lib/srtgui/widgets.py b/lib/srtgui/widgets.py
index b43b7619..0c2b56bf 100644
--- a/lib/srtgui/widgets.py
+++ b/lib/srtgui/widgets.py
@@ -34,7 +34,7 @@ from django.utils import timezone
from django.http import JsonResponse
from django.core.urlresolvers import reverse
-from orm.models import Vulnerability, SrtSetting, Access, Keywords
+from orm.models import SrtSetting, Access, Keywords
from srtgui.templatetags.projecttags import sectohms, get_tasks
from srtgui.templatetags.projecttags import json as template_json
@@ -89,8 +89,12 @@ class ToasterTable(TemplateView):
context['empty_state'] = self.empty_state
# global variables
- context['project_enable'] = ('1' == os.environ.get('TOASTER_BUILDSERVER'))
- context['access'] = Access()
+ context['report_id_list'] = ''
+
+ # Number of visits to this view, as counted in the session variable.
+ srt_user_id=int(self.request.session.get('srt_user_id', '0'))
+ context['srt_user_id'] = srt_user_id ### REMOVE
+ context['access'] = Access(srt_user_id)
return context
@@ -113,6 +117,12 @@ class ToasterTable(TemplateView):
return super(ToasterTable, self).get(request, *args, **kwargs)
+ def put(self, *args, **kwargs):
+ """ function to implement in the subclass which sets up
+ the put method """
+ _log("TABLE_PUT_SUPER")
+ pass
+
def get_filter_info(self, request, **kwargs):
self.setup_filters(**kwargs)
diff --git a/lib/srtmain/settings.py b/lib/srtmain/settings.py
index c69bedfb..0fbc73ba 100644
--- a/lib/srtmain/settings.py
+++ b/lib/srtmain/settings.py
@@ -19,7 +19,7 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-# Django settings for SRT
+# Django settings for SRT
import os
@@ -49,6 +49,10 @@ DATABASES = {
'PASSWORD': '',
#'HOST': '127.0.0.1', # e.g. mysql server
#'PORT': '3306', # e.g. mysql port
+ },
+ # Sqlite database lock problem
+ 'OPTIONS': {
+ 'timeout': 20,
}
}