diff --git a/lib/kmxgit/organisation_manager.ex b/lib/kmxgit/organisation_manager.ex
index a19bcf8..3909bc2 100644
--- a/lib/kmxgit/organisation_manager.ex
+++ b/lib/kmxgit/organisation_manager.ex
@@ -60,7 +60,7 @@ defmodule Kmxgit.OrganisationManager do
end
def add_user(%Organisation{} = org, login) do
- user = UserManager.get_user_by_slug(login)
+ user = UserManager.get_user_by_login(login)
if user do
users = [user | org.users]
org
@@ -73,7 +73,7 @@ defmodule Kmxgit.OrganisationManager do
end
def remove_user(%Organisation{} = org, login) do
- user = UserManager.get_user_by_slug(login)
+ user = UserManager.get_user_by_login(login)
if user do
users = Enum.reject(org.users, &(&1.id == user.id))
org
diff --git a/lib/kmxgit/plug/ensure_admin.ex b/lib/kmxgit/plug/ensure_admin.ex
index 5c506b6..4c21e8c 100644
--- a/lib/kmxgit/plug/ensure_admin.ex
+++ b/lib/kmxgit/plug/ensure_admin.ex
@@ -6,7 +6,7 @@ defmodule Kmxgit.Plug.EnsureAdmin do
def call(conn, _) do
conn
- |> ensure_admin(Guardian.Plug.current_resource(conn))
+ |> ensure_admin(conn.assigns.current_user)
end
defp ensure_admin(conn, user = %User{is_admin: true}) do
diff --git a/lib/kmxgit/repository_manager.ex b/lib/kmxgit/repository_manager.ex
index 6748c96..a015cfe 100644
--- a/lib/kmxgit/repository_manager.ex
+++ b/lib/kmxgit/repository_manager.ex
@@ -129,7 +129,7 @@ defmodule Kmxgit.RepositoryManager do
end
def add_member(%Repository{} = repo, login) do
- user = UserManager.get_user_by_slug(login)
+ user = UserManager.get_user_by_login(login)
if user do
members = [user | repo.members]
repo
@@ -142,7 +142,7 @@ defmodule Kmxgit.RepositoryManager do
end
def remove_member(%Repository{} = repo, login) do
- user = UserManager.get_user_by_slug(login)
+ user = UserManager.get_user_by_login(login)
if user do
members = Enum.reject(repo.members, &(&1.id == user.id))
repo
diff --git a/lib/kmxgit/user_manager.ex b/lib/kmxgit/user_manager.ex
index d86d22a..053d944 100644
--- a/lib/kmxgit/user_manager.ex
+++ b/lib/kmxgit/user_manager.ex
@@ -25,11 +25,11 @@ defmodule Kmxgit.UserManager do
get_user(id) || raise Ecto.NoResultsError
end
- def get_user_by_slug(slug) do
+ def get_user_by_login(login) do
Repo.one from u in User,
join: s in Slug,
on: s.user_id == u.id,
- where: fragment("lower(?)", s.slug) == ^String.downcase(slug),
+ where: fragment("lower(?)", s.slug) == ^String.downcase(login),
limit: 1,
preload: [:slug,
organisations: :slug,
@@ -37,7 +37,13 @@ defmodule Kmxgit.UserManager do
user: :slug]]
end
- def get_user_by_email(email) when is_binary(email) do
+ def get_user_by_login_and_password(login, password)
+ when is_binary(login) and is_binary(password) do
+ user = get_user_by_login(login)
+ if User.valid_password?(user, password), do: user
+ end
+
+ def get_user_by_email(email) do
Repo.one from u in User,
where: u.email == ^email,
limit: 1,
@@ -47,12 +53,6 @@ defmodule Kmxgit.UserManager do
user: :slug]]
end
- def get_user_by_email_and_password(email, password)
- when is_binary(email) and is_binary(password) do
- user = get_user_by_email(email) || get_user_by_slug(email)
- if User.valid_password?(user, password), do: user
- end
-
def register_user(attrs) do
%User{}
|> User.registration_changeset(attrs)
@@ -130,7 +130,10 @@ defmodule Kmxgit.UserManager do
def get_user_by_session_token(token) do
{:ok, query} = UserToken.verify_session_token_query(token)
- Repo.one(query)
+ user = Repo.one(query)
+ if user do
+ get_user(user.id)
+ end
end
def delete_session_token(token) do
@@ -210,6 +213,12 @@ defmodule Kmxgit.UserManager do
|> Repo.update()
end
+ def admin_update_user_password(%User{} = user, attrs) do
+ user
+ |> User.password_changeset(attrs)
+ |> Repo.update()
+ end
+
def delete_user(%User{} = user) do
user
|> change_user()
diff --git a/lib/kmxgit/user_manager/user.ex b/lib/kmxgit/user_manager/user.ex
index b03d6e8..9d382c2 100644
--- a/lib/kmxgit/user_manager/user.ex
+++ b/lib/kmxgit/user_manager/user.ex
@@ -171,7 +171,7 @@ defmodule Kmxgit.UserManager.User do
def admin_changeset(user, attrs \\ %{}) do
user
- |> cast(attrs, [:deploy_only, :description, :email, :is_admin, :name, :password, :password_confirmation, :ssh_keys])
+ |> cast(attrs, [:deploy_only, :description, :email, :is_admin, :name, :ssh_keys])
|> common_changeset()
end
diff --git a/lib/kmxgit_web/controllers/admin/user_controller.ex b/lib/kmxgit_web/controllers/admin/user_controller.ex
index 2eec94c..34f062b 100644
--- a/lib/kmxgit_web/controllers/admin/user_controller.ex
+++ b/lib/kmxgit_web/controllers/admin/user_controller.ex
@@ -15,56 +15,79 @@ defmodule KmxgitWeb.Admin.UserController do
def show(conn, params) do
user = UserManager.get_user(params["id"])
- show_user(conn, user)
- end
-
- defp show_user(conn, nil) do
- not_found(conn)
- end
-
- defp show_user(conn, user) do
- conn
- |> assign(:page_title, gettext("User %{login}", login: user.slug.slug))
- |> assign(:user, user)
- |> render("show.html")
+ if user do
+ conn
+ |> assign(:page_title, gettext("User %{login}", login: user.slug.slug))
+ |> assign(:user, user)
+ |> render("show.html")
+ else
+ not_found(conn)
+ end
end
def edit(conn, params) do
user = UserManager.get_user(params["id"])
- edit_user(conn, user)
- end
-
- defp edit_user(conn, nil) do
- not_found(conn)
- end
-
- defp edit_user(conn, user) do
- changeset = UserManager.change_user(user)
- conn
- |> render("edit.html", user: user, changeset: changeset)
+ if user do
+ changeset = UserManager.change_user(user)
+ conn
+ |> assign(:changeset, changeset)
+ |> assign(:user, user)
+ |> render("edit.html")
+ else
+ not_found(conn)
+ end
end
def update(conn, params) do
user = UserManager.get_user(params["id"])
- update_user(conn, user, params)
+ if user do
+ case UserManager.admin_update_user(user, params["user"]) do
+ {:ok, user1} ->
+ case GitManager.update_auth() do
+ :ok -> nil
+ error -> IO.inspect(error)
+ end
+ conn
+ |> redirect(to: Routes.admin_user_path(conn, :show, user1))
+ {:error, changeset} ->
+ conn
+ |> assign(:changeset, changeset)
+ |> assign(:user, user)
+ |> render("edit.html")
+ end
+ else
+ not_found(conn)
+ end
end
- defp update_user(conn, nil, _params) do
- not_found(conn)
+ def edit_password(conn, params) do
+ user = UserManager.get_user(params["user_id"])
+ if user do
+ changeset = UserManager.change_user(user)
+ conn
+ |> assign(:changeset, changeset)
+ |> assign(:user, user)
+ |> render("edit_password.html")
+ else
+ not_found(conn)
+ end
end
- defp update_user(conn, user, params) do
- case UserManager.admin_update_user(user, params["user"]) do
- {:ok, user1} ->
- case GitManager.update_auth() do
- :ok -> nil
- error -> IO.inspect(error)
- end
- conn
- |> redirect(to: Routes.admin_user_path(conn, :show, user1))
- {:error, changeset} ->
- conn
- |> render("edit.html", changeset: changeset)
+ def update_password(conn, params) do
+ user = UserManager.get_user(params["user_id"])
+ if user do
+ case UserManager.admin_update_user_password(user, params["user"]) do
+ {:ok, user1} ->
+ conn
+ |> redirect(to: Routes.admin_user_path(conn, :show, user1))
+ {:error, changeset} ->
+ conn
+ |> assign(:changeset, changeset)
+ |> assign(:user, user)
+ |> render("edit_password.html")
+ end
+ else
+ not_found(conn)
end
end
diff --git a/lib/kmxgit_web/controllers/user_session_controller.ex b/lib/kmxgit_web/controllers/user_session_controller.ex
index f22052a..e46f9ef 100644
--- a/lib/kmxgit_web/controllers/user_session_controller.ex
+++ b/lib/kmxgit_web/controllers/user_session_controller.ex
@@ -9,15 +9,18 @@ defmodule KmxgitWeb.UserSessionController do
end
def create(conn, %{"user" => user_params}) do
- %{"email" => email, "password" => password} = user_params
+ %{"login" => login, "password" => password} = user_params
- if user = UserManager.get_user_by_email_and_password(email, password) do
+ if user = UserManager.get_user_by_login_and_password(login, password) do
UserAuth.log_in_user(conn, user, user_params)
else
# In order to prevent user enumeration attacks, don't disclose whether the email is registered.
render(conn, "new.html", error_message: "Invalid email or password")
end
end
+ def create(conn, _params) do
+ not_found(conn)
+ end
def delete(conn, _params) do
conn
diff --git a/lib/kmxgit_web/router.ex b/lib/kmxgit_web/router.ex
index 275bf4b..1084dbc 100644
--- a/lib/kmxgit_web/router.ex
+++ b/lib/kmxgit_web/router.ex
@@ -21,16 +21,6 @@ defmodule KmxgitWeb.Router do
plug PlugRecaptcha2, recaptcha_secret: Application.get_env(:kmxgit, :recaptcha_secret)
end
- # Our pipeline implements "maybe" authenticated. We'll use the `:ensure_auth` below for when we need to make sure someone is logged in.
- pipeline :auth do
- plug Kmxgit.UserManager.Pipeline
- end
-
-# We use ensure_auth to fail if there is no one logged in
- pipeline :ensure_auth do
- plug Guardian.Plug.EnsureAuthenticated
- end
-
pipeline :admin do
plug Kmxgit.Plug.EnsureAdmin
plug :put_root_layout, {KmxgitWeb.LayoutView, "admin.html"}
@@ -46,17 +36,28 @@ defmodule KmxgitWeb.Router do
get "/_new_admin", PageController, :new_admin
post "/_new_admin", PageController, :new_admin_post
- scope "/_sessions" do
- get "/new", SessionController, :new
- get "/logout", SessionController, :logout
+ delete "/users/log_out", UserSessionController, :delete
+ get "/users/confirm", UserConfirmationController, :new
+ post "/users/confirm", UserConfirmationController, :create
+ get "/users/confirm/:token", UserConfirmationController, :edit
+ post "/users/confirm/:token", UserConfirmationController, :update
+ end
+
+ ## Authentication routes
- post "/new", SessionController, :login
- end
+ scope "/", KmxgitWeb do
+ pipe_through [:browser, :redirect_if_user_is_authenticated]
- get "/_register", RegistrationController, :new
+ get "/users/log_in", UserSessionController, :new
+ get "/users/register", UserRegistrationController, :new
+ get "/users/reset_password", UserResetPasswordController, :new
+ get "/users/reset_password/:token", UserResetPasswordController, :edit
+ put "/users/reset_password/:token", UserResetPasswordController, :update
pipe_through :recaptcha
- post "/_register", RegistrationController, :register
+ post "/users/log_in", UserSessionController, :create
+ post "/users/register", UserRegistrationController, :create
+ post "/users/reset_password", UserResetPasswordController, :create
end
scope "/", KmxgitWeb do
@@ -122,7 +123,10 @@ defmodule KmxgitWeb.Router do
get "/remove_user", RepositoryController, :remove_user, as: :""
post "/remove_user", RepositoryController, :remove_user_post, as: :""
end
- resources "/users", UserController
+ resources "/users", UserController do
+ get "/password/edit", UserController, :edit_password, as: :""
+ put "/password", UserController, :update_password, as: :""
+ end
import Phoenix.LiveDashboard.Router
live_dashboard "/dashboard", metrics: KmxgitWeb.Telemetry
@@ -148,31 +152,4 @@ defmodule KmxgitWeb.Router do
forward "/mailbox", Plug.Swoosh.MailboxPreview
end
end
-
- ## Authentication routes
-
- scope "/", KmxgitWeb do
- pipe_through [:browser, :redirect_if_user_is_authenticated]
-
- get "/users/register", UserRegistrationController, :new
- get "/users/log_in", UserSessionController, :new
- get "/users/reset_password", UserResetPasswordController, :new
- post "/users/reset_password", UserResetPasswordController, :create
- get "/users/reset_password/:token", UserResetPasswordController, :edit
- put "/users/reset_password/:token", UserResetPasswordController, :update
-
- pipe_through :recaptcha
- post "/users/register", UserRegistrationController, :create
- post "/users/log_in", UserSessionController, :create
- end
-
- scope "/", KmxgitWeb do
- pipe_through [:browser]
-
- delete "/users/log_out", UserSessionController, :delete
- get "/users/confirm", UserConfirmationController, :new
- post "/users/confirm", UserConfirmationController, :create
- get "/users/confirm/:token", UserConfirmationController, :edit
- post "/users/confirm/:token", UserConfirmationController, :update
- end
end
diff --git a/lib/kmxgit_web/templates/admin/user/edit_password.html.heex b/lib/kmxgit_web/templates/admin/user/edit_password.html.heex
new file mode 100644
index 0000000..5731463
--- /dev/null
+++ b/lib/kmxgit_web/templates/admin/user/edit_password.html.heex
@@ -0,0 +1,31 @@
+<div class="container-fluid">
+ <h1><%= gettext "Edit user" %> <%= @user.slug.slug %></h1>
+
+ <%= form_for @changeset, Routes.admin_user__path(@conn, :update_password, @user), fn f -> %>
+ <div class="mb-3">
+ <%= label f, :password, class: "form-label" %>
+ <%= password_input f, :password, class: "form-control" %>
+ <%= error_tag f, :password %>
+ </div>
+
+ <div class="mb-3">
+ <%= label f, :password_confirmation, class: "form-label" %>
+ <%= password_input f, :password_confirmation, class: "form-control" %>
+ <%= error_tag f, :password_confirmation %>
+ </div>
+
+ <div class="mb-3">
+ <%= if @conn.assigns[:user] do %>
+ <%= link gettext("Cancel"),
+ to: Routes.admin_user_path(@conn, :show, @user),
+ class: "btn btn-secondary" %>
+ <% else %>
+ <%= link gettext("Cancel"),
+ to: Routes.admin_user_path(@conn, :index),
+ class: "btn btn-secondary" %>
+ <% end %>
+ <%= submit gettext("Submit"), class: "btn btn-primary" %>
+ </div>
+ <% end %>
+
+</div>
diff --git a/lib/kmxgit_web/templates/admin/user/form.html.heex b/lib/kmxgit_web/templates/admin/user/form.html.heex
index 9687c73..38805dc 100644
--- a/lib/kmxgit_web/templates/admin/user/form.html.heex
+++ b/lib/kmxgit_web/templates/admin/user/form.html.heex
@@ -32,18 +32,6 @@
<%= error_tag f, :ssh_keys %>
</div>
- <div class="mb-3">
- <%= label f, :password, class: "form-label" %>
- <%= password_input f, :password, class: "form-control" %>
- <%= error_tag f, :password %>
- </div>
-
- <div class="mb-3">
- <%= label f, :password_confirmation, class: "form-label" %>
- <%= password_input f, :password_confirmation, class: "form-control" %>
- <%= error_tag f, :password_confirmation %>
- </div>
-
<div class="mb-3 form-check">
<%= checkbox f, :is_admin, class: "form-check-input" %>
<%= label f, :is_admin, class: "form-check-label" %>
@@ -56,7 +44,7 @@
<%= error_tag f, :deploy_only %>
</div>
- <div class="form-group">
+ <div class="mb-3">
<%= if @conn.assigns[:user] do %>
<%= link gettext("Cancel"),
to: Routes.admin_user_path(@conn, :show, @user),
diff --git a/lib/kmxgit_web/templates/admin/user/show.html.heex b/lib/kmxgit_web/templates/admin/user/show.html.heex
index 2c6ca42..e2986ed 100644
--- a/lib/kmxgit_web/templates/admin/user/show.html.heex
+++ b/lib/kmxgit_web/templates/admin/user/show.html.heex
@@ -60,6 +60,10 @@
to: Routes.admin_user_path(@conn, :edit, @user),
class: "btn btn-primary" %>
+ <%= link gettext("Edit password"),
+ to: Routes.admin_user__path(@conn, :edit_password, @user),
+ class: "btn btn-primary" %>
+
<%= link gettext("Show"),
to: Routes.slug_path(@conn, :show, @user.slug.slug),
class: "btn btn-primary" %>
diff --git a/lib/kmxgit_web/templates/layout/admin_nav.html.heex b/lib/kmxgit_web/templates/layout/admin_nav.html.heex
index 9b63bf7..de4ee7a 100644
--- a/lib/kmxgit_web/templates/layout/admin_nav.html.heex
+++ b/lib/kmxgit_web/templates/layout/admin_nav.html.heex
@@ -22,7 +22,7 @@
<%= link "kmx git", to: "/", class: "nav-link" %>
</li>
<li class="navbar-item">
- <%= link gettext("Logout"), to: Routes.session_path(@conn, :logout), class: "nav-link" %>
+ <%= link gettext("Logout"), to: Routes.user_session_path(@conn, :delete), class: "nav-link" %>
</li>
</ul>
</div>
diff --git a/lib/kmxgit_web/templates/session/new.html.eex b/lib/kmxgit_web/templates/session/new.html.eex
deleted file mode 100644
index a9eac1f..0000000
--- a/lib/kmxgit_web/templates/session/new.html.eex
+++ /dev/null
@@ -1,29 +0,0 @@
-<div class="container-fluid center">
- <div class="login-form">
- <h1>
- <%= gettext "Connection" %>
- </h1>
- <%= form_for @changeset, @action, fn f -> %>
-
- <div class="mb-3">
- <%= label f, :login, class: "form-label" %>
- <%= text_input f, :login, class: "form-control" %>
- <%= error_tag f, :login %>
- </div>
-
- <div class="mb-3">
- <%= label f, :password, class: "form-label" %>
- <%= password_input f, :password, class: "form-control" %>
- <%= error_tag f, :password %>
- </div>
-
- <%= render "recaptcha.html", assigns %>
-
- <div class="mb-3">
- <%= submit "Submit", class: "btn btn-primary" %>
- </div>
-
- <% end %>
-
- </div>
-</div>
diff --git a/lib/kmxgit_web/templates/user_reset_password/new.html.heex b/lib/kmxgit_web/templates/user_reset_password/new.html.heex
index 4ad481d..423ae41 100644
--- a/lib/kmxgit_web/templates/user_reset_password/new.html.heex
+++ b/lib/kmxgit_web/templates/user_reset_password/new.html.heex
@@ -8,6 +8,8 @@
<%= email_input f, :email, class: "form-control", required: true %>
</div>
+ <%= render "recaptcha.html", assigns %>
+
<div>
<%= submit gettext("Submit"), class: "btn btn-primary" %>
</div>
diff --git a/lib/kmxgit_web/templates/user_reset_password/recaptcha.html.heex b/lib/kmxgit_web/templates/user_reset_password/recaptcha.html.heex
new file mode 100644
index 0000000..fd68017
--- /dev/null
+++ b/lib/kmxgit_web/templates/user_reset_password/recaptcha.html.heex
@@ -0,0 +1,9 @@
+<%= tag :input, type: 'hidden', name: 'recaptcha' %>
+<script src={"https://www.google.com/recaptcha/api.js?render=#{recaptcha_site_key()}"}></script>
+<script>
+ grecaptcha.ready(function() {
+ grecaptcha.execute('<%= recaptcha_site_key() %>', {action: 'reset_password'}).then(function(token) {
+ $('input[name="recaptcha"]').val(token);
+ });
+ });
+</script>
diff --git a/lib/kmxgit_web/templates/user_session/new.html.heex b/lib/kmxgit_web/templates/user_session/new.html.heex
index 6781588..c49ae2a 100644
--- a/lib/kmxgit_web/templates/user_session/new.html.heex
+++ b/lib/kmxgit_web/templates/user_session/new.html.heex
@@ -9,9 +9,9 @@
<% end %>
<div class="mb-3">
- <%= label f, :email, class: "form-label" %>
- <%= text_input f, :email, class: "form-control", required: true %>
- <%= error_tag f, :email %>
+ <%= label f, :login, class: "form-label" %>
+ <%= text_input f, :login, class: "form-control", required: true %>
+ <%= error_tag f, :login %>
</div>
<div class="mb-3">
@@ -20,9 +20,9 @@
<%= error_tag f, :password %>
</div>
- <div class="mb-3">
- <%= label f, :remember_me, "Keep me logged in for 60 days", class: "form-label" %>
- <%= checkbox f, :remember_me, class: "form-control" %>
+ <div class="mb-3 form-check">
+ <%= checkbox f, :remember_me, class: "form-check-input" %>
+ <%= label f, :remember_me, "Keep me logged in for 60 days", class: "form-check-label" %>
</div>
<%= render "recaptcha.html", assigns %>