Packages
livebook
0.12.1
0.19.8
0.19.7
0.19.6
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.19.0
0.18.6
0.18.5
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.3
0.17.2
0.17.1
0.17.0
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.7
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.14.0-rc.1
0.14.0-rc.0
0.13.3
0.13.2
0.13.1
0.13.0
0.12.1
0.12.0
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.3
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.1
0.4.0
0.3.2
0.3.1
0.3.0
0.2.3
0.2.2
0.2.1
0.2.0
0.1.2
0.1.1
0.1.0
Automate code & data workflows with interactive notebooks
Current section
Files
Jump to
Current section
Files
lib/livebook_web/endpoint.ex
defmodule LivebookWeb.Endpoint do
use Phoenix.Endpoint, otp_app: :livebook
# The session will be stored in the cookie and signed,
# this means its contents can be read but not tampered with.
# Set :encryption_salt if you would also like to encrypt it.
@session_options [
store: :cookie,
key: "lb:session",
signing_salt: "deadbook"
]
# Don't check the origin as we don't know how the web app is gonna be accessed.
# It runs locally, but may be exposed via IP or domain name. The WebSocket
# connection is already protected from CSWSH by using CSRF token.
@websocket_options [
check_origin: false,
connect_info: [:user_agent, :uri, session: @session_options]
]
socket "/live", Phoenix.LiveView.Socket, websocket: @websocket_options
socket "/socket", LivebookWeb.Socket, websocket: @websocket_options
# We use Escript for distributing Livebook, so we don't have access to the static
# files at runtime in the prod environment. To overcome this we load contents of
# those files at compilation time, so that they become a part of the executable
# and can be served from memory.
defmodule AssetsMemoryProvider do
use LivebookWeb.MemoryProvider,
from: Path.expand("../../static", __DIR__),
gzip: true
end
defmodule AssetsFileSystemProvider do
use LivebookWeb.FileSystemProvider,
from: "tmp/static_dev"
end
# Serve static files at "/"
if code_reloading? do
# In development we use assets from tmp/static_dev (rebuilt dynamically on every change).
# Note that this directory doesn't contain predefined files (e.g. images), so we also
# use `AssetsMemoryProvider` to serve those from static/.
plug LivebookWeb.StaticPlug,
at: "/",
file_provider: AssetsFileSystemProvider,
gzip: false
end
plug LivebookWeb.StaticPlug,
at: "/",
file_provider: AssetsMemoryProvider,
gzip: true
plug :force_ssl
# Code reloading can be explicitly enabled under the
# :code_reloader configuration of your endpoint.
if code_reloading? do
socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket
plug Phoenix.LiveReloader
plug Phoenix.CodeReloader
end
plug Phoenix.LiveDashboard.RequestLogger,
param_key: "request_logger",
cookie_key: "request_logger"
plug Plug.RequestId
plug Plug.Telemetry, event_prefix: [:phoenix, :endpoint]
plug Plug.Parsers,
parsers: [:urlencoded, :multipart, :json],
pass: ["*/*"],
json_decoder: Phoenix.json_library()
plug Plug.MethodOverride
plug Plug.Head
plug :session
plug :purge_cookies
# Run custom plugs from the app configuration
plug LivebookWeb.ConfiguredPlug
plug LivebookWeb.Router
@plug_session Plug.Session.init(@session_options ++ [same_site: "Lax"])
@plug_session_iframe Plug.Session.init(@session_options ++ [same_site: "None", secure: true])
def session(conn, _opts) do
if Livebook.Config.within_iframe?() do
Plug.Session.call(conn, @plug_session_iframe)
else
Plug.Session.call(conn, @plug_session)
end
end
@plug_ssl Plug.SSL.init(host: {Livebook.Config, :force_ssl_host, []})
def force_ssl(conn, _opts) do
if Livebook.Config.force_ssl_host() do
Plug.SSL.call(conn, @plug_ssl)
else
conn
end
end
def cookie_options() do
if Livebook.Config.within_iframe?() do
[same_site: "None", secure: true]
else
[same_site: "Lax"]
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
%URI{scheme: "https", port: 0} = uri ->
%{uri | port: port(:https, 433)}
%URI{scheme: "http", port: 0} = uri ->
%{uri | port: port(:http, 80)}
%URI{} = uri ->
uri
end
base = update_in(base.path, &(&1 || "/"))
if Livebook.Config.auth_mode() == :token do
token = Application.fetch_env!(:livebook, :token)
%{base | query: "token=" <> token}
else
base
end
end
def access_url do
URI.to_string(access_struct_url())
end
defp port(scheme, default) do
try do
server_info(scheme)
rescue
_ -> default
else
{:ok, {_, port}} when is_integer(port) -> port
_ -> default
end
end
end