Class: GitHubPages::HealthCheck::Domain
- Defined in:
- lib/github-pages-health-check/domain.rb
Constant Summary collapse
- LEGACY_IP_ADDRESSES =
[ # Legacy GitHub Datacenter "207.97.227.245", "204.232.175.78", # Legacy Fastly Datacenter "199.27.73.133", "199.27.76.133" ].freeze
- CURRENT_IP_ADDRESSES =
%w[ 192.30.252.153 192.30.252.154 ].freeze
- HASH_METHODS =
[ :host, :uri, :dns_resolves?, :proxied?, :cloudflare_ip?, :fastly_ip?, :old_ip_address?, :a_record?, :cname_record?, :valid_domain?, :apex_domain?, :should_be_a_record?, :cname_to_github_user_domain?, :cname_to_pages_dot_github_dot_com?, :cname_to_fastly?, :pointed_to_github_pages_ip?, :pages_domain?, :served_by_pages?, :valid_domain? ].freeze
Instance Attribute Summary collapse
-
#host ⇒ Object
readonly
Returns the value of attribute host.
Instance Method Summary collapse
-
#a_record? ⇒ Boolean
Is this domain’s first response an A record?.
-
#apex_domain? ⇒ Boolean
Is this domain an apex domain, meaning a CNAME would be innapropriate.
-
#check! ⇒ Object
Runs all checks, raises an error if invalid.
-
#cloudflare_ip? ⇒ Boolean
Does the domain resolve to a CloudFlare-owned IP.
-
#cname ⇒ Object
The domain to which this domain’s CNAME resolves Returns nil if the domain is not a CNAME.
-
#cname_record? ⇒ Boolean
(also: #cname?)
Is this domain’s first response a CNAME record?.
-
#cname_to_fastly? ⇒ Boolean
Is the given domain CNAME’d directly to our Fastly account?.
-
#cname_to_github_user_domain? ⇒ Boolean
Is the domain’s first response a CNAME to a pages domain?.
-
#cname_to_pages_dot_github_dot_com? ⇒ Boolean
Is the given domain a CNAME to pages.github.(io|com) instead of being CNAME’d to the user’s subdomain?.
- #deprecated_ip? ⇒ Boolean
-
#dns ⇒ Object
Returns an array of DNS answers.
-
#dns? ⇒ Boolean
(also: #dns_resolves?)
Are we even able to get the DNS record?.
-
#fastly? ⇒ Boolean
Is the host our Fastly CNAME?.
-
#fastly_ip? ⇒ Boolean
Does the domain resolve to a Fastly-owned IP.
-
#github_domain? ⇒ Boolean
Is this domain owned by GitHub?.
-
#initialize(host) ⇒ Domain
constructor
A new instance of Domain.
- #invalid_a_record? ⇒ Boolean
- #invalid_cname? ⇒ Boolean
-
#old_ip_address? ⇒ Boolean
Does this domain have any A record that points to the legacy IPs?.
-
#pages_domain? ⇒ Boolean
Is the host a *.github.io domain?.
-
#pages_dot_github_dot_com? ⇒ Boolean
Is the host pages.github.com or pages.github.io?.
-
#pointed_to_github_pages_ip? ⇒ Boolean
Is the domain’s first response an A record to a valid GitHub Pages IP?.
-
#proxied? ⇒ Boolean
Does this non-GitHub-pages domain proxy a GitHub Pages site?.
- #served_by_pages? ⇒ Boolean
-
#should_be_a_record? ⇒ Boolean
Should the domain be an apex record?.
- #uri ⇒ Object
-
#valid_domain? ⇒ Boolean
Is this a valid domain that PublicSuffix recognizes? Used as an escape hatch to prevent false positives on DNS checkes.
Methods inherited from Checkable
#reason, #to_hash, #to_json, #to_s, #to_s_pretty, #valid?
Constructor Details
#initialize(host) ⇒ Domain
Returns a new instance of Domain.
31 32 33 34 35 36 37 |
# File 'lib/github-pages-health-check/domain.rb', line 31 def initialize(host) unless host.is_a? String raise ArgumentError, "Expected string, got #{host.class}" end @host = normalize_host(host) end |
Instance Attribute Details
#host ⇒ Object (readonly)
Returns the value of attribute host.
5 6 7 |
# File 'lib/github-pages-health-check/domain.rb', line 5 def host @host end |
Instance Method Details
#a_record? ⇒ Boolean
Is this domain’s first response an A record?
194 195 196 197 |
# File 'lib/github-pages-health-check/domain.rb', line 194 def a_record? return unless dns? dns.first.class == Net::DNS::RR::A end |
#apex_domain? ⇒ Boolean
Is this domain an apex domain, meaning a CNAME would be innapropriate
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/github-pages-health-check/domain.rb', line 79 def apex_domain? return @apex_domain if defined?(@apex_domain) return unless valid_domain? answers = begin Resolv::DNS.open { |dns| dns.timeouts = TIMEOUT dns.getresources(absolute_domain, Resolv::DNS::Resource::IN::NS) } rescue Timeout::Error, NoMethodError [] end @apex_domain = answers.any? end |
#check! ⇒ Object
Runs all checks, raises an error if invalid
40 41 42 43 44 45 46 47 48 49 |
# File 'lib/github-pages-health-check/domain.rb', line 40 def check! raise Errors::InvalidDomainError.new(domain: self) unless valid_domain? raise Errors::InvalidDNSError.new(domain: self) unless dns_resolves? raise Errors::DeprecatedIPError.new(domain: self) if deprecated_ip? return true if proxied? raise Errors::InvalidARecordError.new(domain: self) if invalid_a_record? raise Errors::InvalidCNAMEError.new(domain: self) if invalid_cname? raise Errors::NotServedByPagesError.new(domain: self) unless served_by_pages? true end |
#cloudflare_ip? ⇒ Boolean
Does the domain resolve to a CloudFlare-owned IP
144 145 146 |
# File 'lib/github-pages-health-check/domain.rb', line 144 def cloudflare_ip? cdn_ip?(CloudFlare) end |
#cname ⇒ Object
The domain to which this domain’s CNAME resolves Returns nil if the domain is not a CNAME
208 209 210 211 |
# File 'lib/github-pages-health-check/domain.rb', line 208 def cname return unless cname? @cname ||= Domain.new(dns.first.cname.to_s) end |
#cname_record? ⇒ Boolean Also known as: cname?
Is this domain’s first response a CNAME record?
200 201 202 203 |
# File 'lib/github-pages-health-check/domain.rb', line 200 def cname_record? return unless dns? dns.first.class == Net::DNS::RR::CNAME end |
#cname_to_fastly? ⇒ Boolean
Is the given domain CNAME’d directly to our Fastly account?
119 120 121 |
# File 'lib/github-pages-health-check/domain.rb', line 119 def cname_to_fastly? cname? && !pages_domain? && cname.fastly? end |
#cname_to_github_user_domain? ⇒ Boolean
Is the domain’s first response a CNAME to a pages domain?
106 107 108 |
# File 'lib/github-pages-health-check/domain.rb', line 106 def cname_to_github_user_domain? cname? && !cname_to_pages_dot_github_dot_com? && cname.pages_domain? end |
#cname_to_pages_dot_github_dot_com? ⇒ Boolean
Is the given domain a CNAME to pages.github.(io|com) instead of being CNAME’d to the user’s subdomain?
domain - the domain to check, generaly the target of a cname
114 115 116 |
# File 'lib/github-pages-health-check/domain.rb', line 114 def cname_to_pages_dot_github_dot_com? cname? && cname.pages_dot_github_dot_com? end |
#deprecated_ip? ⇒ Boolean
51 52 53 54 |
# File 'lib/github-pages-health-check/domain.rb', line 51 def deprecated_ip? return @deprecated_ip if defined? @deprecated_ip @deprecated_ip = (valid_domain? && a_record? && old_ip_address?) end |
#dns ⇒ Object
Returns an array of DNS answers
168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/github-pages-health-check/domain.rb', line 168 def dns return @dns if defined? @dns return unless valid_domain? @dns = Timeout.timeout(TIMEOUT) do GitHubPages::HealthCheck.without_warnings do Net::DNS::Resolver.start(absolute_domain).answer unless host.nil? end end rescue StandardError @dns = nil end |
#dns? ⇒ Boolean Also known as: dns_resolves?
Are we even able to get the DNS record?
181 182 183 |
# File 'lib/github-pages-health-check/domain.rb', line 181 def dns? !(dns.nil? || dns.empty?) end |
#fastly? ⇒ Boolean
Is the host our Fastly CNAME?
139 140 141 |
# File 'lib/github-pages-health-check/domain.rb', line 139 def fastly? !!host.match(/\Agithub\.map\.fastly\.net\.?\z/i) end |
#fastly_ip? ⇒ Boolean
Does the domain resolve to a Fastly-owned IP
149 150 151 |
# File 'lib/github-pages-health-check/domain.rb', line 149 def fastly_ip? cdn_ip?(Fastly) end |
#github_domain? ⇒ Boolean
Is this domain owned by GitHub?
134 135 136 |
# File 'lib/github-pages-health-check/domain.rb', line 134 def github_domain? !!host.match(/\.github\.com\z/) end |
#invalid_a_record? ⇒ Boolean
56 57 58 59 |
# File 'lib/github-pages-health-check/domain.rb', line 56 def invalid_a_record? return @invalid_a_record if defined? @invalid_a_record @invalid_a_record = (valid_domain? && a_record? && !should_be_a_record?) end |
#invalid_cname? ⇒ Boolean
61 62 63 64 65 66 67 68 69 |
# File 'lib/github-pages-health-check/domain.rb', line 61 def invalid_cname? return @invalid_cname if defined? @invalid_cname @invalid_cname = begin return false unless valid_domain? return false if github_domain? || apex_domain? return true if cname_to_pages_dot_github_dot_com? || cname_to_fastly? !cname_to_github_user_domain? end end |
#old_ip_address? ⇒ Boolean
Does this domain have any A record that points to the legacy IPs?
187 188 189 190 191 |
# File 'lib/github-pages-health-check/domain.rb', line 187 def old_ip_address? dns.any? do |answer| answer.class == Net::DNS::RR::A && LEGACY_IP_ADDRESSES.include?(answer.address.to_s) end if dns? end |
#pages_domain? ⇒ Boolean
Is the host a *.github.io domain?
124 125 126 |
# File 'lib/github-pages-health-check/domain.rb', line 124 def pages_domain? !!host.match(/\A[\w-]+\.github\.(io|com)\.?\z/i) end |
#pages_dot_github_dot_com? ⇒ Boolean
Is the host pages.github.com or pages.github.io?
129 130 131 |
# File 'lib/github-pages-health-check/domain.rb', line 129 def pages_dot_github_dot_com? !!host.match(/\Apages\.github\.(io|com)\.?\z/i) end |
#pointed_to_github_pages_ip? ⇒ Boolean
Is the domain’s first response an A record to a valid GitHub Pages IP?
101 102 103 |
# File 'lib/github-pages-health-check/domain.rb', line 101 def pointed_to_github_pages_ip? a_record? && CURRENT_IP_ADDRESSES.include?(dns.first.value) end |
#proxied? ⇒ Boolean
Does this non-GitHub-pages domain proxy a GitHub Pages site?
This can be:
1. A Cloudflare-owned IP address
2. A site that returns GitHub.com server headers, but isn't CNAME'd to a GitHub domain
3. A site that returns GitHub.com server headers, but isn't CNAME'd to a GitHub IP
159 160 161 162 163 164 165 |
# File 'lib/github-pages-health-check/domain.rb', line 159 def proxied? return unless dns? return true if cloudflare_ip? return false if pointed_to_github_pages_ip? || cname_to_github_user_domain? return false if cname_to_pages_dot_github_dot_com? || cname_to_fastly? || fastly_ip? served_by_pages? end |
#served_by_pages? ⇒ Boolean
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
# File 'lib/github-pages-health-check/domain.rb', line 213 def served_by_pages? return @served_by_pages if defined? @served_by_pages return unless dns_resolves? @served_by_pages = begin response = Typhoeus.head(uri, TYPHOEUS_OPTIONS) # Workaround for webmock not playing nicely with Typhoeus redirects # See https://github.com/bblimke/webmock/issues/237 if response.mock? && response.headers["Location"] response = Typhoeus.head(response.headers["Location"], TYPHOEUS_OPTIONS) end return false unless response.mock? || response.return_code == :ok return true if response.headers["Server"] == "GitHub.com" # Typhoeus mangles the case of the header, compare insensitively response.headers.any? { |k,v| k =~ /X-GitHub-Request-Id/i } end end |
#should_be_a_record? ⇒ Boolean
Should the domain be an apex record?
96 97 98 |
# File 'lib/github-pages-health-check/domain.rb', line 96 def should_be_a_record? !pages_domain? && apex_domain? end |
#uri ⇒ Object
234 235 236 237 238 239 |
# File 'lib/github-pages-health-check/domain.rb', line 234 def uri @uri ||= begin = { :host => host, :scheme => scheme, :path => "/" } Addressable::URI.new().normalize.to_s end end |
#valid_domain? ⇒ Boolean
Is this a valid domain that PublicSuffix recognizes? Used as an escape hatch to prevent false positives on DNS checkes
73 74 75 76 |
# File 'lib/github-pages-health-check/domain.rb', line 73 def valid_domain? return @valid if defined? @valid @valid = PublicSuffix.valid?(host) end |