defmodule Blossom.Controllers.Users do alias Blossom.Controllers.Users alias Blossom.Passwords alias KilnCore.Utils def new_user_own_role(outcome, ctx) do case outcome do {:ok, user} -> case ctx[:settings].get_value("new_users_own_role") do nil -> outcome value -> ctx[:roles_assignments].assign(user, value, nil, user.id) outcome end e -> e end end def make_user(outcome, user, model) do case outcome do {:ok, params} -> params |> Map.replace("email", String.downcase(params["email"])) |> model.new(user) error -> error end end def autojoin_orgs(outcome, ctx) do case outcome do {:ok, user} -> ctx[:casks].process_autojoins(user) _ -> nil end outcome end def queue(outcome, kind, ctx) do case outcome do {:ok, user} -> ctx[:worker].queue(user.id, kind) _ -> nil end outcome end def process_password(params, realm, ctx) do settings = ctx[:settings].password_settings(realm) password = params["password"] case ctx[:auth].validate_new_password(password, settings) do {:ok, _} -> {:ok, Map.put(params, "password", Passwords.hash(password))} error -> error end end def handle_password(params, realm, ctx) do case params do %{"password" => _} -> Users.process_password(params, realm, ctx) _ -> {:ok, params} end end def handle_new_user(params, user, ctx) do params |> Users.handle_password(params["realm"], ctx) |> Users.make_user(user, ctx[:model]) |> Users.new_user_own_role(ctx) |> Users.autojoin_orgs(ctx) |> Users.queue("email_verification", ctx) end def new(params, user, ctx) do case params do %{"email" => _, "realm" => realm} -> if ctx[:settings].is_enabled?("allow_new_users", realm) do Users.handle_new_user(params, user, ctx) else {:error, :forbidden} end _ -> {:error, :unprocessable} end end def edit(params, id, user, ctx) do case Users.handle_password(params, user["iss"], ctx) do {:ok, new_params} -> ctx[:model].edit(new_params, id, user) error -> error end end def get_login_user(email, realm, ctx) do %{"email" => String.downcase(email), "realm" => realm} |> ctx[:model].get(:system) |> List.first() end def make_login(outcome, email, password, ctx) do case outcome do [client] -> email |> Users.get_login_user(client.casks.realm, ctx) |> ctx[:auth].login(password, client) _ -> {:error, :unauthorized} end end def login(params, ctx) do case params do %{"email" => email, "password" => password, "client_id" => client_id} -> %{"id" => client_id, "embeds" => ["casks"]} |> ctx[:clients].get(:system) |> Users.make_login(email, password, ctx) _ -> {:error, :unprocessable} end end def verify_email(code, user, ctx) do params = %{"code" => code, "kind" => "email_verification"} case ctx[:codes].verify(params, user) do {:ok, code} -> ctx[:model].edit(%{"email_verified" => true}, code.user, :system) error -> error end end def start_reset_password(params, ctx) do case params do %{"email" => email, "realm" => realm} -> case ctx[:model].get(%{"email" => email, "realm" => realm}, :system) do [user] -> Users.queue({:ok, user}, "password_reset", ctx) [] -> {:error, :forbidden} end _ -> {:error, :unprocessable} end end def make_new_password(params, ctx) do new_params = Map.put(params, "kind", "password_reset") case ctx[:codes].verify(new_params, :system) do {:ok, code} -> %{"password" => Passwords.hash(params["password"])} |> ctx[:model].edit(code.user, :system) _error -> {:error, :forbidden} end end def confirm_reset_password(params, ctx) do if params["password"] != nil do settings = ctx[:settings].password_settings(params["realm"]) case ctx[:auth].validate_new_password(params["password"], settings) do {:ok, _} -> Users.make_new_password(params, ctx) e -> e end else {:error, :unprocessable} end end defmacro __using__(opts \\ []) do quote do use KilnCore.Controller, unquote(opts) @auth Utils.option_or_mod_replace( @caller, unquote(opts), :auth, Auth, 1, 0..1 ) @casks Utils.option_or_mod_replace( @caller, unquote(opts), :casks, Casks, 2 ) @clients Utils.option_or_mod_replace( @caller, unquote(opts), :clients, Clients, 2 ) @codes Utils.option_or_mod_replace( @caller, unquote(opts), :otp_codes, OtpCodes, 2 ) @roles_assignments Utils.option_or_mod_replace( @caller, unquote(opts), :roles_assignments, RolesAssignments, 2 ) @settings Utils.option_or_mod_replace( @caller, unquote(opts), :settings, Settings, 2 ) @worker Utils.option_or_mod_replace( Utils.replace_module(@caller, Workers), unquote(opts), :worker, Mailer, 2 ) @ctx [ auth: @auth, casks: @casks, clients: @clients, codes: @codes, model: @model, settings: @settings, worker: @worker ] def new(params, user, _opts) do Users.new(params, user, @ctx) end def edit(params, id, user, _opts) do Users.edit(params, id, user, @ctx) end def login(params, _user, _opts), do: Users.login(params, @ctx) def verify_email(code, user, _opts) do Users.verify_email(code, user, @ctx) end def start_reset_password(params, _user, _opts) do Users.start_reset_password(params, @ctx) end def confirm_reset_password(params, _user, _opts) do Users.confirm_reset_password(params, @ctx) end defoverridable new: 3, login: 3, verify_email: 3, start_reset_password: 3, confirm_reset_password: 3 end end end