recog 3.1.1 → 3.1.2

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 (50) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/Gemfile +6 -0
  4. data/Rakefile +7 -5
  5. data/lib/recog/db.rb +67 -68
  6. data/lib/recog/db_manager.rb +22 -21
  7. data/lib/recog/fingerprint/regexp_factory.rb +10 -13
  8. data/lib/recog/fingerprint/test.rb +9 -8
  9. data/lib/recog/fingerprint.rb +252 -262
  10. data/lib/recog/fingerprint_parse_error.rb +3 -1
  11. data/lib/recog/formatter.rb +41 -39
  12. data/lib/recog/match_reporter.rb +82 -83
  13. data/lib/recog/matcher.rb +37 -40
  14. data/lib/recog/matcher_factory.rb +7 -6
  15. data/lib/recog/nizer.rb +218 -224
  16. data/lib/recog/verifier.rb +30 -28
  17. data/lib/recog/verify_reporter.rb +69 -73
  18. data/lib/recog/version.rb +3 -1
  19. data/lib/recog.rb +2 -0
  20. data/recog/bin/recog_match +21 -20
  21. data/recog/xml/apache_modules.xml +2 -0
  22. data/recog/xml/dhcp_vendor_class.xml +1 -1
  23. data/recog/xml/favicons.xml +133 -1
  24. data/recog/xml/ftp_banners.xml +1 -1
  25. data/recog/xml/html_title.xml +140 -1
  26. data/recog/xml/http_cookies.xml +20 -2
  27. data/recog/xml/http_servers.xml +38 -17
  28. data/recog/xml/http_wwwauth.xml +17 -4
  29. data/recog/xml/mdns_device-info_txt.xml +49 -15
  30. data/recog/xml/sip_banners.xml +0 -2
  31. data/recog/xml/sip_user_agents.xml +1 -1
  32. data/recog/xml/snmp_sysdescr.xml +1 -2
  33. data/recog/xml/ssh_banners.xml +8 -0
  34. data/recog/xml/telnet_banners.xml +3 -2
  35. data/recog/xml/tls_jarm.xml +1 -1
  36. data/recog/xml/x11_banners.xml +1 -0
  37. data/recog/xml/x509_issuers.xml +1 -1
  38. data/recog/xml/x509_subjects.xml +0 -1
  39. data/recog.gemspec +14 -13
  40. data/spec/lib/recog/db_spec.rb +37 -36
  41. data/spec/lib/recog/fingerprint/regexp_factory_spec.rb +19 -20
  42. data/spec/lib/recog/fingerprint_spec.rb +44 -42
  43. data/spec/lib/recog/formatter_spec.rb +20 -18
  44. data/spec/lib/recog/match_reporter_spec.rb +35 -30
  45. data/spec/lib/recog/nizer_spec.rb +85 -101
  46. data/spec/lib/recog/verify_reporter_spec.rb +45 -44
  47. data/spec/spec_helper.rb +2 -1
  48. data.tar.gz.sig +1 -3
  49. metadata +3 -3
  50. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: adbba4275e0d4b8b6c41541ea76d522529d17525f1f1fcce5147625d2a8adb59
4
- data.tar.gz: 71929660f907cd74dfcd3f74ea0f3761efd33992821333059b50e5e6e5d52629
3
+ metadata.gz: 06e7e85a8a5531bf315f482708ed3ada966be06efea9d09d85add533d098c2f9
4
+ data.tar.gz: e683dd6e7c529d95eef78cf1ebf32a19594449a2105593234860619393643aa0
5
5
  SHA512:
6
- metadata.gz: e37368c659cbeadbc38cd90e9a71b41825a02d2e060d88b19f06bab86f791474033b0a26c0481be4a89ab46dc9ddbc5f151241f45bdf96eeb0644edd19be548b
7
- data.tar.gz: c7d438651a3b40f1586793ce60d1589c00541fd8fe587e480d477af6f02618d013c2edd5afeafff010931aa495ef6c417ba980072c8667e5e41a1a25efe585c6
6
+ metadata.gz: 69bc3fe5c446de07ee4234f668293839c902eb7df8dbd89e5e5b410a8d43bcddecd4cda0d0acb513c3f262d6aa5496e3ade0a2ad4df02b724a6b5b21edc37f9c
7
+ data.tar.gz: 2fb2209fcc598a8a592e4f81ced771dc5520e4cb46f06277e8e9a47e3827f7d0f4d0348a6c41bb759eb538943e06694c3b1f34d04fe09c235ac375110c2cedb1
checksums.yaml.gz.sig CHANGED
Binary file
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  gemspec name: 'recog'
@@ -8,3 +10,7 @@ group :test do
8
10
  gem 'rake'
9
11
  gem 'regexp_parser'
10
12
  end
13
+
14
+ group :rubocop do
15
+ gem 'rubocop'
16
+ end
data/Rakefile CHANGED
@@ -1,15 +1,17 @@
1
- require "bundler/gem_tasks"
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
2
4
 
3
5
  require 'rspec/core/rake_task'
4
6
  RSpec::Core::RakeTask.new do |t|
5
- t.pattern = ['spec/**/*_spec.rb', 'recog/spec/**/*_spec.rb']
7
+ t.pattern = ['spec/**/*_spec.rb', 'recog/spec/**/*_spec.rb']
6
8
  end
7
9
 
8
10
  require 'yard'
9
11
  require 'yard/rake/yardoc_task'
10
12
  YARD::Rake::YardocTask.new do |t|
11
- t.files = ['lib/**/*.rb', '-', 'README.md']
13
+ t.files = ['lib/**/*.rb', '-', 'README.md']
12
14
  end
13
15
 
14
- task :default => [ :tests, :yard ]
15
- task :tests => [ :spec ]
16
+ task default: %i[tests yard]
17
+ task tests: [:spec]
data/lib/recog/db.rb CHANGED
@@ -1,79 +1,78 @@
1
- module Recog
2
-
3
- # A collection of {Fingerprint fingerprints} for matching against a particular
4
- # kind of fingerprintable data, e.g. an HTTP `Server` header
5
- class DB
6
- require 'nokogiri'
7
- require 'recog/fingerprint'
8
-
9
- # @return [String]
10
- attr_reader :path
11
-
12
- # @return [Array<Fingerprint>] {Fingerprint} objects that can be matched
13
- # against strings that make sense for the {#match_key}
14
- attr_reader :fingerprints
15
-
16
- # @return [String] Taken from the `fingerprints/matches` attribute, or
17
- # defaults to the basename of {#path} without the `.xml` extension.
18
- attr_reader :match_key
19
-
20
- # @return [String] Taken from the `fingerprints/protocol` attribute, or
21
- # defaults to an empty string
22
- attr_reader :protocol
23
-
24
- # @return [String] Taken from the `fingerprints/database_type` attribute
25
- # defaults to an empty string
26
- attr_reader :database_type
27
-
28
- # @return [Float] Taken from the `fingerprints/preference` attribute,
29
- # defaults to 0.10. Used when ordering databases, highest numbers
30
- # are given priority and are processed first.
31
- attr_reader :preference
32
-
33
- # Default Fingerprint database preference when it isn't specified in file
34
- # Do not use a value below 0.10 so as to allow users to specify lower
35
- # values in their own custom XML that will always run last.
36
- DEFAULT_FP_PREFERENCE = 0.10
37
-
38
- # @param path [String]
39
- def initialize(path)
40
- @match_key = nil
41
- @protocol = ''
42
- @database_type = ''
43
- @preference = DEFAULT_FP_PREFERENCE.to_f
44
- @path = path
45
- @fingerprints = []
46
-
47
- parse_fingerprints
48
- end
1
+ # frozen_string_literal: true
49
2
 
50
- # @return [void]
51
- def parse_fingerprints
52
- xml = nil
53
-
54
- File.open(self.path, 'rb') do |fd|
55
- xml = Nokogiri::XML(fd.read(fd.stat.size))
3
+ module Recog
4
+ # A collection of {Fingerprint fingerprints} for matching against a particular
5
+ # kind of fingerprintable data, e.g. an HTTP `Server` header
6
+ class DB
7
+ require 'nokogiri'
8
+ require 'recog/fingerprint'
9
+
10
+ # @return [String]
11
+ attr_reader :path
12
+
13
+ # @return [Array<Fingerprint>] {Fingerprint} objects that can be matched
14
+ # against strings that make sense for the {#match_key}
15
+ attr_reader :fingerprints
16
+
17
+ # @return [String] Taken from the `fingerprints/matches` attribute, or
18
+ # defaults to the basename of {#path} without the `.xml` extension.
19
+ attr_reader :match_key
20
+
21
+ # @return [String] Taken from the `fingerprints/protocol` attribute, or
22
+ # defaults to an empty string
23
+ attr_reader :protocol
24
+
25
+ # @return [String] Taken from the `fingerprints/database_type` attribute
26
+ # defaults to an empty string
27
+ attr_reader :database_type
28
+
29
+ # @return [Float] Taken from the `fingerprints/preference` attribute,
30
+ # defaults to 0.10. Used when ordering databases, highest numbers
31
+ # are given priority and are processed first.
32
+ attr_reader :preference
33
+
34
+ # Default Fingerprint database preference when it isn't specified in file
35
+ # Do not use a value below 0.10 so as to allow users to specify lower
36
+ # values in their own custom XML that will always run last.
37
+ DEFAULT_FP_PREFERENCE = 0.10
38
+
39
+ # @param path [String]
40
+ def initialize(path)
41
+ @match_key = nil
42
+ @protocol = ''
43
+ @database_type = ''
44
+ @preference = DEFAULT_FP_PREFERENCE.to_f
45
+ @path = path
46
+ @fingerprints = []
47
+
48
+ parse_fingerprints
56
49
  end
57
50
 
58
- raise "#{self.path} is invalid XML: #{xml.errors.join(',')}" unless xml.errors.empty?
51
+ # @return [void]
52
+ def parse_fingerprints
53
+ xml = nil
59
54
 
60
- xml.xpath('/fingerprints').each do |fbase|
55
+ File.open(path, 'rb') do |fd|
56
+ xml = Nokogiri::XML(fd.read(fd.stat.size))
57
+ end
61
58
 
62
- @match_key = fbase['matches'].to_s if fbase['matches']
63
- @protocol = fbase['protocol'].to_s if fbase['protocol']
64
- @database_type = fbase['database_type'].to_s if fbase['database_type']
65
- @preference = fbase['preference'].to_f if fbase['preference']
59
+ raise "#{path} is invalid XML: #{xml.errors.join(',')}" unless xml.errors.empty?
66
60
 
67
- end
61
+ xml.xpath('/fingerprints').each do |fbase|
62
+ @match_key = fbase['matches'].to_s if fbase['matches']
63
+ @protocol = fbase['protocol'].to_s if fbase['protocol']
64
+ @database_type = fbase['database_type'].to_s if fbase['database_type']
65
+ @preference = fbase['preference'].to_f if fbase['preference']
66
+ end
68
67
 
69
- filepath = self.path.sub(/\.xml$/, '')
70
- @match_key = File.basename(self.path).sub(/\.xml$/, '') unless @match_key
68
+ filepath = path.sub(/\.xml$/, '')
69
+ @match_key ||= File.basename(path).sub(/\.xml$/, '')
71
70
 
72
- xml.xpath('/fingerprints/fingerprint').each do |fprint|
73
- @fingerprints << Fingerprint.new(fprint, @match_key, @protocol, filepath)
74
- end
71
+ xml.xpath('/fingerprints/fingerprint').each do |fprint|
72
+ @fingerprints << Fingerprint.new(fprint, @match_key, @protocol, filepath)
73
+ end
75
74
 
76
- xml = nil
75
+ xml = nil
76
+ end
77
77
  end
78
78
  end
79
- end
@@ -1,31 +1,32 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Recog
2
- class DBManager
3
- require 'nokogiri'
4
- require 'recog/db'
4
+ class DBManager
5
+ require 'nokogiri'
6
+ require 'recog/db'
5
7
 
6
- attr_accessor :path, :databases
8
+ attr_accessor :path, :databases
7
9
 
8
- DefaultDatabasePath = File.expand_path(File.join(File.expand_path(__dir__), ["..", "..", "recog", "xml"]))
10
+ DefaultDatabasePath = File.expand_path(File.join(File.expand_path(__dir__), ['..', '..', 'recog', 'xml']))
9
11
 
10
- def initialize(path = DefaultDatabasePath)
11
- self.path = path
12
- reload
13
- end
12
+ def initialize(path = DefaultDatabasePath)
13
+ self.path = path
14
+ reload
15
+ end
14
16
 
15
- def load_databases
16
- if File.directory?(self.path)
17
- Dir[self.path + "/*.xml"].each do |dbxml|
18
- self.databases << DB.new(dbxml)
17
+ def load_databases
18
+ if File.directory?(path)
19
+ Dir["#{path}/*.xml"].each do |dbxml|
20
+ databases << DB.new(dbxml)
21
+ end
22
+ else
23
+ databases << DB.new(path)
19
24
  end
20
- else
21
- self.databases << DB.new(self.path)
22
25
  end
23
- end
24
26
 
25
- def reload
26
- self.databases = []
27
- load_databases
27
+ def reload
28
+ self.databases = []
29
+ load_databases
30
+ end
28
31
  end
29
-
30
- end
31
32
  end
@@ -1,14 +1,13 @@
1
+ # frozen_string_literal: true
1
2
 
2
3
  module Recog
3
4
  class Fingerprint
4
-
5
5
  #
6
6
  # @example
7
7
  # r = RegexpFactory.build("^Apache[ -]Coyote/(\d\.\d)$", "REG_ICASE")
8
8
  # r.match("Apache-Coyote/1.1")
9
9
  #
10
10
  module RegexpFactory
11
-
12
11
  # Currently, only options relating to case insensitivity and
13
12
  # multiline/newline are supported. Because Recog's data is used by tools
14
13
  # written in different languages like Ruby and Java, we currently support
@@ -19,13 +18,13 @@ module Recog
19
18
  # that use Recog data translate accordingly
20
19
  FLAG_MAP = {
21
20
  # multiline variations
22
- 'REG_DOT_NEWLINE' => Regexp::MULTILINE,
21
+ 'REG_DOT_NEWLINE' => Regexp::MULTILINE,
23
22
  'REG_LINE_ANY_CRLF' => Regexp::MULTILINE,
24
- 'REG_MULTILINE' => Regexp::MULTILINE,
23
+ 'REG_MULTILINE' => Regexp::MULTILINE,
25
24
  # case variations
26
- 'REG_ICASE' => Regexp::IGNORECASE,
27
- 'IGNORECASE' => Regexp::IGNORECASE
28
- }
25
+ 'REG_ICASE' => Regexp::IGNORECASE,
26
+ 'IGNORECASE' => Regexp::IGNORECASE
27
+ }.freeze
29
28
 
30
29
  DEFAULT_FLAGS = 0
31
30
 
@@ -42,15 +41,13 @@ module Recog
42
41
  # @param flags [Array<String>]
43
42
  # @return [Fixnum] Flags for creating a regular expression object
44
43
  def self.build_options(flags)
45
- unsupported_flags = flags.select { |flag| !FLAG_MAP.key?(flag) }
46
- unless unsupported_flags.empty?
47
- fail "Unsupported regular expression flags found: #{unsupported_flags.join(',')}. Must be one of: #{FLAG_MAP.keys.join(',')}"
48
- end
44
+ unsupported_flags = flags.reject { |flag| FLAG_MAP.key?(flag) }
45
+ raise "Unsupported regular expression flags found: #{unsupported_flags.join(',')}. Must be one of: #{FLAG_MAP.keys.join(',')}" unless unsupported_flags.empty?
46
+
49
47
  flags.reduce(DEFAULT_FLAGS) do |sum, flag|
50
- sum |= (FLAG_MAP[flag] || 0)
48
+ sum | (FLAG_MAP[flag] || 0)
51
49
  end
52
50
  end
53
51
  end
54
52
  end
55
53
  end
56
-
@@ -1,15 +1,16 @@
1
+ # frozen_string_literal: true
1
2
 
2
3
  class Recog::Fingerprint::Test
3
- attr_accessor :content
4
- attr_accessor :attributes
5
- def initialize(content, attributes=[])
4
+ attr_accessor :content, :attributes
5
+
6
+ def initialize(content, attributes = [])
6
7
  @attributes = attributes
7
8
 
8
- if @attributes['_encoding'] && @attributes['_encoding'] == 'base64'
9
- @content = content.to_s.unpack('m*').first
10
- else
11
- @content = content
12
- end
9
+ @content = if @attributes['_encoding'] && @attributes['_encoding'] == 'base64'
10
+ content.to_s.unpack1('m*')
11
+ else
12
+ content
13
+ end
13
14
  end
14
15
 
15
16
  def to_s