Page MenuHomePhorge

No OneTemporary

Size
7 KB
Referenced Files
None
Subscribers
None
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

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)

Event Timeline