From a0c4ebb4d73f43a9c567c5309f0e8d1b88995481 Mon Sep 17 00:00:00 2001 From: Maksim Date: Mon, 24 Jun 2019 19:01:56 +0000 Subject: [#184] small refactoring reset password --- lib/mix/tasks/pleroma/user.ex | 4 +- lib/pleroma/PasswordResetToken.ex | 50 --------------------- lib/pleroma/emails/user_email.ex | 9 +--- lib/pleroma/password_reset_token.ex | 51 ++++++++++++++++++++++ lib/pleroma/user.ex | 49 +++++++++++---------- lib/pleroma/web/oauth/authorization.ex | 12 ++--- lib/pleroma/web/router.ex | 4 +- .../twitter_api/password/invalid_token.html.eex | 1 + .../templates/twitter_api/password/reset.html.eex | 13 ++++++ .../twitter_api/password/reset_failed.html.eex | 2 + .../twitter_api/password/reset_success.html.eex | 2 + .../twitter_api/util/invalid_token.html.eex | 1 - .../twitter_api/util/password_reset.html.eex | 13 ------ .../util/password_reset_failed.html.eex | 2 - .../util/password_reset_success.html.eex | 2 - .../twitter_api/controllers/password_controller.ex | 37 ++++++++++++++++ .../web/twitter_api/controllers/util_controller.ex | 22 ---------- lib/pleroma/web/twitter_api/views/password_view.ex | 8 ++++ 18 files changed, 154 insertions(+), 128 deletions(-) delete mode 100644 lib/pleroma/PasswordResetToken.ex create mode 100644 lib/pleroma/password_reset_token.ex create mode 100644 lib/pleroma/web/templates/twitter_api/password/invalid_token.html.eex create mode 100644 lib/pleroma/web/templates/twitter_api/password/reset.html.eex create mode 100644 lib/pleroma/web/templates/twitter_api/password/reset_failed.html.eex create mode 100644 lib/pleroma/web/templates/twitter_api/password/reset_success.html.eex delete mode 100644 lib/pleroma/web/templates/twitter_api/util/invalid_token.html.eex delete mode 100644 lib/pleroma/web/templates/twitter_api/util/password_reset.html.eex delete mode 100644 lib/pleroma/web/templates/twitter_api/util/password_reset_failed.html.eex delete mode 100644 lib/pleroma/web/templates/twitter_api/util/password_reset_success.html.eex create mode 100644 lib/pleroma/web/twitter_api/controllers/password_controller.ex create mode 100644 lib/pleroma/web/twitter_api/views/password_view.ex (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index ab158f57e..8a78b4fe6 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -204,9 +204,9 @@ defmodule Mix.Tasks.Pleroma.User do IO.puts( "URL: #{ - Pleroma.Web.Router.Helpers.util_url( + Pleroma.Web.Router.Helpers.reset_password_url( Pleroma.Web.Endpoint, - :show_password_reset, + :reset, token.token ) }" diff --git a/lib/pleroma/PasswordResetToken.ex b/lib/pleroma/PasswordResetToken.ex deleted file mode 100644 index f31ea5bc5..000000000 --- a/lib/pleroma/PasswordResetToken.ex +++ /dev/null @@ -1,50 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.PasswordResetToken do - use Ecto.Schema - - import Ecto.Changeset - - alias Pleroma.PasswordResetToken - alias Pleroma.Repo - alias Pleroma.User - - schema "password_reset_tokens" do - belongs_to(:user, User, type: Pleroma.FlakeId) - field(:token, :string) - field(:used, :boolean, default: false) - - timestamps() - end - - def create_token(%User{} = user) do - token = :crypto.strong_rand_bytes(32) |> Base.url_encode64() - - token = %PasswordResetToken{ - user_id: user.id, - used: false, - token: token - } - - Repo.insert(token) - end - - def used_changeset(struct) do - struct - |> cast(%{}, []) - |> put_change(:used, true) - end - - def reset_password(token, data) do - with %{used: false} = token <- Repo.get_by(PasswordResetToken, %{token: token}), - %User{} = user <- User.get_cached_by_id(token.user_id), - {:ok, _user} <- User.reset_password(user, data), - {:ok, token} <- Repo.update(used_changeset(token)) do - {:ok, token} - else - _e -> {:error, token} - end - end -end diff --git a/lib/pleroma/emails/user_email.ex b/lib/pleroma/emails/user_email.ex index 8502a0d0c..934620765 100644 --- a/lib/pleroma/emails/user_email.ex +++ b/lib/pleroma/emails/user_email.ex @@ -23,13 +23,8 @@ defmodule Pleroma.Emails.UserEmail do defp recipient(email, name), do: {name, email} defp recipient(%Pleroma.User{} = user), do: recipient(user.email, user.name) - def password_reset_email(user, password_reset_token) when is_binary(password_reset_token) do - password_reset_url = - Router.Helpers.util_url( - Endpoint, - :show_password_reset, - password_reset_token - ) + def password_reset_email(user, token) when is_binary(token) do + password_reset_url = Router.Helpers.reset_password_url(Endpoint, :reset, token) html_body = """

Reset your password at #{instance_name()}

diff --git a/lib/pleroma/password_reset_token.ex b/lib/pleroma/password_reset_token.ex new file mode 100644 index 000000000..4a833f6a5 --- /dev/null +++ b/lib/pleroma/password_reset_token.ex @@ -0,0 +1,51 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.PasswordResetToken do + use Ecto.Schema + + import Ecto.Changeset + + alias Pleroma.PasswordResetToken + alias Pleroma.Repo + alias Pleroma.User + + schema "password_reset_tokens" do + belongs_to(:user, User, type: Pleroma.FlakeId) + field(:token, :string) + field(:used, :boolean, default: false) + + timestamps() + end + + def create_token(%User{} = user) do + token = :crypto.strong_rand_bytes(32) |> Base.url_encode64() + + token = %PasswordResetToken{ + user_id: user.id, + used: false, + token: token + } + + Repo.insert(token) + end + + def used_changeset(struct) do + struct + |> cast(%{}, []) + |> put_change(:used, true) + end + + @spec reset_password(binary(), map()) :: {:ok, User.t()} | {:error, binary()} + def reset_password(token, data) do + with %{used: false} = token <- Repo.get_by(PasswordResetToken, %{token: token}), + %User{} = user <- User.get_cached_by_id(token.user_id), + {:ok, _user} <- User.reset_password(user, data), + {:ok, token} <- Repo.update(used_changeset(token)) do + {:ok, token} + else + _e -> {:error, token} + end + end +end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 1e59a4121..f7191762f 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -9,6 +9,7 @@ defmodule Pleroma.User do import Ecto.Query alias Comeonin.Pbkdf2 + alias Ecto.Multi alias Pleroma.Activity alias Pleroma.Keys alias Pleroma.Notification @@ -194,29 +195,26 @@ defmodule Pleroma.User do end def password_update_changeset(struct, params) do - changeset = - struct - |> cast(params, [:password, :password_confirmation]) - |> validate_required([:password, :password_confirmation]) - |> validate_confirmation(:password) - - OAuth.Token.delete_user_tokens(struct) - OAuth.Authorization.delete_user_authorizations(struct) - - if changeset.valid? do - hashed = Pbkdf2.hashpwsalt(changeset.changes[:password]) - - changeset - |> put_change(:password_hash, hashed) - else - changeset + struct + |> cast(params, [:password, :password_confirmation]) + |> validate_required([:password, :password_confirmation]) + |> validate_confirmation(:password) + |> put_password_hash + end + + def reset_password(%User{id: user_id} = user, data) do + multi = + Multi.new() + |> Multi.update(:user, password_update_changeset(user, data)) + |> Multi.delete_all(:tokens, OAuth.Token.Query.get_by_user(user_id)) + |> Multi.delete_all(:auth, OAuth.Authorization.delete_by_user_query(user)) + + case Repo.transaction(multi) do + {:ok, %{user: user} = _} -> set_cache(user) + {:error, _, changeset, _} -> {:error, changeset} end end - def reset_password(user, data) do - update_and_set_cache(password_update_changeset(user, data)) - end - def register_changeset(struct, params \\ %{}, opts \\ []) do need_confirmation? = if is_nil(opts[:need_confirmation]) do @@ -250,12 +248,11 @@ defmodule Pleroma.User do end if changeset.valid? do - hashed = Pbkdf2.hashpwsalt(changeset.changes[:password]) ap_id = User.ap_id(%User{nickname: changeset.changes[:nickname]}) followers = User.ap_followers(%User{nickname: changeset.changes[:nickname]}) changeset - |> put_change(:password_hash, hashed) + |> put_password_hash |> put_change(:ap_id, ap_id) |> unique_constraint(:ap_id) |> put_change(:following, [followers]) @@ -1349,4 +1346,12 @@ defmodule Pleroma.User do end defdelegate search(query, opts \\ []), to: User.Search + + defp put_password_hash( + %Ecto.Changeset{valid?: true, changes: %{password: password}} = changeset + ) do + change(changeset, password_hash: Pbkdf2.hashpwsalt(password)) + end + + defp put_password_hash(changeset), do: changeset end diff --git a/lib/pleroma/web/oauth/authorization.ex b/lib/pleroma/web/oauth/authorization.ex index 18973413e..d53e20d12 100644 --- a/lib/pleroma/web/oauth/authorization.ex +++ b/lib/pleroma/web/oauth/authorization.ex @@ -76,14 +76,16 @@ defmodule Pleroma.Web.OAuth.Authorization do def use_token(%Authorization{used: true}), do: {:error, "already used"} @spec delete_user_authorizations(User.t()) :: {integer(), any()} - def delete_user_authorizations(%User{id: user_id}) do - from( - a in Pleroma.Web.OAuth.Authorization, - where: a.user_id == ^user_id - ) + def delete_user_authorizations(%User{} = user) do + user + |> delete_by_user_query |> Repo.delete_all() end + def delete_by_user_query(%User{id: user_id}) do + from(a in __MODULE__, where: a.user_id == ^user_id) + end + @doc "gets auth for app by token" @spec get_by_token(App.t(), String.t()) :: {:ok, t()} | {:error, :not_found} def get_by_token(%App{id: app_id} = _app, token) do diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 837153ed4..c504116b6 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -133,8 +133,8 @@ defmodule Pleroma.Web.Router do scope "/api/pleroma", Pleroma.Web.TwitterAPI do pipe_through(:pleroma_api) - get("/password_reset/:token", UtilController, :show_password_reset) - post("/password_reset", UtilController, :password_reset) + get("/password_reset/:token", PasswordController, :reset, as: :reset_password) + post("/password_reset", PasswordController, :do_reset, as: :reset_password) get("/emoji", UtilController, :emoji) get("/captcha", UtilController, :captcha) get("/healthcheck", UtilController, :healthcheck) diff --git a/lib/pleroma/web/templates/twitter_api/password/invalid_token.html.eex b/lib/pleroma/web/templates/twitter_api/password/invalid_token.html.eex new file mode 100644 index 000000000..ee84750c7 --- /dev/null +++ b/lib/pleroma/web/templates/twitter_api/password/invalid_token.html.eex @@ -0,0 +1 @@ +

Invalid Token

diff --git a/lib/pleroma/web/templates/twitter_api/password/reset.html.eex b/lib/pleroma/web/templates/twitter_api/password/reset.html.eex new file mode 100644 index 000000000..7d3ef6b0d --- /dev/null +++ b/lib/pleroma/web/templates/twitter_api/password/reset.html.eex @@ -0,0 +1,13 @@ +

Password Reset for <%= @user.nickname %>

+<%= form_for @conn, reset_password_path(@conn, :do_reset), [as: "data"], fn f -> %> +
+ <%= label f, :password, "Password" %> + <%= password_input f, :password %> +
+
+ <%= label f, :password_confirmation, "Confirmation" %> + <%= password_input f, :password_confirmation %> +
+ <%= hidden_input f, :token, value: @token.token %> + <%= submit "Reset" %> +<% end %> diff --git a/lib/pleroma/web/templates/twitter_api/password/reset_failed.html.eex b/lib/pleroma/web/templates/twitter_api/password/reset_failed.html.eex new file mode 100644 index 000000000..df037c01e --- /dev/null +++ b/lib/pleroma/web/templates/twitter_api/password/reset_failed.html.eex @@ -0,0 +1,2 @@ +

Password reset failed

+

Homepage

diff --git a/lib/pleroma/web/templates/twitter_api/password/reset_success.html.eex b/lib/pleroma/web/templates/twitter_api/password/reset_success.html.eex new file mode 100644 index 000000000..f30ba3274 --- /dev/null +++ b/lib/pleroma/web/templates/twitter_api/password/reset_success.html.eex @@ -0,0 +1,2 @@ +

Password changed!

+

Homepage

diff --git a/lib/pleroma/web/templates/twitter_api/util/invalid_token.html.eex b/lib/pleroma/web/templates/twitter_api/util/invalid_token.html.eex deleted file mode 100644 index ee84750c7..000000000 --- a/lib/pleroma/web/templates/twitter_api/util/invalid_token.html.eex +++ /dev/null @@ -1 +0,0 @@ -

Invalid Token

diff --git a/lib/pleroma/web/templates/twitter_api/util/password_reset.html.eex b/lib/pleroma/web/templates/twitter_api/util/password_reset.html.eex deleted file mode 100644 index a3facf017..000000000 --- a/lib/pleroma/web/templates/twitter_api/util/password_reset.html.eex +++ /dev/null @@ -1,13 +0,0 @@ -

Password Reset for <%= @user.nickname %>

-<%= form_for @conn, util_path(@conn, :password_reset), [as: "data"], fn f -> %> -
- <%= label f, :password, "Password" %> - <%= password_input f, :password %> -
-
- <%= label f, :password_confirmation, "Confirmation" %> - <%= password_input f, :password_confirmation %> -
- <%= hidden_input f, :token, value: @token.token %> - <%= submit "Reset" %> -<% end %> diff --git a/lib/pleroma/web/templates/twitter_api/util/password_reset_failed.html.eex b/lib/pleroma/web/templates/twitter_api/util/password_reset_failed.html.eex deleted file mode 100644 index df037c01e..000000000 --- a/lib/pleroma/web/templates/twitter_api/util/password_reset_failed.html.eex +++ /dev/null @@ -1,2 +0,0 @@ -

Password reset failed

-

Homepage

diff --git a/lib/pleroma/web/templates/twitter_api/util/password_reset_success.html.eex b/lib/pleroma/web/templates/twitter_api/util/password_reset_success.html.eex deleted file mode 100644 index f30ba3274..000000000 --- a/lib/pleroma/web/templates/twitter_api/util/password_reset_success.html.eex +++ /dev/null @@ -1,2 +0,0 @@ -

Password changed!

-

Homepage

diff --git a/lib/pleroma/web/twitter_api/controllers/password_controller.ex b/lib/pleroma/web/twitter_api/controllers/password_controller.ex new file mode 100644 index 000000000..1941e6143 --- /dev/null +++ b/lib/pleroma/web/twitter_api/controllers/password_controller.ex @@ -0,0 +1,37 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.TwitterAPI.PasswordController do + @moduledoc """ + The module containts functions for reset password. + """ + + use Pleroma.Web, :controller + + require Logger + + alias Pleroma.PasswordResetToken + alias Pleroma.Repo + alias Pleroma.User + + def reset(conn, %{"token" => token}) do + with %{used: false} = token <- Repo.get_by(PasswordResetToken, %{token: token}), + %User{} = user <- User.get_cached_by_id(token.user_id) do + render(conn, "reset.html", %{ + token: token, + user: user + }) + else + _e -> render(conn, "invalid_token.html") + end + end + + def do_reset(conn, %{"data" => data}) do + with {:ok, _} <- PasswordResetToken.reset_password(data["token"], data) do + render(conn, "reset_success.html") + else + _e -> render(conn, "reset_failed.html") + end + end +end diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 489170d80..b1863528f 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -11,8 +11,6 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do alias Pleroma.Activity alias Pleroma.Emoji alias Pleroma.Notification - alias Pleroma.PasswordResetToken - alias Pleroma.Repo alias Pleroma.User alias Pleroma.Web alias Pleroma.Web.ActivityPub.ActivityPub @@ -20,26 +18,6 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do alias Pleroma.Web.OStatus alias Pleroma.Web.WebFinger - def show_password_reset(conn, %{"token" => token}) do - with %{used: false} = token <- Repo.get_by(PasswordResetToken, %{token: token}), - %User{} = user <- User.get_cached_by_id(token.user_id) do - render(conn, "password_reset.html", %{ - token: token, - user: user - }) - else - _e -> render(conn, "invalid_token.html") - end - end - - def password_reset(conn, %{"data" => data}) do - with {:ok, _} <- PasswordResetToken.reset_password(data["token"], data) do - render(conn, "password_reset_success.html") - else - _e -> render(conn, "password_reset_failed.html") - end - end - def help_test(conn, _params) do json(conn, "ok") end diff --git a/lib/pleroma/web/twitter_api/views/password_view.ex b/lib/pleroma/web/twitter_api/views/password_view.ex new file mode 100644 index 000000000..b166b925d --- /dev/null +++ b/lib/pleroma/web/twitter_api/views/password_view.ex @@ -0,0 +1,8 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.TwitterAPI.PasswordView do + use Pleroma.Web, :view + import Phoenix.HTML.Form +end -- cgit v1.2.3