# Pleroma: A lightweight social networking server # Copyright © 2017-2022 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.PleromaAPI.TwoFactorAuthenticationControllerTest do use Pleroma.Web.ConnCase, async: true import Pleroma.Factory alias Pleroma.MFA.Settings alias Pleroma.MFA.TOTP describe "GET /api/pleroma/accounts/mfa/settings" do test "returns user mfa settings for new user", %{conn: conn} do token = insert(:oauth_token, scopes: ["read", "follow"]) token2 = insert(:oauth_token, scopes: ["write"]) assert conn |> put_req_header("authorization", "Bearer #{token.token}") |> get("/api/pleroma/accounts/mfa") |> json_response(:ok) == %{ "settings" => %{"enabled" => false, "totp" => false} } assert conn |> put_req_header("authorization", "Bearer #{token2.token}") |> get("/api/pleroma/accounts/mfa") |> json_response(403) == %{ "error" => "Insufficient permissions: read:security." } end test "returns user mfa settings with enabled totp", %{conn: conn} do user = insert(:user, multi_factor_authentication_settings: %Settings{ enabled: true, totp: %Settings.TOTP{secret: "XXX", delivery_type: "app", confirmed: true} } ) token = insert(:oauth_token, scopes: ["read", "follow"], user: user) assert conn |> put_req_header("authorization", "Bearer #{token.token}") |> get("/api/pleroma/accounts/mfa") |> json_response(:ok) == %{ "settings" => %{"enabled" => true, "totp" => true} } end end describe "GET /api/pleroma/accounts/mfa/backup_codes" do test "returns backup codes", %{conn: conn} do user = insert(:user, multi_factor_authentication_settings: %Settings{ backup_codes: ["1", "2", "3"], totp: %Settings.TOTP{secret: "secret"} } ) token = insert(:oauth_token, scopes: ["write", "follow"], user: user) token2 = insert(:oauth_token, scopes: ["read"]) response = conn |> put_req_header("authorization", "Bearer #{token.token}") |> get("/api/pleroma/accounts/mfa/backup_codes") |> json_response(:ok) assert [<<_::bytes-size(6)>>, <<_::bytes-size(6)>>] = response["codes"] user = refresh_record(user) mfa_settings = user.multi_factor_authentication_settings assert mfa_settings.totp.secret == "secret" refute mfa_settings.backup_codes == ["1", "2", "3"] refute mfa_settings.backup_codes == [] assert conn |> put_req_header("authorization", "Bearer #{token2.token}") |> get("/api/pleroma/accounts/mfa/backup_codes") |> json_response(403) == %{ "error" => "Insufficient permissions: write:security." } end end describe "GET /api/pleroma/accounts/mfa/setup/totp" do test "return errors when method is invalid", %{conn: conn} do user = insert(:user) token = insert(:oauth_token, scopes: ["write", "follow"], user: user) response = conn |> put_req_header("authorization", "Bearer #{token.token}") |> get("/api/pleroma/accounts/mfa/setup/torf") |> json_response(400) assert response == %{"error" => "undefined method"} end test "returns key and provisioning_uri", %{conn: conn} do user = insert(:user, multi_factor_authentication_settings: %Settings{backup_codes: ["1", "2", "3"]} ) token = insert(:oauth_token, scopes: ["write", "follow"], user: user) token2 = insert(:oauth_token, scopes: ["read"]) response = conn |> put_req_header("authorization", "Bearer #{token.token}") |> get("/api/pleroma/accounts/mfa/setup/totp") |> json_response(:ok) user = refresh_record(user) mfa_settings = user.multi_factor_authentication_settings secret = mfa_settings.totp.secret refute mfa_settings.enabled assert mfa_settings.backup_codes == ["1", "2", "3"] assert response == %{ "key" => secret, "provisioning_uri" => TOTP.provisioning_uri(secret, "#{user.email}") } assert conn |> put_req_header("authorization", "Bearer #{token2.token}") |> get("/api/pleroma/accounts/mfa/setup/totp") |> json_response(403) == %{ "error" => "Insufficient permissions: write:security." } end end describe "GET /api/pleroma/accounts/mfa/confirm/totp" do test "returns success result", %{conn: conn} do secret = TOTP.generate_secret() code = TOTP.generate_token(secret) user = insert(:user, multi_factor_authentication_settings: %Settings{ backup_codes: ["1", "2", "3"], totp: %Settings.TOTP{secret: secret} } ) token = insert(:oauth_token, scopes: ["write", "follow"], user: user) token2 = insert(:oauth_token, scopes: ["read"]) assert conn |> put_req_header("authorization", "Bearer #{token.token}") |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "test", code: code}) |> json_response(:ok) settings = refresh_record(user).multi_factor_authentication_settings assert settings.enabled assert settings.totp.secret == secret assert settings.totp.confirmed assert settings.backup_codes == ["1", "2", "3"] assert conn |> put_req_header("authorization", "Bearer #{token2.token}") |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "test", code: code}) |> json_response(403) == %{ "error" => "Insufficient permissions: write:security." } end test "returns error if password incorrect", %{conn: conn} do secret = TOTP.generate_secret() code = TOTP.generate_token(secret) user = insert(:user, multi_factor_authentication_settings: %Settings{ backup_codes: ["1", "2", "3"], totp: %Settings.TOTP{secret: secret} } ) token = insert(:oauth_token, scopes: ["write", "follow"], user: user) response = conn |> put_req_header("authorization", "Bearer #{token.token}") |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "xxx", code: code}) |> json_response(422) settings = refresh_record(user).multi_factor_authentication_settings refute settings.enabled refute settings.totp.confirmed assert settings.backup_codes == ["1", "2", "3"] assert response == %{"error" => "Invalid password."} end test "returns error if code incorrect", %{conn: conn} do secret = TOTP.generate_secret() user = insert(:user, multi_factor_authentication_settings: %Settings{ backup_codes: ["1", "2", "3"], totp: %Settings.TOTP{secret: secret} } ) token = insert(:oauth_token, scopes: ["write", "follow"], user: user) token2 = insert(:oauth_token, scopes: ["read"]) response = conn |> put_req_header("authorization", "Bearer #{token.token}") |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "test", code: "code"}) |> json_response(422) settings = refresh_record(user).multi_factor_authentication_settings refute settings.enabled refute settings.totp.confirmed assert settings.backup_codes == ["1", "2", "3"] assert response == %{"error" => "invalid_token"} assert conn |> put_req_header("authorization", "Bearer #{token2.token}") |> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "test", code: "code"}) |> json_response(403) == %{ "error" => "Insufficient permissions: write:security." } end end describe "DELETE /api/pleroma/accounts/mfa/totp" do test "returns success result", %{conn: conn} do user = insert(:user, multi_factor_authentication_settings: %Settings{ backup_codes: ["1", "2", "3"], totp: %Settings.TOTP{secret: "secret"} } ) token = insert(:oauth_token, scopes: ["write", "follow"], user: user) token2 = insert(:oauth_token, scopes: ["read"]) assert conn |> put_req_header("authorization", "Bearer #{token.token}") |> delete("/api/pleroma/accounts/mfa/totp", %{password: "test"}) |> json_response(:ok) settings = refresh_record(user).multi_factor_authentication_settings refute settings.enabled assert settings.totp.secret == nil refute settings.totp.confirmed assert conn |> put_req_header("authorization", "Bearer #{token2.token}") |> delete("/api/pleroma/accounts/mfa/totp", %{password: "test"}) |> json_response(403) == %{ "error" => "Insufficient permissions: write:security." } end end end