26cca1345b7b3e334485b16c1ff791db9bc6df85
[anni] / test / pleroma / web / twitter_api / password_controller_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.TwitterAPI.PasswordControllerTest do
6   use Pleroma.Web.ConnCase
7
8   alias Pleroma.Config
9   alias Pleroma.PasswordResetToken
10   alias Pleroma.Repo
11   alias Pleroma.Tests.ObanHelpers
12   alias Pleroma.User
13   alias Pleroma.Web.OAuth.Token
14   import Pleroma.Factory
15   import Swoosh.TestAssertions
16
17   describe "GET /api/pleroma/password_reset/token" do
18     test "it returns error when token invalid", %{conn: conn} do
19       response =
20         conn
21         |> get("/api/pleroma/password_reset/token")
22         |> html_response(:ok)
23
24       assert response =~ "<h2>Invalid Token</h2>"
25     end
26
27     test "it shows password reset form", %{conn: conn} do
28       user = insert(:user)
29       {:ok, token} = PasswordResetToken.create_token(user)
30
31       response =
32         conn
33         |> get("/api/pleroma/password_reset/#{token.token}")
34         |> html_response(:ok)
35
36       assert response =~ "<h2>Password Reset for #{user.nickname}</h2>"
37     end
38
39     test "it returns an error when the token has expired", %{conn: conn} do
40       clear_config([:instance, :password_reset_token_validity], 0)
41
42       user = insert(:user)
43       {:ok, token} = PasswordResetToken.create_token(user)
44       {:ok, token} = time_travel(token, -2)
45
46       response =
47         conn
48         |> get("/api/pleroma/password_reset/#{token.token}")
49         |> html_response(:ok)
50
51       assert response =~ "<h2>Invalid Token</h2>"
52     end
53   end
54
55   describe "POST /api/pleroma/password_reset" do
56     test "it fails for an expired token", %{conn: conn} do
57       clear_config([:instance, :password_reset_token_validity], 0)
58
59       user = insert(:user)
60       {:ok, token} = PasswordResetToken.create_token(user)
61       {:ok, token} = time_travel(token, -2)
62       {:ok, _access_token} = Token.create(insert(:oauth_app), user, %{})
63
64       params = %{
65         "password" => "test",
66         password_confirmation: "test",
67         token: token.token
68       }
69
70       response =
71         conn
72         |> assign(:user, user)
73         |> post("/api/pleroma/password_reset", %{data: params})
74         |> html_response(:ok)
75
76       refute response =~ "<h2>Password changed!</h2>"
77     end
78
79     test "it returns HTTP 200", %{conn: conn} do
80       user = insert(:user)
81       {:ok, token} = PasswordResetToken.create_token(user)
82       {:ok, _access_token} = Token.create(insert(:oauth_app), user, %{})
83
84       params = %{
85         "password" => "test",
86         password_confirmation: "test",
87         token: token.token
88       }
89
90       response =
91         conn
92         |> assign(:user, user)
93         |> post("/api/pleroma/password_reset", %{data: params})
94         |> html_response(:ok)
95
96       assert response =~ "<h2>Password changed!</h2>"
97
98       user = refresh_record(user)
99       assert Pleroma.Password.Pbkdf2.verify_pass("test", user.password_hash)
100       assert Enum.empty?(Token.get_user_tokens(user))
101     end
102
103     test "it sets password_reset_pending to false", %{conn: conn} do
104       user = insert(:user, password_reset_pending: true)
105
106       {:ok, token} = PasswordResetToken.create_token(user)
107       {:ok, _access_token} = Token.create(insert(:oauth_app), user, %{})
108
109       params = %{
110         "password" => "test",
111         password_confirmation: "test",
112         token: token.token
113       }
114
115       conn
116       |> assign(:user, user)
117       |> post("/api/pleroma/password_reset", %{data: params})
118       |> html_response(:ok)
119
120       assert User.get_by_id(user.id).password_reset_pending == false
121     end
122   end
123
124   describe "POST /auth/password, with valid parameters" do
125     setup %{conn: conn} do
126       user = insert(:user)
127       conn = post(conn, "/auth/password?email=#{user.email}")
128       %{conn: conn, user: user}
129     end
130
131     test "it returns 204", %{conn: conn} do
132       assert empty_json_response(conn)
133     end
134
135     test "it creates a PasswordResetToken record for user", %{user: user} do
136       token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
137       assert token_record
138     end
139
140     test "it sends an email to user", %{user: user} do
141       ObanHelpers.perform_all()
142       token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
143
144       email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token)
145       notify_email = Config.get([:instance, :notify_email])
146       instance_name = Config.get([:instance, :name])
147
148       assert_email_sent(
149         from: {instance_name, notify_email},
150         to: {user.name, user.email},
151         html_body: email.html_body
152       )
153     end
154   end
155
156   describe "POST /auth/password, with nickname" do
157     test "it returns 204", %{conn: conn} do
158       user = insert(:user)
159
160       assert conn
161              |> post("/auth/password?nickname=#{user.nickname}")
162              |> empty_json_response()
163
164       ObanHelpers.perform_all()
165       token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
166
167       email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token)
168       notify_email = Config.get([:instance, :notify_email])
169       instance_name = Config.get([:instance, :name])
170
171       assert_email_sent(
172         from: {instance_name, notify_email},
173         to: {user.name, user.email},
174         html_body: email.html_body
175       )
176     end
177
178     test "it doesn't fail when a user has no email", %{conn: conn} do
179       user = insert(:user, %{email: nil})
180
181       assert conn
182              |> post("/auth/password?nickname=#{user.nickname}")
183              |> empty_json_response()
184     end
185   end
186
187   describe "POST /auth/password, with invalid parameters" do
188     setup do
189       user = insert(:user)
190       {:ok, user: user}
191     end
192
193     test "it returns 204 when user is not found", %{conn: conn, user: user} do
194       conn = post(conn, "/auth/password?email=nonexisting_#{user.email}")
195
196       assert empty_json_response(conn)
197     end
198
199     test "it returns 204 when user is not local", %{conn: conn, user: user} do
200       {:ok, user} = Repo.update(Ecto.Changeset.change(user, local: false))
201       conn = post(conn, "/auth/password?email=#{user.email}")
202
203       assert empty_json_response(conn)
204     end
205
206     test "it returns 204 when user is deactivated", %{conn: conn, user: user} do
207       {:ok, user} = Repo.update(Ecto.Changeset.change(user, is_active: false, local: true))
208       conn = post(conn, "/auth/password?email=#{user.email}")
209
210       assert empty_json_response(conn)
211     end
212   end
213 end