Merge branch 'authenticated-api-oauth-check-enforcement' into 'develop'
Enforcement of OAuth scopes check for authenticated API endpoints See merge request pleroma/pleroma!2349
This commit is contained in:
parent
1ebf8db2a5
commit
da4923f2e5
|
@ -0,0 +1,17 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Plugs.AuthExpectedPlug do
|
||||||
|
import Plug.Conn
|
||||||
|
|
||||||
|
def init(options), do: options
|
||||||
|
|
||||||
|
def call(conn, _) do
|
||||||
|
put_private(conn, :auth_expected, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
def auth_expected?(conn) do
|
||||||
|
conn.private[:auth_expected]
|
||||||
|
end
|
||||||
|
end
|
|
@ -8,12 +8,15 @@ defmodule Pleroma.Plugs.OAuthScopesPlug do
|
||||||
|
|
||||||
alias Pleroma.Config
|
alias Pleroma.Config
|
||||||
alias Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug
|
alias Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug
|
||||||
|
alias Pleroma.Plugs.PlugHelper
|
||||||
|
|
||||||
|
use Pleroma.Web, :plug
|
||||||
|
|
||||||
@behaviour Plug
|
@behaviour Plug
|
||||||
|
|
||||||
def init(%{scopes: _} = options), do: options
|
def init(%{scopes: _} = options), do: options
|
||||||
|
|
||||||
def call(%Plug.Conn{assigns: assigns} = conn, %{scopes: scopes} = options) do
|
def perform(%Plug.Conn{assigns: assigns} = conn, %{scopes: scopes} = options) do
|
||||||
op = options[:op] || :|
|
op = options[:op] || :|
|
||||||
token = assigns[:token]
|
token = assigns[:token]
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Plugs.PlugHelper do
|
||||||
|
@moduledoc "Pleroma Plug helper"
|
||||||
|
|
||||||
|
def append_to_called_plugs(conn, plug_module) do
|
||||||
|
append_to_private_list(conn, :called_plugs, plug_module)
|
||||||
|
end
|
||||||
|
|
||||||
|
def append_to_skipped_plugs(conn, plug_module) do
|
||||||
|
append_to_private_list(conn, :skipped_plugs, plug_module)
|
||||||
|
end
|
||||||
|
|
||||||
|
def plug_called?(conn, plug_module) do
|
||||||
|
contained_in_private_list?(conn, :called_plugs, plug_module)
|
||||||
|
end
|
||||||
|
|
||||||
|
def plug_skipped?(conn, plug_module) do
|
||||||
|
contained_in_private_list?(conn, :skipped_plugs, plug_module)
|
||||||
|
end
|
||||||
|
|
||||||
|
def plug_called_or_skipped?(conn, plug_module) do
|
||||||
|
plug_called?(conn, plug_module) || plug_skipped?(conn, plug_module)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp append_to_private_list(conn, private_variable, value) do
|
||||||
|
list = conn.private[private_variable] || []
|
||||||
|
modified_list = Enum.uniq(list ++ [value])
|
||||||
|
Plug.Conn.put_private(conn, private_variable, modified_list)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp contained_in_private_list?(conn, private_variable, value) do
|
||||||
|
list = conn.private[private_variable] || []
|
||||||
|
value in list
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,31 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
# A test controller reachable only in :test env.
|
||||||
|
# Serves to test OAuth scopes check skipping / enforcement.
|
||||||
|
defmodule Pleroma.Tests.OAuthTestController do
|
||||||
|
@moduledoc false
|
||||||
|
|
||||||
|
use Pleroma.Web, :controller
|
||||||
|
|
||||||
|
alias Pleroma.Plugs.OAuthScopesPlug
|
||||||
|
|
||||||
|
plug(:skip_plug, OAuthScopesPlug when action == :skipped_oauth)
|
||||||
|
|
||||||
|
plug(OAuthScopesPlug, %{scopes: ["read"]} when action != :missed_oauth)
|
||||||
|
|
||||||
|
def skipped_oauth(conn, _params) do
|
||||||
|
noop(conn)
|
||||||
|
end
|
||||||
|
|
||||||
|
def performed_oauth(conn, _params) do
|
||||||
|
noop(conn)
|
||||||
|
end
|
||||||
|
|
||||||
|
def missed_oauth(conn, _params) do
|
||||||
|
noop(conn)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp noop(conn), do: json(conn, %{})
|
||||||
|
end
|
|
@ -17,7 +17,7 @@ defmodule Pleroma.Web.MastoFEController do
|
||||||
when action == :index
|
when action == :index
|
||||||
)
|
)
|
||||||
|
|
||||||
plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug when action != :index)
|
plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug when action not in [:index, :manifest])
|
||||||
|
|
||||||
@doc "GET /web/*path"
|
@doc "GET /web/*path"
|
||||||
def index(%{assigns: %{user: user, token: token}} = conn, _params)
|
def index(%{assigns: %{user: user, token: token}} = conn, _params)
|
||||||
|
|
|
@ -15,10 +15,13 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
alias Pleroma.Web.MastodonAPI.ListView
|
alias Pleroma.Web.MastodonAPI.ListView
|
||||||
alias Pleroma.Web.MastodonAPI.MastodonAPI
|
alias Pleroma.Web.MastodonAPI.MastodonAPI
|
||||||
|
alias Pleroma.Web.MastodonAPI.MastodonAPIController
|
||||||
alias Pleroma.Web.MastodonAPI.StatusView
|
alias Pleroma.Web.MastodonAPI.StatusView
|
||||||
alias Pleroma.Web.OAuth.Token
|
alias Pleroma.Web.OAuth.Token
|
||||||
alias Pleroma.Web.TwitterAPI.TwitterAPI
|
alias Pleroma.Web.TwitterAPI.TwitterAPI
|
||||||
|
|
||||||
|
plug(:skip_plug, OAuthScopesPlug when action == :identity_proofs)
|
||||||
|
|
||||||
plug(
|
plug(
|
||||||
OAuthScopesPlug,
|
OAuthScopesPlug,
|
||||||
%{fallback: :proceed_unauthenticated, scopes: ["read:accounts"]}
|
%{fallback: :proceed_unauthenticated, scopes: ["read:accounts"]}
|
||||||
|
@ -366,6 +369,8 @@ def blocks(%{assigns: %{user: user}} = conn, _) do
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc "GET /api/v1/endorsements"
|
@doc "GET /api/v1/endorsements"
|
||||||
def endorsements(conn, params),
|
def endorsements(conn, params), do: MastodonAPIController.empty_array(conn, params)
|
||||||
do: Pleroma.Web.MastodonAPI.MastodonAPIController.empty_array(conn, params)
|
|
||||||
|
@doc "GET /api/v1/identity_proofs"
|
||||||
|
def identity_proofs(conn, params), do: MastodonAPIController.empty_array(conn, params)
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,21 +3,31 @@
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
||||||
|
@moduledoc """
|
||||||
|
Contains stubs for unimplemented Mastodon API endpoints.
|
||||||
|
|
||||||
|
Note: instead of routing directly to this controller's action,
|
||||||
|
it's preferable to define an action in relevant (non-generic) controller,
|
||||||
|
set up OAuth rules for it and call this controller's function from it.
|
||||||
|
"""
|
||||||
|
|
||||||
use Pleroma.Web, :controller
|
use Pleroma.Web, :controller
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
|
plug(:skip_plug, Pleroma.Plugs.OAuthScopesPlug when action in [:empty_array, :empty_object])
|
||||||
|
|
||||||
|
plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)
|
||||||
|
|
||||||
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
|
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
|
||||||
|
|
||||||
# Stubs for unimplemented mastodon api
|
|
||||||
#
|
|
||||||
def empty_array(conn, _) do
|
def empty_array(conn, _) do
|
||||||
Logger.debug("Unimplemented, returning an empty array")
|
Logger.debug("Unimplemented, returning an empty array (list)")
|
||||||
json(conn, [])
|
json(conn, [])
|
||||||
end
|
end
|
||||||
|
|
||||||
def empty_object(conn, _) do
|
def empty_object(conn, _) do
|
||||||
Logger.debug("Unimplemented, returning an empty object")
|
Logger.debug("Unimplemented, returning an empty object (map)")
|
||||||
json(conn, %{})
|
json(conn, %{})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,10 +5,13 @@
|
||||||
defmodule Pleroma.Web.MastodonAPI.SuggestionController do
|
defmodule Pleroma.Web.MastodonAPI.SuggestionController do
|
||||||
use Pleroma.Web, :controller
|
use Pleroma.Web, :controller
|
||||||
|
|
||||||
|
alias Pleroma.Plugs.OAuthScopesPlug
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
|
plug(OAuthScopesPlug, %{scopes: ["read"]} when action == :index)
|
||||||
|
|
||||||
@doc "GET /api/v1/suggestions"
|
@doc "GET /api/v1/suggestions"
|
||||||
def index(conn, _) do
|
def index(conn, params),
|
||||||
json(conn, [])
|
do: Pleroma.Web.MastodonAPI.MastodonAPIController.empty_array(conn, params)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,6 +27,8 @@ defmodule Pleroma.Web.OAuth.OAuthController do
|
||||||
plug(:fetch_flash)
|
plug(:fetch_flash)
|
||||||
plug(RateLimiter, [name: :authentication] when action == :create_authorization)
|
plug(RateLimiter, [name: :authentication] when action == :create_authorization)
|
||||||
|
|
||||||
|
plug(:skip_plug, Pleroma.Plugs.OAuthScopesPlug)
|
||||||
|
|
||||||
action_fallback(Pleroma.Web.OAuth.FallbackController)
|
action_fallback(Pleroma.Web.OAuth.FallbackController)
|
||||||
|
|
||||||
@oob_token_redirect_uri "urn:ietf:wg:oauth:2.0:oob"
|
@oob_token_redirect_uri "urn:ietf:wg:oauth:2.0:oob"
|
||||||
|
|
|
@ -34,7 +34,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
|
||||||
|
|
||||||
plug(
|
plug(
|
||||||
OAuthScopesPlug,
|
OAuthScopesPlug,
|
||||||
%{scopes: ["write:conversations"]} when action == :update_conversation
|
%{scopes: ["write:conversations"]} when action in [:update_conversation, :read_conversations]
|
||||||
)
|
)
|
||||||
|
|
||||||
plug(OAuthScopesPlug, %{scopes: ["write:notifications"]} when action == :read_notification)
|
plug(OAuthScopesPlug, %{scopes: ["write:notifications"]} when action == :read_notification)
|
||||||
|
|
|
@ -34,6 +34,7 @@ defmodule Pleroma.Web.Router do
|
||||||
pipeline :authenticated_api do
|
pipeline :authenticated_api do
|
||||||
plug(:accepts, ["json"])
|
plug(:accepts, ["json"])
|
||||||
plug(:fetch_session)
|
plug(:fetch_session)
|
||||||
|
plug(Pleroma.Plugs.AuthExpectedPlug)
|
||||||
plug(Pleroma.Plugs.OAuthPlug)
|
plug(Pleroma.Plugs.OAuthPlug)
|
||||||
plug(Pleroma.Plugs.BasicAuthDecoderPlug)
|
plug(Pleroma.Plugs.BasicAuthDecoderPlug)
|
||||||
plug(Pleroma.Plugs.UserFetcherPlug)
|
plug(Pleroma.Plugs.UserFetcherPlug)
|
||||||
|
@ -334,7 +335,7 @@ defmodule Pleroma.Web.Router do
|
||||||
get("/accounts/relationships", AccountController, :relationships)
|
get("/accounts/relationships", AccountController, :relationships)
|
||||||
|
|
||||||
get("/accounts/:id/lists", AccountController, :lists)
|
get("/accounts/:id/lists", AccountController, :lists)
|
||||||
get("/accounts/:id/identity_proofs", MastodonAPIController, :empty_array)
|
get("/accounts/:id/identity_proofs", AccountController, :identity_proofs)
|
||||||
|
|
||||||
get("/follow_requests", FollowRequestController, :index)
|
get("/follow_requests", FollowRequestController, :index)
|
||||||
get("/blocks", AccountController, :blocks)
|
get("/blocks", AccountController, :blocks)
|
||||||
|
@ -657,6 +658,17 @@ defmodule Pleroma.Web.Router do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Test-only routes needed to test action dispatching and plug chain execution
|
||||||
|
if Pleroma.Config.get(:env) == :test do
|
||||||
|
scope "/test/authenticated_api", Pleroma.Tests do
|
||||||
|
pipe_through(:authenticated_api)
|
||||||
|
|
||||||
|
for action <- [:skipped_oauth, :performed_oauth, :missed_oauth] do
|
||||||
|
get("/#{action}", OAuthTestController, action)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
scope "/", Pleroma.Web.MongooseIM do
|
scope "/", Pleroma.Web.MongooseIM do
|
||||||
get("/user_exists", MongooseIMController, :user_exists)
|
get("/user_exists", MongooseIMController, :user_exists)
|
||||||
get("/check_password", MongooseIMController, :check_password)
|
get("/check_password", MongooseIMController, :check_password)
|
||||||
|
|
|
@ -15,6 +15,8 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
|
||||||
|
|
||||||
plug(OAuthScopesPlug, %{scopes: ["write:notifications"]} when action == :notifications_read)
|
plug(OAuthScopesPlug, %{scopes: ["write:notifications"]} when action == :notifications_read)
|
||||||
|
|
||||||
|
plug(:skip_plug, OAuthScopesPlug when action in [:oauth_tokens, :revoke_token])
|
||||||
|
|
||||||
plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)
|
plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)
|
||||||
|
|
||||||
action_fallback(:errors)
|
action_fallback(:errors)
|
||||||
|
|
|
@ -29,11 +29,40 @@ def controller do
|
||||||
import Pleroma.Web.Router.Helpers
|
import Pleroma.Web.Router.Helpers
|
||||||
import Pleroma.Web.TranslationHelpers
|
import Pleroma.Web.TranslationHelpers
|
||||||
|
|
||||||
|
alias Pleroma.Plugs.PlugHelper
|
||||||
|
|
||||||
plug(:set_put_layout)
|
plug(:set_put_layout)
|
||||||
|
|
||||||
defp set_put_layout(conn, _) do
|
defp set_put_layout(conn, _) do
|
||||||
put_layout(conn, Pleroma.Config.get(:app_layout, "app.html"))
|
put_layout(conn, Pleroma.Config.get(:app_layout, "app.html"))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Marks a plug intentionally skipped and blocks its execution if it's present in plugs chain
|
||||||
|
defp skip_plug(conn, plug_module) do
|
||||||
|
try do
|
||||||
|
plug_module.ensure_skippable()
|
||||||
|
rescue
|
||||||
|
UndefinedFunctionError ->
|
||||||
|
raise "#{plug_module} is not skippable. Append `use Pleroma.Web, :plug` to its code."
|
||||||
|
end
|
||||||
|
|
||||||
|
PlugHelper.append_to_skipped_plugs(conn, plug_module)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Here we can apply before-action hooks (e.g. verify whether auth checks were preformed)
|
||||||
|
defp action(conn, params) do
|
||||||
|
if Pleroma.Plugs.AuthExpectedPlug.auth_expected?(conn) &&
|
||||||
|
not PlugHelper.plug_called_or_skipped?(conn, Pleroma.Plugs.OAuthScopesPlug) do
|
||||||
|
conn
|
||||||
|
|> render_error(
|
||||||
|
:forbidden,
|
||||||
|
"Security violation: OAuth scopes check was neither handled nor explicitly skipped."
|
||||||
|
)
|
||||||
|
|> halt()
|
||||||
|
else
|
||||||
|
super(conn, params)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -96,6 +125,26 @@ def channel do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def plug do
|
||||||
|
quote do
|
||||||
|
alias Pleroma.Plugs.PlugHelper
|
||||||
|
|
||||||
|
def ensure_skippable, do: :noop
|
||||||
|
|
||||||
|
@impl Plug
|
||||||
|
@doc "If marked as skipped, returns `conn`, and calls `perform/2` otherwise."
|
||||||
|
def call(%Plug.Conn{} = conn, options) do
|
||||||
|
if PlugHelper.plug_skipped?(conn, __MODULE__) do
|
||||||
|
conn
|
||||||
|
else
|
||||||
|
conn
|
||||||
|
|> PlugHelper.append_to_called_plugs(__MODULE__)
|
||||||
|
|> perform(options)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
When used, dispatch to the appropriate controller/view/etc.
|
When used, dispatch to the appropriate controller/view/etc.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -7,6 +7,7 @@ defmodule Pleroma.Plugs.OAuthScopesPlugTest do
|
||||||
|
|
||||||
alias Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug
|
alias Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug
|
||||||
alias Pleroma.Plugs.OAuthScopesPlug
|
alias Pleroma.Plugs.OAuthScopesPlug
|
||||||
|
alias Pleroma.Plugs.PlugHelper
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
|
|
||||||
import Mock
|
import Mock
|
||||||
|
@ -16,6 +17,18 @@ defmodule Pleroma.Plugs.OAuthScopesPlugTest do
|
||||||
:ok
|
:ok
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "is not performed if marked as skipped", %{conn: conn} do
|
||||||
|
with_mock OAuthScopesPlug, [:passthrough], perform: &passthrough([&1, &2]) do
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> PlugHelper.append_to_skipped_plugs(OAuthScopesPlug)
|
||||||
|
|> OAuthScopesPlug.call(%{scopes: ["random_scope"]})
|
||||||
|
|
||||||
|
refute called(OAuthScopesPlug.perform(:_, :_))
|
||||||
|
refute conn.halted
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
test "if `token.scopes` fulfills specified 'any of' conditions, " <>
|
test "if `token.scopes` fulfills specified 'any of' conditions, " <>
|
||||||
"proceeds with no op",
|
"proceeds with no op",
|
||||||
%{conn: conn} do
|
%{conn: conn} do
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Tests.OAuthTestControllerTest do
|
||||||
|
use Pleroma.Web.ConnCase
|
||||||
|
|
||||||
|
import Pleroma.Factory
|
||||||
|
|
||||||
|
setup %{conn: conn} do
|
||||||
|
user = insert(:user)
|
||||||
|
conn = assign(conn, :user, user)
|
||||||
|
%{conn: conn, user: user}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "missed_oauth", %{conn: conn} do
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> get("/test/authenticated_api/missed_oauth")
|
||||||
|
|> json_response(403)
|
||||||
|
|
||||||
|
assert res ==
|
||||||
|
%{
|
||||||
|
"error" =>
|
||||||
|
"Security violation: OAuth scopes check was neither handled nor explicitly skipped."
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "skipped_oauth", %{conn: conn} do
|
||||||
|
conn
|
||||||
|
|> assign(:token, nil)
|
||||||
|
|> get("/test/authenticated_api/skipped_oauth")
|
||||||
|
|> json_response(200)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "performed_oauth", %{user: user} do
|
||||||
|
%{conn: good_token_conn} = oauth_access(["read"], user: user)
|
||||||
|
|
||||||
|
good_token_conn
|
||||||
|
|> get("/test/authenticated_api/performed_oauth")
|
||||||
|
|> json_response(200)
|
||||||
|
|
||||||
|
%{conn: bad_token_conn} = oauth_access(["follow"], user: user)
|
||||||
|
|
||||||
|
bad_token_conn
|
||||||
|
|> get("/test/authenticated_api/performed_oauth")
|
||||||
|
|> json_response(403)
|
||||||
|
end
|
||||||
|
end
|
|
@ -7,34 +7,8 @@ defmodule Pleroma.Web.MastodonAPI.SuggestionControllerTest do
|
||||||
|
|
||||||
alias Pleroma.Config
|
alias Pleroma.Config
|
||||||
|
|
||||||
import Pleroma.Factory
|
|
||||||
import Tesla.Mock
|
|
||||||
|
|
||||||
setup do: oauth_access(["read"])
|
setup do: oauth_access(["read"])
|
||||||
|
|
||||||
setup %{user: user} do
|
|
||||||
other_user = insert(:user)
|
|
||||||
host = Config.get([Pleroma.Web.Endpoint, :url, :host])
|
|
||||||
url500 = "http://test500?#{host}&#{user.nickname}"
|
|
||||||
url200 = "http://test200?#{host}&#{user.nickname}"
|
|
||||||
|
|
||||||
mock(fn
|
|
||||||
%{method: :get, url: ^url500} ->
|
|
||||||
%Tesla.Env{status: 500, body: "bad request"}
|
|
||||||
|
|
||||||
%{method: :get, url: ^url200} ->
|
|
||||||
%Tesla.Env{
|
|
||||||
status: 200,
|
|
||||||
body:
|
|
||||||
~s([{"acct":"yj455","avatar":"https://social.heldscal.la/avatar/201.jpeg","avatar_static":"https://social.heldscal.la/avatar/s/201.jpeg"}, {"acct":"#{
|
|
||||||
other_user.ap_id
|
|
||||||
}","avatar":"https://social.heldscal.la/avatar/202.jpeg","avatar_static":"https://social.heldscal.la/avatar/s/202.jpeg"}])
|
|
||||||
}
|
|
||||||
end)
|
|
||||||
|
|
||||||
[other_user: other_user]
|
|
||||||
end
|
|
||||||
|
|
||||||
test "returns empty result", %{conn: conn} do
|
test "returns empty result", %{conn: conn} do
|
||||||
res =
|
res =
|
||||||
conn
|
conn
|
||||||
|
|
|
@ -203,7 +203,7 @@ test "PATCH /api/v1/pleroma/conversations/:id" do
|
||||||
|
|
||||||
test "POST /api/v1/pleroma/conversations/read" do
|
test "POST /api/v1/pleroma/conversations/read" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
%{user: other_user, conn: conn} = oauth_access(["write:notifications"])
|
%{user: other_user, conn: conn} = oauth_access(["write:conversations"])
|
||||||
|
|
||||||
{:ok, _activity} =
|
{:ok, _activity} =
|
||||||
CommonAPI.post(user, %{"status" => "Hi @#{other_user.nickname}", "visibility" => "direct"})
|
CommonAPI.post(user, %{"status" => "Hi @#{other_user.nickname}", "visibility" => "direct"})
|
||||||
|
|
Loading…
Reference in New Issue