lib/cpe.rb in cpe-0.3.1 vs lib/cpe.rb in cpe-0.4.0

- old
+ new

@@ -1,112 +1,134 @@ -# = cpe.rb +# Public: CPE is a lightweight library built to simplify working with the +# Common Platform Enumeration spec managed by Mitre. See http://cpe.mitre.org/ +# for further details. # -# Copyright (c) Chris Wuest <chris@chriswuest.com> -# Expectr is freely distributable under the terms of an MIT-style license. -# See LICENSE.txt or http://www.opensource.org/licenses/mit-license.php. +# Examples # - -# Fixes for Ruby pre-1.9 -if RUBY_VERSION =~ /^1.[^9]/ - # - # Ruby does not implement KeyError before 1.9 - # - class KeyError < IndexError - def initialize message = nil - super message || "Key not found" - end - end -end - -# == Description -# Cpe is a small library built to simplify working with the Common Platform -# Enumeration spec managed by Mitre. See http://cpe.mitre.org/ for further -# details. +# # Parse a CPE string +# cpe = Cpe.parse("cpe:/o:microsoft:windows_xp:::pro") +# cpe.vendor +# # => "microsoft" +# cpe.language +# # => "" # -# == Examples -# === Parsing CPE -# -# cpe = Cpe.parse "cpe:/o:microsoft:windows_xp:::pro" -# cpe.vendor # => "microsoft" -# cpe.generate # => "cpe:/o:microsoft:windows_xp:::pro:" -# -# === Generating CPE string -# cpe = Cpe.new :part => Cpe::OS +# # Generate a CPE String +# cpe = Cpe.new(part: Cpe::OS) # cpe.vendor = "microsoft" # cpe.product = "windows_xp" -# cpe.generate # => "cpe:/o:microsoft:windows_xp::::" -class Cpe - # Part type. Can be /o (Cpe::OS), /a (Cpe::Application), /h (Cpe::Hardware) - attr_accessor :part - # Vendor - attr_accessor :vendor - # Product - attr_accessor :product - # Version - attr_accessor :version - # Update/patch level - attr_accessor :update - # Edition - attr_accessor :edition - # Language - attr_accessor :language +# cpe.language = "en_US" +# cpe.generate # => "cpe:/o:microsoft:windows_xp::::en_US" +class CPE + # Public: Gets/sets the part type String. Can be '/o' (Cpe::OS), + # '/a' (Cpe::Application), or '/h' (Cpe::Hardware) + attr_accessor :part + # Public: Gets/sets the vendor String + attr_accessor :vendor + # Public: Gets/sets the product String + attr_accessor :product + # Public: Gets/sets the version String + attr_accessor :version + # Public: Gets/sets the Update or patch level String + attr_accessor :update + # Public: Gets/sets the part edition String + attr_accessor :edition + # Public: Gets/sets the language String + attr_accessor :language - # - # Create a new Cpe object, initializing all relevent variables to known - # values, or else an empty string. Part must be one of /o, /a, /h or else - # be nil. - # - def initialize args={} - raise ArgumentError unless args.kind_of? Hash - raise ArgumentError unless /\/[oah]/.match args[:part].to_s or args[:part].nil? - @part = args[:part] || "" - @vendor = args[:vendor] || "" - @product = args[:product] || "" - @version = args[:version] || "" - @update = args[:update] || "" - @edition = args[:edition] || "" - @language = args[:language] || "" - end + # Public: String to give easier readability for "/o" + OS = "/o" + # Public: String to give easier readability for "/a" + Application = "/a" + # Public: String to give easier readability for "/h" + Hardware = "/h" - # - # Check that at least Part and one other piece of information have been - # collected, and return generated CPE string. - # - def generate - raise KeyError unless /\/[oah]/.match @part - 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? - return ["cpe", @part, @vendor, @product, @version, @update, @edition, @language].join(":").downcase - end + # Public: Initialize a new CPE Object, initializing all relevent variables to + # passed values, or else an empty string. Part must be one of CPE::OS, + # CPE::Application, CPE::Hardware, or else be nil. + # + # args - Hash containing values to set the CPE (default: {}): + # :part - String describing the part. Must be one of CPE::OS, + # CPE::Application or CPE::Hardware, or nil. + # :vendor - String containing the name of the vendor of the part. + # :product - String containing the name of the part described by the + # CPE. + # :version - String containing the version of the part. + # :update - String describing the update/patch level of the part. + # :edition - String containing any relevant edition text for the + # part. + # :language - String describing the language the part targets. + # + # Raises ArgumentError if anything other than a Hash is passed. + # Raises ArgumentError if anything but '/o', '/a', or '/h' are set as the + # part. + def initialize(args={}) + raise ArgumentError unless args.kind_of?(Hash) + unless /\/[oah]/.match(args[:part].to_s) || args[:part].nil? + raise ArgumentError + end - # - # Test for equality of generated CPE strings - def == cpe - raise ArgumentError unless cpe.kind_of? Cpe - self.generate == cpe.generate - end + @part = args[:part] || "" + @vendor = args[:vendor] || "" + @product = args[:product] || "" + @version = args[:version] || "" + @update = args[:update] || "" + @edition = args[:edition] || "" + @language = args[:language] || "" + end - # - # Parse pre-existing CPE string and return new Cpe object - # - # String parsing is permissive regarding the number of trailing colons and whitespace - # provided, filling in empty strings if needed. - # - def Cpe.parse cpe - raise ArgumentError unless cpe.kind_of? String or cpe.kind_of? File - cpe = cpe.read if cpe.kind_of? File - cpe = cpe.downcase.chomp - raise ArgumentError, "CPE malformed" unless /^cpe:\/[hoa]:/.match cpe and !/[\s\n]/.match cpe + # Public: Check that at least Part and one other piece of information have + # been set, and return generated CPE string. + # + # Returns a valid CPE string. + # Raises KeyError if the part specified is invalid. + # Raises KeyError if at least one piece of information is not set aside from + # the part type. + def generate + raise KeyError unless /\/[oah]/.match(@part.downcase) + if @vendor.to_s.empty? && @product.to_s.empty? && @version.to_s.empty? && + @update.to_s.empty? && @edition.to_s.empty? && @language.to_s.empty? + raise KeyError + end - data = Hash.new - discard, data[:part], data[:vendor], data[:product], data[:version], - data[:update], data[:edition], data[:language] = cpe.split(/:/, 8) + ["cpe", @part, @vendor, @product, @version, @update, @edition, + @language].join(":").downcase + end - return self.new data - end -end + # Public: Test for equality of two CPE strings. + # + # cpe - CPE object to compare against, or String containing CPE data + # + # Returns a boolean value depending on whether the CPEs are equivalent. + # Raises ArgumentError if data passed isn't either a String or CPE Object. + def ==(cpe) + cpe = cpe.generate if cpe.kind_of?(CPE) + raise ArgumentError unless cpe.kind_of?(String) -# Variable for readability for "/o" -Cpe::OS = "/o" -# Variable for readability for "/a" -Cpe::Application = "/a" -# Variable for readability for "/h" -Cpe::Hardware = "/h" + self.generate == cpe + end + + # Public: Parse a pre-existing CPE from a String or contained in a File. + # Attempt to be permissive regarding the number of trailing colons and + # whitespace. + # + # cpe - A String or File object containing the CPE string to parse. + # + # Returns a new CPE object. + # Raises ArgumentError if given anything other than a File or String object. + # Raises ArgumentError if the string doesn't begin with "cpe:" and a valid + # part type indicator. + def CPE.parse(cpe) + raise ArgumentError unless cpe.kind_of? String or cpe.kind_of? File + + cpe = cpe.read if cpe.kind_of? File + cpe = cpe.to_s.downcase.strip + raise ArgumentError, "CPE malformed" unless /^cpe:\/[hoa]:/.match cpe and !/[\s\n]/.match cpe + + data = Hash.new + discard, data[:part], data[:vendor], data[:product], data[:version], + data[:update], data[:edition], data[:language] = cpe.split(/:/, 8) + + return self.new data + end + + alias :to_s :generate +end