livebook/lib/livebook_cli/server.ex
Jonatan Kłosko e9766ed7a5
Introduce token auth and add basic cli configuration (#148)
* Add token authentication

* Restructure CLI

* Allow port configuration

* Further refactoring

* Make sure livebook node starts with unique name

* Improve startup error handling

* Further refactoring

* Add authentication tests

* Add authentication view for entering the token

* Fix auth tests

* Always use random Livebook name for distribution

* Don't enable ANSI on Windows

* Define CLI Task behaviour and move generic logic to the main module

* Generalize convertion from cli arguments to configuration

* Randomly generate secret key base

* Update test/livebook_web/plugs/auth_plug_test.exs

Co-authored-by: José Valim <jose.valim@dashbit.co>

* Override app config in persistent manner

* Update lib/litebook_cli.ex

Co-authored-by: José Valim <jose.valim@dashbit.co>

* Move auth error to ErrorView

* Unify node name configuration and allow it via CLI

* Set all applications configs at once

* Move token generation to application.ex to work outside CLI

* Clean up overriding configuration

* Store auth token in separate cookies

* Update lib/livebook_cli/server.ex

Co-authored-by: José Valim <jose.valim@dashbit.co>

* Update lib/livebook_web/endpoint.ex

Co-authored-by: José Valim <jose.valim@dashbit.co>

* Update lib/livebook_web/plugs/auth_plug.ex

Co-authored-by: José Valim <jose.valim@dashbit.co>

Co-authored-by: José Valim <jose.valim@dashbit.co>
2021-04-08 11:41:52 +02:00

97 lines
2.8 KiB
Elixir

defmodule LivebookCLI.Server do
@moduledoc false
@behaviour LivebookCLI.Task
@impl true
def usage() do
"""
Usage: livebook server [options]
Available options:
-p, --port The port to start the web application on, defaults to 8080
--no-token Disable token authentication, enabled by default
--sname Set a shot name for the app distributed node
--name Set a name for the app distributed node
The --help option can be given for usage information.
"""
end
@impl true
def call(args) do
config_entries = args_to_config(args)
put_config_entries(config_entries)
case start_server() do
:ok ->
Process.sleep(:infinity)
:error ->
IO.ANSI.format([:red, "Livebook failed to start"]) |> IO.puts()
end
end
# Takes a list of {app, key, value} config entries
# and overrides the current applications' configuration accordingly.
# Multiple values for the same key are deeply merged (provided they are keyword lists).
defp put_config_entries(config_entries) do
config_entries
|> Enum.reduce([], fn {app, key, value}, acc ->
acc = Keyword.put_new_lazy(acc, app, fn -> Application.get_all_env(app) end)
Config.Reader.merge(acc, [{app, [{key, value}]}])
end)
|> Application.put_all_env(persistent: true)
end
defp start_server() do
Application.put_env(:phoenix, :serve_endpoints, true, persistent: true)
case Application.ensure_all_started(:livebook) do
{:ok, _} -> :ok
{:error, _} -> :error
end
end
defp args_to_config(args) do
{opts, _} =
OptionParser.parse!(
args,
strict: [token: :boolean, port: :integer, name: :string, sname: :string],
aliases: [p: :port]
)
validate_options!(opts)
opts_to_config(opts, [])
end
defp validate_options!(opts) do
if Keyword.has_key?(opts, :name) and Keyword.has_key?(opts, :sname) do
raise "the provided --sname and --name options are mutually exclusive, please specify only one of them"
end
end
defp opts_to_config([], config), do: config
defp opts_to_config([{:token, token_auth?} | opts], config) do
opts_to_config(opts, [{:livebook, :token_authentication, token_auth?} | config])
end
defp opts_to_config([{:port, port} | opts], config) do
opts_to_config(opts, [{:livebook, LivebookWeb.Endpoint, http: [port: port]} | config])
end
defp opts_to_config([{:sname, sname} | opts], config) do
sname = String.to_atom(sname)
opts_to_config(opts, [{:livebook, :node, {:shortnames, sname}} | config])
end
defp opts_to_config([{:name, name} | opts], config) do
name = String.to_atom(name)
opts_to_config(opts, [{:livebook, :node, {:longnames, name}} | config])
end
defp opts_to_config([_opt | opts], config), do: opts_to_config(opts, config)
end