Merge branch 'split-masto-api/auth' into 'develop'
Extract auth actions from `MastodonAPIController` to `AuthController` See merge request pleroma/pleroma!1759
This commit is contained in:
commit
8557176808
91
lib/pleroma/web/mastodon_api/controllers/auth_controller.ex
Normal file
91
lib/pleroma/web/mastodon_api/controllers/auth_controller.ex
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.MastodonAPI.AuthController do
|
||||||
|
use Pleroma.Web, :controller
|
||||||
|
|
||||||
|
alias Pleroma.User
|
||||||
|
alias Pleroma.Web.OAuth.App
|
||||||
|
alias Pleroma.Web.OAuth.Authorization
|
||||||
|
alias Pleroma.Web.OAuth.Token
|
||||||
|
alias Pleroma.Web.TwitterAPI.TwitterAPI
|
||||||
|
|
||||||
|
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
|
||||||
|
|
||||||
|
@local_mastodon_name "Mastodon-Local"
|
||||||
|
|
||||||
|
plug(Pleroma.Plugs.RateLimiter, :password_reset when action == :password_reset)
|
||||||
|
|
||||||
|
@doc "GET /web/login"
|
||||||
|
def login(%{assigns: %{user: %User{}}} = conn, _params) do
|
||||||
|
redirect(conn, to: local_mastodon_root_path(conn))
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc "Local Mastodon FE login init action"
|
||||||
|
def login(conn, %{"code" => auth_token}) do
|
||||||
|
with {:ok, app} <- get_or_make_app(),
|
||||||
|
{:ok, auth} <- Authorization.get_by_token(app, auth_token),
|
||||||
|
{:ok, token} <- Token.exchange_token(app, auth) do
|
||||||
|
conn
|
||||||
|
|> put_session(:oauth_token, token.token)
|
||||||
|
|> redirect(to: local_mastodon_root_path(conn))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc "Local Mastodon FE callback action"
|
||||||
|
def login(conn, _) do
|
||||||
|
with {:ok, app} <- get_or_make_app() do
|
||||||
|
path =
|
||||||
|
o_auth_path(conn, :authorize,
|
||||||
|
response_type: "code",
|
||||||
|
client_id: app.client_id,
|
||||||
|
redirect_uri: ".",
|
||||||
|
scope: Enum.join(app.scopes, " ")
|
||||||
|
)
|
||||||
|
|
||||||
|
redirect(conn, to: path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc "DELETE /auth/sign_out"
|
||||||
|
def logout(conn, _) do
|
||||||
|
conn
|
||||||
|
|> clear_session
|
||||||
|
|> redirect(to: "/")
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc "POST /auth/password"
|
||||||
|
def password_reset(conn, params) do
|
||||||
|
nickname_or_email = params["email"] || params["nickname"]
|
||||||
|
|
||||||
|
with {:ok, _} <- TwitterAPI.password_reset(nickname_or_email) do
|
||||||
|
conn
|
||||||
|
|> put_status(:no_content)
|
||||||
|
|> json("")
|
||||||
|
else
|
||||||
|
{:error, "unknown user"} ->
|
||||||
|
send_resp(conn, :not_found, "")
|
||||||
|
|
||||||
|
{:error, _} ->
|
||||||
|
send_resp(conn, :bad_request, "")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp local_mastodon_root_path(conn) do
|
||||||
|
case get_session(conn, :return_to) do
|
||||||
|
nil ->
|
||||||
|
mastodon_api_path(conn, :index, ["getting-started"])
|
||||||
|
|
||||||
|
return_to ->
|
||||||
|
delete_session(conn, :return_to)
|
||||||
|
return_to
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@spec get_or_make_app() :: {:ok, App.t()} | {:error, Ecto.Changeset.t()}
|
||||||
|
defp get_or_make_app do
|
||||||
|
%{client_name: @local_mastodon_name, redirect_uris: "."}
|
||||||
|
|> App.get_or_make(["read", "write", "follow", "push"])
|
||||||
|
end
|
||||||
|
end
|
@ -10,7 +10,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||||||
alias Pleroma.Bookmark
|
alias Pleroma.Bookmark
|
||||||
alias Pleroma.Config
|
alias Pleroma.Config
|
||||||
alias Pleroma.Pagination
|
alias Pleroma.Pagination
|
||||||
alias Pleroma.Plugs.RateLimiter
|
|
||||||
alias Pleroma.Stats
|
alias Pleroma.Stats
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web
|
alias Pleroma.Web
|
||||||
@ -19,18 +18,11 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||||||
alias Pleroma.Web.MastodonAPI.AccountView
|
alias Pleroma.Web.MastodonAPI.AccountView
|
||||||
alias Pleroma.Web.MastodonAPI.MastodonView
|
alias Pleroma.Web.MastodonAPI.MastodonView
|
||||||
alias Pleroma.Web.MastodonAPI.StatusView
|
alias Pleroma.Web.MastodonAPI.StatusView
|
||||||
alias Pleroma.Web.OAuth.App
|
|
||||||
alias Pleroma.Web.OAuth.Authorization
|
|
||||||
alias Pleroma.Web.OAuth.Token
|
|
||||||
alias Pleroma.Web.TwitterAPI.TwitterAPI
|
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
plug(RateLimiter, :password_reset when action == :password_reset)
|
|
||||||
|
|
||||||
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
|
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
|
||||||
|
|
||||||
@local_mastodon_name "Mastodon-Local"
|
|
||||||
@mastodon_api_level "2.7.2"
|
@mastodon_api_level "2.7.2"
|
||||||
|
|
||||||
def masto_instance(conn, _params) do
|
def masto_instance(conn, _params) do
|
||||||
@ -268,61 +260,6 @@ def put_settings(%{assigns: %{user: user}} = conn, %{"data" => settings} = _para
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def login(%{assigns: %{user: %User{}}} = conn, _params) do
|
|
||||||
redirect(conn, to: local_mastodon_root_path(conn))
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc "Local Mastodon FE login init action"
|
|
||||||
def login(conn, %{"code" => auth_token}) do
|
|
||||||
with {:ok, app} <- get_or_make_app(),
|
|
||||||
{:ok, auth} <- Authorization.get_by_token(app, auth_token),
|
|
||||||
{:ok, token} <- Token.exchange_token(app, auth) do
|
|
||||||
conn
|
|
||||||
|> put_session(:oauth_token, token.token)
|
|
||||||
|> redirect(to: local_mastodon_root_path(conn))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc "Local Mastodon FE callback action"
|
|
||||||
def login(conn, _) do
|
|
||||||
with {:ok, app} <- get_or_make_app() do
|
|
||||||
path =
|
|
||||||
o_auth_path(conn, :authorize,
|
|
||||||
response_type: "code",
|
|
||||||
client_id: app.client_id,
|
|
||||||
redirect_uri: ".",
|
|
||||||
scope: Enum.join(app.scopes, " ")
|
|
||||||
)
|
|
||||||
|
|
||||||
redirect(conn, to: path)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defp local_mastodon_root_path(conn) do
|
|
||||||
case get_session(conn, :return_to) do
|
|
||||||
nil ->
|
|
||||||
mastodon_api_path(conn, :index, ["getting-started"])
|
|
||||||
|
|
||||||
return_to ->
|
|
||||||
delete_session(conn, :return_to)
|
|
||||||
return_to
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec get_or_make_app() :: {:ok, App.t()} | {:error, Ecto.Changeset.t()}
|
|
||||||
defp get_or_make_app do
|
|
||||||
App.get_or_make(
|
|
||||||
%{client_name: @local_mastodon_name, redirect_uris: "."},
|
|
||||||
["read", "write", "follow", "push"]
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
def logout(conn, _) do
|
|
||||||
conn
|
|
||||||
|> clear_session
|
|
||||||
|> redirect(to: "/")
|
|
||||||
end
|
|
||||||
|
|
||||||
# Stubs for unimplemented mastodon api
|
# Stubs for unimplemented mastodon api
|
||||||
#
|
#
|
||||||
def empty_array(conn, _) do
|
def empty_array(conn, _) do
|
||||||
@ -335,22 +272,6 @@ def empty_object(conn, _) do
|
|||||||
json(conn, %{})
|
json(conn, %{})
|
||||||
end
|
end
|
||||||
|
|
||||||
def password_reset(conn, params) do
|
|
||||||
nickname_or_email = params["email"] || params["nickname"]
|
|
||||||
|
|
||||||
with {:ok, _} <- TwitterAPI.password_reset(nickname_or_email) do
|
|
||||||
conn
|
|
||||||
|> put_status(:no_content)
|
|
||||||
|> json("")
|
|
||||||
else
|
|
||||||
{:error, "unknown user"} ->
|
|
||||||
send_resp(conn, :not_found, "")
|
|
||||||
|
|
||||||
{:error, _} ->
|
|
||||||
send_resp(conn, :bad_request, "")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defp present?(nil), do: false
|
defp present?(nil), do: false
|
||||||
defp present?(false), do: false
|
defp present?(false), do: false
|
||||||
defp present?(_), do: true
|
defp present?(_), do: true
|
||||||
|
@ -661,10 +661,10 @@ defmodule Pleroma.Web.Router do
|
|||||||
scope "/", Pleroma.Web.MastodonAPI do
|
scope "/", Pleroma.Web.MastodonAPI do
|
||||||
pipe_through(:mastodon_html)
|
pipe_through(:mastodon_html)
|
||||||
|
|
||||||
get("/web/login", MastodonAPIController, :login)
|
get("/web/login", AuthController, :login)
|
||||||
delete("/auth/sign_out", MastodonAPIController, :logout)
|
delete("/auth/sign_out", AuthController, :logout)
|
||||||
|
|
||||||
post("/auth/password", MastodonAPIController, :password_reset)
|
post("/auth/password", AuthController, :password_reset)
|
||||||
|
|
||||||
scope [] do
|
scope [] do
|
||||||
pipe_through(:oauth_read)
|
pipe_through(:oauth_read)
|
||||||
|
121
test/web/mastodon_api/controllers/auth_controller_test.exs
Normal file
121
test/web/mastodon_api/controllers/auth_controller_test.exs
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.MastodonAPI.AuthControllerTest do
|
||||||
|
use Pleroma.Web.ConnCase
|
||||||
|
|
||||||
|
alias Pleroma.Config
|
||||||
|
alias Pleroma.Repo
|
||||||
|
alias Pleroma.Tests.ObanHelpers
|
||||||
|
|
||||||
|
import Pleroma.Factory
|
||||||
|
import Swoosh.TestAssertions
|
||||||
|
|
||||||
|
describe "GET /web/login" do
|
||||||
|
setup %{conn: conn} do
|
||||||
|
session_opts = [
|
||||||
|
store: :cookie,
|
||||||
|
key: "_test",
|
||||||
|
signing_salt: "cooldude"
|
||||||
|
]
|
||||||
|
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> Plug.Session.call(Plug.Session.init(session_opts))
|
||||||
|
|> fetch_session()
|
||||||
|
|
||||||
|
test_path = "/web/statuses/test"
|
||||||
|
%{conn: conn, path: test_path}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "redirects to the saved path after log in", %{conn: conn, path: path} do
|
||||||
|
app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
|
||||||
|
auth = insert(:oauth_authorization, app: app)
|
||||||
|
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> put_session(:return_to, path)
|
||||||
|
|> get("/web/login", %{code: auth.token})
|
||||||
|
|
||||||
|
assert conn.status == 302
|
||||||
|
assert redirected_to(conn) == path
|
||||||
|
end
|
||||||
|
|
||||||
|
test "redirects to the getting-started page when referer is not present", %{conn: conn} do
|
||||||
|
app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
|
||||||
|
auth = insert(:oauth_authorization, app: app)
|
||||||
|
|
||||||
|
conn = get(conn, "/web/login", %{code: auth.token})
|
||||||
|
|
||||||
|
assert conn.status == 302
|
||||||
|
assert redirected_to(conn) == "/web/getting-started"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "POST /auth/password, with valid parameters" do
|
||||||
|
setup %{conn: conn} do
|
||||||
|
user = insert(:user)
|
||||||
|
conn = post(conn, "/auth/password?email=#{user.email}")
|
||||||
|
%{conn: conn, user: user}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it returns 204", %{conn: conn} do
|
||||||
|
assert json_response(conn, :no_content)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it creates a PasswordResetToken record for user", %{user: user} do
|
||||||
|
token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
|
||||||
|
assert token_record
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it sends an email to user", %{user: user} do
|
||||||
|
ObanHelpers.perform_all()
|
||||||
|
token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
|
||||||
|
|
||||||
|
email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token)
|
||||||
|
notify_email = Config.get([:instance, :notify_email])
|
||||||
|
instance_name = Config.get([:instance, :name])
|
||||||
|
|
||||||
|
assert_email_sent(
|
||||||
|
from: {instance_name, notify_email},
|
||||||
|
to: {user.name, user.email},
|
||||||
|
html_body: email.html_body
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "POST /auth/password, with invalid parameters" do
|
||||||
|
setup do
|
||||||
|
user = insert(:user)
|
||||||
|
{:ok, user: user}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it returns 404 when user is not found", %{conn: conn, user: user} do
|
||||||
|
conn = post(conn, "/auth/password?email=nonexisting_#{user.email}")
|
||||||
|
assert conn.status == 404
|
||||||
|
assert conn.resp_body == ""
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it returns 400 when user is not local", %{conn: conn, user: user} do
|
||||||
|
{:ok, user} = Repo.update(Ecto.Changeset.change(user, local: false))
|
||||||
|
conn = post(conn, "/auth/password?email=#{user.email}")
|
||||||
|
assert conn.status == 400
|
||||||
|
assert conn.resp_body == ""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "DELETE /auth/sign_out" do
|
||||||
|
test "redirect to root page", %{conn: conn} do
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> assign(:user, user)
|
||||||
|
|> delete("/auth/sign_out")
|
||||||
|
|
||||||
|
assert conn.status == 302
|
||||||
|
assert redirected_to(conn) == "/"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -9,12 +9,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
|
|||||||
alias Pleroma.Config
|
alias Pleroma.Config
|
||||||
alias Pleroma.Notification
|
alias Pleroma.Notification
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
alias Pleroma.Tests.ObanHelpers
|
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
|
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
import Swoosh.TestAssertions
|
|
||||||
import Tesla.Mock
|
import Tesla.Mock
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
@ -307,95 +305,6 @@ test "saves referer path to session", %{conn: conn, path: path} do
|
|||||||
|
|
||||||
assert return_to == path
|
assert return_to == path
|
||||||
end
|
end
|
||||||
|
|
||||||
test "redirects to the saved path after log in", %{conn: conn, path: path} do
|
|
||||||
app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
|
|
||||||
auth = insert(:oauth_authorization, app: app)
|
|
||||||
|
|
||||||
conn =
|
|
||||||
conn
|
|
||||||
|> put_session(:return_to, path)
|
|
||||||
|> get("/web/login", %{code: auth.token})
|
|
||||||
|
|
||||||
assert conn.status == 302
|
|
||||||
assert redirected_to(conn) == path
|
|
||||||
end
|
|
||||||
|
|
||||||
test "redirects to the getting-started page when referer is not present", %{conn: conn} do
|
|
||||||
app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
|
|
||||||
auth = insert(:oauth_authorization, app: app)
|
|
||||||
|
|
||||||
conn = get(conn, "/web/login", %{code: auth.token})
|
|
||||||
|
|
||||||
assert conn.status == 302
|
|
||||||
assert redirected_to(conn) == "/web/getting-started"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "POST /auth/password, with valid parameters" do
|
|
||||||
setup %{conn: conn} do
|
|
||||||
user = insert(:user)
|
|
||||||
conn = post(conn, "/auth/password?email=#{user.email}")
|
|
||||||
%{conn: conn, user: user}
|
|
||||||
end
|
|
||||||
|
|
||||||
test "it returns 204", %{conn: conn} do
|
|
||||||
assert json_response(conn, :no_content)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "it creates a PasswordResetToken record for user", %{user: user} do
|
|
||||||
token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
|
|
||||||
assert token_record
|
|
||||||
end
|
|
||||||
|
|
||||||
test "it sends an email to user", %{user: user} do
|
|
||||||
ObanHelpers.perform_all()
|
|
||||||
token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
|
|
||||||
|
|
||||||
email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token)
|
|
||||||
notify_email = Config.get([:instance, :notify_email])
|
|
||||||
instance_name = Config.get([:instance, :name])
|
|
||||||
|
|
||||||
assert_email_sent(
|
|
||||||
from: {instance_name, notify_email},
|
|
||||||
to: {user.name, user.email},
|
|
||||||
html_body: email.html_body
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "POST /auth/password, with invalid parameters" do
|
|
||||||
setup do
|
|
||||||
user = insert(:user)
|
|
||||||
{:ok, user: user}
|
|
||||||
end
|
|
||||||
|
|
||||||
test "it returns 404 when user is not found", %{conn: conn, user: user} do
|
|
||||||
conn = post(conn, "/auth/password?email=nonexisting_#{user.email}")
|
|
||||||
assert conn.status == 404
|
|
||||||
assert conn.resp_body == ""
|
|
||||||
end
|
|
||||||
|
|
||||||
test "it returns 400 when user is not local", %{conn: conn, user: user} do
|
|
||||||
{:ok, user} = Repo.update(Changeset.change(user, local: false))
|
|
||||||
conn = post(conn, "/auth/password?email=#{user.email}")
|
|
||||||
assert conn.status == 400
|
|
||||||
assert conn.resp_body == ""
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "DELETE /auth/sign_out" do
|
|
||||||
test "redirect to root page", %{conn: conn} do
|
|
||||||
user = insert(:user)
|
|
||||||
|
|
||||||
conn =
|
|
||||||
conn
|
|
||||||
|> assign(:user, user)
|
|
||||||
|> delete("/auth/sign_out")
|
|
||||||
|
|
||||||
assert conn.status == 302
|
|
||||||
assert redirected_to(conn) == "/"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "empty_array, stubs for mastodon api" do
|
describe "empty_array, stubs for mastodon api" do
|
||||||
|
Loading…
Reference in New Issue
Block a user