Add password reset.
authorRoger Braun <rbraun@Bobble.local>
Thu, 19 Oct 2017 15:37:24 +0000 (17:37 +0200)
committerRoger Braun <rbraun@Bobble.local>
Thu, 19 Oct 2017 15:37:24 +0000 (17:37 +0200)
lib/pleroma/PasswordResetToken.ex [new file with mode: 0644]
lib/pleroma/user.ex
lib/pleroma/web/router.ex
lib/pleroma/web/templates/twitter_api/util/invalid_token.html.eex [new file with mode: 0644]
lib/pleroma/web/templates/twitter_api/util/password_reset.html.eex [new file with mode: 0644]
lib/pleroma/web/templates/twitter_api/util/password_reset_failed.html.eex [new file with mode: 0644]
lib/pleroma/web/templates/twitter_api/util/password_reset_success.html.eex [new file with mode: 0644]
lib/pleroma/web/twitter_api/controllers/util_controller.ex
lib/pleroma/web/twitter_api/views/util_view.ex [new file with mode: 0644]
priv/repo/migrations/20171019141706_create_password_reset_tokens.exs [new file with mode: 0644]

diff --git a/lib/pleroma/PasswordResetToken.ex b/lib/pleroma/PasswordResetToken.ex
new file mode 100644 (file)
index 0000000..79e60bf
--- /dev/null
@@ -0,0 +1,44 @@
+defmodule Pleroma.PasswordResetToken do
+  use Ecto.Schema
+
+  import Ecto.{Changeset, Query}
+
+  alias Pleroma.{User, PasswordResetToken, Repo}
+
+  schema "password_reset_tokens" do
+    belongs_to :user, User
+    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
+    changeset = 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 <- Repo.get(User, 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
index a04bbe276e74a0220015de1eeb2398924f085b31..938b57d90c47322e754e02704cc8c459519e4edd 100644 (file)
@@ -97,6 +97,25 @@ defmodule Pleroma.User do
     |> validate_length(:name, min: 1, max: 100)
   end
 
+  def password_update_changeset(struct, params) do
+    changeset = struct
+    |> cast(params, [:password, :password_confirmation])
+    |> validate_required([:password, :password_confirmation])
+    |> validate_confirmation(:password)
+
+    if changeset.valid? do
+      hashed = Pbkdf2.hashpwsalt(changeset.changes[:password])
+      changeset
+      |> put_change(:password_hash, hashed)
+    else
+      changeset
+    end
+  end
+
+  def reset_password(user, data) do
+    Repo.update(password_update_changeset(user, data))
+  end
+
   def register_changeset(struct, params \\ %{}) do
     changeset = struct
     |> cast(params, [:bio, :email, :name, :nickname, :password, :password_confirmation])
index 6abf234c6640555d588e392bba6e727ed802fee6..8497685a692f5578766db05c2eecdc3522ea1440 100644 (file)
@@ -33,6 +33,16 @@ defmodule Pleroma.Web.Router do
     plug :accepts, ["html", "json"]
   end
 
+  pipeline :password_reset do
+    plug :accepts, ["html"]
+  end
+
+  scope "/api/pleroma", Pleroma.Web.TwitterAPI do
+    pipe_through :password_reset
+    get "/password_reset/:token", UtilController, :show_password_reset
+    post "/password_reset", UtilController, :password_reset
+  end
+
   scope "/oauth", Pleroma.Web.OAuth do
     get "/authorize", OAuthController, :authorize
     post "/authorize", OAuthController, :create_authorization
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
new file mode 100644 (file)
index 0000000..ee84750
--- /dev/null
@@ -0,0 +1 @@
+<h2>Invalid Token</h2>
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
new file mode 100644 (file)
index 0000000..3c79609
--- /dev/null
@@ -0,0 +1,12 @@
+<h2>Password Reset for <%= @user.nickname %></h2>
+<%= form_for @conn, util_path(@conn, :password_reset), [as: "data"], fn f -> %>
+<%= label f, :password, "Password" %>
+<%= password_input f, :password %>
+<br>
+
+<%= label f, :password_confirmation, "Confirmation" %>
+<%= password_input f, :password_confirmation %>
+<br>
+<%= 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
new file mode 100644 (file)
index 0000000..58a3736
--- /dev/null
@@ -0,0 +1 @@
+<h2>Password reset failed</h2>
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
new file mode 100644 (file)
index 0000000..c7dfcb6
--- /dev/null
@@ -0,0 +1 @@
+<h2>Password changed!</h2>
index 32910d92c84841a4bc4cb64e288c6f2cde97ac2c..11d8fa6c2eb8a01d570094d7b494eab090b05106 100644 (file)
@@ -2,6 +2,28 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
   use Pleroma.Web, :controller
   alias Pleroma.Web
 
+  alias Pleroma.{Repo, PasswordResetToken, User}
+
+  def show_password_reset(conn, %{"token" => token}) do
+    with %{used: false} = token <- Repo.get_by(PasswordResetToken, %{token: token}),
+      %User{} = user <- Repo.get(User, 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/util_view.ex b/lib/pleroma/web/twitter_api/views/util_view.ex
new file mode 100644 (file)
index 0000000..71b04e6
--- /dev/null
@@ -0,0 +1,4 @@
+defmodule Pleroma.Web.TwitterAPI.UtilView do
+  use Pleroma.Web, :view
+  import Phoenix.HTML.Form
+end
diff --git a/priv/repo/migrations/20171019141706_create_password_reset_tokens.exs b/priv/repo/migrations/20171019141706_create_password_reset_tokens.exs
new file mode 100644 (file)
index 0000000..2d9be3a
--- /dev/null
@@ -0,0 +1,13 @@
+defmodule Pleroma.Repo.Migrations.CreatePasswordResetTokens do
+  use Ecto.Migration
+
+  def change do
+    create table(:password_reset_tokens) do
+      add :token, :string
+      add :user_id, references(:users)
+      add :used, :boolean, default: false
+
+      timestamps()
+    end
+  end
+end