Skip to content

Commit

Permalink
Request logger cookie custom domain (phoenixframework#200)
Browse files Browse the repository at this point in the history
  • Loading branch information
cblavier authored Oct 13, 2020
1 parent 16bbfaf commit 60f9b64
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 18 deletions.
9 changes: 7 additions & 2 deletions assets/js/request_logger_cookie/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
/** LiveView Hook **/

const setCookie = (params) => {
document.cookie = `${params.key}=${params.value};samesite=strict;path=/`;
let cookie = `${params.key}=${params.value};samesite=strict;path=/`
if (params.domain) {
cookie += `;domain=${params.domain}`
}
document.cookie = cookie
}

const removeCookie = (params) => {
Expand All @@ -16,7 +20,8 @@ const isCookieEnabled = (hook) => {
const cookieParams = (hook) => {
return {
key: hook.el.getAttribute('data-cookie-key'),
value: hook.el.getAttribute('data-cookie-value')
value: hook.el.getAttribute('data-cookie-value'),
domain: hook.el.getAttribute('data-cookie-domain')
}
}

Expand Down
13 changes: 12 additions & 1 deletion lib/phoenix/live_dashboard/pages/request_logger_page.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ defmodule Phoenix.LiveDashboard.RequestLoggerPage do

@impl true
def mount(%{"stream" => stream}, session, socket) do
%{"request_logger" => {param_key, cookie_key}} = session
%{
"request_logger" => {param_key, cookie_key},
"request_logger_cookie_domain" => cookie_domain
} = session

if connected?(socket) do
# TODO: Remove || once we support Phoenix v1.5+
Expand All @@ -20,6 +23,7 @@ defmodule Phoenix.LiveDashboard.RequestLoggerPage do
stream: stream,
param_key: param_key,
cookie_key: cookie_key,
cookie_domain: read_cookie_domain(socket, cookie_domain),
cookie_enabled: false,
autoscroll_enabled: true,
messages_present: false
Expand Down Expand Up @@ -135,6 +139,7 @@ defmodule Phoenix.LiveDashboard.RequestLoggerPage do
<div phx-hook="PhxRequestLoggerCookie" id="request-logger-cookie-buttons"
data-cookie-key=<%=@cookie_key %>
data-cookie-value=<%=sign(@socket, @cookie_key, @stream) %>
<%= if @cookie_domain do %>data-cookie-domain="<%=@cookie_domain %>"<% end %>
data-cookie-enabled="<%= @cookie_enabled %>">
<%= if @cookie_enabled do %>
Expand Down Expand Up @@ -177,4 +182,10 @@ defmodule Phoenix.LiveDashboard.RequestLoggerPage do
</div>
"""
end

defp read_cookie_domain(socket, :parent) do
socket.host_uri.host |> String.split(".", parts: 2) |> List.last()
end

defp read_cookie_domain(_socket, domain), do: domain
end
49 changes: 45 additions & 4 deletions lib/phoenix/live_dashboard/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ defmodule Phoenix.LiveDashboard.Router do
If not set, metrics will start out empty/blank and only display
data that occurs while the browser page is open.
* `:request_logger_cookie_domain` - Configures the domain the request_logger
cookie will be written to. It can be a string or `:parent` atom.
When a string is given, it will directly set cookie domain to the given
value.
When `:parent` is given, it will take the parent domain from current endpoint
host (if host is "www.acme.com" the cookie will be scoped on "acme.com").
When not set, the cookie will be scoped to current domain.
## Examples
defmodule MyAppWeb.Router do
Expand All @@ -42,7 +50,8 @@ defmodule Phoenix.LiveDashboard.Router do
live_dashboard "/dashboard",
metrics: {MyAppWeb.Telemetry, :metrics},
env_keys: ["APP_USER", "VERSION"],
metrics_history: {MyStorage, :metrics_history, []}
metrics_history: {MyStorage, :metrics_history, []},
request_logger_cookie_domain: ".acme.com"
end
end
Expand Down Expand Up @@ -122,8 +131,32 @@ defmodule Phoenix.LiveDashboard.Router do
raise ArgumentError, ":additional_pages must be a keyword, got: " <> inspect(other)
end

request_logger_cookie_domain =
case options[:request_logger_cookie_domain] do
nil ->
nil

domain when is_binary(domain) ->
domain

:parent ->
:parent

other ->
raise ArgumentError,
":request_logger_cookie_domain must be a binary or :parent atom, got: " <>
inspect(other)
end

csp_nonce_assign_key = options[:csp_nonce_assign_key]
session_args = [metrics, env_keys, metrics_history, additional_pages]

session_args = [
metrics,
env_keys,
metrics_history,
additional_pages,
request_logger_cookie_domain
]

[
session: {__MODULE__, :__session__, session_args},
Expand Down Expand Up @@ -152,14 +185,22 @@ defmodule Phoenix.LiveDashboard.Router do
end

@doc false
def __session__(conn, metrics, env_keys, metrics_history, additional_pages) do
def __session__(
conn,
metrics,
env_keys,
metrics_history,
additional_pages,
request_logger_cookie_domain
) do
metrics_session = %{
"metrics" => metrics,
"metrics_history" => metrics_history
}

request_logger_session = %{
"request_logger" => Phoenix.LiveDashboard.RequestLogger.param_key(conn)
"request_logger" => Phoenix.LiveDashboard.RequestLogger.param_key(conn),
"request_logger_cookie_domain" => request_logger_cookie_domain
}

{pages, requirements} =
Expand Down
2 changes: 1 addition & 1 deletion priv/static/js/app.js

Large diffs are not rendered by default.

41 changes: 31 additions & 10 deletions test/phoenix/live_dashboard/router_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ defmodule Phoenix.LiveDashboard.RouterTest do

test "default options" do
assert Router.__options__([]) == [
session: {Phoenix.LiveDashboard.Router, :__session__, [nil, nil, nil, []]},
session: {Phoenix.LiveDashboard.Router, :__session__, [nil, nil, nil, [], nil]},
private: %{live_socket_path: "/live", csp_nonce_assign_key: nil},
layout: {Phoenix.LiveDashboard.LayoutView, :dash},
as: :live_dashboard
Expand All @@ -23,10 +23,10 @@ defmodule Phoenix.LiveDashboard.RouterTest do

test "configures metrics" do
assert Router.__options__(metrics: Foo)[:session] ==
{Phoenix.LiveDashboard.Router, :__session__, [{Foo, :metrics}, nil, nil, []]}
{Phoenix.LiveDashboard.Router, :__session__, [{Foo, :metrics}, nil, nil, [], nil]}

assert Router.__options__(metrics: {Foo, :bar})[:session] ==
{Phoenix.LiveDashboard.Router, :__session__, [{Foo, :bar}, nil, nil, []]}
{Phoenix.LiveDashboard.Router, :__session__, [{Foo, :bar}, nil, nil, [], nil]}

assert_raise ArgumentError, fn ->
Router.__options__(metrics: [])
Expand All @@ -35,7 +35,8 @@ defmodule Phoenix.LiveDashboard.RouterTest do

test "configures env_keys" do
assert Router.__options__(env_keys: ["USER", "ROOTDIR"])[:session] ==
{Phoenix.LiveDashboard.Router, :__session__, [nil, ["USER", "ROOTDIR"], nil, []]}
{Phoenix.LiveDashboard.Router, :__session__,
[nil, ["USER", "ROOTDIR"], nil, [], nil]}

assert_raise ArgumentError, fn ->
Router.__options__(env_keys: "FOO")
Expand All @@ -45,7 +46,7 @@ defmodule Phoenix.LiveDashboard.RouterTest do
test "accepts metrics_history option" do
assert Router.__options__(metrics_history: {MyStorage, :metrics_history, []})[:session] ==
{Phoenix.LiveDashboard.Router, :__session__,
[nil, nil, {MyStorage, :metrics_history, []}, []]}
[nil, nil, {MyStorage, :metrics_history, []}, [], nil]}

assert_raise ArgumentError, fn ->
Router.__options__(metrics_history: %{namespace: {MyStorage, :metrics_history, []}})
Expand All @@ -58,15 +59,15 @@ defmodule Phoenix.LiveDashboard.RouterTest do

test "configures additional_pages" do
assert Router.__options__(additional_pages: [])[:session] ==
{Phoenix.LiveDashboard.Router, :__session__, [nil, nil, nil, []]}
{Phoenix.LiveDashboard.Router, :__session__, [nil, nil, nil, [], nil]}

assert Router.__options__(additional_pages: [{"custom", CustomPage}])[:session] ==
{Phoenix.LiveDashboard.Router, :__session__,
[nil, nil, nil, [{"custom", {CustomPage, %{}}}]]}
[nil, nil, nil, [{"custom", {CustomPage, %{}}}], nil]}

assert Router.__options__(additional_pages: [{"custom", {CustomPage, [1]}}])[:session] ==
{Phoenix.LiveDashboard.Router, :__session__,
[nil, nil, nil, [{"custom", {CustomPage, [1]}}]]}
[nil, nil, nil, [{"custom", {CustomPage, [1]}}], nil]}

assert_raise ArgumentError, fn ->
Router.__options__(additional_pages: [{CustomPage, 1}])
Expand All @@ -81,6 +82,25 @@ defmodule Phoenix.LiveDashboard.RouterTest do
end
end

test "configures request_logger_cookie_domain" do
assert Router.__options__(request_logger_cookie_domain: nil)[:session] ==
{Phoenix.LiveDashboard.Router, :__session__, [nil, nil, nil, [], nil]}

assert Router.__options__(request_logger_cookie_domain: ".acme.com")[:session] ==
{Phoenix.LiveDashboard.Router, :__session__, [nil, nil, nil, [], ".acme.com"]}

assert Router.__options__(request_logger_cookie_domain: :parent)[:session] ==
{Phoenix.LiveDashboard.Router, :__session__, [nil, nil, nil, [], :parent]}

assert_raise ArgumentError, fn ->
Router.__options__(request_logger_cookie_domain: :unknown_atom)
end

assert_raise ArgumentError, fn ->
Router.__options__(request_logger_cookie_domain: [])
end
end

describe "__session__/5" do
test "generates pages & requirements" do
assert %{
Expand All @@ -90,15 +110,16 @@ defmodule Phoenix.LiveDashboard.RouterTest do
{"metrics",
{Phoenix.LiveDashboard.MetricsPage, %{"metrics" => [], "metrics_history" => []}}},
{"request_logger",
{Phoenix.LiveDashboard.RequestLoggerPage, %{"request_logger" => nil}}},
{Phoenix.LiveDashboard.RequestLoggerPage,
%{"request_logger" => nil, "request_logger_cookie_domain" => nil}}},
{"applications", {Phoenix.LiveDashboard.ApplicationsPage, %{}}},
{"processes", {Phoenix.LiveDashboard.ProcessesPage, %{}}},
{"ports", {Phoenix.LiveDashboard.PortsPage, %{}}},
{"sockets", {Phoenix.LiveDashboard.SocketsPage, %{}}},
{"ets", {Phoenix.LiveDashboard.EtsPage, %{}}}
],
"requirements" => [{:application, :os_mon}]
} = Phoenix.LiveDashboard.Router.__session__(build_conn(), [], [], [], [])
} = Phoenix.LiveDashboard.Router.__session__(build_conn(), [], [], [], [], nil)
end
end
end

0 comments on commit 60f9b64

Please sign in to comment.