From 83900448dfde9b1ed575da9cd31037c7d8f9f95e Mon Sep 17 00:00:00 2001 From: Steffen Deusch Date: Tue, 19 Nov 2024 17:38:06 +0100 Subject: [PATCH] Check live_session when patching to same LiveView (#3521) Fixes #3520 --- lib/phoenix_live_view/channel.ex | 35 ++++++++++++++++++++------ lib/phoenix_live_view/route.ex | 5 +++- test/phoenix_live_view/router_test.exs | 31 +++++++++++++++++++++++ 3 files changed, 63 insertions(+), 8 deletions(-) diff --git a/lib/phoenix_live_view/channel.ex b/lib/phoenix_live_view/channel.ex index 78a48c960d..d4f1f7ad5b 100644 --- a/lib/phoenix_live_view/channel.ex +++ b/lib/phoenix_live_view/channel.ex @@ -1110,11 +1110,9 @@ defmodule Phoenix.LiveView.Channel do %Session{ id: id, view: view, - root_view: root_view, parent_pid: parent, root_pid: root_pid, session: verified_user_session, - assign_new: assign_new, router: router } = verified @@ -1164,7 +1162,7 @@ defmodule Phoenix.LiveView.Channel do merged_session = Map.merge(socket_session, verified_user_session) lifecycle = load_lifecycle(config, route) - case mount_private(parent, root_view, assign_new, connect_params, connect_info, lifecycle) do + case mount_private(verified, connect_params, connect_info, lifecycle) do {:ok, mount_priv} -> socket = Utils.configure_socket(socket, mount_priv, action, flash, host_uri) @@ -1254,7 +1252,14 @@ defmodule Phoenix.LiveView.Channel do socket end - defp mount_private(nil, root_view, assign_new, connect_params, connect_info, lifecycle) do + defp mount_private(%Session{parent_pid: nil} = session, connect_params, connect_info, lifecycle) do + %{ + root_view: root_view, + assign_new: assign_new, + live_session_name: live_session_name, + live_session_vsn: live_session_vsn + } = session + {:ok, %{ connect_params: connect_params, @@ -1262,11 +1267,25 @@ defmodule Phoenix.LiveView.Channel do assign_new: {%{}, assign_new}, lifecycle: lifecycle, root_view: root_view, - live_temp: %{} + live_temp: %{}, + live_session_name: live_session_name, + live_session_vsn: live_session_vsn }} end - defp mount_private(parent, root_view, assign_new, connect_params, connect_info, lifecycle) do + defp mount_private( + %Session{parent_pid: parent} = session, + connect_params, + connect_info, + lifecycle + ) do + %{ + root_view: root_view, + assign_new: assign_new, + live_session_name: live_session_name, + live_session_vsn: live_session_vsn + } = session + case sync_with_parent(parent, assign_new) do {:ok, parent_assigns} -> # Child live views always ignore the layout on `:use`. @@ -1278,7 +1297,9 @@ defmodule Phoenix.LiveView.Channel do live_layout: false, lifecycle: lifecycle, root_view: root_view, - live_temp: %{} + live_temp: %{}, + live_session_name: live_session_name, + live_session_vsn: live_session_vsn }} {:error, :noproc} -> diff --git a/lib/phoenix_live_view/route.ex b/lib/phoenix_live_view/route.ex index 5c8e766548..d6bea78a77 100644 --- a/lib/phoenix_live_view/route.ex +++ b/lib/phoenix_live_view/route.ex @@ -29,8 +29,11 @@ defmodule Phoenix.LiveView.Route do end def live_link_info!(%Socket{} = socket, view, uri) do + %{private: %{live_session_name: session_name, live_session_vsn: session_version}} = socket + case live_link_info(socket.endpoint, socket.router, uri) do - {:internal, %Route{view: ^view} = route} -> + {:internal, + %Route{view: ^view, live_session: %{name: ^session_name, vsn: ^session_version}} = route} -> {:internal, route} {:internal, %Route{view: _view} = route} -> diff --git a/test/phoenix_live_view/router_test.exs b/test/phoenix_live_view/router_test.exs index 983e511354..03f1400bd4 100644 --- a/test/phoenix_live_view/router_test.exs +++ b/test/phoenix_live_view/router_test.exs @@ -283,5 +283,36 @@ defmodule Phoenix.LiveView.RouterTest do assert html_response(conn, 200) =~ ~r|]+>LIVEOVERRIDESTART\-123\-The value is: 123\-LIVEOVERRIDEEND| end + + test "classifies route as external when same view, but different session" do + # previously, a patch to the same LV, but a different path in a different live_session + # would succeed when it should not + {_, %Route{live_session: %{vsn: vsn}}} = + Route.live_link_info( + @endpoint, + Phoenix.LiveViewTest.Support.Router, + "/clock-live-session" + ) + + socket = %Phoenix.LiveView.Socket{ + router: Phoenix.LiveViewTest.Support.Router, + endpoint: @endpoint, + private: %{live_session_name: :test, live_session_vsn: vsn} + } + + assert {:external, _} = + Route.live_link_info!( + socket, + Phoenix.LiveViewTest.Support.ClockLive, + "/clock-live-session-admin" + ) + + assert {:internal, _} = + Route.live_link_info!( + socket, + Phoenix.LiveViewTest.Support.ClockLive, + "/clock-live-session" + ) + end end end