mirror of
https://github.com/livebook-dev/livebook.git
synced 2024-09-25 12:26:05 +08:00
52 lines
1.3 KiB
Elixir
52 lines
1.3 KiB
Elixir
|
defmodule LivebookWeb.InvalidTokenError do
|
||
|
defexception plug_status: 401, message: "invalid token"
|
||
|
end
|
||
|
|
||
|
defmodule LivebookWeb.AuthPlug do
|
||
|
@moduledoc false
|
||
|
|
||
|
@behaviour Plug
|
||
|
|
||
|
import Plug.Conn
|
||
|
import Phoenix.Controller
|
||
|
|
||
|
@cookie_opts [sign: true, max_age: 2_592_000]
|
||
|
|
||
|
@impl true
|
||
|
def init(opts), do: opts
|
||
|
|
||
|
@impl true
|
||
|
def call(conn, _otps) do
|
||
|
case Application.get_env(:livebook, :token) do
|
||
|
nil -> conn
|
||
|
token -> token_authentication(conn, token)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
defp token_authentication(conn, token) do
|
||
|
# The user may run multiple Livebook instances on the same host
|
||
|
# on different ports, so we scope the cookie name under port
|
||
|
token_cookie = "#{conn.port}:token"
|
||
|
|
||
|
conn = fetch_cookies(conn, signed: [token_cookie])
|
||
|
|
||
|
param_token = Map.get(conn.query_params, "token")
|
||
|
cookie_token = conn.cookies[token_cookie]
|
||
|
|
||
|
cond do
|
||
|
is_binary(param_token) and Plug.Crypto.secure_compare(param_token, token) ->
|
||
|
conn
|
||
|
|> put_resp_cookie(token_cookie, param_token, @cookie_opts)
|
||
|
# Redirect to the same path without query params
|
||
|
|> redirect(to: conn.request_path)
|
||
|
|> halt()
|
||
|
|
||
|
is_binary(cookie_token) and Plug.Crypto.secure_compare(cookie_token, token) ->
|
||
|
conn
|
||
|
|
||
|
true ->
|
||
|
raise LivebookWeb.InvalidTokenError
|
||
|
end
|
||
|
end
|
||
|
end
|