whois-parser-next 0.4.6 → 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 +20 -0
- data/lib/whois/parser/version.rb +1 -1
- data/lib/whois/parsers/www.gt.rb +107 -0
- metadata +2 -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,26 @@
|
|
|
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
|
+
|
|
5
25
|
#### Release 0.4.6 (2026-10-19)
|
|
6
26
|
|
|
7
27
|
- ADDED: Added `.ga` parsing for ANINF's current French WHOIS response, requiring
|
data/lib/whois/parser/version.rb
CHANGED
|
@@ -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
|
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
|
|
@@ -753,6 +753,7 @@ files:
|
|
|
753
753
|
- lib/whois/parsers/whois.za.org.rb
|
|
754
754
|
- lib/whois/parsers/whois.zicta.zm.rb
|
|
755
755
|
- lib/whois/parsers/whois1.nic.bi.rb
|
|
756
|
+
- lib/whois/parsers/www.gt.rb
|
|
756
757
|
- lib/whois/parsers/za_central_registry.rb
|
|
757
758
|
- lib/whois/safe_record.rb
|
|
758
759
|
- lib/whois/scanners/base.rb
|