cpe 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/cpe/version.rb +1 -1
- data/lib/cpe.rb +122 -100
- data/test/test_cpe.rb +36 -28
- metadata +2 -2
data/lib/cpe/version.rb
CHANGED
data/lib/cpe.rb
CHANGED
@@ -1,112 +1,134 @@
|
|
1
|
-
#
|
1
|
+
# Public: CPE is a lightweight library built to simplify working with the
|
2
|
+
# Common Platform Enumeration spec managed by Mitre. See http://cpe.mitre.org/
|
3
|
+
# for further details.
|
2
4
|
#
|
3
|
-
#
|
4
|
-
# Expectr is freely distributable under the terms of an MIT-style license.
|
5
|
-
# See LICENSE.txt or http://www.opensource.org/licenses/mit-license.php.
|
5
|
+
# Examples
|
6
6
|
#
|
7
|
-
|
8
|
-
#
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
class KeyError < IndexError
|
14
|
-
def initialize message = nil
|
15
|
-
super message || "Key not found"
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
# == Description
|
21
|
-
# Cpe is a small library built to simplify working with the Common Platform
|
22
|
-
# Enumeration spec managed by Mitre. See http://cpe.mitre.org/ for further
|
23
|
-
# details.
|
7
|
+
# # Parse a CPE string
|
8
|
+
# cpe = Cpe.parse("cpe:/o:microsoft:windows_xp:::pro")
|
9
|
+
# cpe.vendor
|
10
|
+
# # => "microsoft"
|
11
|
+
# cpe.language
|
12
|
+
# # => ""
|
24
13
|
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
# cpe = Cpe.parse "cpe:/o:microsoft:windows_xp:::pro"
|
29
|
-
# cpe.vendor # => "microsoft"
|
30
|
-
# cpe.generate # => "cpe:/o:microsoft:windows_xp:::pro:"
|
31
|
-
#
|
32
|
-
# === Generating CPE string
|
33
|
-
# cpe = Cpe.new :part => Cpe::OS
|
14
|
+
# # Generate a CPE String
|
15
|
+
# cpe = Cpe.new(part: Cpe::OS)
|
34
16
|
# cpe.vendor = "microsoft"
|
35
17
|
# cpe.product = "windows_xp"
|
36
|
-
# cpe.
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
18
|
+
# cpe.language = "en_US"
|
19
|
+
# cpe.generate # => "cpe:/o:microsoft:windows_xp::::en_US"
|
20
|
+
class CPE
|
21
|
+
# Public: Gets/sets the part type String. Can be '/o' (Cpe::OS),
|
22
|
+
# '/a' (Cpe::Application), or '/h' (Cpe::Hardware)
|
23
|
+
attr_accessor :part
|
24
|
+
# Public: Gets/sets the vendor String
|
25
|
+
attr_accessor :vendor
|
26
|
+
# Public: Gets/sets the product String
|
27
|
+
attr_accessor :product
|
28
|
+
# Public: Gets/sets the version String
|
29
|
+
attr_accessor :version
|
30
|
+
# Public: Gets/sets the Update or patch level String
|
31
|
+
attr_accessor :update
|
32
|
+
# Public: Gets/sets the part edition String
|
33
|
+
attr_accessor :edition
|
34
|
+
# Public: Gets/sets the language String
|
35
|
+
attr_accessor :language
|
52
36
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
raise ArgumentError unless args.kind_of? Hash
|
60
|
-
raise ArgumentError unless /\/[oah]/.match args[:part].to_s or args[:part].nil?
|
61
|
-
@part = args[:part] || ""
|
62
|
-
@vendor = args[:vendor] || ""
|
63
|
-
@product = args[:product] || ""
|
64
|
-
@version = args[:version] || ""
|
65
|
-
@update = args[:update] || ""
|
66
|
-
@edition = args[:edition] || ""
|
67
|
-
@language = args[:language] || ""
|
68
|
-
end
|
37
|
+
# Public: String to give easier readability for "/o"
|
38
|
+
OS = "/o"
|
39
|
+
# Public: String to give easier readability for "/a"
|
40
|
+
Application = "/a"
|
41
|
+
# Public: String to give easier readability for "/h"
|
42
|
+
Hardware = "/h"
|
69
43
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
44
|
+
# Public: Initialize a new CPE Object, initializing all relevent variables to
|
45
|
+
# passed values, or else an empty string. Part must be one of CPE::OS,
|
46
|
+
# CPE::Application, CPE::Hardware, or else be nil.
|
47
|
+
#
|
48
|
+
# args - Hash containing values to set the CPE (default: {}):
|
49
|
+
# :part - String describing the part. Must be one of CPE::OS,
|
50
|
+
# CPE::Application or CPE::Hardware, or nil.
|
51
|
+
# :vendor - String containing the name of the vendor of the part.
|
52
|
+
# :product - String containing the name of the part described by the
|
53
|
+
# CPE.
|
54
|
+
# :version - String containing the version of the part.
|
55
|
+
# :update - String describing the update/patch level of the part.
|
56
|
+
# :edition - String containing any relevant edition text for the
|
57
|
+
# part.
|
58
|
+
# :language - String describing the language the part targets.
|
59
|
+
#
|
60
|
+
# Raises ArgumentError if anything other than a Hash is passed.
|
61
|
+
# Raises ArgumentError if anything but '/o', '/a', or '/h' are set as the
|
62
|
+
# part.
|
63
|
+
def initialize(args={})
|
64
|
+
raise ArgumentError unless args.kind_of?(Hash)
|
65
|
+
unless /\/[oah]/.match(args[:part].to_s) || args[:part].nil?
|
66
|
+
raise ArgumentError
|
67
|
+
end
|
79
68
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
69
|
+
@part = args[:part] || ""
|
70
|
+
@vendor = args[:vendor] || ""
|
71
|
+
@product = args[:product] || ""
|
72
|
+
@version = args[:version] || ""
|
73
|
+
@update = args[:update] || ""
|
74
|
+
@edition = args[:edition] || ""
|
75
|
+
@language = args[:language] || ""
|
76
|
+
end
|
86
77
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
78
|
+
# Public: Check that at least Part and one other piece of information have
|
79
|
+
# been set, and return generated CPE string.
|
80
|
+
#
|
81
|
+
# Returns a valid CPE string.
|
82
|
+
# Raises KeyError if the part specified is invalid.
|
83
|
+
# Raises KeyError if at least one piece of information is not set aside from
|
84
|
+
# the part type.
|
85
|
+
def generate
|
86
|
+
raise KeyError unless /\/[oah]/.match(@part.downcase)
|
87
|
+
if @vendor.to_s.empty? && @product.to_s.empty? && @version.to_s.empty? &&
|
88
|
+
@update.to_s.empty? && @edition.to_s.empty? && @language.to_s.empty?
|
89
|
+
raise KeyError
|
90
|
+
end
|
98
91
|
|
99
|
-
|
100
|
-
|
101
|
-
|
92
|
+
["cpe", @part, @vendor, @product, @version, @update, @edition,
|
93
|
+
@language].join(":").downcase
|
94
|
+
end
|
102
95
|
|
103
|
-
|
104
|
-
|
105
|
-
|
96
|
+
# Public: Test for equality of two CPE strings.
|
97
|
+
#
|
98
|
+
# cpe - CPE object to compare against, or String containing CPE data
|
99
|
+
#
|
100
|
+
# Returns a boolean value depending on whether the CPEs are equivalent.
|
101
|
+
# Raises ArgumentError if data passed isn't either a String or CPE Object.
|
102
|
+
def ==(cpe)
|
103
|
+
cpe = cpe.generate if cpe.kind_of?(CPE)
|
104
|
+
raise ArgumentError unless cpe.kind_of?(String)
|
106
105
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
#
|
112
|
-
|
106
|
+
self.generate == cpe
|
107
|
+
end
|
108
|
+
|
109
|
+
# Public: Parse a pre-existing CPE from a String or contained in a File.
|
110
|
+
# Attempt to be permissive regarding the number of trailing colons and
|
111
|
+
# whitespace.
|
112
|
+
#
|
113
|
+
# cpe - A String or File object containing the CPE string to parse.
|
114
|
+
#
|
115
|
+
# Returns a new CPE object.
|
116
|
+
# Raises ArgumentError if given anything other than a File or String object.
|
117
|
+
# Raises ArgumentError if the string doesn't begin with "cpe:" and a valid
|
118
|
+
# part type indicator.
|
119
|
+
def CPE.parse(cpe)
|
120
|
+
raise ArgumentError unless cpe.kind_of? String or cpe.kind_of? File
|
121
|
+
|
122
|
+
cpe = cpe.read if cpe.kind_of? File
|
123
|
+
cpe = cpe.to_s.downcase.strip
|
124
|
+
raise ArgumentError, "CPE malformed" unless /^cpe:\/[hoa]:/.match cpe and !/[\s\n]/.match cpe
|
125
|
+
|
126
|
+
data = Hash.new
|
127
|
+
discard, data[:part], data[:vendor], data[:product], data[:version],
|
128
|
+
data[:update], data[:edition], data[:language] = cpe.split(/:/, 8)
|
129
|
+
|
130
|
+
return self.new data
|
131
|
+
end
|
132
|
+
|
133
|
+
alias :to_s :generate
|
134
|
+
end
|
data/test/test_cpe.rb
CHANGED
@@ -1,55 +1,63 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
|
-
# CPE examples borrowed from CPE Spec document ver. 2.2
|
4
|
-
|
3
|
+
# CPE examples borrowed from CPE Spec document ver. 2.2:
|
4
|
+
# http://cpe.mitre.org/specification/
|
5
|
+
class TestCPE < Test::Unit::TestCase
|
5
6
|
def setup
|
6
7
|
@valid = "cpe:/o:microsoft:windows_xp:::pro"
|
7
8
|
@invalid = ["cpe::", "cpe://redhat:enterprise_linux:3::as", "cpe:/o:redhat:Enterprise Linux:3::", ":/o:redhat:enterprise_linux:3", 4]
|
8
9
|
end
|
9
10
|
|
10
11
|
def test_parse_valid
|
11
|
-
cpe =
|
12
|
-
assert_equal
|
13
|
-
assert_equal
|
14
|
-
assert_equal
|
15
|
-
assert_equal
|
16
|
-
assert_equal
|
17
|
-
assert_equal
|
18
|
-
assert_equal
|
12
|
+
cpe = CPE.parse(@valid)
|
13
|
+
assert_equal("/o", cpe.part)
|
14
|
+
assert_equal("microsoft", cpe.vendor)
|
15
|
+
assert_equal("windows_xp", cpe.product)
|
16
|
+
assert_equal("", cpe.version)
|
17
|
+
assert_equal("", cpe.update)
|
18
|
+
assert_equal("pro", cpe.edition)
|
19
|
+
assert_equal("", cpe.language)
|
19
20
|
end
|
20
21
|
|
21
22
|
def test_parse_invalid
|
22
23
|
@invalid.each do |cpe|
|
23
|
-
assert_raises(ArgumentError) {
|
24
|
+
assert_raises(ArgumentError) { CPE.parse(cpe) }
|
24
25
|
end
|
26
|
+
|
27
|
+
assert_raises(ArgumentError) { CPE.parse(1) }
|
25
28
|
end
|
26
29
|
|
27
30
|
def test_generation
|
28
|
-
cpe =
|
29
|
-
|
31
|
+
cpe = CPE.new(part: CPE::OS, vendor: "microsoft",
|
32
|
+
product: "windows_xp", edition: "pro")
|
33
|
+
assert_equal("cpe:/o:microsoft:windows_xp:::pro:", cpe.generate)
|
30
34
|
|
31
|
-
cpe =
|
32
|
-
|
35
|
+
cpe = CPE.new(part: CPE::Application, vendor: "ACME", product: "Product",
|
36
|
+
version: "1.0", update: "update2", edition: "-",
|
37
|
+
language: "en-us")
|
38
|
+
assert_equal("cpe:/a:acme:product:1.0:update2:-:en-us", cpe.generate)
|
33
39
|
|
34
|
-
cpe =
|
35
|
-
|
40
|
+
cpe = CPE.new(part: CPE::Hardware, vendor: "cisco", product: "router",
|
41
|
+
version: 3825)
|
42
|
+
assert_equal("cpe:/h:cisco:router:3825:::", cpe.generate)
|
36
43
|
|
37
|
-
assert_nothing_raised {
|
38
|
-
assert_raises(ArgumentError) {
|
44
|
+
assert_nothing_raised { CPE.parse(File.open('test/data/cpe-test-valid')) }
|
45
|
+
assert_raises(ArgumentError) { CPE.parse(File.open('test/data/cpe-test-invalid')) }
|
39
46
|
|
40
|
-
assert_raises(ArgumentError) {
|
41
|
-
assert_nothing_raised {
|
47
|
+
assert_raises(ArgumentError) { CPE.new(:part => 2) }
|
48
|
+
assert_nothing_raised { CPE.new }
|
42
49
|
|
43
|
-
assert_raises(KeyError) {
|
44
|
-
assert_raises(KeyError) {
|
45
|
-
assert_raises(KeyError) {
|
46
|
-
assert_nothing_raised {
|
50
|
+
assert_raises(KeyError) { CPE.new.generate }
|
51
|
+
assert_raises(KeyError) { CPE.new(part: CPE::OS).generate }
|
52
|
+
assert_raises(KeyError) { CPE.new(vendor: "redhat").generate }
|
53
|
+
assert_nothing_raised { CPE.new(vendor: "redhat", part: CPE::OS).generate }
|
47
54
|
end
|
48
55
|
|
49
56
|
def test_equality
|
50
|
-
cpe_a =
|
51
|
-
|
52
|
-
|
57
|
+
cpe_a = CPE.new(part: CPE::OS, vendor: "redhat",
|
58
|
+
product: "enterprise_linux", version: 3)
|
59
|
+
cpe_b = CPE.parse("cpe:/o:redhat:enterprise_linux:3")
|
60
|
+
cpe_c = CPE.parse(File.open('test/data/cpe-test-valid'))
|
53
61
|
|
54
62
|
assert_equal cpe_a, cpe_b
|
55
63
|
assert_equal cpe_a, cpe_c
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cpe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-10-
|
12
|
+
date: 2012-10-31 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Library for parsing and generating Common Platform Enumeration strings
|
15
15
|
(see http://cpe.mitre.org)
|