Skip to content

Commit 0b31deb

Browse files
authored
Remove version from live_session (#3715)
Previously, live_session's had a version field that was generated randomly whenever the router was compiled. We checked the version field on live_redirects and enforce a full redirect (as when a user navigates, that is a good point in time to force a full navigation, right?). It turns out that live navigation on the client is actually implemented in a way that every reconnect after the first live navigation is also treated as a navigation. Therefore, after a deployment that changed the router, LiveViews that were mounted through a live navigation were never remounted, but always fully reloaded, losing any state and preventing form recovery from working. As the security mechanism of live_session is primarily based on the live_session name, checking the name is generally enough. There could be a case where previously a live_session called `:admin` was defined where a user had access to and after deployment, those routes were instead moved to a `:semiadmin` live session and now super sensitive routes are accessible in the `:admin` live session. In this case, a user could try to mount a route from this super sensitive section, but even then, those routes SHOULD be protected by on_mount hooks that run and properly check authorization, e.g. based on the user_id in the session. So to sum this up, the version field of the live session is not needed, causes problems at the moment and is therefore removed.
1 parent f4c6d5c commit 0b31deb

File tree

5 files changed

+16
-38
lines changed

5 files changed

+16
-38
lines changed

lib/phoenix_live_view/channel.ex

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1287,8 +1287,7 @@ defmodule Phoenix.LiveView.Channel do
12871287
%{
12881288
root_view: root_view,
12891289
assign_new: assign_new,
1290-
live_session_name: live_session_name,
1291-
live_session_vsn: live_session_vsn
1290+
live_session_name: live_session_name
12921291
} = session
12931292

12941293
{:ok,
@@ -1299,8 +1298,7 @@ defmodule Phoenix.LiveView.Channel do
12991298
lifecycle: lifecycle,
13001299
root_view: root_view,
13011300
live_temp: %{},
1302-
live_session_name: live_session_name,
1303-
live_session_vsn: live_session_vsn
1301+
live_session_name: live_session_name
13041302
}}
13051303
end
13061304

@@ -1313,8 +1311,7 @@ defmodule Phoenix.LiveView.Channel do
13131311
%{
13141312
root_view: root_view,
13151313
assign_new: assign_new,
1316-
live_session_name: live_session_name,
1317-
live_session_vsn: live_session_vsn
1314+
live_session_name: live_session_name
13181315
} = session
13191316

13201317
case sync_with_parent(parent, assign_new) do
@@ -1329,8 +1326,7 @@ defmodule Phoenix.LiveView.Channel do
13291326
lifecycle: lifecycle,
13301327
root_view: root_view,
13311328
live_temp: %{},
1332-
live_session_name: live_session_name,
1333-
live_session_vsn: live_session_vsn
1329+
live_session_name: live_session_name
13341330
}}
13351331

13361332
{:error, :noproc} ->

lib/phoenix_live_view/router.ex

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,6 @@ defmodule Phoenix.LiveView.Router do
240240
@doc false
241241
def __live_session__(module, opts, name) do
242242
Module.register_attribute(module, :phoenix_live_sessions, accumulate: true)
243-
vsn = session_vsn(module)
244243

245244
if not is_atom(name) do
246245
raise ArgumentError, """
@@ -264,7 +263,7 @@ defmodule Phoenix.LiveView.Router do
264263
"""
265264
end
266265

267-
current = %{name: name, extra: extra, vsn: vsn}
266+
current = %{name: name, extra: extra}
268267
Module.put_attribute(module, :phoenix_live_session_current, current)
269268

270269
Module.put_attribute(module, :phoenix_live_sessions, name)
@@ -375,7 +374,7 @@ defmodule Phoenix.LiveView.Router do
375374
when is_atom(action) and is_list(opts) do
376375
live_session =
377376
Module.get_attribute(router, :phoenix_live_session_current) ||
378-
%{name: :default, extra: %{}, vsn: session_vsn(router)}
377+
%{name: :default, extra: %{}}
379378

380379
helpers = Module.get_attribute(router, :phoenix_helpers)
381380

@@ -488,14 +487,4 @@ defmodule Phoenix.LiveView.Router do
488487
end
489488

490489
defp cookie_flash(%Plug.Conn{} = conn), do: {conn, nil}
491-
492-
defp session_vsn(module) do
493-
if vsn = Module.get_attribute(module, :phoenix_session_vsn) do
494-
vsn
495-
else
496-
vsn = System.system_time()
497-
Module.put_attribute(module, :phoenix_session_vsn, vsn)
498-
vsn
499-
end
500-
end
501490
end

lib/phoenix_live_view/session.ex

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,15 @@ defmodule Phoenix.LiveView.Session do
1212
router: nil,
1313
flash: nil,
1414
live_session_name: nil,
15-
live_session_vsn: nil,
1615
assign_new: []
1716

1817
def main?(%Session{} = session), do: session.router != nil and session.parent_pid == nil
1918

2019
def authorize_root_redirect(%Session{} = session, %Route{} = route) do
21-
%Session{live_session_name: session_name, live_session_vsn: session_vsn} = session
20+
%Session{live_session_name: session_name} = session
2221

2322
case route.live_session do
24-
# We check the version because if there was a new deploy,
25-
# we can use this opportunity to reload the whole thing.
26-
%{name: ^session_name, vsn: ^session_vsn} ->
23+
%{name: ^session_name} ->
2724
{:ok, replace_root(session, route.view, self())}
2825

2926
%{} ->
@@ -63,7 +60,7 @@ defmodule Phoenix.LiveView.Session do
6360
:ok <- verify_topic(topic, id),
6461
{:ok, static} <- verify_static_token(endpoint, id, static_token) do
6562
merged_session = Map.merge(session, static)
66-
{live_session_name, vsn} = merged_session[:live_session] || {nil, nil}
63+
live_session_name = merged_session[:live_session_name]
6764

6865
session = %Session{
6966
id: id,
@@ -74,7 +71,6 @@ defmodule Phoenix.LiveView.Session do
7471
session: merged_session.session,
7572
assign_new: merged_session.assign_new,
7673
live_session_name: live_session_name,
77-
live_session_vsn: vsn,
7874
# optional keys
7975
router: merged_session[:router],
8076
flash: merged_session[:flash]

lib/phoenix_live_view/static.ex

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ defmodule Phoenix.LiveView.Static do
99
alias Phoenix.LiveView.{Socket, Utils, Diff, Route, Lifecycle}
1010

1111
# Token version. Should be changed whenever new data is stored.
12-
@token_vsn 5
12+
@token_vsn 6
1313
@phoenix_reload_status "__phoenix_reload_status__"
1414

1515
def token_vsn, do: @token_vsn
@@ -39,7 +39,7 @@ defmodule Phoenix.LiveView.Static do
3939

4040
defp live_session(%Plug.Conn{} = conn) do
4141
case conn.private[:phoenix_live_view] do
42-
{_view, _opts, %{name: _name, extra: _extra, vsn: _vsn} = lv_session} -> lv_session
42+
{_view, _opts, %{name: _name, extra: _extra} = lv_session} -> lv_session
4343
nil -> nil
4444
end
4545
end
@@ -354,9 +354,9 @@ defmodule Phoenix.LiveView.Static do
354354
end
355355

356356
defp sign_root_session(%Socket{} = socket, router, view, session, live_session) do
357-
live_session_pair =
357+
live_session_name =
358358
case live_session do
359-
%{name: name, vsn: vsn} -> {name, vsn}
359+
%{name: name} -> name
360360
nil -> nil
361361
end
362362

@@ -366,7 +366,7 @@ defmodule Phoenix.LiveView.Static do
366366
view: view,
367367
root_view: view,
368368
router: router,
369-
live_session: live_session_pair,
369+
live_session_name: live_session_name,
370370
parent_pid: nil,
371371
root_pid: nil,
372372
session: session

test/phoenix_live_view/router_test.exs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ defmodule Phoenix.LiveView.RouterTest do
8686
)
8787

8888
assert route.live_session.name == :test
89-
assert route.live_session.vsn
9089

9190
assert conn |> get(path) |> html_response(200) |> verified_session() == %{}
9291
end
@@ -102,7 +101,6 @@ defmodule Phoenix.LiveView.RouterTest do
102101
)
103102

104103
assert route.live_session.name == :admin
105-
assert route.live_session.vsn
106104

107105
assert conn |> get(path) |> html_response(200) |> verified_session() ==
108106
%{"admin" => true}
@@ -119,7 +117,6 @@ defmodule Phoenix.LiveView.RouterTest do
119117
)
120118

121119
assert route.live_session.name == :mfa
122-
assert route.live_session.vsn
123120

124121
assert conn |> get(path) |> html_response(200) |> verified_session() ==
125122
%{"inlined" => true, "called" => true}
@@ -323,7 +320,7 @@ defmodule Phoenix.LiveView.RouterTest do
323320
test "classifies route as external when same view, but different session" do
324321
# previously, a patch to the same LV, but a different path in a different live_session
325322
# would succeed when it should not
326-
{_, %Route{live_session: %{vsn: vsn}}} =
323+
{_, %Route{live_session: %{name: :test}}} =
327324
Route.live_link_info_without_checks(
328325
@endpoint,
329326
Phoenix.LiveViewTest.Support.Router,
@@ -333,7 +330,7 @@ defmodule Phoenix.LiveView.RouterTest do
333330
socket = %Phoenix.LiveView.Socket{
334331
router: Phoenix.LiveViewTest.Support.Router,
335332
endpoint: @endpoint,
336-
private: %{live_session_name: :test, live_session_vsn: vsn}
333+
private: %{live_session_name: :test}
337334
}
338335

339336
assert {:external, _} =

0 commit comments

Comments
 (0)