cve_crawler 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/cve_crawler/cve_core.rb +42 -0
- data/lib/cve_crawler/cve_crawler.rb +37 -0
- data/lib/cve_crawler/cve_filter.rb +35 -0
- data/lib/cve_crawler/cve_parser.rb +74 -0
- data/lib/cve_crawler/cve_vulnerability.rb +62 -0
- data/spec/crawler_spec.rb +15 -0
- data/spec/filter_spec.rb +19 -0
- data/spec/parser_spec.rb +38 -0
- data/spec/spec_helper.rb +84 -0
- data/spec/vulnerability_spec.rb +137 -0
- metadata +54 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9c5c9a85897586ed3cf7cc66e9e97b9b7b09269b
|
4
|
+
data.tar.gz: 14af3dafda87aef7f5697c5d0b080036a9dc2488
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 272da0467bb4e39f284a810e6d304929cb12085cb57e838387e6d2042613f75541b1ba8af882d004ef7bfc7be0c377dde054732d373488cb8f5fc0dd3e1a891c
|
7
|
+
data.tar.gz: d319e15080382fec62bf9a36452b94b35c0f9969687fcd19a23e45c29639e28b83b8733defce524cb347cee7c7a9c78a405b8faae4b9f4dbe49b77e4b3a0d8b6
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'time'
|
2
|
+
require 'cve_crawler'
|
3
|
+
require 'cve_parser'
|
4
|
+
|
5
|
+
module CVE
|
6
|
+
VERSION_MAJOR = 0
|
7
|
+
VERSION_MINOR = 1
|
8
|
+
VERSION_BUILD = 0
|
9
|
+
VERSION = "#{VERSION_MAJOR}.#{VERSION_MINOR}.#{VERSION_BUILD}".freeze
|
10
|
+
|
11
|
+
class Core
|
12
|
+
def initialize(crawl_type='default', verify_cert=true, user_agent=nil, filters=nil)
|
13
|
+
unless user_agent
|
14
|
+
user_agent = create_user_agent
|
15
|
+
end
|
16
|
+
|
17
|
+
@crawler = Crawler.new(crawl_type, verify_cert, user_agent)
|
18
|
+
@parser = Parser.new(filters)
|
19
|
+
end
|
20
|
+
|
21
|
+
def fetch
|
22
|
+
body = crawl.body
|
23
|
+
parse(body)
|
24
|
+
end
|
25
|
+
|
26
|
+
def crawl
|
27
|
+
@crawler.crawl
|
28
|
+
end
|
29
|
+
|
30
|
+
def parse(data)
|
31
|
+
@parser.parse(data)
|
32
|
+
end
|
33
|
+
|
34
|
+
def create_user_agent
|
35
|
+
'RubyCVECrawler/' + VERSION + ' (https://github.com/zarthus/ruby-cve-crawler)'
|
36
|
+
end
|
37
|
+
|
38
|
+
def inspect
|
39
|
+
"<CVE::Core crawler=#{@crawler.inspect} parser=#{@parser.inspect}>"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'net/https'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
module CVE
|
5
|
+
class Crawler
|
6
|
+
DATA_FEED_DEFAULT = URI('https://nvd.nist.gov/download/nvd-rss.xml')
|
7
|
+
DATA_FEED_ANALYZED = URI('https://nvd.nist.gov/download/nvd-rss-analyzed.xml')
|
8
|
+
|
9
|
+
def initialize(type, verify_cert, user_agent)
|
10
|
+
@crawl_url = type.downcase == 'analyzed' ? DATA_FEED_ANALYZED : DATA_FEED_DEFAULT
|
11
|
+
@verify_cert = verify_cert ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
|
12
|
+
@user_agent = user_agent
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :crawl_url, :verify_cert, :user_agent
|
16
|
+
|
17
|
+
def crawl
|
18
|
+
http = Net::HTTP.new(@crawl_url.host, @crawl_url.port)
|
19
|
+
http.use_ssl = @crawl_url.scheme == 'https'
|
20
|
+
|
21
|
+
if http.use_ssl?
|
22
|
+
http.verify_mode = @verify_cert
|
23
|
+
end
|
24
|
+
|
25
|
+
request = Net::HTTP::Get.new(@crawl_url, {'User-Agent' => @user_agent})
|
26
|
+
response = http.request(request)
|
27
|
+
|
28
|
+
response.value # Raise an error if status is not 200
|
29
|
+
|
30
|
+
response
|
31
|
+
end
|
32
|
+
|
33
|
+
def inspect
|
34
|
+
"#<CVE::Crawler url=#{@crawl_url.to_s}>"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module CVE
|
2
|
+
class Filter
|
3
|
+
def initialize(history_size=100)
|
4
|
+
@history = []
|
5
|
+
@history_size = history_size
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :history_size
|
9
|
+
|
10
|
+
def filter(contents)
|
11
|
+
return true unless contents.is_a?(Vulnerability)
|
12
|
+
return true if cve_exists?(contents.identifier)
|
13
|
+
|
14
|
+
history_check_limit
|
15
|
+
false
|
16
|
+
end
|
17
|
+
|
18
|
+
def cve_exists?(identifier)
|
19
|
+
return true if @history.include?(identifier)
|
20
|
+
|
21
|
+
@history << identifier
|
22
|
+
false
|
23
|
+
end
|
24
|
+
|
25
|
+
def history_check_limit
|
26
|
+
if @history.length >= @history_size
|
27
|
+
@history.drop((@history_size / 2).round)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def inspect
|
32
|
+
"#<CVE::Filter history=#{@history.count} limit=#{@history_size}>"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'rss'
|
2
|
+
require 'cve_filter'
|
3
|
+
require 'cve_vulnerability'
|
4
|
+
|
5
|
+
module CVE
|
6
|
+
class Parser
|
7
|
+
def initialize(filters=nil)
|
8
|
+
@filters = []
|
9
|
+
|
10
|
+
@filters << CVE::Filter.new
|
11
|
+
@filters << filters if filters
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse(content)
|
15
|
+
results = parse_rss_feed(content)
|
16
|
+
|
17
|
+
filter(results)
|
18
|
+
end
|
19
|
+
|
20
|
+
def parse_rss_feed(content)
|
21
|
+
rss = RSS::Parser.parse(content)
|
22
|
+
|
23
|
+
parse_items(rss)
|
24
|
+
end
|
25
|
+
|
26
|
+
def parse_items(rss)
|
27
|
+
items = []
|
28
|
+
|
29
|
+
if rss.nil?
|
30
|
+
raise 'RSS object failed to parse, is it valid XML?'
|
31
|
+
end
|
32
|
+
|
33
|
+
rss.items.each do |item|
|
34
|
+
items << parse_item(item)
|
35
|
+
end
|
36
|
+
|
37
|
+
items
|
38
|
+
end
|
39
|
+
|
40
|
+
def parse_item(item)
|
41
|
+
CVE::Vulnerability.new({
|
42
|
+
:identifier => extract_cve_identifier(item.title),
|
43
|
+
:title => item.title,
|
44
|
+
:link => item.link,
|
45
|
+
:description => item.description,
|
46
|
+
:date => item.date
|
47
|
+
})
|
48
|
+
end
|
49
|
+
|
50
|
+
def extract_cve_identifier(title)
|
51
|
+
title.split(' ')[0]
|
52
|
+
end
|
53
|
+
|
54
|
+
def filter(results)
|
55
|
+
filtered_contents = []
|
56
|
+
|
57
|
+
results.each do |result|
|
58
|
+
result_ok = true
|
59
|
+
|
60
|
+
@filters.each do |filter|
|
61
|
+
result_ok = result_ok && !filter.filter(result)
|
62
|
+
end
|
63
|
+
|
64
|
+
filtered_contents << result if result_ok
|
65
|
+
end
|
66
|
+
|
67
|
+
filtered_contents
|
68
|
+
end
|
69
|
+
|
70
|
+
def inspect
|
71
|
+
"<CVE::Parser filters=#{@filters.inspect}>"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module CVE
|
2
|
+
class Vulnerability
|
3
|
+
SOFTWARE_EXTRACT_REGEXP = Regexp.new('[(, ]([^(), ]+)')
|
4
|
+
|
5
|
+
def initialize(data)
|
6
|
+
unless data.instance_of?(Hash)
|
7
|
+
raise 'CVE Vulnerability needs to be initialized with a hash'
|
8
|
+
end
|
9
|
+
|
10
|
+
if malformed?(data)
|
11
|
+
raise 'CVE Vulnerability data is malformed'
|
12
|
+
end
|
13
|
+
|
14
|
+
@identifier = data[:identifier]
|
15
|
+
@date = data[:date]
|
16
|
+
@description = data[:description]
|
17
|
+
@link = data[:link]
|
18
|
+
@title = data[:title]
|
19
|
+
@affected_software = extract_software_from_title(data[:title])
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :identifier, :date, :description, :link, :title, :affected_software
|
23
|
+
|
24
|
+
def malformed?(data)
|
25
|
+
!(data.has_key?(:identifier) && data.has_key?(:date) && data.has_key?(:description) &&
|
26
|
+
data.has_key?(:link) && data.has_key?(:title))
|
27
|
+
end
|
28
|
+
|
29
|
+
def extract_software_from_title(title)
|
30
|
+
software = []
|
31
|
+
|
32
|
+
title.scan(SOFTWARE_EXTRACT_REGEXP) do |scan|
|
33
|
+
software << scan[0]
|
34
|
+
end
|
35
|
+
|
36
|
+
software.count == 0 ? nil : software
|
37
|
+
end
|
38
|
+
|
39
|
+
def affected_count
|
40
|
+
@affected_software.nil? ? 0 : @affected_software.count
|
41
|
+
end
|
42
|
+
|
43
|
+
def equal?(cve_item, strict=false)
|
44
|
+
return false unless cve_item.is_a?(Vulnerability)
|
45
|
+
|
46
|
+
if strict
|
47
|
+
return @identifier == cve_item.identifier && @link == cve_item.link && @date.utc.iso8601 == cve_item.date.utc.iso8601 &&
|
48
|
+
@title == cve_item.title && @description == cve_item.description
|
49
|
+
end
|
50
|
+
|
51
|
+
@identifier == cve_item.identifier && @link == cve_item.link
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_s
|
55
|
+
"#{@title} - #{@link}"
|
56
|
+
end
|
57
|
+
|
58
|
+
def inspect
|
59
|
+
"#<CVE::Vulnerability id=#{@identifier} affected=#{affected_count}>"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe CVE::Crawler do
|
4
|
+
it 'should crawl the analyzed file when constructed with the analyzed type' do
|
5
|
+
crawler = CVE::Crawler.new('analyzed', false, false)
|
6
|
+
|
7
|
+
expect(crawler.crawl_url).to equal(CVE::Crawler::DATA_FEED_ANALYZED)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should crawl the default file when constructed any non-analyzed type' do
|
11
|
+
crawler = CVE::Crawler.new('anything', false, false)
|
12
|
+
|
13
|
+
expect(crawler.crawl_url).to equal(CVE::Crawler::DATA_FEED_DEFAULT)
|
14
|
+
end
|
15
|
+
end
|
data/spec/filter_spec.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe CVE::Filter do
|
4
|
+
it 'should filter repeated identifiers' do
|
5
|
+
filter = CVE::Filter.new
|
6
|
+
vulnerability = VulnerabilityMock.generate
|
7
|
+
|
8
|
+
expect(filter.filter(vulnerability)).to equal(false)
|
9
|
+
expect(filter.filter(vulnerability)).to equal(true)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should not filter different identifiers' do
|
13
|
+
filter = CVE::Filter.new
|
14
|
+
|
15
|
+
3.times do
|
16
|
+
expect(filter.filter(VulnerabilityMock.generate)).to equal(false)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/spec/parser_spec.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe CVE::Parser do
|
4
|
+
crawler_mock = CrawlerResultMock.new
|
5
|
+
parser = CVE::Parser.new
|
6
|
+
|
7
|
+
it 'should parse a full xml body with three items and return an array of CVE items' do
|
8
|
+
result = parser.parse(crawler_mock.xml_full)
|
9
|
+
|
10
|
+
expect(result).to be_a(Array)
|
11
|
+
expect(result.length).to eq(3)
|
12
|
+
|
13
|
+
all_cve_items = true
|
14
|
+
result.each do |value|
|
15
|
+
all_cve_items = all_cve_items && value.is_a?(CVE::Vulnerability)
|
16
|
+
end
|
17
|
+
|
18
|
+
expect(all_cve_items).to equal(true)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should raise an error when non-xml is passed' do
|
22
|
+
expect{ parser.parse('Not xml') }.to raise_error(RuntimeError)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should extract the CVE identifier from a title' do
|
26
|
+
title = VulnerabilityMock.new.title
|
27
|
+
|
28
|
+
expect(parser.extract_cve_identifier(title)).to match(/^CVE\-\d{4}\-\d+$/)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should accept a custom filter' do
|
32
|
+
CVE::Parser.new(CVE::Filter.new)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should accept an array of custom filters' do
|
36
|
+
CVE::Parser.new([CVE::Filter.new, CVE::Filter.new])
|
37
|
+
end
|
38
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require_relative File.join('..', 'lib', 'cve_crawler', 'cve_core')
|
3
|
+
|
4
|
+
class CrawlerResultMock
|
5
|
+
def xml_full
|
6
|
+
<<-eos
|
7
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
8
|
+
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://purl.org/rss/1.0/" xmlns:dc="http://purl.org/dc/elements/1.1/">
|
9
|
+
<channel rdf:about="http://web.nvd.nist.gov/view/vuln/search">
|
10
|
+
<title>National Vulnerability Database</title>
|
11
|
+
<link>http://web.nvd.nist.gov/view/vuln/search</link>
|
12
|
+
<description>This feed contains the most recent CVE cyber vulnerabilities published within the National Vulnerability Database.</description>
|
13
|
+
<items>
|
14
|
+
<rdf:Seq>
|
15
|
+
<rdf:li rdf:resource="http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2015-4476" />
|
16
|
+
<rdf:li rdf:resource="http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2015-4500" />
|
17
|
+
<rdf:li rdf:resource="http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2015-4501" />
|
18
|
+
</rdf:Seq>
|
19
|
+
</items>
|
20
|
+
<dc:date>2015-09-27T04:50:00Z</dc:date>
|
21
|
+
<dc:language>en-us</dc:language>
|
22
|
+
<dc:rights>This material is not copywritten and may be freely used, however, attribution is requested.</dc:rights>
|
23
|
+
</channel>
|
24
|
+
<item rdf:about="http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2015-4476">
|
25
|
+
<title>CVE-2015-4476 (firefox)</title>
|
26
|
+
<link>http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2015-4476</link>
|
27
|
+
<description>Mozilla Firefox before 41.0 on Android allows user-assisted remote attackers to spoof address-bar attributes by leveraging lack of navigation after a paste of a URL with a nonstandard scheme, as demonstrated by spoofing an SSL attribute.</description>
|
28
|
+
<dc:date>2015-09-24T04:59:00Z</dc:date>
|
29
|
+
</item>
|
30
|
+
<item rdf:about="http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2015-4500">
|
31
|
+
<title>CVE-2015-4500 (firefox, firefox_esr)</title>
|
32
|
+
<link>http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2015-4500</link>
|
33
|
+
<description>Multiple unspecified vulnerabilities in the browser engine in Mozilla Firefox before 41.0 and Firefox ESR 38.x before 38.3 allow remote attackers to cause a denial of service (memory corruption and application crash) or possibly execute arbitrary code via unknown vectors.</description>
|
34
|
+
<dc:date>2015-09-24T04:59:02Z</dc:date>
|
35
|
+
</item>
|
36
|
+
<item rdf:about="http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2015-4501">
|
37
|
+
<title>CVE-2015-4501 (firefox)</title>
|
38
|
+
<link>http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2015-4501</link>
|
39
|
+
<description>Multiple unspecified vulnerabilities in the browser engine in Mozilla Firefox before 41.0 allow remote attackers to cause a denial of service (memory corruption and application crash) or possibly execute arbitrary code via unknown vectors.</description>
|
40
|
+
<dc:date>2015-09-24T04:59:03Z</dc:date>
|
41
|
+
</item>
|
42
|
+
</rdf:RDF>
|
43
|
+
eos
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class VulnerabilityMock
|
48
|
+
def self.generate
|
49
|
+
mocker = VulnerabilityMock.new
|
50
|
+
id = mocker.identifier
|
51
|
+
|
52
|
+
CVE::Vulnerability.new({
|
53
|
+
:identifier => id,
|
54
|
+
:title => mocker.title(id),
|
55
|
+
:link => mocker.link(id),
|
56
|
+
:description => mocker.description,
|
57
|
+
:date => mocker.date
|
58
|
+
})
|
59
|
+
end
|
60
|
+
|
61
|
+
def identifier
|
62
|
+
year = Time.now.year
|
63
|
+
"CVE-#{rand(2000..year)}-#{rand(0..9999)}"
|
64
|
+
end
|
65
|
+
|
66
|
+
def title(id=nil)
|
67
|
+
(id || identifier) + ' (' + ['Lorem Ipsum', 'Some vulnerability', 'Your favourite software',
|
68
|
+
'Firefox', 'Chromium', 'Thunderbird'].sample.split('').shuffle.join + ')'
|
69
|
+
end
|
70
|
+
|
71
|
+
def link(id=nil)
|
72
|
+
'http://web.nvd.nist.gov/view/vuln/detail?vulnId=' + (id || identifier)
|
73
|
+
end
|
74
|
+
|
75
|
+
def description
|
76
|
+
['Hakuna Matata', 'What a wonderful phrase', 'Ain\'t no passing phrase', 'It means no worries',
|
77
|
+
'for the rest of your days', 'It\'s our problem-free philosophy', 'Yeah. That\'s our motto',
|
78
|
+
'What\'s a motto?'].sample.split('').shuffle.join
|
79
|
+
end
|
80
|
+
|
81
|
+
def date
|
82
|
+
Time.now
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe CVE::Vulnerability do
|
4
|
+
mocker = VulnerabilityMock.new
|
5
|
+
cve_vul_obj = VulnerabilityMock.generate
|
6
|
+
|
7
|
+
it 'should not error when passing a valid hash' do
|
8
|
+
id = mocker.identifier
|
9
|
+
|
10
|
+
item = CVE::Vulnerability.new({
|
11
|
+
:identifier => id,
|
12
|
+
:title => mocker.title(id),
|
13
|
+
:link => mocker.link(id),
|
14
|
+
:description => mocker.description,
|
15
|
+
:date => mocker.date
|
16
|
+
})
|
17
|
+
|
18
|
+
expect(item).to be_a(CVE::Vulnerability)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should compare to a CVE with the same identifier and link' do
|
22
|
+
id = mocker.identifier
|
23
|
+
link = mocker.link(id)
|
24
|
+
item = CVE::Vulnerability.new({
|
25
|
+
:identifier => id,
|
26
|
+
:title => mocker.title(id),
|
27
|
+
:link => link,
|
28
|
+
:description => mocker.description,
|
29
|
+
:date => mocker.date
|
30
|
+
})
|
31
|
+
|
32
|
+
item_roughly_identical = CVE::Vulnerability.new({
|
33
|
+
:identifier => id,
|
34
|
+
:title => mocker.title(id),
|
35
|
+
:link => link,
|
36
|
+
:description => mocker.description,
|
37
|
+
:date => mocker.date
|
38
|
+
})
|
39
|
+
|
40
|
+
expect(item.equal?(item_roughly_identical, false)).to equal(true)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should compare strictly to an identical CVE' do
|
44
|
+
id = mocker.identifier
|
45
|
+
item = CVE::Vulnerability.new({
|
46
|
+
:identifier => id,
|
47
|
+
:title => mocker.title(id),
|
48
|
+
:link => mocker.link(id),
|
49
|
+
:description => mocker.description,
|
50
|
+
:date => mocker.date
|
51
|
+
})
|
52
|
+
|
53
|
+
item_identical = item.clone
|
54
|
+
|
55
|
+
expect(item.equal?(item_identical, true)).to equal(true)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should fail compare strictly to an unidentical CVE with the same ID' do
|
59
|
+
id = mocker.identifier
|
60
|
+
item = CVE::Vulnerability.new({
|
61
|
+
:identifier => id,
|
62
|
+
:title => mocker.title(id),
|
63
|
+
:link => mocker.link(id),
|
64
|
+
:description => mocker.description,
|
65
|
+
:date => mocker.date
|
66
|
+
})
|
67
|
+
|
68
|
+
item_unidentical = CVE::Vulnerability.new({
|
69
|
+
:identifier => id,
|
70
|
+
:title => mocker.title(id),
|
71
|
+
:link => mocker.link(id),
|
72
|
+
:description => mocker.description,
|
73
|
+
:date => mocker.date
|
74
|
+
})
|
75
|
+
|
76
|
+
expect(item.equal?(item_unidentical, true)).to equal(false)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should fail compare to an unidentical CVE' do
|
80
|
+
id = mocker.identifier
|
81
|
+
item = CVE::Vulnerability.new({
|
82
|
+
:identifier => id,
|
83
|
+
:title => mocker.title(id),
|
84
|
+
:link => mocker.link(id),
|
85
|
+
:description => mocker.description,
|
86
|
+
:date => mocker.date
|
87
|
+
})
|
88
|
+
|
89
|
+
id = mocker.identifier
|
90
|
+
item_unidentical = CVE::Vulnerability.new({
|
91
|
+
:identifier => id,
|
92
|
+
:title => mocker.title(id),
|
93
|
+
:link => mocker.link(id),
|
94
|
+
:description => mocker.description,
|
95
|
+
:date => mocker.date
|
96
|
+
})
|
97
|
+
|
98
|
+
expect(item.equal?(item_unidentical, false)).to equal(false)
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'should be able to extract a single software from the title' do
|
102
|
+
title = 'CVE-2015-123 (firefox)'
|
103
|
+
extract = cve_vul_obj.extract_software_from_title(title)
|
104
|
+
|
105
|
+
expect(extract.count).to eq(1)
|
106
|
+
expect(extract[0]).to eq('firefox')
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'should be able to extract many software from the title' do
|
110
|
+
title = 'CVE-2015-123 (firefox, firefox_esr, flash)'
|
111
|
+
extract = cve_vul_obj.extract_software_from_title(title)
|
112
|
+
|
113
|
+
expect(extract.count).to eq(3)
|
114
|
+
expect(extract[0]).to eq('firefox')
|
115
|
+
expect(extract[1]).to eq('firefox_esr')
|
116
|
+
expect(extract[2]).to eq('flash')
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'should return nil for affected software when not included' do
|
120
|
+
title = 'CVE-2015-123'
|
121
|
+
extract = cve_vul_obj.extract_software_from_title(title)
|
122
|
+
|
123
|
+
expect(extract).to eq(nil)
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'should error when not passing a hash' do
|
127
|
+
expect{ CVE::Vulnerability.new('') }.to raise_error(RuntimeError)
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'should error when passing an empty hash' do
|
131
|
+
expect{ CVE::Vulnerability.new({}) }.to raise_error(RuntimeError)
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'should error when passing a hash with missing keys' do
|
135
|
+
expect{ CVE::Vulnerability.new({:identifier => 'abc', :title => 'title'}) }.to raise_error(RuntimeError)
|
136
|
+
end
|
137
|
+
end
|
metadata
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cve_crawler
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jos Ahrens
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-09-27 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: A periodic crawler that fetches the latest CVE additions, parses them,
|
14
|
+
and filters them
|
15
|
+
email: gems@zarth.us
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/cve_crawler/cve_core.rb
|
21
|
+
- lib/cve_crawler/cve_crawler.rb
|
22
|
+
- lib/cve_crawler/cve_filter.rb
|
23
|
+
- lib/cve_crawler/cve_parser.rb
|
24
|
+
- lib/cve_crawler/cve_vulnerability.rb
|
25
|
+
- spec/crawler_spec.rb
|
26
|
+
- spec/filter_spec.rb
|
27
|
+
- spec/parser_spec.rb
|
28
|
+
- spec/spec_helper.rb
|
29
|
+
- spec/vulnerability_spec.rb
|
30
|
+
homepage: https://github.com/zarthus/ruby-cve-crawler
|
31
|
+
licenses:
|
32
|
+
- MIT
|
33
|
+
metadata: {}
|
34
|
+
post_install_message:
|
35
|
+
rdoc_options: []
|
36
|
+
require_paths:
|
37
|
+
- lib
|
38
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
requirements: []
|
49
|
+
rubyforge_project:
|
50
|
+
rubygems_version: 2.4.5
|
51
|
+
signing_key:
|
52
|
+
specification_version: 4
|
53
|
+
summary: CVE Crawler
|
54
|
+
test_files: []
|