This repository has been archived by the owner on Dec 23, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
CVEList.java
298 lines (251 loc) · 9.57 KB
/
CVEList.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
package kamil.cve;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
public class CVEList {
static Logger log = LogManager.getLogger();
// timeout for webpage download in miliseconds
static final int TIMEOUT = 10000;
// URL definitions
private static final String url_search_prefix = "https://web.nvd.nist.gov/view/vuln/search-results?query=";
private static final String url_search_sufix = "&search_type=last3months&cves=on";
// CSS selectors
private static final String css_CVE_link = "div#searchResultsSection.searchResults dl dt a[href^=detail?vulnId=CVE-]";
private static final String css_Page_Navigator = "div.pageNavigator:nth-child(3)";
// Storage objects
private List<CVEListEntry> entries = new ArrayList<CVEListEntry>();
private LinkedHashMap<String,String> pageNavigatorButtons = new LinkedHashMap<String,String>();
// UI elements
private JFrame jf;
private JTextField searchField;
private JPanel pageNavigator;
private JList<DefaultListModel<String>> list;
private DefaultListModel<CVEListEntry> model;
private JScrollPane scrollPane;
// Action Listeners
private CVESearchButtonAL searchButtonAL = new CVESearchButtonAL(this);
private CVEListMouseAdapter mouseAdapter = new CVEListMouseAdapter();
/**
* Constructor of CVEList, which triggers GUI rendering after object is created.
*/
public CVEList(){
log.info("CVEList created!");
// Spawn GUI
createAndDisplayGUI();
}
/**
* Function creating and displaying initial GUI. It is run inside AWT Event Dispatcher thread.
*/
private void createAndDisplayGUI(){
// execute GUI creation in AWT Event Dispatcher thread
javax.swing.SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
log.info("Starting to draw GUI");
// create main frame
jf = new JFrame("CVE Explorer");
// search panel
JPanel searchPanel = new JPanel();
searchPanel.setLayout(new FlowLayout());
// search button
JButton searchButton = new JButton("Search");
searchButton.addActionListener(searchButtonAL);
// search field
searchField = new JTextField(30);
searchField.setText("Type in a product or vendor name");
searchField.setToolTipText("Type in search query and press search.");
// add search button and search field to search panel
searchPanel.add(searchField);
searchPanel.add(searchButton);
// create empty list
model = new DefaultListModel<CVEListEntry>();
list = new JList(model);
list.addMouseListener(mouseAdapter);
list.setCellRenderer(new CVEListEntryRenderer());
// put search list in scroll pane
scrollPane = new JScrollPane();
scrollPane.setViewportView(list);
scrollPane.setVisible(false);
// Page navigation panel
pageNavigator = new JPanel();
pageNavigator.setLayout(new FlowLayout());
// Add everything to main frame
jf.setLayout(new BorderLayout());
jf.getContentPane().add(searchPanel, BorderLayout.NORTH);
jf.getContentPane().add(scrollPane, BorderLayout.CENTER);
jf.getContentPane().add(pageNavigator, BorderLayout.SOUTH);
// Pack and display main frame
jf.pack();
jf.setVisible(true);
// Set default close action
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Bind default (enter key) button to Search button
jf.getRootPane().setDefaultButton(searchButton);
log.info("GUI created!");
}
});
}
/**
* This method executes a search query for given URL. It will try to download the page, parse it and finally trigger UI update.
* Each query is run is separate thread.
* @param url Full URL of website to fetch
*/
public void runSearch(String url){
Thread queryThread = new Thread() {
@Override
public void run() {
try {
log.info("Downloading: " + url);
Document page = Jsoup.connect(url).timeout(TIMEOUT).get();
log.info("Download complete. Paring...");
parse(page);
log.info("Parsing complete. Updating list...");
updateList();
log.info("List update complete.");
}
catch (IOException e){
log.error("Fetching failed for url: " + url + " " + e.getMessage());
log.error("Connection timed out.");
JOptionPane.showMessageDialog(new JFrame(), "Connection timed out for: " + url,"Connection timed out", JOptionPane.ERROR_MESSAGE);
}
catch (CVEParseException e){
log.error("Parsing failed for url: " + url + " " + e.getMessage());
JOptionPane.showMessageDialog(new JFrame(), "Parsing failed for: " + url,"Parsing failed", JOptionPane.ERROR_MESSAGE);
}
}
};
queryThread.start();
}
/**
* This method executes a search query for currently entered keywords in search box. It will try to download the page, parse it and finally trigger UI update.
* Each query is run is separate thread.
*
*/
public void runSearch(){
String url = url_search_prefix + searchField.getText()+ url_search_sufix;
log.info("Running search for newest entries. URL: " + url);
runSearch(url);
}
/**
* Parse received webpage and insert results to entries and pageNavigatorButtons.
* @param page Downloaded CVE search result webpage
* @throws CVEParseException Exception raised when parsing failed
*/
private void parse(Document page) throws CVEParseException{
log.debug("Clearing entries list and buttons list");
// Clear old entries
entries.clear();
log.info("Parsing CVE entries");
try {
// Find all CVE entries
Elements CVEs = page.select(css_CVE_link);
// Parse each found entry
for (Element CVE : CVEs){
String number = CVE.ownText();
// Set default values
String summary = "Not found";
String date = "Unknown date";
String score = "Unknown";
// get element containing CVE description
Element descriptionElement = CVE.parent().nextElementSibling();
// parse summary
Elements summaryElements = descriptionElement.select("span.label:matches(^Summary:");
if ( !summaryElements.isEmpty() ){
summary = summaryElements.first().parent().ownText();
log.debug("Found summary: " + summary);
}
// parse date
Elements dateElements = descriptionElement.select("span.label:matches(^Published:");
if ( !dateElements.isEmpty() ){
date = dateElements.first().parent().ownText();
log.debug("Found date: " + date);
}
// parse CVV score
Elements scoreElements = descriptionElement.select("span.label:matches(^CVSS Severity:");
if ( !scoreElements.isEmpty() ){
score = scoreElements.first().parent().ownText();
log.debug("Found score: " + score);
}
log.info("Parsed list element: " + number);
// add parsed data to storage variable
entries.add(new CVEListEntry(number,summary,score,date));
}
// clear old nav buttons data
pageNavigatorButtons.clear();
log.info("Parsing navigation panel");
// get element containing navigation buttons
Elements navPanel = page.select(css_Page_Navigator).first().children();
// parse each found button link
for (Element navButton : navPanel){
log.debug("Parsed navButton: " + navButton.ownText() + " " + navButton.attr("href") );
pageNavigatorButtons.put(navButton.ownText(),navButton.attr("href"));
}
log.info("Parsing complete");
}
catch (Exception e){
// Cleanup storage variables
entries.clear();
pageNavigatorButtons.clear();
// Rethrow exception as CVEParseException
throw new CVEParseException(e);
}
}
/**
* Update list view with data from entries and pageNavigatorButtons.
*/
public void updateList() {
log.info("Updating list.");
// create action listener for new buttons
CVEListNavButtonAL actionListener = new CVEListNavButtonAL(this,pageNavigatorButtons);
// execute GUI update in AWT Event Dispatcher thread
javax.swing.SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
// clear old list entries
model.clear();
// clear old page buttons
pageNavigator.removeAll();
// hide list in case of update failure
scrollPane.setVisible(false);
log.debug("List cleared. Adding new entries.");
// based on stored data, create and add entry to the list
for (CVEListEntry entry : entries) {
log.debug("Adding " + entry + " to the list.");
model.addElement(entry);
}
// based on stored data, create and add navigation buttons
for (String key : pageNavigatorButtons.keySet()){
JButton newButton = new JButton(key);
// disable currently selected page button
if ( pageNavigatorButtons.get(key) == "" ){
newButton.setEnabled(false);
}
newButton.addActionListener(actionListener);
pageNavigator.add(newButton);
}
log.info("Adding complete. Refreshing window");
// redraw GUI
scrollPane.setVisible(true);
pageNavigator.revalidate();
jf.pack();
}
});
};
}