domain_sanity 0.1.0

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.
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "domain_sanity/version"
4
+ require_relative "domain_sanity/policy"
5
+ require_relative "domain_sanity/reason"
6
+ require_relative "domain_sanity/idn"
7
+ require_relative "domain_sanity/ip"
8
+ require_relative "domain_sanity/name"
9
+ require_relative "domain_sanity/subject"
10
+ require_relative "domain_sanity/data"
11
+
12
+ # DomainSanity validates and inspects domain names the strict way a
13
+ # certificate authority must: RFC 1035 label rules, IDN/punycode handling,
14
+ # Public Suffix List and TLD checks, CA/Browser Forum aware wildcard rules,
15
+ # and IP / reserved-range / reverse-zone detection.
16
+ #
17
+ # Scope: this is offline, structural validation only. It does NOT resolve DNS,
18
+ # check CAA records, verify that a name exists, or enforce certificate field
19
+ # lengths (e.g. CN <= 64). IDN conversion is IDNA2003-style punycode via
20
+ # SimpleIDN, not full UTS-46 (see DomainSanity::IDN). Those remain the caller's
21
+ # responsibility.
22
+ #
23
+ # What "valid" means is governed by a Policy; pass `policy:` a preset symbol
24
+ # (:ca_baseline, :dns_zone, :lenient), a Hash of overrides, or a Policy. The
25
+ # module-level methods are the friendly front door. For several questions about
26
+ # one subject, build a typed Subject once with .analyze and reuse it.
27
+ module DomainSanity
28
+ module_function
29
+
30
+ # Structurally valid FQDN with a real public TLD under the given policy.
31
+ # Wildcards, IP literals, and reverse-zone names are excluded here.
32
+ def valid?(subject, policy: :ca_baseline)
33
+ Name.valid?(subject, policy: policy)
34
+ end
35
+
36
+ # Structured reasons subject is not a valid FQDN, as Reason objects (code,
37
+ # message, label). Empty array means valid.
38
+ def reasons(subject, policy: :ca_baseline)
39
+ Name.reasons(subject, policy: policy)
40
+ end
41
+
42
+ def wildcard?(subject)
43
+ Name.wildcard?(subject)
44
+ end
45
+
46
+ # Baseline-Requirements-valid wildcard: "*" is the whole leftmost label and
47
+ # the remainder is not a bare public suffix.
48
+ def valid_wildcard?(subject, policy: :ca_baseline)
49
+ Name.valid_wildcard?(subject, policy: policy)
50
+ end
51
+
52
+ # True when subject is itself a recognized public suffix (eTLD), e.g. "com"
53
+ # or "co.uk". A full name like "example.com" is not a suffix and returns
54
+ # false.
55
+ def valid_tld?(subject, policy: :ca_baseline)
56
+ Name.valid_tld?(subject, policy: policy)
57
+ end
58
+
59
+ def registrable_domain(subject, policy: :ca_baseline)
60
+ Name.registrable_domain(subject, policy: policy)
61
+ end
62
+
63
+ def public_suffix(subject, policy: :ca_baseline)
64
+ Name.public_suffix(subject, policy: policy)
65
+ end
66
+
67
+ def ip?(subject)
68
+ IP.ip?(subject)
69
+ end
70
+
71
+ # Private or otherwise reserved (non-public) IP. The BRs forbid issuing for
72
+ # these.
73
+ def reserved_ip?(subject)
74
+ IP.reserved?(subject)
75
+ end
76
+
77
+ def public_ip?(subject)
78
+ IP.public?(subject)
79
+ end
80
+
81
+ def reverse_zone?(subject)
82
+ IP.reverse_zone?(subject)
83
+ end
84
+
85
+ def to_ascii(subject)
86
+ IDN.to_ascii(subject)
87
+ end
88
+
89
+ def to_unicode(subject)
90
+ IDN.to_unicode(subject)
91
+ end
92
+
93
+ # True when any label mixes scripts in a homograph-suspicious way (Latin with
94
+ # Cyrillic, etc.). Opt in to enforcing this during validation with a policy of
95
+ # { require_single_script: true }.
96
+ def mixed_script?(subject)
97
+ IDN.mixed_script?(subject)
98
+ end
99
+
100
+ # A typed, lazily-memoized Subject (Hostname / Wildcard / IPSubject /
101
+ # ReverseZone / MalformedSubject) exposing every fact about subject. Named
102
+ # .analyze (not .inspect) so it does not shadow Object#inspect.
103
+ def analyze(subject, policy: :ca_baseline)
104
+ Subject.for(subject, policy: policy)
105
+ end
106
+
107
+ # Provenance and staleness of the reference data (reserved-IP snapshot, PSL
108
+ # and IDNA gem versions).
109
+ def data_versions
110
+ Data.versions
111
+ end
112
+ end
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: domain_sanity
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Suleyman Musayev
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-07-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: public_suffix
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '5.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '5.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: simpleidn
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0.2'
41
+ description: 'A small, fast Ruby gem for validating and inspecting domain names the
42
+ way a certificate authority has to: RFC 1035 label rules, IDN/punycode round-tripping,
43
+ Public Suffix List and TLD checks, CA/Browser Forum aware wildcard rules, plus IP
44
+ address, private/reserved range, and reverse-zone detection. Two runtime dependencies,
45
+ both pure Ruby.'
46
+ email:
47
+ - slmusayev@gmail.com
48
+ executables: []
49
+ extensions: []
50
+ extra_rdoc_files: []
51
+ files:
52
+ - CHANGELOG.md
53
+ - LICENSE
54
+ - README.md
55
+ - lib/domain_sanity.rb
56
+ - lib/domain_sanity/data.rb
57
+ - lib/domain_sanity/idn.rb
58
+ - lib/domain_sanity/ip.rb
59
+ - lib/domain_sanity/name.rb
60
+ - lib/domain_sanity/policy.rb
61
+ - lib/domain_sanity/reason.rb
62
+ - lib/domain_sanity/subject.rb
63
+ - lib/domain_sanity/version.rb
64
+ homepage: https://github.com/msuliq/domain_sanity
65
+ licenses:
66
+ - MIT
67
+ metadata:
68
+ rubygems_mfa_required: 'true'
69
+ homepage_uri: https://github.com/msuliq/domain_sanity
70
+ source_code_uri: https://github.com/msuliq/domain_sanity
71
+ changelog_uri: https://github.com/msuliq/domain_sanity/blob/main/CHANGELOG.md
72
+ bug_tracker_uri: https://github.com/msuliq/domain_sanity/issues
73
+ post_install_message:
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: 3.1.0
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ requirements: []
88
+ rubygems_version: 3.5.22
89
+ signing_key:
90
+ specification_version: 4
91
+ summary: Strict, standards-based domain name validation for certificate and PKI workflows
92
+ test_files: []