Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85805244
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
7 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/lib/pleroma/web/twitter_api/controllers/two_factor_authentication_controller.ex b/lib/pleroma/web/twitter_api/controllers/two_factor_authentication_controller.ex
index cda9000fa..01ba6a1ca 100644
--- a/lib/pleroma/web/twitter_api/controllers/two_factor_authentication_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/two_factor_authentication_controller.ex
@@ -1,117 +1,117 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.TwitterAPI.TwoFactorAuthenticationController do
@moduledoc "The module represents actions to manage 2FA/TOTP"
use Pleroma.Web, :controller
alias Comeonin.Pbkdf2
alias Pleroma.User
alias Pleroma.Web.Auth.TOTP
alias Pleroma.Web.CommonAPI.Utils
@doc """
Generates secret key for 2FA and returns provisioning_uri to generate qr code.
## Endpoint
GET /api/pleroma/2fa/provisioning_uri
## Response
### Success
- `{status: 'success', provisioning_uri: [uri] }`
+ `{status: 'success', provisioning_uri: [uri], key: otp_secret_key }`
### Error
`{error: [error_message]}`
"""
def provisioning_uri(%{assigns: %{user: user}} = conn, _params) do
with {:ok, %User{otp_secret: secret} = _} <- User.set_2fa_secret(user) do
- provisioning_uri = TOTP.provisioning_uri(secret, "#{user.email}")
- json(conn, %{status: "success", provisioning_uri: provisioning_uri})
+ uri = TOTP.provisioning_uri(secret, "#{user.email}")
+ json(conn, %{status: "success", provisioning_uri: uri, key: secret})
else
{:error, msg} ->
json(conn, %{error: msg})
end
end
@doc """
Enables 2FA support for user account.
## Endpoint
POST /api/pleroma/2fa/enable
## Required params
`password` - current password of user
`otp_token` - token from Google Auth. app
## Response
### Success
`{status: 'success'}`
### Error
`{error: [error_message]}`
"""
def enable(%{assigns: %{user: user}} = conn, params) do
with {:ok, user} <- Utils.confirm_current_password(user, params["password"]),
{:ok, :pass} <- TOTP.validate_token(user.otp_secret, params["otp_token"]) do
Pleroma.Async.start(fn -> User.enable_2fa(user) end)
json(conn, %{status: "success"})
else
{:error, msg} ->
json(conn, %{error: msg, status: "error"})
end
end
@doc """
Disables 2FA for user account.
## Endpoint
POST /api/pleroma/2fa/disable
## Required params
`password` - current password of user
## Response
### Success
`{status: 'success'}`
### Error
`{error: [error_message]}`
"""
def disable(%{assigns: %{user: user}} = conn, params) do
with {:ok, user} <- Utils.confirm_current_password(user, params["password"]) do
Pleroma.Async.start(fn -> User.disable_2fa(user) end)
json(conn, %{status: "success"})
else
{:error, msg} ->
json(conn, %{error: msg})
end
end
@doc """
Generates backup codes for 2fa
## Endpoint
GET /api/pleroma/2fa/backup_codes
## Response
### Success
`{status: 'success', codes: [codes]}`
### Error
`{error: [error_message]}`
"""
def backup_codes(%{assigns: %{user: user}} = conn, _params) do
with codes <- TOTP.generate_backup_codes(),
hashed_codes <- Enum.map(codes, fn code -> Pbkdf2.hashpwsalt(code) end),
{:ok, _user} <- User.update_2fa_backup_codes(user, hashed_codes) do
json(conn, %{status: "success", codes: codes})
else
{:error, msg} ->
json(conn, %{error: msg})
end
end
end
diff --git a/test/web/twitter_api/two_factor_authentication_controller_test.exs b/test/web/twitter_api/two_factor_authentication_controller_test.exs
index 19203047a..050eb7ac8 100644
--- a/test/web/twitter_api/two_factor_authentication_controller_test.exs
+++ b/test/web/twitter_api/two_factor_authentication_controller_test.exs
@@ -1,121 +1,122 @@
defmodule Pleroma.Web.TwitterAPI.TwoFactorAuthenticationControllerTest do
use Pleroma.Web.ConnCase
import Pleroma.Factory
alias Pleroma.Web.Auth.TOTP
describe "GET /api/pleroma/2fa/provisioning_uri" do
test "returns provisioning_uri for qr code", %{conn: conn} do
user = insert(:user)
response =
conn
|> assign(:user, user)
|> get("/api/pleroma/2fa/provisioning_uri")
|> json_response(:ok)
user = refresh_record(user)
assert response == %{
"status" => "success",
+ "key" => user.otp_secret,
"provisioning_uri" =>
"otpauth://totp/#{user.email}?digits=6&issuer=Pleroma&period=30&secret=#{
user.otp_secret
}"
}
refute user.otp_enabled
assert user.otp_secret
end
end
describe "POST /api/pleroma/2fa/enable" do
test "returns success with correct data", %{conn: conn} do
user = insert(:user, otp_secret: TOTP.generate_secret())
otp_token = TOTP.generate_token(user.otp_secret)
response =
conn
|> assign(:user, user)
|> post("/api/pleroma/2fa/enable", %{password: "test", otp_token: otp_token})
|> json_response(:ok)
assert response == %{"status" => "success"}
user = refresh_record(user)
assert user.otp_enabled
end
test "returns error if current password is incorrect", %{conn: conn} do
user = insert(:user)
response =
conn
|> assign(:user, user)
|> post("/api/pleroma/2fa/enable", %{password: "42"})
|> json_response(:ok)
assert response == %{"error" => "Invalid password.", "status" => "error"}
refute refresh_record(user).otp_enabled
end
test "returns error if otp_token is incorrect", %{conn: conn} do
user = insert(:user, otp_secret: TOTP.generate_secret())
response =
conn
|> assign(:user, user)
|> post("/api/pleroma/2fa/enable", %{password: "test", otp_token: "incorrect"})
|> json_response(:ok)
assert response == %{"error" => "invalid_token", "status" => "error"}
end
end
describe "POST /api/pleroma/2fa/disable" do
test "returns success if current password is correct", %{conn: conn} do
user = insert(:user, otp_enabled: true)
response =
conn
|> assign(:user, user)
|> post("/api/pleroma/2fa/disable", %{password: "test"})
|> json_response(:ok)
assert response == %{"status" => "success"}
refute refresh_record(user).otp_enabled
end
test "returns error if current password is incorrect", %{conn: conn} do
user = insert(:user)
response =
conn
|> assign(:user, user)
|> post("/api/pleroma/2fa/disable", %{password: "42"})
|> json_response(:ok)
assert response == %{"error" => "Invalid password."}
end
end
describe "GET /api/pleroma/2fa/backup_codes" do
test "returns backup codes", %{conn: conn} do
user = insert(:user, otp_backup_codes: [])
response =
conn
|> assign(:user, user)
|> get("/api/pleroma/2fa/backup_codes")
|> json_response(:ok)
assert response["status"] == "success"
assert [<<_::bytes-size(6)>>, <<_::bytes-size(6)>>] = response["codes"]
hashed_codes = refresh_record(user).otp_backup_codes
assert Enum.zip(response["codes"], hashed_codes)
|> Enum.all?(fn {code, hash} ->
Comeonin.Pbkdf2.checkpw(code, hash)
end)
end
end
end
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Oct 11, 4:11 AM (1 d, 11 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1785597
Default Alt Text
(7 KB)
Attached To
Mode
rPUBE pleroma-upstream
Attached
Detach File
Event Timeline
Log In to Comment