whois-parser-next 0.4.5 → 0.4.7
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 +4 -4
- data/CHANGELOG.md +52 -0
- data/lib/whois/parser/version.rb +1 -1
- data/lib/whois/parsers/whois.isoc.org.il.rb +13 -11
- data/lib/whois/parsers/whois.nic.ga.rb +64 -0
- data/lib/whois/parsers/whois.nic.net.jo.rb +41 -0
- data/lib/whois/parsers/whois.sx.rb +34 -1
- data/lib/whois/parsers/www.gt.rb +107 -0
- data/lib/whois/scanners/whois.nic.net.jo.rb +15 -0
- data/lib/whois/scanners/whois.sx.rb +5 -0
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bf39e6c3afbb1b6a0cb49c48cb3fb11cf6db7d0162aaba77c9027ca4d2fadc3f
|
|
4
|
+
data.tar.gz: 1134d08ab3b1bcef0551f8008c366234805614e86cbe02ffe90501f5203dae84
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: addd71819acd60b21142b60e419625ac8ebbed5b160b33e6cfe5562bcd064727e04b98c820f53bb98c1e1649158829b10b10d3c9ae7b900b47b25f57c1023043
|
|
7
|
+
data.tar.gz: 56a6dde832f4f0a9990e7753ea7f709a2bcba56d461d4eac0aa299bdd69b5896fd3b584647b6766267e621c4f6d52e42961a1fca1521c619b086f96f2dc80fcf
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,58 @@
|
|
|
2
2
|
|
|
3
3
|
This project uses [Semantic Versioning 2.0.0](http://semver.org/).
|
|
4
4
|
|
|
5
|
+
#### Release 0.4.7 (2026-10-19)
|
|
6
|
+
|
|
7
|
+
- ADDED: Added strict parsing for the official `.gt` and `.com.gt` web WHOIS
|
|
8
|
+
response. Registration requires one result heading with a single valid domain
|
|
9
|
+
and `ACTIVO`; absence requires one `alert alert-danger` result with the same
|
|
10
|
+
domain and the registry's exact `no está registrado` marker. Duplicate,
|
|
11
|
+
contradictory, malformed, mismatched, incomplete, denied, throttled, or
|
|
12
|
+
challenge responses remain non-positive. The parser ignores scripts, styles,
|
|
13
|
+
comments, and unrelated page content; contacts and dates are not parsed.
|
|
14
|
+
- EVIDENCE: The official UVG registry lookup is
|
|
15
|
+
[`whois.php?dn=...`](https://www.gt/sitio/whois.php?dn={domain}). Bounded
|
|
16
|
+
2026-10-19 observations returned registered results for `google.gt` and
|
|
17
|
+
`google.com.gt`, and exact absence results for generated eight-letter names
|
|
18
|
+
under both suffixes. The registry's
|
|
19
|
+
[policy](https://www.gt/sitio/registration_policy.php?lang=en) limits lookup
|
|
20
|
+
to individual names rather than lists of registered names. Regression
|
|
21
|
+
examples use only minimal synthetic HTML. This is a web WHOIS source; no
|
|
22
|
+
TCP/43 or RDAP service is claimed. See the
|
|
23
|
+
[dated evidence report](docs/audits/guatemala-web-whois-2026-10-19.md).
|
|
24
|
+
|
|
25
|
+
#### Release 0.4.6 (2026-10-19)
|
|
26
|
+
|
|
27
|
+
- ADDED: Added `.ga` parsing for ANINF's current French WHOIS response, requiring
|
|
28
|
+
one valid domain, `Statut: actif`, and a parseable creation date; absence
|
|
29
|
+
requires the exact `%% NOT FOUND` marker. Added `.jo` parsing for a single
|
|
30
|
+
valid domain with a creation date and `Domain Status: Active`; absence
|
|
31
|
+
requires the exact quoted-name `No match for domain` response and matching
|
|
32
|
+
echoed domain.
|
|
33
|
+
- UPDATED: `.sx` recognizes the current CIRA EPP statuses
|
|
34
|
+
`clientDeleteProhibited` and `clientTransferProhibited`, plus the exact
|
|
35
|
+
`Not found: <name>` absence response, while retaining its legacy format.
|
|
36
|
+
Duplicate, contradictory, malformed, or incomplete evidence remains
|
|
37
|
+
unknown; explicit denials and throttling remain blocked.
|
|
38
|
+
- SAFETY: `.il` no longer treats a missing status as absence. Production
|
|
39
|
+
registered and absent queries returned the same 790-byte disclaimer-only
|
|
40
|
+
reply without an absence marker. Absence now requires the exact
|
|
41
|
+
`% No data was found to match the request criteria.` marker; registration
|
|
42
|
+
requires one valid domain and one `Transfer Locked` or `Transfer Allowed`
|
|
43
|
+
status. Empty, denied, throttled, duplicate, mixed, or incomplete replies
|
|
44
|
+
remain unknown. This corrects false absence; `.il` coverage remains
|
|
45
|
+
unverified.
|
|
46
|
+
- EVIDENCE: Bounded production-host and managed-proxy checks on 2026-10-19 UTC
|
|
47
|
+
observed registered and absent replies for all three hosts. IANA lists
|
|
48
|
+
`whois.nic.net.jo` for [`.jo`](https://www.iana.org/domains/root/db/jo.html)
|
|
49
|
+
and `whois.sx` for [`.sx`](https://www.iana.org/domains/root/db/sx.html).
|
|
50
|
+
IANA has no WHOIS listing for `.ga`; ANINF's current [official
|
|
51
|
+
webWHOIS](https://whois.nic.ga/) and [registration
|
|
52
|
+
policy](https://www.mon.ga/policy/registry_policies.pdf) establish its provenance.
|
|
53
|
+
The `.ga` and `.sx` source terms restrict circulation or use of WHOIS data,
|
|
54
|
+
so the repository fixtures are synthetic technical-shape controls, not
|
|
55
|
+
copies of the captured replies. See the fixture README for details.
|
|
56
|
+
|
|
5
57
|
#### Release 0.4.5 (2026-10-18)
|
|
6
58
|
|
|
7
59
|
- ADDED: Added current CoCCA response parsing for `.bf`, `.td`, and `.mr`,
|
data/lib/whois/parser/version.rb
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
require_relative 'base'
|
|
11
|
+
require_relative 'registry_response_safety'
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
module Whois
|
|
@@ -25,19 +26,20 @@ module Whois
|
|
|
25
26
|
# and examples.
|
|
26
27
|
#
|
|
27
28
|
class WhoisIsocOrgIl < Base
|
|
29
|
+
include RegistryResponseSafety
|
|
28
30
|
|
|
29
31
|
property_supported :status do
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
when "transfer allowed"
|
|
35
|
-
:registered
|
|
36
|
-
else
|
|
37
|
-
Whois::Parser.bug!(ParserError, "Unknown status `#{::Regexp.last_match(1)}'.")
|
|
38
|
-
end
|
|
39
|
-
else
|
|
32
|
+
names = content_for_scanner.scan(/^domain:[ \t]*(.+)$/i).flatten.map(&:strip)
|
|
33
|
+
states = content_for_scanner.scan(/^status:[ \t]*(.+)$/i).flatten.map { |value| value.strip.downcase }
|
|
34
|
+
missing = content_for_scanner.scan(/^% No data was found to match the request criteria\.[ \t]*$/).size
|
|
35
|
+
if missing == 1 && names.empty? && states.empty?
|
|
40
36
|
:available
|
|
37
|
+
elsif missing.zero? && names.size == 1 && states.size == 1 &&
|
|
38
|
+
names.first.match?(/\A(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+il\z/i) &&
|
|
39
|
+
['transfer locked', 'transfer allowed'].include?(states.first)
|
|
40
|
+
:registered
|
|
41
|
+
else
|
|
42
|
+
:unknown
|
|
41
43
|
end
|
|
42
44
|
end
|
|
43
45
|
|
|
@@ -46,7 +48,7 @@ module Whois
|
|
|
46
48
|
end
|
|
47
49
|
|
|
48
50
|
property_supported :registered? do
|
|
49
|
-
|
|
51
|
+
status == :registered
|
|
50
52
|
end
|
|
51
53
|
|
|
52
54
|
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
require_relative 'registry_response_safety'
|
|
5
|
+
|
|
6
|
+
module Whois
|
|
7
|
+
class Parsers
|
|
8
|
+
# ANINF's current French-language registry response, observed 2026-10-19.
|
|
9
|
+
class WhoisNicGa < Base
|
|
10
|
+
include RegistryResponseSafety
|
|
11
|
+
|
|
12
|
+
property_supported(:domain) { header_field('Nom de domaine')&.downcase }
|
|
13
|
+
property_supported(:domain_id) { header_field('Domain ID') }
|
|
14
|
+
property_supported(:status) do
|
|
15
|
+
names = content_for_scanner.scan(/^Nom de domaine:[ \t]*(.+)$/).flatten
|
|
16
|
+
missing = content_for_scanner.scan(/^%% NOT FOUND[ \t]*$/).size
|
|
17
|
+
if missing == 1 && names.empty? && !header_field('Domain ID')
|
|
18
|
+
:available
|
|
19
|
+
elsif missing.zero? && names.size == 1 &&
|
|
20
|
+
names.first.strip.match?(/\A[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.ga\z/i) &&
|
|
21
|
+
header_field('Domain ID') && header_field('Statut') == 'actif' &&
|
|
22
|
+
valid_creation_date?
|
|
23
|
+
:registered
|
|
24
|
+
else
|
|
25
|
+
:unknown
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
property_supported(:available?) { status == :available }
|
|
29
|
+
property_supported(:registered?) { status == :registered }
|
|
30
|
+
property_supported(:created_on) { header_date('Date de création') }
|
|
31
|
+
property_supported(:updated_on) { header_date('Dernière modification') }
|
|
32
|
+
property_supported(:expires_on) { header_date("Date d'expiration") }
|
|
33
|
+
property_supported(:registrar) do
|
|
34
|
+
name = header_field('Registrar')
|
|
35
|
+
Parser::Registrar.new(name: name) if name
|
|
36
|
+
end
|
|
37
|
+
property_supported(:nameservers) do
|
|
38
|
+
content_for_scanner.scan(/^Serveur de noms:[ \t]*(\S+)[ \t]*$/).flatten.map do |name|
|
|
39
|
+
Parser::Nameserver.new(name: name.downcase)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def header_field(label)
|
|
46
|
+
header = content_for_scanner.split(/^\[/, 2).first.to_s
|
|
47
|
+
values = header.scan(/^#{Regexp.escape(label)}:[ \t]*(.+)$/).flatten.map(&:strip)
|
|
48
|
+
values.first if values.size == 1 && !values.first.empty?
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def header_date(label)
|
|
52
|
+
value = header_field(label)
|
|
53
|
+
parse_time(value) if value
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def valid_creation_date?
|
|
57
|
+
value = header_field('Date de création')
|
|
58
|
+
value && value.match?(/\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z\z/) && Date.iso8601(value[0, 10]) && Time.iso8601(value)
|
|
59
|
+
rescue ArgumentError
|
|
60
|
+
false
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_cocca2'
|
|
4
|
+
require_relative 'registry_response_safety'
|
|
5
|
+
require 'whois/scanners/whois.nic.net.jo'
|
|
6
|
+
|
|
7
|
+
module Whois
|
|
8
|
+
class Parsers
|
|
9
|
+
# Jordan's official registry endpoint, observed 2026-10-19.
|
|
10
|
+
class WhoisNicNetJo < BaseCocca2
|
|
11
|
+
include RegistryResponseSafety
|
|
12
|
+
self.scanner = Scanners::WhoisNicNetJo
|
|
13
|
+
|
|
14
|
+
property_supported(:status) do
|
|
15
|
+
names = content_for_scanner.scan(/^Domain Name:[ \t]*(.+)$/i).flatten.map(&:strip)
|
|
16
|
+
absent = content_for_scanner.scan(/^No match for domain "([^"\n]+)"[ \t]*$/i).flatten
|
|
17
|
+
statuses = content_for_scanner.scan(/^Domain Status:[ \t]*(.+)$/i).flatten.map(&:strip)
|
|
18
|
+
valid_name = names.size == 1 && names.first.match?(/\A(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+jo\z/i)
|
|
19
|
+
if valid_name && absent.size == 1 && absent.first.casecmp?(names.first) && statuses.empty? &&
|
|
20
|
+
!content_for_scanner.match?(/^Creation Date:/i)
|
|
21
|
+
:available
|
|
22
|
+
elsif valid_name && absent.empty? && statuses == ['Active'] && valid_creation_date?
|
|
23
|
+
:registered
|
|
24
|
+
else
|
|
25
|
+
:unknown
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
property_supported(:available?) { status == :available }
|
|
29
|
+
property_supported(:registered?) { status == :registered }
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def valid_creation_date?
|
|
34
|
+
values = content_for_scanner.scan(/^Creation Date:[ \t]*(.+)$/i).flatten.map(&:strip)
|
|
35
|
+
values.size == 1 && values.first.match?(/\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z\z/) && Date.iso8601(values.first[0, 10]) && Time.iso8601(values.first)
|
|
36
|
+
rescue ArgumentError
|
|
37
|
+
false
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
require_relative 'base'
|
|
11
|
+
require_relative 'registry_response_safety'
|
|
11
12
|
require 'whois/scanners/whois.sx.rb'
|
|
12
13
|
|
|
13
14
|
|
|
@@ -20,6 +21,7 @@ module Whois
|
|
|
20
21
|
# The Example parser for the list of all available methods.
|
|
21
22
|
#
|
|
22
23
|
class WhoisSx < Base
|
|
24
|
+
include RegistryResponseSafety
|
|
23
25
|
include Scanners::Scannable
|
|
24
26
|
|
|
25
27
|
self.scanner = Scanners::WhoisSx
|
|
@@ -31,7 +33,7 @@ module Whois
|
|
|
31
33
|
|
|
32
34
|
|
|
33
35
|
property_supported :domain do
|
|
34
|
-
node("Domain Name"
|
|
36
|
+
(node("Domain Name") || node("Not found"))&.downcase
|
|
35
37
|
end
|
|
36
38
|
|
|
37
39
|
property_supported :domain_id do
|
|
@@ -40,6 +42,9 @@ module Whois
|
|
|
40
42
|
|
|
41
43
|
|
|
42
44
|
property_supported :status do
|
|
45
|
+
current = current_registry_status
|
|
46
|
+
return current if current
|
|
47
|
+
|
|
43
48
|
case (s = node("Domain Status", &:downcase))
|
|
44
49
|
when "available"
|
|
45
50
|
:available
|
|
@@ -103,6 +108,34 @@ module Whois
|
|
|
103
108
|
end
|
|
104
109
|
|
|
105
110
|
|
|
111
|
+
# Keep the historical scanner for old fixtures, while recognizing the
|
|
112
|
+
# current EPP record and exact missing reply before scanning legacy text.
|
|
113
|
+
def current_registry_status
|
|
114
|
+
names = content_for_scanner.scan(/^Domain Name:[ \t]*(.+)$/i).flatten.map(&:strip)
|
|
115
|
+
absent = content_for_scanner.scan(/^Not found:[ \t]*(\S+)[ \t]*$/i).flatten
|
|
116
|
+
return nil if absent.empty? && !content_for_scanner.match?(/^Registry Domain ID:/i)
|
|
117
|
+
|
|
118
|
+
valid = ->(name) { name.match?(/\A[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.sx\z/i) }
|
|
119
|
+
if absent.size == 1 && names.empty? && valid.call(absent.first) &&
|
|
120
|
+
!content_for_scanner.match?(/^(?:Creation Date|Registry Domain ID|Domain Status):/i)
|
|
121
|
+
return :available
|
|
122
|
+
end
|
|
123
|
+
return :unknown unless absent.empty? && names.size == 1 && valid.call(names.first)
|
|
124
|
+
|
|
125
|
+
statuses = content_for_scanner.scan(/^Domain Status:[ \t]*(\S+)(?:[^\n]*)$/i).flatten
|
|
126
|
+
dates = content_for_scanner.scan(/^Creation Date:[ \t]*(.+)$/i).flatten.map(&:strip)
|
|
127
|
+
return :unknown unless dates.size == 1 && dates.first.match?(/\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z\z/)
|
|
128
|
+
Date.iso8601(dates.first[0, 10])
|
|
129
|
+
Time.iso8601(dates.first)
|
|
130
|
+
if statuses.any? && statuses.all? { |value| value.match?(/\A(?:ok|active|(?:client|server)(?:Delete|Transfer|Update|Renew)Prohibited)\z/) }
|
|
131
|
+
:registered
|
|
132
|
+
else
|
|
133
|
+
:unknown
|
|
134
|
+
end
|
|
135
|
+
rescue ArgumentError
|
|
136
|
+
:unknown
|
|
137
|
+
end
|
|
138
|
+
|
|
106
139
|
private
|
|
107
140
|
|
|
108
141
|
def build_contact(element, type)
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'cgi'
|
|
4
|
+
require 'strscan'
|
|
5
|
+
require_relative 'base'
|
|
6
|
+
require_relative 'registry_response_safety'
|
|
7
|
+
|
|
8
|
+
module Whois
|
|
9
|
+
class Parsers
|
|
10
|
+
# The registry's per-domain public web WHOIS, observed 2026-10-19.
|
|
11
|
+
# Inspect only its result heading/alert, never navigation or script text.
|
|
12
|
+
class WwwGt < Base
|
|
13
|
+
include RegistryResponseSafety
|
|
14
|
+
|
|
15
|
+
property_supported(:status) { web_result[:status] }
|
|
16
|
+
property_supported(:domain) { web_result[:domain] }
|
|
17
|
+
property_supported(:registered?) { status == :registered }
|
|
18
|
+
property_supported(:available?) { status == :available }
|
|
19
|
+
|
|
20
|
+
def response_unavailable?
|
|
21
|
+
super || content_for_scanner.match?(/<cap-widget\b|\bclass=["']g-recaptcha["']|cf-chl-/i)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def web_result
|
|
27
|
+
@web_result ||= classify_web_result
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def classify_web_result
|
|
31
|
+
blocks = result_blocks
|
|
32
|
+
return { status: :unknown } unless blocks
|
|
33
|
+
|
|
34
|
+
candidates = blocks.filter_map do |kind, text|
|
|
35
|
+
text = CGI.unescapeHTML(text.gsub('á', 'á').gsub('Á', 'Á')).gsub(/[ \t\r\n]+/, ' ').strip
|
|
36
|
+
if kind == 'h3' && (match = /\A(\S+)\. ACTIVO\z/i.match(text))
|
|
37
|
+
[match[1].downcase, :registered]
|
|
38
|
+
elsif kind == 'div' && (match = /\A(\S+)\. no está registrado \.\z/i.match(text))
|
|
39
|
+
[match[1].downcase, :available]
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
return { status: :unknown } unless candidates.size == 1
|
|
43
|
+
|
|
44
|
+
name, state = candidates.first
|
|
45
|
+
return { status: :unknown } unless name.bytesize <= 253 &&
|
|
46
|
+
name.match?(/\A(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+gt\z/)
|
|
47
|
+
|
|
48
|
+
{ domain: name, status: state }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# One forward scan, including malformed tags. Limit each tag before
|
|
52
|
+
# inspecting attributes and skip scripts, styles and comments entirely.
|
|
53
|
+
def result_blocks
|
|
54
|
+
input = StringScanner.new(content_for_scanner)
|
|
55
|
+
blocks = []
|
|
56
|
+
active = nil
|
|
57
|
+
depth = 0
|
|
58
|
+
text = +''
|
|
59
|
+
until input.eos?
|
|
60
|
+
chunk = input.scan_until(/</)
|
|
61
|
+
unless chunk
|
|
62
|
+
text << input.rest if active
|
|
63
|
+
input.terminate
|
|
64
|
+
break
|
|
65
|
+
end
|
|
66
|
+
text << chunk[0...-1] if active
|
|
67
|
+
if input.peek(3) == '!--'
|
|
68
|
+
return nil unless input.scan_until(/-->/)
|
|
69
|
+
next
|
|
70
|
+
end
|
|
71
|
+
tag = input.scan_until(/>/)
|
|
72
|
+
return nil unless tag && tag.bytesize <= 16_384
|
|
73
|
+
match = /\A[ \t]*(\/?)[ \t]*([a-z0-9]+)/i.match(tag)
|
|
74
|
+
next unless match
|
|
75
|
+
closing = match[1] == '/'
|
|
76
|
+
name = match[2].downcase
|
|
77
|
+
if !closing && %w[script style].include?(name)
|
|
78
|
+
return nil if active
|
|
79
|
+
return nil unless input.scan_until(%r{</#{name}[ \t\r\n]*>}i)
|
|
80
|
+
next
|
|
81
|
+
end
|
|
82
|
+
if active
|
|
83
|
+
depth += 1 if !closing && name == active
|
|
84
|
+
depth -= 1 if closing && name == active
|
|
85
|
+
if depth.zero?
|
|
86
|
+
blocks << [active, text]
|
|
87
|
+
active = nil
|
|
88
|
+
text = +''
|
|
89
|
+
else
|
|
90
|
+
text << ' '
|
|
91
|
+
end
|
|
92
|
+
elsif !closing && (name == 'h3' || (name == 'div' && alert_classes?(tag)))
|
|
93
|
+
active = name
|
|
94
|
+
depth = 1
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
active ? nil : blocks
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def alert_classes?(tag)
|
|
101
|
+
value = tag[/\bclass[ \t]*=[ \t]*["']([^"']*)["']/i, 1]
|
|
102
|
+
classes = value.to_s.split
|
|
103
|
+
classes.include?('alert') && classes.include?('alert-danger')
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_cocca2'
|
|
4
|
+
|
|
5
|
+
module Whois
|
|
6
|
+
module Scanners
|
|
7
|
+
class WhoisNicNetJo < BaseCocca2
|
|
8
|
+
self.tokenizers += [:skip_jordan_absence]
|
|
9
|
+
|
|
10
|
+
tokenizer :skip_jordan_absence do
|
|
11
|
+
@input.skip(/^No match for domain "[^"\n]+"[ \t]*\n/i)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -11,6 +11,7 @@ module Whois
|
|
|
11
11
|
:scan_keyvalue,
|
|
12
12
|
:skip_lastupdate,
|
|
13
13
|
:scan_disclaimer,
|
|
14
|
+
:skip_comment,
|
|
14
15
|
]
|
|
15
16
|
|
|
16
17
|
|
|
@@ -25,6 +26,10 @@ module Whois
|
|
|
25
26
|
@input.skip(/>>>(.+?)<<<\n/)
|
|
26
27
|
end
|
|
27
28
|
|
|
29
|
+
tokenizer :skip_comment do
|
|
30
|
+
@input.skip(/^%[^\n]*\n/)
|
|
31
|
+
end
|
|
32
|
+
|
|
28
33
|
tokenizer :scan_disclaimer do
|
|
29
34
|
if @input.match?(/^% WHOIS LEGAL STATEMENT/)
|
|
30
35
|
@ast["field:disclaimer"] = _scan_lines_to_array(/%(.*)\n/).map(&:strip).join("\n")
|
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.
|
|
4
|
+
version: 0.4.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Simone Carletti
|
|
@@ -439,6 +439,7 @@ files:
|
|
|
439
439
|
- lib/whois/parsers/whois.nic.furniture.rb
|
|
440
440
|
- lib/whois/parsers/whois.nic.futbol.rb
|
|
441
441
|
- lib/whois/parsers/whois.nic.fyi.rb
|
|
442
|
+
- lib/whois/parsers/whois.nic.ga.rb
|
|
442
443
|
- lib/whois/parsers/whois.nic.gal.rb
|
|
443
444
|
- lib/whois/parsers/whois.nic.games.rb
|
|
444
445
|
- lib/whois/parsers/whois.nic.gd.rb
|
|
@@ -537,6 +538,7 @@ files:
|
|
|
537
538
|
- lib/whois/parsers/whois.nic.mx.rb
|
|
538
539
|
- lib/whois/parsers/whois.nic.name.rb
|
|
539
540
|
- lib/whois/parsers/whois.nic.net.bw.rb
|
|
541
|
+
- lib/whois/parsers/whois.nic.net.jo.rb
|
|
540
542
|
- lib/whois/parsers/whois.nic.net.ng.rb
|
|
541
543
|
- lib/whois/parsers/whois.nic.net.sa.rb
|
|
542
544
|
- lib/whois/parsers/whois.nic.net.sb.rb
|
|
@@ -751,6 +753,7 @@ files:
|
|
|
751
753
|
- lib/whois/parsers/whois.za.org.rb
|
|
752
754
|
- lib/whois/parsers/whois.zicta.zm.rb
|
|
753
755
|
- lib/whois/parsers/whois1.nic.bi.rb
|
|
756
|
+
- lib/whois/parsers/www.gt.rb
|
|
754
757
|
- lib/whois/parsers/za_central_registry.rb
|
|
755
758
|
- lib/whois/safe_record.rb
|
|
756
759
|
- lib/whois/scanners/base.rb
|
|
@@ -778,6 +781,7 @@ files:
|
|
|
778
781
|
- lib/whois/scanners/whois.nc.rb
|
|
779
782
|
- lib/whois/scanners/whois.nic.cz.rb
|
|
780
783
|
- lib/whois/scanners/whois.nic.it.rb
|
|
784
|
+
- lib/whois/scanners/whois.nic.net.jo.rb
|
|
781
785
|
- lib/whois/scanners/whois.pir.org.rb
|
|
782
786
|
- lib/whois/scanners/whois.rnids.rs.rb
|
|
783
787
|
- lib/whois/scanners/whois.smallregistry.net.rb
|