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.
Files changed (4) hide show
  1. data/lib/cpe/version.rb +1 -1
  2. data/lib/cpe.rb +122 -100
  3. data/test/test_cpe.rb +36 -28
  4. metadata +2 -2
data/lib/cpe/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class CPE
2
- VERSION = '0.3.1'
2
+ VERSION = '0.4.0'
3
3
  end
data/lib/cpe.rb CHANGED
@@ -1,112 +1,134 @@
1
- # = cpe.rb
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
- # Copyright (c) Chris Wuest <chris@chriswuest.com>
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
- # Fixes for Ruby pre-1.9
9
- if RUBY_VERSION =~ /^1.[^9]/
10
- #
11
- # Ruby does not implement KeyError before 1.9
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
- # == Examples
26
- # === Parsing CPE
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.generate # => "cpe:/o:microsoft:windows_xp::::"
37
- class Cpe
38
- # Part type. Can be /o (Cpe::OS), /a (Cpe::Application), /h (Cpe::Hardware)
39
- attr_accessor :part
40
- # Vendor
41
- attr_accessor :vendor
42
- # Product
43
- attr_accessor :product
44
- # Version
45
- attr_accessor :version
46
- # Update/patch level
47
- attr_accessor :update
48
- # Edition
49
- attr_accessor :edition
50
- # Language
51
- attr_accessor :language
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
- # Create a new Cpe object, initializing all relevent variables to known
55
- # values, or else an empty string. Part must be one of /o, /a, /h or else
56
- # be nil.
57
- #
58
- def initialize args={}
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
- # Check that at least Part and one other piece of information have been
72
- # collected, and return generated CPE string.
73
- #
74
- def generate
75
- raise KeyError unless /\/[oah]/.match @part
76
- raise KeyError if @vendor.to_s.empty? and @product.to_s.empty? and @version.to_s.empty? and @update.to_s.empty? and @edition.to_s.empty? and @language.to_s.empty?
77
- return ["cpe", @part, @vendor, @product, @version, @update, @edition, @language].join(":").downcase
78
- end
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
- # Test for equality of generated CPE strings
82
- def == cpe
83
- raise ArgumentError unless cpe.kind_of? Cpe
84
- self.generate == cpe.generate
85
- end
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
- # Parse pre-existing CPE string and return new Cpe object
89
- #
90
- # String parsing is permissive regarding the number of trailing colons and whitespace
91
- # provided, filling in empty strings if needed.
92
- #
93
- def Cpe.parse cpe
94
- raise ArgumentError unless cpe.kind_of? String or cpe.kind_of? File
95
- cpe = cpe.read if cpe.kind_of? File
96
- cpe = cpe.downcase.chomp
97
- raise ArgumentError, "CPE malformed" unless /^cpe:\/[hoa]:/.match cpe and !/[\s\n]/.match cpe
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
- data = Hash.new
100
- discard, data[:part], data[:vendor], data[:product], data[:version],
101
- data[:update], data[:edition], data[:language] = cpe.split(/:/, 8)
92
+ ["cpe", @part, @vendor, @product, @version, @update, @edition,
93
+ @language].join(":").downcase
94
+ end
102
95
 
103
- return self.new data
104
- end
105
- end
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
- # Variable for readability for "/o"
108
- Cpe::OS = "/o"
109
- # Variable for readability for "/a"
110
- Cpe::Application = "/a"
111
- # Variable for readability for "/h"
112
- Cpe::Hardware = "/h"
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
- class TestCpe < Test::Unit::TestCase
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 = Cpe.parse(@valid)
12
- assert_equal "/o", cpe.part
13
- assert_equal "microsoft", cpe.vendor
14
- assert_equal "windows_xp", cpe.product
15
- assert_equal "", cpe.version
16
- assert_equal "", cpe.update
17
- assert_equal "pro", cpe.edition
18
- assert_equal "", cpe.language
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) { Cpe.parse(cpe) }
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 = Cpe.new :part => Cpe::OS, :vendor => "microsoft", :product => "windows_xp", :edition => "pro"
29
- assert_equal cpe.generate, "cpe:/o:microsoft:windows_xp:::pro:"
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 = Cpe.new :part => Cpe::Application, :vendor => "ACME", :product => "Product", :version => "1.0", :update => "update2", :edition => "-", :language => "en-us"
32
- assert_equal cpe.generate, "cpe:/a:acme:product:1.0:update2:-:en-us"
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 = Cpe.new :part => Cpe::Hardware, :vendor => "cisco", :product => "router", :version => 3825
35
- assert_equal cpe.generate, "cpe:/h:cisco:router:3825:::"
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 { Cpe.parse File.open('test/data/cpe-test-valid') }
38
- assert_raises(ArgumentError) { Cpe.parse File.open('test/data/cpe-test-invalid') }
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) { Cpe.new :part => 2 }
41
- assert_nothing_raised { Cpe.new }
47
+ assert_raises(ArgumentError) { CPE.new(:part => 2) }
48
+ assert_nothing_raised { CPE.new }
42
49
 
43
- assert_raises(KeyError) { Cpe.new.generate }
44
- assert_raises(KeyError) { Cpe.new(:part => Cpe::OS).generate }
45
- assert_raises(KeyError) { Cpe.new(:vendor => "redhat").generate }
46
- assert_nothing_raised { Cpe.new(:vendor => "redhat", :part => Cpe::OS).generate }
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 = Cpe.new :part => Cpe::OS, :vendor => "redhat", :product => "enterprise_linux", :version => 3
51
- cpe_b = Cpe.parse "cpe:/o:redhat:enterprise_linux:3"
52
- cpe_c = Cpe.parse File.open('test/data/cpe-test-valid')
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.3.1
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-08 00:00:00.000000000 Z
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)