Skip to content

Commit 4d9bfa7

Browse files
authored
Merge pull request #847 from nexB/798-refine-ui
Improve web user interface #798
2 parents 25bea6b + b0a1ee2 commit 4d9bfa7

21 files changed

Lines changed: 4419 additions & 350 deletions

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ sqlite:
109109
@$(MAKE) migrate
110110

111111
run:
112-
${MANAGE} runserver 8001 --noreload --insecure
112+
${MANAGE} runserver 8001 --insecure
113113

114114
test:
115115
@echo "-> Run the test suite"

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ classifiers =
2525
Topic :: Security
2626
Topic :: Software Development :: Bug Tracking
2727
Framework :: Django
28-
28+
2929
keywords =
3030
open source
3131
vulnerability

vulnerabilities/forms.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,13 @@ class PackageForm(forms.Form):
3434

3535
type = forms.ChoiceField(choices=get_package_types)
3636
name = forms.CharField(
37-
required=False, widget=forms.TextInput(attrs={"placeholder": "package name"})
37+
required=False, widget=forms.TextInput(attrs={"placeholder": "Package name or purl"})
3838
)
3939

4040

4141
class CVEForm(forms.Form):
4242

43-
vuln_id = forms.CharField(widget=forms.TextInput(attrs={"placeholder": "vulnerability id"}))
43+
vuln_id = forms.CharField(
44+
required=False,
45+
widget=forms.TextInput(attrs={"placeholder": "Vulnerability ID or CVE/GHSA"}),
46+
)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Generated by Django 4.0.6 on 2022-08-18 20:58
2+
3+
from django.db import migrations
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('vulnerabilities', '0017_delete_reference_to_cpes_with_empty_urls'),
10+
]
11+
12+
operations = [
13+
migrations.AlterModelOptions(
14+
name='alias',
15+
options={'ordering': ['alias']},
16+
),
17+
]
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Generated by Django 4.0.6 on 2022-08-23 19:15
2+
3+
from django.db import migrations
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('vulnerabilities', '0018_alter_alias_options'),
10+
]
11+
12+
operations = [
13+
migrations.AlterModelOptions(
14+
name='vulnerabilityreference',
15+
options={'ordering': ['reference_id', 'url']},
16+
),
17+
]

vulnerabilities/models.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ class Meta:
124124
"url",
125125
"reference_id",
126126
)
127+
ordering = ["reference_id", "url"]
127128

128129
def __str__(self):
129130
reference_id = f" {self.reference_id}" if self.reference_id else ""
@@ -362,6 +363,21 @@ class Alias(models.Model):
362363
related_name="aliases",
363364
)
364365

366+
@property
367+
def url(self):
368+
"""
369+
Create a URL for the alias.
370+
"""
371+
alias: str = self.alias
372+
if alias.startswith("CVE"):
373+
return f"https://nvd.nist.gov/vuln/detail/{alias}"
374+
375+
if alias.startswith("GHSA"):
376+
return f"https://github.com/advisories/{alias}"
377+
378+
class Meta:
379+
ordering = ["alias"]
380+
365381
def __str__(self):
366382
return self.alias
367383

Lines changed: 31 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,40 @@
1+
{% load static %}
12
<!DOCTYPE html>
23
<html lang="en">
3-
{% load static %}
4+
45
<head>
5-
<title>VulnerableCode</title>
6+
<meta charset="utf-8">
7+
<meta name="viewport" content="width=device-width, initial-scale=1">
8+
<title>{% block title %}VulnerableCode.io{% endblock %}</title>
9+
<link rel="icon" href="{% static 'images/favicon.ico' %}" />
10+
11+
<link rel="stylesheet" href="{% static 'css/bulma.css' %}" />
12+
<link rel="stylesheet" href="{% static 'css/custom.css' %}" />
13+
<link rel="stylesheet" href="{% static 'css/font-awesome.css' %}" />
14+
<link rel="stylesheet" href="{% static 'css/bulma-tooltip.css' %}" />
15+
16+
{% block extrahead %}{% endblock %}
617
</head>
7-
<link rel="stylesheet" href="{% static 'css/bulma.css' %}"/>
8-
<link rel="stylesheet" href="{% static 'css/custom.css' %}"/>
9-
<link rel="stylesheet" href="{% static 'css/font-awesome.css' %}"/>
10-
<meta name="viewport" content="width=device-width, initial-scale=1">
18+
1119
<body class="Site">
12-
<nav class="navbar is-light" role="navigation" aria-label="main navigation">
13-
<div class="navbar-menu">
14-
<div class="navbar-start">
15-
<a class="navbar-item" href="{% url 'home' %}">
16-
Home
17-
</a>
18-
<a class="navbar-item" href="{% url 'redoc' %}">
19-
API Docs
20-
</a>
21-
<a class="navbar-item" href="{% url 'package_search' %}">
22-
Packages
23-
</a>
24-
<a class="navbar-item" href="{% url 'vulnerability_search' %}">
25-
Vulnerabilities
26-
</a>
20+
<div class="container max-desktop-width is-fullheight">
21+
{% block content %}{% endblock %}
22+
<script src="{% static 'js/main.js' %}" crossorigin="anonymous"></script>
23+
24+
<footer class="footer">
25+
<div class="content has-text-centered">
26+
<p>
27+
<strong>VulnerableCode</strong> is free software by <a href="https://github.com/nexB/vulnerablecode"> nexB Inc. and others</a>.
28+
The source code is licensed under <a href="https://github.com/nexB/vulnerablecode/blob/main/apache-2.0.LICENSE">Apache-2.0</a>.
29+
The data is licensed under <a href="https://github.com/nexB/vulnerablecode/blob/main/cc-by-sa-4.0.LICENSE">CC-BY-SA-4.0</a>.
30+
</p>
2731
</div>
28-
</div>
29-
</nav>
30-
<main class="Site-content">
31-
32-
<section class="section is-small has-text-centered">
33-
<div class="container ">
34-
{% block title %}
35-
{% endblock %}
36-
</div>
37-
</section>
38-
{% block content %}
39-
{% endblock %}
32+
</footer>
33+
</div>
34+
35+
{% block scripts %}
4036

41-
</main>
42-
<footer class="footer">
43-
<div class="content has-text-centered">
44-
<p>
45-
<strong>VulnerableCode</strong> is free software by <a href="https://github.com/nexB/vulnerablecode"> nexB Inc. and others</a>.
46-
The source code is licensed under <a href="https://github.com/nexB/vulnerablecode/blob/main/apache-2.0.LICENSE">Apache-2.0</a>.
47-
The data is licensed under <a href="https://github.com/nexB/vulnerablecode/blob/main/cc-by-sa-4.0.LICENSE">CC-BY-SA-4.0</a>.
48-
</p>
49-
</div>
50-
</footer>
37+
{% endblock %}
5138
</body>
52-
{% block javascript %}
53-
{% endblock %}
39+
5440
</html>
Lines changed: 155 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,161 @@
1-
{% extends 'base.html' %}
1+
{% extends "base.html" %}
2+
{% load widget_tweaks %}
23

34
{% block title %}
4-
<h1 class="title">
5-
Welcome to VulnerableCode!
6-
</h1>
5+
VCIO Home
76
{% endblock %}
87

98
{% block content %}
10-
<div class = "hero is-large has-text-centered">
11-
<a class="button is-medium has-background-light has-text-link" href="{% url 'vulnerability_search' %}"> Search Vulnerabilities</a>
12-
<a class="button is-medium has-background-light has-text-link" href="{% url 'package_search' %}"> Search Packages</a>
13-
</div>
9+
10+
{% include 'navbar.html' %}
11+
12+
<section class="section pt-0">
13+
<div class="columns">
14+
<div class="column is-size-4 has-text-weight-bold">
15+
Welcome to VulnerableCode<span class="nexb-orange">.</span>io.
16+
</div>
17+
</div>
18+
<article class='panel is-info'>
19+
<div class='panel-heading py-2 is-size-6'>
20+
Search for vulnerable packages
21+
<div class="dropdown is-hoverable has-text-weight-normal">
22+
<div class="dropdown-trigger">
23+
<i class="fa fa-question-circle ml-2"></i>
24+
</div>
25+
<div class="dropdown-menu dropdown-instructions-width" id="dropdown-menu4" role="menu">
26+
<div class="dropdown-content dropdown-instructions-box-shadow">
27+
<div class="dropdown-item">
28+
<div>
29+
<div>Search for currently known vulnerabilities for a <a href="https://github.com/package-url/purl-spec" target="_blank">Package-URL</a> (aka <span class="inline-code">purl</span>) or a package <span class="inline-code">name</span>.</div>
30+
<ul>
31+
<li>
32+
Search by package <span class="inline-code">name</span> -- type the <span class="inline-code">name</span> in the search box and, if relevant to your search, select the package <span class="inline-code">type</span> from the dropdown.
33+
</li>
34+
<li>
35+
Search by <span class="inline-code">purl</span> -- type the <span class="inline-code">purl</span> in the search box. <span class="is-italic">(The <span class="inline-code">type</span> dropdown does not apply to a <span class="inline-code">purl</span> search.)</span>
36+
</li>
37+
</ul>
38+
</div>
39+
</div>
40+
</div>
41+
</div>
42+
</div>
43+
</div>
44+
<div class="panel-block">
45+
<div class="pb-3 width-100-pct">
46+
<form action="{% url 'package_search' %}" method="get" name="pkg_form" onsubmit="return validatePkgForm()">
47+
<div class="field has-addons mt-3">
48+
<div class="control">
49+
<div class="select">
50+
{{ package_form.type }}
51+
</div>
52+
</div>
53+
<div class="control width-100-pct">
54+
{{ package_form.name|add_class:"input" }}
55+
</div>
56+
<div class="control">
57+
<button class="button is-link" type="submit" id="submit_pkg" name="template" value="index">
58+
Search
59+
</button>
60+
</div>
61+
</div>
62+
</form>
63+
<div>
64+
{% if package_search %}
65+
<div class="notification search-alert">
66+
<button class=" delete"></button>
67+
{{ package_search }}
68+
</div>
69+
{% endif %}
70+
</div>
71+
</div>
72+
</div>
73+
</article>
74+
75+
<div class="pt-5"></div>
76+
77+
<article class='panel is-info'>
78+
<div class='panel-heading py-2 is-size-6'>
79+
Search for vulnerabilities
80+
<div class="dropdown is-hoverable has-text-weight-normal">
81+
<div class="dropdown-trigger">
82+
<i class="fa fa-question-circle ml-2"></i>
83+
</div>
84+
<div class="dropdown-menu dropdown-instructions-width" id="dropdown-menu4" role="menu">
85+
<div class="dropdown-content dropdown-instructions-box-shadow">
86+
<div class="dropdown-item">
87+
<div>Search for comprehensive information for a <span class="inline-code">VULCOID</span> (VulnerableCode Database ID). <span class="is-italic">(Only the first of these methods requires that the input be all uppercase.)</span>
88+
<ul>
89+
<li>
90+
Search for a specific <span class="inline-code">VULCOID</span> (e.g., "VULCOID-1").
91+
</li>
92+
<li>
93+
Search for all <span class="inline-code">VULCOID</span>s that are associated with a specific <span class="inline-code">CVE</span> (e.g., "CVE-2009-3898") or <span class="inline-code">GHSA</span> (e.g., "GHSA-2qrg-x229-3v8q").
94+
</li>
95+
<li>
96+
Search for "CVE" or "GHSA" -- this will return all <span class="inline-code">VULCOID</span>s that are associated with one or more <span class="inline-code">CVE</span>s or <span class="inline-code">GHSA</span>s, respectively.
97+
</li>
98+
</ul>
99+
</div>
100+
</div>
101+
</div>
102+
</div>
103+
</div>
104+
</div>
105+
<div class="panel-block">
106+
<div class="pb-3 width-100-pct">
107+
<form action="{% url 'vulnerability_search' %}" method="get" name="vuln_form" onsubmit="return validateVulnForm()">
108+
<div class="field has-addons mt-3">
109+
<div class="control width-100-pct">
110+
{% render_field vuln_form.vuln_id class="input" %}
111+
</div>
112+
<div class="control">
113+
<button class="button is-link" type="submit" id="submit_vuln">
114+
Search
115+
</button>
116+
</div>
117+
</div>
118+
</form>
119+
<div>
120+
{% if vuln_search %}
121+
<div class="notification search-alert">
122+
<button class=" delete"></button>
123+
{{ vuln_search }}
124+
</div>
125+
{% endif %}
126+
</div>
127+
</div>
128+
</div>
129+
</article>
130+
</section>
131+
132+
{% endblock %}
133+
134+
{% block scripts %}
135+
<script>
136+
document.addEventListener('DOMContentLoaded', () => {
137+
(document.querySelectorAll('.notification .delete') || []).forEach(($delete) => {
138+
const $notification = $delete.parentNode;
139+
140+
$delete.addEventListener('click', () => {
141+
$notification.parentNode.removeChild($notification);
142+
});
143+
});
144+
});
145+
146+
function validatePkgForm() {
147+
var x = document.forms["pkg_form"]["name"].value;
148+
if (x.trim().length == "") {
149+
return false;
150+
}
151+
}
152+
153+
function validateVulnForm() {
154+
var x = document.forms["vuln_form"]["vuln_id"].value;
155+
if (x.trim().length == "") {
156+
return false;
157+
}
158+
}
159+
160+
</script>
14161
{% endblock %}

0 commit comments

Comments
 (0)