Skip to content

Commit b915794

Browse files
Add :remote_address_reader PlugContext option (#519)
1 parent ff7f148 commit b915794

File tree

2 files changed

+34
-8
lines changed

2 files changed

+34
-8
lines changed

lib/sentry/plug_context.ex

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,18 @@ defmodule Sentry.PlugContext do
7979
which Plug.RequestId (and therefore Phoenix) also default to.
8080
8181
plug Sentry.PlugContext, request_id_header: "application-request-id"
82+
83+
### Remote Address Reader
84+
85+
Sentry.PlugContext includes a request's originating IP address under the `REMOTE_ADDR`
86+
Environment key in Sentry. By default it is read from the `x-forwarded-for` HTTP header,
87+
and if this header is not present, it is read from `conn.remote_ip`.
88+
89+
If you wish to read this value differently (e.g. from a different HTTP header),
90+
or modify it in some other way (e.g. by masking it), you can configure this behavior
91+
by passing the `:remote_address_reader` option:
92+
93+
plug Sentry.PlugContext, remote_address_reader: &MyModule.read_ip/1
8294
"""
8395

8496
if Code.ensure_loaded?(Plug) do
@@ -111,6 +123,9 @@ defmodule Sentry.PlugContext do
111123

112124
request_id = Keyword.get(opts, :request_id_header) || @default_plug_request_id_header
113125

126+
remote_address_reader =
127+
Keyword.get(opts, :remote_address_reader, {__MODULE__, :default_remote_address_reader})
128+
114129
conn =
115130
Plug.Conn.fetch_cookies(conn)
116131
|> Plug.Conn.fetch_query_params()
@@ -123,7 +138,7 @@ defmodule Sentry.PlugContext do
123138
cookies: handle_data(conn, cookie_scrubber),
124139
headers: handle_data(conn, header_scrubber),
125140
env: %{
126-
"REMOTE_ADDR" => remote_address(conn),
141+
"REMOTE_ADDR" => handle_data(conn, remote_address_reader),
127142
"REMOTE_PORT" => remote_port(conn),
128143
"SERVER_NAME" => conn.host,
129144
"SERVER_PORT" => conn.port,
@@ -132,7 +147,8 @@ defmodule Sentry.PlugContext do
132147
}
133148
end
134149

135-
defp remote_address(conn) do
150+
@spec default_remote_address_reader(Plug.Conn.t()) :: String.t()
151+
def default_remote_address_reader(conn) do
136152
if header_value = get_header(conn, "x-forwarded-for") do
137153
header_value
138154
|> String.split(",")

test/plug_context_test.exs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@ defmodule Sentry.PlugContextTest do
1616
|> Map.take(["not-secret"])
1717
end
1818

19-
defp add_x_forwarded_for(conn, ip_str) do
20-
%{conn | req_headers: [{"x-forwarded-for", ip_str} | conn.req_headers]}
19+
def remote_address_reader(conn) do
20+
case get_req_header(conn, "cf-connecting-ip") do
21+
[remote_ip | _] -> remote_ip
22+
_ -> conn.remote_ip
23+
end
2124
end
2225

2326
test "sets request context" do
@@ -43,10 +46,9 @@ defmodule Sentry.PlugContextTest do
4346
end
4447

4548
test "sets request context with real client ip if request is forwarded" do
46-
Sentry.PlugContext.call(
47-
conn(:get, "/test?hello=world") |> add_x_forwarded_for("10.0.0.1"),
48-
[]
49-
)
49+
conn(:get, "/test?hello=world")
50+
|> put_req_header("x-forwarded-for", "10.0.0.1")
51+
|> Sentry.PlugContext.call([])
5052

5153
assert %{
5254
request: %{
@@ -67,6 +69,14 @@ defmodule Sentry.PlugContextTest do
6769
} = Sentry.Context.get_all()
6870
end
6971

72+
test "allows configuring request address reader" do
73+
conn(:get, "/test")
74+
|> put_req_header("cf-connecting-ip", "10.0.0.2")
75+
|> Sentry.PlugContext.call(remote_address_reader: {__MODULE__, :remote_address_reader})
76+
77+
assert %{"REMOTE_ADDR" => "10.0.0.2"} = Sentry.Context.get_all().request.env
78+
end
79+
7080
test "allows configuring body scrubber" do
7181
Sentry.PlugContext.call(conn(:get, "/test?hello=world&foo=bar"),
7282
body_scrubber: {__MODULE__, :body_scrubber}

0 commit comments

Comments
 (0)