whois-parser-next 0.4.9 → 0.4.10

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a5663fd18a8e122c6ccc8085b25e18be3b61fab9ff9cbd9bda64cdefbf2e10f5
4
- data.tar.gz: a34398419d706543bf070bfa3edda47c501b06cb9ac0452c8e18c0c11d414204
3
+ metadata.gz: 9e023caaec0b71465576d51e1aab35e0fa956f22fe435c9ebe91e7eae29e0d18
4
+ data.tar.gz: e90fe07318d7c90413f88ba7201eade76e7fc8ada882da016f1bcfb9574bc68e
5
5
  SHA512:
6
- metadata.gz: 2ae5c942ba61ee7143b6eec11d41d33b16f0a13046b8c1c150be040fbcedc377fea3580caeab8a8bce22b063e7d09c8f6fa7436056dd1240e17250670478dfcc
7
- data.tar.gz: '089dfc0682b7bee5730c452b7ffb7b4e9022b3b82cea695f0ac6532d789c052cf2eead16de4d8ca6f651f9909b2f4e9ac34f80f2f2f7bab9e4bd43d69d66c1d2'
6
+ metadata.gz: 2a55f20c2508a3a06d2a704e255532940ddf67b7ae3c9249b1a893b60c1f664c56ddd497aeac46cb1e14b4f6a9a8576db3411d318f768504027f0131916232c2
7
+ data.tar.gz: 3bd083076d0699b8520cd1cd232f09a8c755dcd33192198d7512974f44d73c50044201e34a919eb617c6132079710628c4fa3069e4306b4754292fbc8446f406
data/CHANGELOG.md CHANGED
@@ -2,6 +2,24 @@
2
2
 
3
3
  This project uses [Semantic Versioning 2.0.0](http://semver.org/).
4
4
 
5
+ #### Release 0.4.10 (2026-11-02)
6
+
7
+ - SAFETY: A response no longer keeps a scanner looping forever. A reply cut
8
+ off right after a disclaimer or notice header, with no final newline (for
9
+ example a Verisign body of just `TERMS OF USE:`, or the CIRA, `.ie`, ATI,
10
+ SX, PIR and configured Afilias disclaimers), made the tokenizer report
11
+ success without consuming input, so parsing never finished. The scanner now
12
+ raises `Whois::ParserError` when tokens stop consuming input, while still
13
+ allowing the short in-place state changes some scanners use to close a
14
+ section.
15
+ - SAFETY: The `whois.iana.org` scanner matches repeated field keys literally.
16
+ A key taken from the response was used as a regular expression, so a key
17
+ such as `()|^` matched without consuming input and looped forever. Contact
18
+ handles in the `.fr`-family, `.br` and `.ua` parsers are also matched
19
+ literally instead of as patterns.
20
+ - TESTED: `spec/whois/scanners/progress_spec.rb` covers each truncated
21
+ prefix and the regex-shaped IANA keys under a deadline.
22
+
5
23
  #### Release 0.4.9 (2026-10-25)
6
24
 
7
25
  - ADDED: Added `registrar`, `registrant_contacts` and `technical_contacts` to
@@ -1,6 +1,6 @@
1
1
  module Whois
2
2
  class Parser
3
3
  # The current library version.
4
- VERSION = "0.4.9".freeze
4
+ VERSION = "0.4.10".freeze
5
5
  end
6
6
  end
@@ -117,7 +117,7 @@ module Whois
117
117
  return unless content_for_scanner =~ /#{element}:\s+(.+)\n/
118
118
 
119
119
  id = ::Regexp.last_match(1)
120
- content_for_scanner.scan(/nic-hdl:\s+#{id}\n((.+\n)+)\n/).any? ||
120
+ content_for_scanner.scan(/nic-hdl:\s+#{Regexp.escape(id)}\n((.+\n)+)\n/).any? ||
121
121
  Whois::Parser.bug!(ParserError, "Unable to parse contact block for nic-hdl: #{id}")
122
122
  values = build_hash(::Regexp.last_match(1).scan(/(.+?):\s+(.+?)\n/))
123
123
 
@@ -96,7 +96,7 @@ module Whois
96
96
  return unless content_for_scanner =~ /#{element}:\s+(.+)\n/
97
97
 
98
98
  id = ::Regexp.last_match(1)
99
- content_for_scanner.scan(/nic-hdl-br:\s+#{id}\n((.+\n)+)\n/).any? ||
99
+ content_for_scanner.scan(/nic-hdl-br:\s+#{Regexp.escape(id)}\n((.+\n)+)\n/).any? ||
100
100
  Whois.bug!(ParserError, "Unable to parse contact block for nic-hdl-br: #{id}")
101
101
  values = build_hash(::Regexp.last_match(1).scan(/(.+?):\s+(.+?)\n/))
102
102
 
@@ -65,7 +65,7 @@ module Whois
65
65
  return if contact_ids.empty?
66
66
 
67
67
  contact_ids.map do |contact_id|
68
- textblock = content.slice(/contact-id:\s+#{contact_id}\n((?:.+\n)+)\n/, 1)
68
+ textblock = content.slice(/contact-id:\s+#{Regexp.escape(contact_id)}\n((?:.+\n)+)\n/, 1)
69
69
 
70
70
  address = textblock.scan(/address:\s+(.+)\n/).flatten
71
71
  address = address.reject { |a| a == "n/a" }
@@ -137,7 +137,7 @@ module Whois
137
137
  return if contact_ids.empty?
138
138
 
139
139
  contact_ids.map do |contact_id|
140
- textblock = content.slice(/nic-handle:\s+#{contact_id}\n((?:.+\n)+)\n/, 1)
140
+ textblock = content.slice(/nic-handle:\s+#{Regexp.escape(contact_id)}\n((?:.+\n)+)\n/, 1)
141
141
 
142
142
  address = textblock.scan(/address:\s+(.+)\n/).flatten
143
143
  zip = nil
@@ -6,6 +6,9 @@ module Whois
6
6
  class_attribute :tokenizers
7
7
  self.tokenizers = []
8
8
 
9
+ # Consecutive tokens allowed to succeed without consuming input.
10
+ MAX_IDLE_TOKENS = 100
11
+
9
12
  def self.tokenizer(name, &block)
10
13
  define_method(name, &block)
11
14
  end
@@ -26,7 +29,21 @@ module Whois
26
29
  @ast = {}
27
30
 
28
31
  @input = StringScanner.new(content)
29
- tokenize until @input.eos?
32
+ idle = 0
33
+ until @input.eos?
34
+ position = @input.pos
35
+ tokenize
36
+ if @input.pos == position
37
+ # Some tokenizers succeed once without consuming input to change
38
+ # state (e.g. close a section) for the next one. One that keeps
39
+ # succeeding in place loops forever, e.g. a disclaimer header matched
40
+ # by lookahead in a reply truncated before its final newline.
41
+ idle += 1
42
+ unexpected_token if idle > MAX_IDLE_TOKENS
43
+ else
44
+ idle = 0
45
+ end
46
+ end
30
47
 
31
48
  @ast
32
49
  end
@@ -79,7 +79,9 @@ module Whois
79
79
  end
80
80
 
81
81
  def parse_section_pair_newlinevalue(key)
82
- if @input.scan(/^#{key}:\s*(.+)\n/)
82
+ # The key comes from the response: match it literally. As a pattern, a
83
+ # key such as "()|^" matches without consuming input and loops forever.
84
+ if @input.scan(/^#{Regexp.escape(key)}:\s*(.+)\n/)
83
85
  @input[1].strip
84
86
  end
85
87
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: whois-parser-next
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.9
4
+ version: 0.4.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simone Carletti