Module: CompletionKit::ProviderEndpoint
- Defined in:
- app/services/completion_kit/provider_endpoint.rb
Defined Under Namespace
Classes: UnsafeEndpoint
Constant Summary collapse
- BLOCKED_NETS =
[IPAddr.new("0.0.0.0/8"), IPAddr.new("100.64.0.0/10")].freeze
- ISSUE_MESSAGES =
{ invalid_url: "is not a valid http or https URL", unresolvable: "could not be resolved", unsafe_host: "resolves to a private address" }.freeze
Class Method Summary collapse
- .addresses(host) ⇒ Object
- .issues_for(addrs) ⇒ Object
- .parse(value) ⇒ Object
- .pin(builder, url) ⇒ Object
- .pinned_address(url) ⇒ Object
- .resolve(host) ⇒ Object
- .safe?(url) ⇒ Boolean
- .unsafe?(ip) ⇒ Boolean
- .validate(url) ⇒ Object
Class Method Details
.addresses(host) ⇒ Object
54 55 56 57 58 59 |
# File 'app/services/completion_kit/provider_endpoint.rb', line 54 def addresses(host) = host.delete_prefix("[").delete_suffix("]").delete_suffix(".") [IPAddr.new()] rescue IPAddr::InvalidAddressError resolve().map { |addr| IPAddr.new(addr) } end |
.issues_for(addrs) ⇒ Object
48 49 50 51 52 |
# File 'app/services/completion_kit/provider_endpoint.rb', line 48 def issues_for(addrs) return [:unresolvable] if addrs.empty? return [:unsafe_host] if addrs.any? { |ip| unsafe?(ip) } [] end |
.parse(value) ⇒ Object
41 42 43 44 45 46 |
# File 'app/services/completion_kit/provider_endpoint.rb', line 41 def parse(value) uri = URI.parse(value.to_s.strip) uri if uri.is_a?(URI::HTTP) && uri.host.present? rescue URI::InvalidURIError nil end |
.pin(builder, url) ⇒ Object
36 37 38 39 |
# File 'app/services/completion_kit/provider_endpoint.rb', line 36 def pin(builder, url) address = pinned_address(url) builder.adapter(:net_http) { |http| http.ipaddr = address } end |
.pinned_address(url) ⇒ Object
27 28 29 30 31 32 33 34 |
# File 'app/services/completion_kit/provider_endpoint.rb', line 27 def pinned_address(url) uri = parse(url) raise UnsafeEndpoint, ISSUE_MESSAGES[:invalid_url] unless uri addrs = addresses(uri.host) issue = issues_for(addrs).first raise UnsafeEndpoint, ISSUE_MESSAGES[issue] if issue (addrs.find(&:ipv4?) || addrs.first).to_s end |
.resolve(host) ⇒ Object
61 62 63 64 65 |
# File 'app/services/completion_kit/provider_endpoint.rb', line 61 def resolve(host) Addrinfo.getaddrinfo(host, nil, nil, :STREAM).map(&:ip_address).uniq rescue SocketError [] end |
.safe?(url) ⇒ Boolean
23 24 25 |
# File 'app/services/completion_kit/provider_endpoint.rb', line 23 def safe?(url) validate(url).empty? end |
.unsafe?(ip) ⇒ Boolean
67 68 69 70 71 72 73 74 75 |
# File 'app/services/completion_kit/provider_endpoint.rb', line 67 def unsafe?(ip) ip = ip.native return true if ip.private? return true if ip.link_local? return true if ip.to_i.zero? return true if ip.ipv4? && BLOCKED_NETS.any? { |net| net.include?(ip) } return true if ip.loopback? && !CompletionKit.config.allow_loopback_endpoints false end |
.validate(url) ⇒ Object
17 18 19 20 21 |
# File 'app/services/completion_kit/provider_endpoint.rb', line 17 def validate(url) uri = parse(url) return [:invalid_url] unless uri issues_for(addresses(uri.host)) end |