24074f4e5415ad45b63e618d91bc2b8ee73ce165
[akkoma] / test / pleroma / web / pleroma_api / controllers / two_factor_authentication_controller_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.PleromaAPI.TwoFactorAuthenticationControllerTest do
6 use Pleroma.Web.ConnCase, async: true
7
8 import Pleroma.Factory
9 alias Pleroma.MFA.Settings
10 alias Pleroma.MFA.TOTP
11
12 describe "GET /api/pleroma/accounts/mfa/settings" do
13 test "returns user mfa settings for new user", %{conn: conn} do
14 token = insert(:oauth_token, scopes: ["read", "follow"])
15 token2 = insert(:oauth_token, scopes: ["write"])
16
17 assert conn
18 |> put_req_header("authorization", "Bearer #{token.token}")
19 |> get("/api/pleroma/accounts/mfa")
20 |> json_response(:ok) == %{
21 "settings" => %{"enabled" => false, "totp" => false}
22 }
23
24 assert conn
25 |> put_req_header("authorization", "Bearer #{token2.token}")
26 |> get("/api/pleroma/accounts/mfa")
27 |> json_response(403) == %{
28 "error" => "Insufficient permissions: read:security."
29 }
30 end
31
32 test "returns user mfa settings with enabled totp", %{conn: conn} do
33 user =
34 insert(:user,
35 multi_factor_authentication_settings: %Settings{
36 enabled: true,
37 totp: %Settings.TOTP{secret: "XXX", delivery_type: "app", confirmed: true}
38 }
39 )
40
41 token = insert(:oauth_token, scopes: ["read", "follow"], user: user)
42
43 assert conn
44 |> put_req_header("authorization", "Bearer #{token.token}")
45 |> get("/api/pleroma/accounts/mfa")
46 |> json_response(:ok) == %{
47 "settings" => %{"enabled" => true, "totp" => true}
48 }
49 end
50 end
51
52 describe "GET /api/pleroma/accounts/mfa/backup_codes" do
53 test "returns backup codes", %{conn: conn} do
54 user =
55 insert(:user,
56 multi_factor_authentication_settings: %Settings{
57 backup_codes: ["1", "2", "3"],
58 totp: %Settings.TOTP{secret: "secret"}
59 }
60 )
61
62 token = insert(:oauth_token, scopes: ["write", "follow"], user: user)
63 token2 = insert(:oauth_token, scopes: ["read"])
64
65 response =
66 conn
67 |> put_req_header("authorization", "Bearer #{token.token}")
68 |> get("/api/pleroma/accounts/mfa/backup_codes")
69 |> json_response(:ok)
70
71 assert [<<_::bytes-size(6)>>, <<_::bytes-size(6)>>] = response["codes"]
72 user = refresh_record(user)
73 mfa_settings = user.multi_factor_authentication_settings
74 assert mfa_settings.totp.secret == "secret"
75 refute mfa_settings.backup_codes == ["1", "2", "3"]
76 refute mfa_settings.backup_codes == []
77
78 assert conn
79 |> put_req_header("authorization", "Bearer #{token2.token}")
80 |> get("/api/pleroma/accounts/mfa/backup_codes")
81 |> json_response(403) == %{
82 "error" => "Insufficient permissions: write:security."
83 }
84 end
85 end
86
87 describe "GET /api/pleroma/accounts/mfa/setup/totp" do
88 test "return errors when method is invalid", %{conn: conn} do
89 user = insert(:user)
90 token = insert(:oauth_token, scopes: ["write", "follow"], user: user)
91
92 response =
93 conn
94 |> put_req_header("authorization", "Bearer #{token.token}")
95 |> get("/api/pleroma/accounts/mfa/setup/torf")
96 |> json_response(400)
97
98 assert response == %{"error" => "undefined method"}
99 end
100
101 test "returns key and provisioning_uri", %{conn: conn} do
102 user =
103 insert(:user,
104 multi_factor_authentication_settings: %Settings{backup_codes: ["1", "2", "3"]}
105 )
106
107 token = insert(:oauth_token, scopes: ["write", "follow"], user: user)
108 token2 = insert(:oauth_token, scopes: ["read"])
109
110 response =
111 conn
112 |> put_req_header("authorization", "Bearer #{token.token}")
113 |> get("/api/pleroma/accounts/mfa/setup/totp")
114 |> json_response(:ok)
115
116 user = refresh_record(user)
117 mfa_settings = user.multi_factor_authentication_settings
118 secret = mfa_settings.totp.secret
119 refute mfa_settings.enabled
120 assert mfa_settings.backup_codes == ["1", "2", "3"]
121
122 assert response == %{
123 "key" => secret,
124 "provisioning_uri" => TOTP.provisioning_uri(secret, "#{user.email}")
125 }
126
127 assert conn
128 |> put_req_header("authorization", "Bearer #{token2.token}")
129 |> get("/api/pleroma/accounts/mfa/setup/totp")
130 |> json_response(403) == %{
131 "error" => "Insufficient permissions: write:security."
132 }
133 end
134 end
135
136 describe "GET /api/pleroma/accounts/mfa/confirm/totp" do
137 test "returns success result", %{conn: conn} do
138 secret = TOTP.generate_secret()
139 code = TOTP.generate_token(secret)
140
141 user =
142 insert(:user,
143 multi_factor_authentication_settings: %Settings{
144 backup_codes: ["1", "2", "3"],
145 totp: %Settings.TOTP{secret: secret}
146 }
147 )
148
149 token = insert(:oauth_token, scopes: ["write", "follow"], user: user)
150 token2 = insert(:oauth_token, scopes: ["read"])
151
152 assert conn
153 |> put_req_header("authorization", "Bearer #{token.token}")
154 |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "test", code: code})
155 |> json_response(:ok)
156
157 settings = refresh_record(user).multi_factor_authentication_settings
158 assert settings.enabled
159 assert settings.totp.secret == secret
160 assert settings.totp.confirmed
161 assert settings.backup_codes == ["1", "2", "3"]
162
163 assert conn
164 |> put_req_header("authorization", "Bearer #{token2.token}")
165 |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "test", code: code})
166 |> json_response(403) == %{
167 "error" => "Insufficient permissions: write:security."
168 }
169 end
170
171 test "returns error if password incorrect", %{conn: conn} do
172 secret = TOTP.generate_secret()
173 code = TOTP.generate_token(secret)
174
175 user =
176 insert(:user,
177 multi_factor_authentication_settings: %Settings{
178 backup_codes: ["1", "2", "3"],
179 totp: %Settings.TOTP{secret: secret}
180 }
181 )
182
183 token = insert(:oauth_token, scopes: ["write", "follow"], user: user)
184
185 response =
186 conn
187 |> put_req_header("authorization", "Bearer #{token.token}")
188 |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "xxx", code: code})
189 |> json_response(422)
190
191 settings = refresh_record(user).multi_factor_authentication_settings
192 refute settings.enabled
193 refute settings.totp.confirmed
194 assert settings.backup_codes == ["1", "2", "3"]
195 assert response == %{"error" => "Invalid password."}
196 end
197
198 test "returns error if code incorrect", %{conn: conn} do
199 secret = TOTP.generate_secret()
200
201 user =
202 insert(:user,
203 multi_factor_authentication_settings: %Settings{
204 backup_codes: ["1", "2", "3"],
205 totp: %Settings.TOTP{secret: secret}
206 }
207 )
208
209 token = insert(:oauth_token, scopes: ["write", "follow"], user: user)
210 token2 = insert(:oauth_token, scopes: ["read"])
211
212 response =
213 conn
214 |> put_req_header("authorization", "Bearer #{token.token}")
215 |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "test", code: "code"})
216 |> json_response(422)
217
218 settings = refresh_record(user).multi_factor_authentication_settings
219 refute settings.enabled
220 refute settings.totp.confirmed
221 assert settings.backup_codes == ["1", "2", "3"]
222 assert response == %{"error" => "invalid_token"}
223
224 assert conn
225 |> put_req_header("authorization", "Bearer #{token2.token}")
226 |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "test", code: "code"})
227 |> json_response(403) == %{
228 "error" => "Insufficient permissions: write:security."
229 }
230 end
231 end
232
233 describe "DELETE /api/pleroma/accounts/mfa/totp" do
234 test "returns success result", %{conn: conn} do
235 user =
236 insert(:user,
237 multi_factor_authentication_settings: %Settings{
238 backup_codes: ["1", "2", "3"],
239 totp: %Settings.TOTP{secret: "secret"}
240 }
241 )
242
243 token = insert(:oauth_token, scopes: ["write", "follow"], user: user)
244 token2 = insert(:oauth_token, scopes: ["read"])
245
246 assert conn
247 |> put_req_header("authorization", "Bearer #{token.token}")
248 |> delete("/api/pleroma/accounts/mfa/totp", %{password: "test"})
249 |> json_response(:ok)
250
251 settings = refresh_record(user).multi_factor_authentication_settings
252 refute settings.enabled
253 assert settings.totp.secret == nil
254 refute settings.totp.confirmed
255
256 assert conn
257 |> put_req_header("authorization", "Bearer #{token2.token}")
258 |> delete("/api/pleroma/accounts/mfa/totp", %{password: "test"})
259 |> json_response(403) == %{
260 "error" => "Insufficient permissions: write:security."
261 }
262 end
263 end
264 end