Browse Source

Merge branch 'split-masto-api/auth' into 'develop'

Extract auth actions from `MastodonAPIController` to `AuthController`

See merge request pleroma/pleroma!1759
object-id-column
kaniini 4 years ago
parent
commit
8557176808
5 changed files with 215 additions and 173 deletions
  1. +91
    -0
      lib/pleroma/web/mastodon_api/controllers/auth_controller.ex
  2. +0
    -79
      lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex
  3. +3
    -3
      lib/pleroma/web/router.ex
  4. +121
    -0
      test/web/mastodon_api/controllers/auth_controller_test.exs
  5. +0
    -91
      test/web/mastodon_api/mastodon_api_controller_test.exs

+ 91
- 0
lib/pleroma/web/mastodon_api/controllers/auth_controller.ex View 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

+ 0
- 79
lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex View File

@@ -10,7 +10,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
alias Pleroma.Bookmark
alias Pleroma.Config
alias Pleroma.Pagination
alias Pleroma.Plugs.RateLimiter
alias Pleroma.Stats
alias Pleroma.User
alias Pleroma.Web
@@ -19,18 +18,11 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
alias Pleroma.Web.MastodonAPI.AccountView
alias Pleroma.Web.MastodonAPI.MastodonView
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

plug(RateLimiter, :password_reset when action == :password_reset)

action_fallback(Pleroma.Web.MastodonAPI.FallbackController)

@local_mastodon_name "Mastodon-Local"
@mastodon_api_level "2.7.2"

def masto_instance(conn, _params) do
@@ -268,61 +260,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
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
#
def empty_array(conn, _) do
@@ -335,22 +272,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
json(conn, %{})
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?(false), do: false
defp present?(_), do: true


+ 3
- 3
lib/pleroma/web/router.ex View File

@@ -661,10 +661,10 @@ defmodule Pleroma.Web.Router do
scope "/", Pleroma.Web.MastodonAPI do
pipe_through(:mastodon_html)

get("/web/login", MastodonAPIController, :login)
delete("/auth/sign_out", MastodonAPIController, :logout)
get("/web/login", AuthController, :login)
delete("/auth/sign_out", AuthController, :logout)

post("/auth/password", MastodonAPIController, :password_reset)
post("/auth/password", AuthController, :password_reset)

scope [] do
pipe_through(:oauth_read)


+ 121
- 0
test/web/mastodon_api/controllers/auth_controller_test.exs View 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

+ 0
- 91
test/web/mastodon_api/mastodon_api_controller_test.exs View File

@@ -9,12 +9,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
alias Pleroma.Config
alias Pleroma.Notification
alias Pleroma.Repo
alias Pleroma.Tests.ObanHelpers
alias Pleroma.User
alias Pleroma.Web.CommonAPI

import Pleroma.Factory
import Swoosh.TestAssertions
import Tesla.Mock

setup do
@@ -307,95 +305,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do

assert return_to == 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(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

describe "empty_array, stubs for mastodon api" do


Loading…
Cancel
Save