Skip to content

Commit 37b4261

Browse files
committed
Add DSN#local?
1 parent 5d4cdb2 commit 37b4261

File tree

2 files changed

+57
-0
lines changed

2 files changed

+57
-0
lines changed

sentry-ruby/lib/sentry/dsn.rb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
# frozen_string_literal: true
22

33
require "uri"
4+
require "ipaddr"
5+
require "resolv"
46

57
module Sentry
68
class DSN
79
PORT_MAP = { "http" => 80, "https" => 443 }.freeze
810
REQUIRED_ATTRIBUTES = %w[host path public_key project_id].freeze
11+
LOCALHOST_NAMES = %w[localhost 127.0.0.1 ::1 [::1]].freeze
12+
LOCALHOST_PATTERN = /\.local(host|domain)?$/i
913

1014
attr_reader :scheme, :secret_key, :port, *REQUIRED_ATTRIBUTES
1115

@@ -49,5 +53,33 @@ def csp_report_uri
4953
def envelope_endpoint
5054
"#{path}/api/#{project_id}/envelope/"
5155
end
56+
57+
def local?
58+
@local ||= (localhost? || private_ip? || resolved_ips_private?)
59+
end
60+
61+
def localhost?
62+
LOCALHOST_NAMES.include?(host.downcase) || LOCALHOST_PATTERN.match?(host)
63+
end
64+
65+
def private_ip?
66+
@private_ip ||= begin
67+
begin
68+
IPAddr.new(host).private?
69+
rescue IPAddr::InvalidAddressError
70+
false
71+
end
72+
end
73+
end
74+
75+
def resolved_ips_private?
76+
@resolved_ips_private ||= begin
77+
begin
78+
Resolv.getaddresses(host).any? { |ip| IPAddr.new(ip).private? }
79+
rescue Resolv::ResolvError, IPAddr::InvalidAddressError
80+
false
81+
end
82+
end
83+
end
5284
end
5385
end

sentry-ruby/spec/sentry/dsn_spec.rb

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,29 @@
3737
expect(subject.csp_report_uri).to eq("http://sentry.localdomain:3000/api/42/security/?sentry_key=12345")
3838
end
3939
end
40+
41+
describe "#local?" do
42+
it "returns true for localhost" do
43+
expect(described_class.new("http://12345:67890@localhost/sentry/42").local?).to eq(true)
44+
end
45+
46+
it "returns true for 127.0.0.1" do
47+
expect(described_class.new("http://12345:67890@127.0.0.1/sentry/42").local?).to eq(true)
48+
end
49+
it "returns true for ::1" do
50+
expect(described_class.new("http://12345:67890@[::1]/sentry/42").local?).to eq(true)
51+
end
52+
53+
it "returns true for private IP" do
54+
expect(described_class.new("http://12345:67890@192.168.0.1/sentry/42").local?).to eq(true)
55+
end
56+
57+
it "returns true for private IP with port" do
58+
expect(described_class.new("http://12345:67890@192.168.0.1:3000/sentry/42").local?).to eq(true)
59+
end
60+
61+
it "returns false for non-local domain" do
62+
expect(described_class.new("http://12345:67890@sentry.io/sentry/42").local?).to eq(false)
63+
end
64+
end
4065
end

0 commit comments

Comments
 (0)