diff --git a/assets/js/lib/user.js b/assets/js/lib/user.js index 7f4f33a1a..a9de85826 100644 --- a/assets/js/lib/user.js +++ b/assets/js/lib/user.js @@ -1,9 +1,9 @@ import { decodeBase64, encodeBase64 } from "./utils"; -const USER_DATA_COOKIE = "user_data"; +const USER_DATA_COOKIE = "lb:user_data"; /** - * Stores user data in the `"user_data"` cookie. + * Stores user data in the `"lb:user_data"` cookie. */ export function storeUserData(userData) { const json = JSON.stringify(userData); @@ -12,7 +12,7 @@ export function storeUserData(userData) { } /** - * Loads user data from the `"user_data"` cookie. + * Loads user data from the `"lb:user_data"` cookie. */ export function loadUserData() { const encoded = getCookieValue(USER_DATA_COOKIE); diff --git a/config/dev.exs b/config/dev.exs index 8becc9eb9..0edd88065 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -8,7 +8,7 @@ import Config config :livebook, LivebookWeb.Endpoint, # Binding to loopback ipv4 address prevents access from other machines. # Change to `ip: {0, 0, 0, 0}` to allow access from other machines. - http: [ip: {127, 0, 0, 1}, port: 4000], + http: [ip: {127, 0, 0, 1}, port: 4000, protocol_options: [max_header_value_length: 32768]], code_reloader: true, debug_errors: true, check_origin: false, diff --git a/config/prod.exs b/config/prod.exs index 2b1572a1c..22220e130 100644 --- a/config/prod.exs +++ b/config/prod.exs @@ -2,7 +2,7 @@ import Config # Default bind and port for production config :livebook, LivebookWeb.Endpoint, - http: [ip: {127, 0, 0, 1}, port: 8080], + http: [ip: {127, 0, 0, 1}, port: 8080, protocol_options: [max_header_value_length: 32768]], server: true config :livebook, :iframe_port, 8081 diff --git a/lib/livebook_web/endpoint.ex b/lib/livebook_web/endpoint.ex index 56b8bdb4d..c3a8e8ac1 100644 --- a/lib/livebook_web/endpoint.ex +++ b/lib/livebook_web/endpoint.ex @@ -6,7 +6,7 @@ defmodule LivebookWeb.Endpoint do # Set :encryption_salt if you would also like to encrypt it. @session_options [ store: :cookie, - key: "_livebook_key", + key: "lb:session", signing_salt: "deadbook" ] @@ -78,6 +78,7 @@ defmodule LivebookWeb.Endpoint do plug Plug.MethodOverride plug Plug.Head plug :session + plug :purge_cookies # Run custom plugs from the app configuration plug LivebookWeb.ConfiguredPlug @@ -103,6 +104,30 @@ defmodule LivebookWeb.Endpoint do end end + # Because we run on localhost, we may accumulate + # cookies from several other apps. Our header limit + # is set to 32kB. Once we are 75% of said limit, + # we clear other cookies to make sure we don't go + # over the limit. + def purge_cookies(conn, _opts) do + cookie_size = + conn + |> Plug.Conn.get_req_header("cookie") + |> Enum.map(&byte_size/1) + |> Enum.sum() + + if cookie_size > 24576 do + conn.cookies + |> Enum.reject(fn {key, _value} -> String.starts_with?(key, "lb:") end) + |> Enum.take(10) + |> Enum.reduce(conn, fn {key, _value}, conn -> + Plug.Conn.delete_resp_cookie(conn, key) + end) + else + conn + end + end + def access_struct_url() do base = case struct_url() do diff --git a/lib/livebook_web/plugs/user_plug.ex b/lib/livebook_web/plugs/user_plug.ex index 8d71ff86f..1b51d4078 100644 --- a/lib/livebook_web/plugs/user_plug.ex +++ b/lib/livebook_web/plugs/user_plug.ex @@ -40,14 +40,14 @@ defmodule LivebookWeb.UserPlug do end defp ensure_user_data(conn) do - if Map.has_key?(conn.req_cookies, "user_data") do + if Map.has_key?(conn.req_cookies, "lb:user_data") do conn else user_data = user_data(User.new()) encoded = user_data |> Jason.encode!() |> Base.encode64() # Set `http_only` to `false`, so that it can be accessed on the client # Set expiration in 5 years - put_resp_cookie(conn, "user_data", encoded, http_only: false, max_age: 157_680_000) + put_resp_cookie(conn, "lb:user_data", encoded, http_only: false, max_age: 157_680_000) end end @@ -60,7 +60,7 @@ defmodule LivebookWeb.UserPlug do # Copies user_data from cookie to session, so that it's # accessible to LiveViews defp mirror_user_data_in_session(conn) do - user_data = conn.cookies["user_data"] |> Base.decode64!() |> Jason.decode!() + user_data = conn.cookies["lb:user_data"] |> Base.decode64!() |> Jason.decode!() put_session(conn, :user_data, user_data) end end diff --git a/test/livebook_web/plugs/user_plug_test.exs b/test/livebook_web/plugs/user_plug_test.exs index f689089be..219195976 100644 --- a/test/livebook_web/plugs/user_plug_test.exs +++ b/test/livebook_web/plugs/user_plug_test.exs @@ -33,7 +33,7 @@ defmodule LivebookWeb.UserPlugTest do |> fetch_cookies() |> call() - assert conn.cookies["user_data"] != nil + assert conn.cookies["lb:user_data"] != nil end test "keeps user_data cookie if present" do @@ -43,10 +43,10 @@ defmodule LivebookWeb.UserPlugTest do conn = conn(:get, "/") |> init_test_session(%{}) - |> put_req_cookie("user_data", cookie_value) + |> put_req_cookie("lb:user_data", cookie_value) |> fetch_cookies() |> call() - assert conn.cookies["user_data"] == cookie_value + assert conn.cookies["lb:user_data"] == cookie_value end end