whois-parser-next 0.2.0 → 0.3.1
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 +56 -0
- data/README.md +20 -10
- data/RELEASING.md +2 -2
- data/ROADMAP.md +20 -15
- data/SECURITY.md +2 -2
- data/lib/whois/parser/version.rb +1 -1
- data/lib/whois/parsers/whois.cctld.uz.rb +50 -14
- data/lib/whois/parsers/whois.nic.ch.rb +6 -2
- data/lib/whois/parsers/whois.nic.digital.rb +8 -0
- data/lib/whois/parsers/whois.nic.email.rb +8 -0
- data/lib/whois/parsers/whois.nic.ge.rb +74 -0
- data/lib/whois/parsers/whois.nic.hn.rb +8 -2
- data/lib/whois/parsers/whois.nic.live.rb +8 -0
- data/lib/whois/parsers/whois.nic.media.rb +8 -0
- data/lib/whois/parsers/whois.nic.net.sa.rb +28 -9
- data/lib/whois/parsers/whois.nic.network.rb +8 -0
- data/lib/whois/parsers/whois.nic.services.rb +8 -0
- data/lib/whois/parsers/whois.nic.top.rb +15 -0
- data/lib/whois/parsers/whois.nic.us.rb +30 -0
- data/lib/whois/parsers/whois.pknic.net.pk.rb +70 -0
- data/lib/whois/parsers/whois.registre.ma.rb +89 -9
- data/lib/whois/scanners/base_cocca2.rb +1 -0
- metadata +10 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1ac79159293403464f7e386fd283634642e6eda102d7e486e105b399089e34cf
|
|
4
|
+
data.tar.gz: 0fb55415df4c88415bac870059b30f25fbf5f488526241b1358ce15257b8bcb9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 58999ed26705e0ee3ff4e78428b70ee0f20f45e184693debdee4a899617274662ba2f1074f8ca0bb6109ac7c6c702a81ed88ee32138a29e68dd7a1391cd13ffa
|
|
7
|
+
data.tar.gz: c537956618e781da069518bc6428e39f7953368f001c833582b349f19c3d4d6a7cc7a73e1e85f93d3973c978083497c2fc424c616ad660dcd4ffaf5d8669be92
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,62 @@
|
|
|
2
2
|
|
|
3
3
|
This project uses [Semantic Versioning 2.0.0](http://semver.org/).
|
|
4
4
|
|
|
5
|
+
#### Release 0.3.1 (2026-09-25)
|
|
6
|
+
|
|
7
|
+
- ADDED: Added paired registered and exact authoritative-absence parsing for
|
|
8
|
+
`.ma` and `.hn`. Empty and denied replies remain unavailable, rate limits
|
|
9
|
+
remain throttled, and conflicting or incomplete replies remain unknown.
|
|
10
|
+
- FIXED: Corrected `.pk` parsing for PKNIC's observed indented response
|
|
11
|
+
fields. Registration and availability still require explicit markers;
|
|
12
|
+
incomplete or conflicting replies remain unknown, and denied or throttled
|
|
13
|
+
replies remain non-positive.
|
|
14
|
+
- EVIDENCE: [Current `.ma` and `.hn` responses](docs/audits/top-126-150-tlds-2026-09-19.md)
|
|
15
|
+
and [production-shaped `.pk` responses](docs/audits/top1000-es-pk-shop-dev-app-2026-09-25.md).
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
#### Release 0.3.0 (2026-09-25)
|
|
19
|
+
|
|
20
|
+
- ADDED: Added evidence-backed `.top` registration and exact authoritative
|
|
21
|
+
absence parsing. `.us` now recognizes registration evidence while keeping
|
|
22
|
+
the registry's non-authoritative `No Data Found` response unknown.
|
|
23
|
+
- ADDED: Added conservative `.pk` parsing for exact PKNIC registered and
|
|
24
|
+
explicitly available responses. The standard `whois` 6.0.3 mapping selects
|
|
25
|
+
a legacy web adapter, and `Whois::Client.new(host: ...)` cannot override
|
|
26
|
+
that adapter. DomScan needs a fixed-host port-43 route through its managed
|
|
27
|
+
relay before `.pk` counts as effective coverage.
|
|
28
|
+
- ADDED: Tightened `.uz` and `.sa` parsing against current registered and
|
|
29
|
+
exact authoritative-absence responses. `.uz` reserved names remain
|
|
30
|
+
`:reserved`, not registered or available. Added a conservative `.ge` parser
|
|
31
|
+
for exact registered and absence responses from IANA's `whois.nic.ge` host;
|
|
32
|
+
`whois` 6.0.3 defaults `.ge` to `whois.registration.ge`, so a fixed-host
|
|
33
|
+
route is still required before counting it as effective coverage.
|
|
34
|
+
- SAFETY: Kept blocked, empty, and ambiguous `.ch` responses unknown, and
|
|
35
|
+
added unavailable-only handling for explicit unsupported responses from
|
|
36
|
+
`.digital`, `.email`, `.live`, `.media`, `.network`, and `.services`.
|
|
37
|
+
- DOCS: Added a scorecard for 1,000 observed TLD strings from the ICANN DNS
|
|
38
|
+
Magnitude snapshot dated 2026-09-12. Its strict count of 175 paired rows is
|
|
39
|
+
pinned to parser baseline `f2c822c` and excludes the Top 100, whose summary
|
|
40
|
+
labels do not expose row-level evidence pairs. The scorecard does not claim
|
|
41
|
+
1,000 effective WHOIS integrations or a single effective-coverage rate.
|
|
42
|
+
Later `.uz`/`.sa` evidence and `.pk`/`.ge` parsers are follow-ups, not
|
|
43
|
+
additions to that pinned count.
|
|
44
|
+
- SOURCES: The audit notes link to the [ICANN DNS Magnitude
|
|
45
|
+
snapshot](https://magnitude.research.icann.org/historic/20260912.full.html),
|
|
46
|
+
[IANA `.top`](https://www.iana.org/domains/root/db/top.html),
|
|
47
|
+
[IANA `.us`](https://www.iana.org/domains/root/db/us.html),
|
|
48
|
+
[IANA `.ch`](https://www.iana.org/domains/root/db/ch.html),
|
|
49
|
+
[IANA `.pk`](https://www.iana.org/domains/root/db/pk.html), and the
|
|
50
|
+
[official PKNIC site](https://www.pknic.net.pk/). The
|
|
51
|
+
[rank 104-105 report](docs/audits/top-101-125-tlds-2026-09-19.md) cites
|
|
52
|
+
[IANA `.uz`](https://www.iana.org/domains/root/db/uz.html),
|
|
53
|
+
[UZINFOCOM](https://www.cctld.uz/),
|
|
54
|
+
[IANA `.sa`](https://www.iana.org/domains/root/db/sa.html), and
|
|
55
|
+
[IANA `.ge`](https://www.iana.org/domains/root/db/ge.html).
|
|
56
|
+
- EVIDENCE: [Top-1,000 scorecard](docs/audits/top-1000-effective-coverage-scorecard-2026-09-25.md),
|
|
57
|
+
[current `.top`/`.us` observations](docs/audits/top-us-current-2026-09-25.md),
|
|
58
|
+
[`.pk` routing and registry evidence](docs/audits/top1000-es-pk-shop-dev-app-2026-09-25.md),
|
|
59
|
+
and [rank 101-125 follow-up evidence](docs/audits/top-101-125-tlds-2026-09-19.md).
|
|
60
|
+
|
|
5
61
|
|
|
6
62
|
#### Release 0.2.0 (2026-09-25)
|
|
7
63
|
|
data/README.md
CHANGED
|
@@ -38,7 +38,9 @@ of current WHOIS responses, explicit unknown states, registry-specific
|
|
|
38
38
|
fixtures, and safe handling of malformed, rate-limited, retired, or changed
|
|
39
39
|
server responses.
|
|
40
40
|
|
|
41
|
-
The
|
|
41
|
+
The current source version is `0.3.1`. Check the [RubyGems project
|
|
42
|
+
page](https://rubygems.org/gems/whois-parser-next) for its publication status
|
|
43
|
+
and the latest published version.
|
|
42
44
|
|
|
43
45
|
## Compatibility
|
|
44
46
|
|
|
@@ -52,12 +54,10 @@ Whois::Parser
|
|
|
52
54
|
```
|
|
53
55
|
|
|
54
56
|
Existing applications can retain `require "whois-parser"` and their
|
|
55
|
-
`Whois::Parser` integrations
|
|
57
|
+
`Whois::Parser` integrations. To install version 0.3.1, pin it as follows:
|
|
56
58
|
|
|
57
59
|
```ruby
|
|
58
|
-
gem "whois-parser-next",
|
|
59
|
-
github: "estevecastells/whois-parser-next",
|
|
60
|
-
require: "whois-parser"
|
|
60
|
+
gem "whois-parser-next", "= 0.3.1", require: "whois-parser"
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
## Requirements
|
|
@@ -82,12 +82,22 @@ bundle exec rspec
|
|
|
82
82
|
|
|
83
83
|
## Coverage evidence
|
|
84
84
|
|
|
85
|
-
The 2026-09-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
The [2026-09-25 scorecard](docs/audits/top-1000-effective-coverage-scorecard-2026-09-25.md)
|
|
86
|
+
summarizes evidence for 1,000 observed TLD strings from the
|
|
87
|
+
[ICANN DNS Magnitude snapshot dated 2026-09-12](https://magnitude.research.icann.org/historic/20260912.full.html).
|
|
88
|
+
These strings are not 1,000 guaranteed working WHOIS registries or
|
|
89
|
+
domain-availability results. Its strict paired count is pinned to baseline
|
|
90
|
+
`f2c822c`, excludes the Top 100 whose summary labels do not expose row-level
|
|
91
|
+
evidence pairs, and does not claim an effective-coverage percentage. The
|
|
92
|
+
scorecard keeps verified parser evidence, explicit unavailable or unsupported
|
|
89
93
|
responses, unknown or unresolved endpoints, and classification-only rows
|
|
90
|
-
distinct.
|
|
94
|
+
distinct. Later `.uz`/`.sa` paired evidence and `.pk`/`.ge` parsers are
|
|
95
|
+
follow-ups, not changes to the pinned scorecard counts. The `.pk` parser does
|
|
96
|
+
not make the default `whois` 6.0.3 Web adapter use port 43; `Whois::Client`
|
|
97
|
+
host configuration does not override that adapter. The `.ge` parser targets
|
|
98
|
+
IANA's `whois.nic.ge`, while the default `whois` route is
|
|
99
|
+
`whois.registration.ge`. Both require explicit fixed-host routing before an
|
|
100
|
+
application can count them as effective coverage.
|
|
91
101
|
|
|
92
102
|
Start with the [source verification report](docs/audits/top-1000-source-verification-2026-09-19.md),
|
|
93
103
|
the [Top 20 review](docs/audits/top-20-tlds-2026-09-19.md), and the [Top 100
|
data/RELEASING.md
CHANGED
|
@@ -21,8 +21,8 @@ RubyGems API key to the repository or its Actions secrets.
|
|
|
21
21
|
Create and push the annotated release tag only after the checks above pass:
|
|
22
22
|
|
|
23
23
|
```shell
|
|
24
|
-
git tag -a v0.
|
|
25
|
-
git push origin v0.
|
|
24
|
+
git tag -a v0.3.0 -m "whois-parser-next 0.3.0"
|
|
25
|
+
git push origin v0.3.0
|
|
26
26
|
```
|
|
27
27
|
|
|
28
28
|
The release workflow repeats the full suite and package smoke test before it
|
data/ROADMAP.md
CHANGED
|
@@ -6,24 +6,29 @@ feature calendar.
|
|
|
6
6
|
|
|
7
7
|
## Current release
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
-
|
|
9
|
+
- Published `whois-parser-next` 0.2.0 to RubyGems, retaining the established
|
|
10
|
+
`require "whois-parser"` and `Whois::Parser` compatibility.
|
|
11
|
+
- Completed the audit of 1,000 observed TLD strings from the ICANN DNS Magnitude
|
|
12
|
+
snapshot dated 2026-09-12. These rows are ranked TLD strings, not 1,000
|
|
13
|
+
confirmed working WHOIS registries or domain-availability results.
|
|
14
|
+
- Kept verified parser evidence, unavailable or unsupported responses,
|
|
15
|
+
unresolved endpoints, and classification-only rows distinct.
|
|
15
16
|
|
|
16
17
|
## Next priorities
|
|
17
18
|
|
|
18
|
-
1.
|
|
19
|
-
|
|
20
|
-
2.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
1. Refresh the existing 1,000-row cohort only against a new, dated source
|
|
20
|
+
snapshot, keeping each snapshot's ranks and labels separate.
|
|
21
|
+
2. Close parser evidence gaps for mapped official WHOIS hosts with bounded
|
|
22
|
+
probes and sanitized fixtures for exact response behavior. DNS failures,
|
|
23
|
+
timeouts, unsupported replies, and ambiguous responses remain unresolved or
|
|
24
|
+
unavailable.
|
|
25
|
+
3. Add or change parser behavior only when current response evidence is backed
|
|
26
|
+
by a regression spec; do not infer one host's behavior for unmapped or
|
|
27
|
+
unverified TLDs.
|
|
28
|
+
4. Scope any expansion beyond rank 1,000 from a separately documented dataset
|
|
29
|
+
before treating it as parser-coverage work.
|
|
30
|
+
5. Reduce avoidable runtime dependencies and improve contributor tooling for
|
|
31
|
+
fixture privacy, server-mapping drift, and response-safety checks.
|
|
27
32
|
|
|
28
33
|
## Performance and Rust
|
|
29
34
|
|
data/SECURITY.md
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## Supported versions
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The current main branch and the latest published release are supported.
|
|
6
6
|
|
|
7
7
|
| Version | Supported |
|
|
8
8
|
|---|---|
|
|
9
9
|
| main | Yes |
|
|
10
|
-
|
|
|
10
|
+
| 0.2.0 (latest release) | Yes |
|
|
11
11
|
|
|
12
12
|
## Reporting a vulnerability
|
|
13
13
|
|
data/lib/whois/parser/version.rb
CHANGED
|
@@ -27,26 +27,15 @@ module Whois
|
|
|
27
27
|
include RegistryResponseSafety
|
|
28
28
|
|
|
29
29
|
property_supported :status do
|
|
30
|
-
|
|
31
|
-
:available
|
|
32
|
-
elsif content_for_scanner =~ /^Status: (.+?)\n/
|
|
33
|
-
case ::Regexp.last_match(1).downcase
|
|
34
|
-
when "active" then :registered
|
|
35
|
-
when "reserved" then :reserved
|
|
36
|
-
else
|
|
37
|
-
Whois::Parser.bug!(ParserError, "Unknown status `#{::Regexp.last_match(1)}'.")
|
|
38
|
-
end
|
|
39
|
-
else
|
|
40
|
-
:unknown
|
|
41
|
-
end
|
|
30
|
+
classify_status
|
|
42
31
|
end
|
|
43
32
|
|
|
44
33
|
property_supported :available? do
|
|
45
|
-
|
|
34
|
+
classify_status == :available
|
|
46
35
|
end
|
|
47
36
|
|
|
48
37
|
property_supported :registered? do
|
|
49
|
-
|
|
38
|
+
classify_status == :registered
|
|
50
39
|
end
|
|
51
40
|
|
|
52
41
|
|
|
@@ -77,6 +66,53 @@ module Whois
|
|
|
77
66
|
end
|
|
78
67
|
end
|
|
79
68
|
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
def classify_status
|
|
72
|
+
return :unknown if absence_conflicts_with_record?
|
|
73
|
+
|
|
74
|
+
evidence = []
|
|
75
|
+
evidence << :registered if registered_evidence?
|
|
76
|
+
evidence << :reserved if reserved_evidence?
|
|
77
|
+
evidence << :available if available_evidence?
|
|
78
|
+
evidence.one? ? evidence.first : :unknown
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def absence_conflicts_with_record?
|
|
82
|
+
return false unless absence_domain_names.any?
|
|
83
|
+
|
|
84
|
+
domain_names.any? || status_values.any? || content_for_scanner.match?(/^[ \t]*Domain Name:/i)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def registered_evidence?
|
|
88
|
+
domain_names.one? && status_values == ["active"]
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def reserved_evidence?
|
|
92
|
+
domain_names.one? && status_values == ["reserved"]
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def available_evidence?
|
|
96
|
+
absence_domain_names.one? && status_values.empty? &&
|
|
97
|
+
!content_for_scanner.match?(/^[ \t]*Domain Name:/i)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def domain_names
|
|
101
|
+
content_for_scanner.scan(
|
|
102
|
+
/^[ \t]*Domain Name:[ \t]*((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+uz)[ \t]*$/i
|
|
103
|
+
).flatten.map(&:downcase).uniq
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def status_values
|
|
107
|
+
content_for_scanner.scan(/^[ \t]*Status:[ \t]*([a-z]+)[ \t]*$/i).flatten.map(&:downcase).uniq
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def absence_domain_names
|
|
111
|
+
content_for_scanner.scan(
|
|
112
|
+
/^[ \t]*Sorry, but domain:[ \t]*"((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+uz)", not found in database[ \t]*$/i
|
|
113
|
+
).flatten.map(&:downcase).uniq
|
|
114
|
+
end
|
|
115
|
+
|
|
80
116
|
end
|
|
81
117
|
|
|
82
118
|
end
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
require_relative 'base'
|
|
11
|
+
require_relative 'registry_response_safety'
|
|
11
12
|
|
|
12
13
|
module Whois
|
|
13
14
|
class Parsers
|
|
@@ -24,12 +25,15 @@ module Whois
|
|
|
24
25
|
# and examples.
|
|
25
26
|
#
|
|
26
27
|
class WhoisNicCh < Base
|
|
28
|
+
include RegistryResponseSafety
|
|
27
29
|
|
|
28
30
|
property_supported :status do
|
|
29
31
|
if available?
|
|
30
32
|
:available
|
|
31
|
-
|
|
33
|
+
elsif content_for_scanner.match?(/^Domain name:\s*\S+/i)
|
|
32
34
|
:registered
|
|
35
|
+
else
|
|
36
|
+
Whois::Parser.bug!(ParserError, "Unable to parse .ch response status.")
|
|
33
37
|
end
|
|
34
38
|
end
|
|
35
39
|
|
|
@@ -38,7 +42,7 @@ module Whois
|
|
|
38
42
|
end
|
|
39
43
|
|
|
40
44
|
property_supported :registered? do
|
|
41
|
-
|
|
45
|
+
status == :registered
|
|
42
46
|
end
|
|
43
47
|
|
|
44
48
|
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Ruby Whois
|
|
3
|
+
#
|
|
4
|
+
# An intelligent pure Ruby WHOIS client and parser.
|
|
5
|
+
#
|
|
6
|
+
# Copyright (c) 2009-2022 Simone Carletti <weppos@weppos.net>
|
|
7
|
+
#++
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
require_relative 'base'
|
|
11
|
+
require_relative 'registry_response_safety'
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
module Whois
|
|
15
|
+
class Parsers
|
|
16
|
+
|
|
17
|
+
# Parser for the whois.nic.ge server.
|
|
18
|
+
#
|
|
19
|
+
class WhoisNicGe < Base
|
|
20
|
+
include RegistryResponseSafety
|
|
21
|
+
|
|
22
|
+
property_supported :status do
|
|
23
|
+
classify_status
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
property_supported :available? do
|
|
27
|
+
classify_status == :available
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
property_supported :registered? do
|
|
31
|
+
classify_status == :registered
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def classify_status
|
|
37
|
+
if registered_evidence?
|
|
38
|
+
:registered
|
|
39
|
+
elsif available_evidence?
|
|
40
|
+
:available
|
|
41
|
+
else
|
|
42
|
+
:unknown
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def registered_evidence?
|
|
47
|
+
registered_domain_names.one? && absence_domain_names.empty? && status_values == ['ok']
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def available_evidence?
|
|
51
|
+
absence_domain_names.one? && registered_domain_names.empty? && status_values.empty? &&
|
|
52
|
+
!content_for_scanner.match?(/^[ \t]*Domain Name:/i)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def registered_domain_names
|
|
56
|
+
content_for_scanner.scan(
|
|
57
|
+
/^[ \t]*Domain Name:[ \t]*((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+ge)[ \t]*$/i
|
|
58
|
+
).flatten.map(&:downcase).uniq
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def status_values
|
|
62
|
+
content_for_scanner.scan(/^[ \t]*Domain Status:[ \t]*(.+?)[ \t]*$/i).flatten.map(&:downcase).uniq
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def absence_domain_names
|
|
66
|
+
content_for_scanner.scan(
|
|
67
|
+
/^[ \t]*No match for "((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+ge)"\.[ \t]*$/i
|
|
68
|
+
).flatten.map(&:downcase).uniq
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -24,14 +24,14 @@ module Whois
|
|
|
24
24
|
|
|
25
25
|
property_supported :status do
|
|
26
26
|
if no_object_found?
|
|
27
|
-
:available
|
|
27
|
+
registration_fields_present? ? :unknown : :available
|
|
28
28
|
else
|
|
29
29
|
super()
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
property_supported :available? do
|
|
34
|
-
|
|
34
|
+
status == :available
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
property_supported :registered? do
|
|
@@ -43,6 +43,12 @@ module Whois
|
|
|
43
43
|
def no_object_found?
|
|
44
44
|
content_for_scanner.match?(/^The queried object does not exist:\s*No Object Found\s*$/i)
|
|
45
45
|
end
|
|
46
|
+
|
|
47
|
+
def registration_fields_present?
|
|
48
|
+
content_for_scanner.match?(
|
|
49
|
+
/^[ \t]*(?:Domain Status|Domain ID|Creation Date|Updated Date|Registry Expiry Date|Name Server|(?:Sponsoring )?Registrar|Registrant|Admin|Billing|Tech):/i
|
|
50
|
+
)
|
|
51
|
+
end
|
|
46
52
|
end
|
|
47
53
|
|
|
48
54
|
end
|
|
@@ -27,21 +27,15 @@ module Whois
|
|
|
27
27
|
include RegistryResponseSafety
|
|
28
28
|
|
|
29
29
|
property_supported :status do
|
|
30
|
-
|
|
31
|
-
:available
|
|
32
|
-
elsif content_for_scanner.match?(/^Domain Name:\s*\S+/i)
|
|
33
|
-
:registered
|
|
34
|
-
else
|
|
35
|
-
:unknown
|
|
36
|
-
end
|
|
30
|
+
classify_status
|
|
37
31
|
end
|
|
38
32
|
|
|
39
33
|
property_supported :available? do
|
|
40
|
-
|
|
34
|
+
classify_status == :available
|
|
41
35
|
end
|
|
42
36
|
|
|
43
37
|
property_supported :registered? do
|
|
44
|
-
|
|
38
|
+
classify_status == :registered
|
|
45
39
|
end
|
|
46
40
|
|
|
47
41
|
|
|
@@ -68,6 +62,31 @@ module Whois
|
|
|
68
62
|
end
|
|
69
63
|
end
|
|
70
64
|
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def classify_status
|
|
68
|
+
registered = registered_domain_names
|
|
69
|
+
absent = absence_domain_names
|
|
70
|
+
|
|
71
|
+
if registered.one? && absent.empty?
|
|
72
|
+
:registered
|
|
73
|
+
elsif absent.one? && registered.empty?
|
|
74
|
+
:available
|
|
75
|
+
else
|
|
76
|
+
:unknown
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def registered_domain_names
|
|
81
|
+
content_for_scanner.scan(/^[ \t]*Domain Name:[ \t]*([^\s]+\.sa)[ \t]*$/i).flatten.map(&:downcase).uniq
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def absence_domain_names
|
|
85
|
+
content_for_scanner.scan(
|
|
86
|
+
/^[ \t]*No Match for (?:domain:[ \t]*)?([^\s]+\.sa)[ \t]*$/i
|
|
87
|
+
).flatten.map(&:downcase).uniq
|
|
88
|
+
end
|
|
89
|
+
|
|
71
90
|
end
|
|
72
91
|
|
|
73
92
|
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require_relative 'base_top1000_icann'
|
|
2
|
+
|
|
3
|
+
module Whois
|
|
4
|
+
class Parsers
|
|
5
|
+
# The .top registry uses the shared ICANN record shape and returns the full
|
|
6
|
+
# queried .top name in its exact no-record response.
|
|
7
|
+
class WhoisNicTop < BaseTop1000Icann
|
|
8
|
+
property_supported :available? do
|
|
9
|
+
super() || content_for_scanner.match?(
|
|
10
|
+
/^The queried object does not exist:\s+(?:[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?\.)*[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?\.top\s*$/i
|
|
11
|
+
)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -19,6 +19,36 @@ module Whois
|
|
|
19
19
|
# The Example parser for the list of all available methods.
|
|
20
20
|
#
|
|
21
21
|
class WhoisNicUs < BaseShared2
|
|
22
|
+
# The .us registry says a missing record does not establish availability.
|
|
23
|
+
# Keep its no-record responses unknown and require record status evidence
|
|
24
|
+
# before reporting a domain as registered.
|
|
25
|
+
property_supported :status do
|
|
26
|
+
statuses = Array.wrap(node("Domain Status"))
|
|
27
|
+
registered_evidence? ? statuses : :unknown
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
property_supported :available? do
|
|
31
|
+
false
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
property_supported :registered? do
|
|
35
|
+
registered_evidence?
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def registered_evidence?
|
|
41
|
+
domain_name = node("Domain Name").to_s.strip
|
|
42
|
+
statuses = Array.wrap(node("Domain Status")).reject { |value| value.to_s.strip.empty? }
|
|
43
|
+
|
|
44
|
+
domain_name.match?(/\A\S+\.us\z/i) && statuses.any? { |status| epp_status?(status) }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def epp_status?(status)
|
|
48
|
+
status.to_s.strip.match?(
|
|
49
|
+
%r{\A(?<status>(?:client|server|pending)[A-Z][A-Za-z]*)(?:\s+https?://icann\.org/epp#\k<status>)?\z}
|
|
50
|
+
)
|
|
51
|
+
end
|
|
22
52
|
end
|
|
23
53
|
|
|
24
54
|
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#--
|
|
2
|
+
# Ruby Whois
|
|
3
|
+
#++
|
|
4
|
+
|
|
5
|
+
require_relative 'base'
|
|
6
|
+
require_relative 'registry_response_safety'
|
|
7
|
+
|
|
8
|
+
module Whois
|
|
9
|
+
class Parsers
|
|
10
|
+
|
|
11
|
+
# Parser for PKNIC's port-43 service.
|
|
12
|
+
#
|
|
13
|
+
# PKNIC identifies positive registration and availability results with
|
|
14
|
+
# separate status lines. Keep other responses unknown rather than
|
|
15
|
+
# inferring absence from an incomplete "Not Registered" message.
|
|
16
|
+
class WhoisPknicNetPk < Base
|
|
17
|
+
include RegistryResponseSafety
|
|
18
|
+
|
|
19
|
+
property_supported :domain do
|
|
20
|
+
echoed_domain
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
property_supported :status do
|
|
24
|
+
registered = registered_evidence?
|
|
25
|
+
available = available_evidence?
|
|
26
|
+
|
|
27
|
+
if registered && !available
|
|
28
|
+
:registered
|
|
29
|
+
elsif available && !registered
|
|
30
|
+
:available
|
|
31
|
+
else
|
|
32
|
+
:unknown
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
property_supported :available? do
|
|
37
|
+
available_evidence? && !registered_evidence?
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
property_supported :registered? do
|
|
41
|
+
registered_evidence? && !available_evidence?
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
property_not_supported :created_on
|
|
45
|
+
property_not_supported :updated_on
|
|
46
|
+
property_not_supported :expires_on
|
|
47
|
+
property_not_supported :registrant_contacts
|
|
48
|
+
property_not_supported :admin_contacts
|
|
49
|
+
property_not_supported :technical_contacts
|
|
50
|
+
property_not_supported :nameservers
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def echoed_domain
|
|
55
|
+
content_for_scanner[/^ {0,8}Domain:[ \t]*((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+pk)[ \t]*$/i, 1]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def registered_evidence?
|
|
59
|
+
!!(echoed_domain && content_for_scanner.match?(/^ {0,8}Status: Domain is Registered[ \t]*$/))
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def available_evidence?
|
|
63
|
+
!!(echoed_domain &&
|
|
64
|
+
content_for_scanner.match?(/^ {0,8}Status: Not Registered, and may be available if valid[ \t]*$/) &&
|
|
65
|
+
content_for_scanner.match?(/^ {0,8}Available: Yes\.[ \t]*$/))
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -27,21 +27,15 @@ module Whois
|
|
|
27
27
|
include RegistryResponseSafety
|
|
28
28
|
|
|
29
29
|
property_supported :status do
|
|
30
|
-
|
|
31
|
-
:available
|
|
32
|
-
elsif content_for_scanner.match?(/^domain:/i)
|
|
33
|
-
:registered
|
|
34
|
-
else
|
|
35
|
-
:unknown
|
|
36
|
-
end
|
|
30
|
+
classify_status
|
|
37
31
|
end
|
|
38
32
|
|
|
39
33
|
property_supported :available? do
|
|
40
|
-
|
|
34
|
+
classify_status == :available
|
|
41
35
|
end
|
|
42
36
|
|
|
43
37
|
property_supported :registered? do
|
|
44
|
-
|
|
38
|
+
classify_status == :registered
|
|
45
39
|
end
|
|
46
40
|
|
|
47
41
|
|
|
@@ -59,6 +53,92 @@ module Whois
|
|
|
59
53
|
|
|
60
54
|
property_not_supported :expires_on
|
|
61
55
|
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def classify_status
|
|
59
|
+
return :unknown if conflicting_evidence?
|
|
60
|
+
|
|
61
|
+
return :registered if registered_evidence?
|
|
62
|
+
return :available if available_evidence?
|
|
63
|
+
|
|
64
|
+
:unknown
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def conflicting_evidence?
|
|
68
|
+
return false unless absence_markers.any?
|
|
69
|
+
|
|
70
|
+
record_details_present? || legacy_record_evidence?
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def registered_evidence?
|
|
74
|
+
return false unless valid_domain_name_fields? && domain_names.one? && absence_markers.empty?
|
|
75
|
+
|
|
76
|
+
current_record_evidence? || legacy_record_evidence?
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def current_record_evidence?
|
|
80
|
+
domain_status_values == ['clientTransferProhibited https://icann.org/epp#clientTransferProhibited']
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def legacy_record_evidence?
|
|
84
|
+
legacy_domain_names.one? &&
|
|
85
|
+
content_for_scanner.match?(/^[ \t]*domain:Class-Name:domain[ \t]*$/i) &&
|
|
86
|
+
content_for_scanner.match?(/^[ \t]*%ok[ \t]*$/i)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def available_evidence?
|
|
90
|
+
absence_markers.one? && valid_domain_name_fields? && !record_details_present? &&
|
|
91
|
+
!legacy_record_evidence?
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def valid_domain_name_fields?
|
|
95
|
+
fields = domain_name_field_values
|
|
96
|
+
return false if domain_name_field? && fields.empty?
|
|
97
|
+
|
|
98
|
+
fields.empty? || (fields.one? && domain_names.one?)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def domain_names
|
|
102
|
+
(current_domain_names + legacy_domain_names).uniq
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def domain_name_field_values
|
|
106
|
+
content_for_scanner.scan(/^[ \t]*Domain Name:[ \t]*(\S+)[ \t]*$/i).flatten +
|
|
107
|
+
content_for_scanner.scan(/^[ \t]*domain:Domain-Name:[ \t]*(\S+)[ \t]*$/i).flatten
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def current_domain_names
|
|
111
|
+
content_for_scanner.scan(
|
|
112
|
+
/^[ \t]*Domain Name:[ \t]*((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+ma)[ \t]*$/i
|
|
113
|
+
).flatten.map(&:downcase)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def legacy_domain_names
|
|
117
|
+
content_for_scanner.scan(
|
|
118
|
+
/^[ \t]*domain:Domain-Name:[ \t]*((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+ma)[ \t]*$/i
|
|
119
|
+
).flatten.map(&:downcase)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def domain_status_values
|
|
123
|
+
content_for_scanner.scan(/^[ \t]*Domain Status:[ \t]*(.+?)[ \t]*$/i).flatten
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def absence_markers
|
|
127
|
+
content_for_scanner.scan(
|
|
128
|
+
/^[ \t]*(?:%error 230 No Objects Found|The queried object does not exist: No Object Found)[ \t]*$/i
|
|
129
|
+
)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def domain_name_field?
|
|
133
|
+
content_for_scanner.match?(/^[ \t]*(?:Domain Name:|domain:Domain-Name:)/i)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def record_details_present?
|
|
137
|
+
content_for_scanner.match?(
|
|
138
|
+
/^[ \t]*(?:Domain Status|Domain ID|Registrar|Creation Date|Updated Date|Registry Expiry Date|Name Server|domain:Class-Name|domain:ID|domain:Auth-Area):/i
|
|
139
|
+
)
|
|
140
|
+
end
|
|
141
|
+
|
|
62
142
|
end
|
|
63
143
|
|
|
64
144
|
end
|
|
@@ -20,6 +20,7 @@ module Whois
|
|
|
20
20
|
DISCLAIMER_MATCHES = [
|
|
21
21
|
"TERMS OF USE:", # global
|
|
22
22
|
"Terminos de Uso:", # whois.nic.hn
|
|
23
|
+
"Queda absolutamente prohibido su uso", # current whois.nic.hn footer
|
|
23
24
|
"The data in the WHOIS database of Meridian", # whois.meridiantld.net
|
|
24
25
|
"This information is provided", # whois.gg
|
|
25
26
|
]
|
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
|
+
version: 0.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Simone Carletti
|
|
@@ -392,6 +392,7 @@ files:
|
|
|
392
392
|
- lib/whois/parsers/whois.nic.democrat.rb
|
|
393
393
|
- lib/whois/parsers/whois.nic.design.rb
|
|
394
394
|
- lib/whois/parsers/whois.nic.diamonds.rb
|
|
395
|
+
- lib/whois/parsers/whois.nic.digital.rb
|
|
395
396
|
- lib/whois/parsers/whois.nic.direct.rb
|
|
396
397
|
- lib/whois/parsers/whois.nic.directory.rb
|
|
397
398
|
- lib/whois/parsers/whois.nic.dm.rb
|
|
@@ -403,6 +404,7 @@ files:
|
|
|
403
404
|
- lib/whois/parsers/whois.nic.ec.rb
|
|
404
405
|
- lib/whois/parsers/whois.nic.eco.rb
|
|
405
406
|
- lib/whois/parsers/whois.nic.education.rb
|
|
407
|
+
- lib/whois/parsers/whois.nic.email.rb
|
|
406
408
|
- lib/whois/parsers/whois.nic.energy.rb
|
|
407
409
|
- lib/whois/parsers/whois.nic.engineer.rb
|
|
408
410
|
- lib/whois/parsers/whois.nic.equipment.rb
|
|
@@ -435,6 +437,7 @@ files:
|
|
|
435
437
|
- lib/whois/parsers/whois.nic.gal.rb
|
|
436
438
|
- lib/whois/parsers/whois.nic.games.rb
|
|
437
439
|
- lib/whois/parsers/whois.nic.gd.rb
|
|
440
|
+
- lib/whois/parsers/whois.nic.ge.rb
|
|
438
441
|
- lib/whois/parsers/whois.nic.gent.rb
|
|
439
442
|
- lib/whois/parsers/whois.nic.giving.rb
|
|
440
443
|
- lib/whois/parsers/whois.nic.gl.rb
|
|
@@ -485,6 +488,7 @@ files:
|
|
|
485
488
|
- lib/whois/parsers/whois.nic.limited.rb
|
|
486
489
|
- lib/whois/parsers/whois.nic.limo.rb
|
|
487
490
|
- lib/whois/parsers/whois.nic.link.rb
|
|
491
|
+
- lib/whois/parsers/whois.nic.live.rb
|
|
488
492
|
- lib/whois/parsers/whois.nic.lk.rb
|
|
489
493
|
- lib/whois/parsers/whois.nic.london.rb
|
|
490
494
|
- lib/whois/parsers/whois.nic.love.rb
|
|
@@ -500,6 +504,7 @@ files:
|
|
|
500
504
|
- lib/whois/parsers/whois.nic.mba.rb
|
|
501
505
|
- lib/whois/parsers/whois.nic.md.rb
|
|
502
506
|
- lib/whois/parsers/whois.nic.me.rb
|
|
507
|
+
- lib/whois/parsers/whois.nic.media.rb
|
|
503
508
|
- lib/whois/parsers/whois.nic.memorial.rb
|
|
504
509
|
- lib/whois/parsers/whois.nic.men.rb
|
|
505
510
|
- lib/whois/parsers/whois.nic.mg.rb
|
|
@@ -521,6 +526,7 @@ files:
|
|
|
521
526
|
- lib/whois/parsers/whois.nic.net.ng.rb
|
|
522
527
|
- lib/whois/parsers/whois.nic.net.sa.rb
|
|
523
528
|
- lib/whois/parsers/whois.nic.net.sb.rb
|
|
529
|
+
- lib/whois/parsers/whois.nic.network.rb
|
|
524
530
|
- lib/whois/parsers/whois.nic.news.rb
|
|
525
531
|
- lib/whois/parsers/whois.nic.nf.rb
|
|
526
532
|
- lib/whois/parsers/whois.nic.ninja.rb
|
|
@@ -574,6 +580,7 @@ files:
|
|
|
574
580
|
- lib/whois/parsers/whois.nic.scot.rb
|
|
575
581
|
- lib/whois/parsers/whois.nic.security.rb
|
|
576
582
|
- lib/whois/parsers/whois.nic.select.rb
|
|
583
|
+
- lib/whois/parsers/whois.nic.services.rb
|
|
577
584
|
- lib/whois/parsers/whois.nic.sh.rb
|
|
578
585
|
- lib/whois/parsers/whois.nic.shoes.rb
|
|
579
586
|
- lib/whois/parsers/whois.nic.shopping.rb
|
|
@@ -620,6 +627,7 @@ files:
|
|
|
620
627
|
- lib/whois/parsers/whois.nic.tm.rb
|
|
621
628
|
- lib/whois/parsers/whois.nic.today.rb
|
|
622
629
|
- lib/whois/parsers/whois.nic.tools.rb
|
|
630
|
+
- lib/whois/parsers/whois.nic.top.rb
|
|
623
631
|
- lib/whois/parsers/whois.nic.town.rb
|
|
624
632
|
- lib/whois/parsers/whois.nic.toyota.rb
|
|
625
633
|
- lib/whois/parsers/whois.nic.toys.rb
|
|
@@ -669,6 +677,7 @@ files:
|
|
|
669
677
|
- lib/whois/parsers/whois.pairnic.com.rb
|
|
670
678
|
- lib/whois/parsers/whois.pandi.or.id.rb
|
|
671
679
|
- lib/whois/parsers/whois.pir.org.rb
|
|
680
|
+
- lib/whois/parsers/whois.pknic.net.pk.rb
|
|
672
681
|
- lib/whois/parsers/whois.pnina.ps.rb
|
|
673
682
|
- lib/whois/parsers/whois.publicinterestregistry.net.rb
|
|
674
683
|
- lib/whois/parsers/whois.register.bg.rb
|