Created
October 26, 2018 19:46
-
-
Save trptcolin/ed63cd4b38a7e9e23eac2825411a3da4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule MyApp.Router do | |
use MyApp, :router | |
use Plug.ErrorHandler | |
use Sentry.Plug | |
alias MyApp.ScrubError | |
defp handle_errors(conn, %{kind: _kind, reason: _reason, stack: _stack} = error) do | |
updated_error = ScrubError.call(error) | |
super(conn, updated_error) | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule MyApp.ScrubError do | |
def call(%{kind: _kind, reason: _reason, stack: _stack} = error) do | |
param_strings_to_filter = Application.get_env(:phoenix, :filter_parameters) | |
as_atoms = Enum.map(param_strings_to_filter, fn x -> String.to_atom(x) end) | |
param_strings_to_filter = param_strings_to_filter ++ as_atoms | |
discard_values(error, param_strings_to_filter) | |
end | |
defp discard_values(%{__struct__: mod} = struct, _params) when is_atom(mod) do | |
struct | |
end | |
defp discard_values(%{} = map, params) do | |
Enum.into(map, %{}, fn {k, v} -> | |
cond do | |
Enum.any?(params, fn x -> x == k end) -> {k, "[FILTERED]"} | |
true -> {k, discard_values(v, params)} | |
end | |
end) | |
end | |
defp discard_values([_ | _] = list, params) do | |
Enum.map(list, &discard_values(&1, params)) | |
end | |
defp discard_values(other, _params), do: other | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule MyApp.ScrubErrorTest do | |
use ExUnit.Case | |
alias MyApp.ScrubError | |
describe "call/1" do | |
test "filters out password at the top level" do | |
error = %{ | |
kind: :error, | |
reason: %{changeset: %{params: %{"password" => "top secret password"}}}, | |
stack: [], | |
more: "stuff" | |
} | |
scrubbed_error = ScrubError.call(error) | |
assert scrubbed_error.reason.changeset.params["password"] == "[FILTERED]" | |
end | |
test "filters out nested password" do | |
error = %{ | |
kind: :error, | |
reason: %{changeset: %{params: %{"secrets" => %{"password" => "top secret password"}}}}, | |
stack: [], | |
more: "stuff" | |
} | |
scrubbed_error = ScrubError.call(error) | |
assert scrubbed_error.reason.changeset.params["secrets"]["password"] == "[FILTERED]" | |
end | |
test "filters out nested password as an atom" do | |
error = %{ | |
kind: :error, | |
reason: %{changeset: %{params: %{"secrets" => %{password: "top secret password"}}}}, | |
stack: [], | |
more: "stuff" | |
} | |
scrubbed_error = ScrubError.call(error) | |
assert scrubbed_error.reason.changeset.params["secrets"].password == "[FILTERED]" | |
end | |
test "filters out nested password underneath a list" do | |
error = %{ | |
kind: :error, | |
reason: %{changeset: %{params: %{"secrets" => [%{password: "top secret password"}]}}}, | |
stack: [], | |
more: "stuff" | |
} | |
scrubbed_error = ScrubError.call(error) | |
assert scrubbed_error.reason.changeset.params["secrets"] == [%{password: "[FILTERED]"}] | |
end | |
test "leaves bad changeset alone" do | |
error = %{kind: :error, reason: %{changeset: "bad"}, stack: [], more: "stuff"} | |
scrubbed_error = ScrubError.call(error) | |
assert scrubbed_error == error | |
end | |
test "leaves bad params alone" do | |
error = %{kind: :error, reason: %{changeset: %{params: "bad"}}, stack: [], more: "stuff"} | |
scrubbed_error = ScrubError.call(error) | |
assert scrubbed_error == error | |
end | |
test "leaves top-level map params alone when no filtered items exist" do | |
error = %{ | |
kind: :error, | |
reason: %{changeset: %{params: %{"user_id" => 1}}}, | |
stack: [], | |
more: "stuff" | |
} | |
scrubbed_error = ScrubError.call(error) | |
assert scrubbed_error == error | |
end | |
test "leaves top-level list params alone when no filtered items exist" do | |
error = %{ | |
kind: :error, | |
reason: %{changeset: %{params: %{"user_ids" => [1]}}}, | |
stack: [], | |
more: "stuff" | |
} | |
scrubbed_error = ScrubError.call(error) | |
assert scrubbed_error == error | |
end | |
test "leaves nested structs alone when no filtered items exist" do | |
error = %{ | |
kind: :error, | |
reason: %{changeset: %{params: %{"users" => [%MyApp.User{}]}}}, | |
stack: [], | |
more: "stuff" | |
} | |
scrubbed_error = ScrubError.call(error) | |
assert scrubbed_error == error | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment