Merge remote-tracking branch 'origin/develop' into reactions
This commit is contained in:
commit
73b6512907
52 changed files with 800 additions and 309 deletions
|
|
@ -19,8 +19,8 @@ defmodule Pleroma.Emails.AdminEmailTest do
|
|||
AdminEmail.report(to_user, reporter, account, [%{name: "Test", id: "12"}], "Test comment")
|
||||
|
||||
status_url = Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, "12")
|
||||
reporter_url = Helpers.o_status_url(Pleroma.Web.Endpoint, :feed_redirect, reporter.nickname)
|
||||
account_url = Helpers.o_status_url(Pleroma.Web.Endpoint, :feed_redirect, account.nickname)
|
||||
reporter_url = Helpers.o_status_url(Pleroma.Web.Endpoint, :feed_redirect, reporter.id)
|
||||
account_url = Helpers.o_status_url(Pleroma.Web.Endpoint, :feed_redirect, account.id)
|
||||
|
||||
assert res.to == [{to_user.name, to_user.email}]
|
||||
assert res.from == {config[:name], config[:notify_email]}
|
||||
|
|
|
|||
|
|
@ -5,24 +5,48 @@
|
|||
defmodule Pleroma.Plugs.OAuthScopesPlugTest do
|
||||
use Pleroma.Web.ConnCase, async: true
|
||||
|
||||
alias Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug
|
||||
alias Pleroma.Plugs.OAuthScopesPlug
|
||||
alias Pleroma.Repo
|
||||
|
||||
import Mock
|
||||
import Pleroma.Factory
|
||||
|
||||
test "proceeds with no op if `assigns[:token]` is nil", %{conn: conn} do
|
||||
conn =
|
||||
conn
|
||||
|> assign(:user, insert(:user))
|
||||
|> OAuthScopesPlug.call(%{scopes: ["read"]})
|
||||
|
||||
refute conn.halted
|
||||
assert conn.assigns[:user]
|
||||
setup_with_mocks([{EnsurePublicOrAuthenticatedPlug, [], [call: fn conn, _ -> conn end]}]) do
|
||||
:ok
|
||||
end
|
||||
|
||||
test "proceeds with no op if `token.scopes` fulfill specified 'any of' conditions", %{
|
||||
conn: conn
|
||||
} do
|
||||
describe "when `assigns[:token]` is nil, " do
|
||||
test "with :skip_instance_privacy_check option, proceeds with no op", %{conn: conn} do
|
||||
conn =
|
||||
conn
|
||||
|> assign(:user, insert(:user))
|
||||
|> OAuthScopesPlug.call(%{scopes: ["read"], skip_instance_privacy_check: true})
|
||||
|
||||
refute conn.halted
|
||||
assert conn.assigns[:user]
|
||||
|
||||
refute called(EnsurePublicOrAuthenticatedPlug.call(conn, :_))
|
||||
end
|
||||
|
||||
test "without :skip_instance_privacy_check option, calls EnsurePublicOrAuthenticatedPlug", %{
|
||||
conn: conn
|
||||
} do
|
||||
conn =
|
||||
conn
|
||||
|> assign(:user, insert(:user))
|
||||
|> OAuthScopesPlug.call(%{scopes: ["read"]})
|
||||
|
||||
refute conn.halted
|
||||
assert conn.assigns[:user]
|
||||
|
||||
assert called(EnsurePublicOrAuthenticatedPlug.call(conn, :_))
|
||||
end
|
||||
end
|
||||
|
||||
test "if `token.scopes` fulfills specified 'any of' conditions, " <>
|
||||
"proceeds with no op",
|
||||
%{conn: conn} do
|
||||
token = insert(:oauth_token, scopes: ["read", "write"]) |> Repo.preload(:user)
|
||||
|
||||
conn =
|
||||
|
|
@ -35,9 +59,9 @@ defmodule Pleroma.Plugs.OAuthScopesPlugTest do
|
|||
assert conn.assigns[:user]
|
||||
end
|
||||
|
||||
test "proceeds with no op if `token.scopes` fulfill specified 'all of' conditions", %{
|
||||
conn: conn
|
||||
} do
|
||||
test "if `token.scopes` fulfills specified 'all of' conditions, " <>
|
||||
"proceeds with no op",
|
||||
%{conn: conn} do
|
||||
token = insert(:oauth_token, scopes: ["scope1", "scope2", "scope3"]) |> Repo.preload(:user)
|
||||
|
||||
conn =
|
||||
|
|
@ -50,73 +74,154 @@ defmodule Pleroma.Plugs.OAuthScopesPlugTest do
|
|||
assert conn.assigns[:user]
|
||||
end
|
||||
|
||||
test "proceeds with cleared `assigns[:user]` if `token.scopes` doesn't fulfill specified 'any of' conditions " <>
|
||||
"and `fallback: :proceed_unauthenticated` option is specified",
|
||||
%{conn: conn} do
|
||||
token = insert(:oauth_token, scopes: ["read", "write"]) |> Repo.preload(:user)
|
||||
describe "with `fallback: :proceed_unauthenticated` option, " do
|
||||
test "if `token.scopes` doesn't fulfill specified 'any of' conditions, " <>
|
||||
"clears `assigns[:user]` and calls EnsurePublicOrAuthenticatedPlug",
|
||||
%{conn: conn} do
|
||||
token = insert(:oauth_token, scopes: ["read", "write"]) |> Repo.preload(:user)
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> assign(:user, token.user)
|
||||
|> assign(:token, token)
|
||||
|> OAuthScopesPlug.call(%{scopes: ["follow"], fallback: :proceed_unauthenticated})
|
||||
conn =
|
||||
conn
|
||||
|> assign(:user, token.user)
|
||||
|> assign(:token, token)
|
||||
|> OAuthScopesPlug.call(%{scopes: ["follow"], fallback: :proceed_unauthenticated})
|
||||
|
||||
refute conn.halted
|
||||
refute conn.assigns[:user]
|
||||
refute conn.halted
|
||||
refute conn.assigns[:user]
|
||||
|
||||
assert called(EnsurePublicOrAuthenticatedPlug.call(conn, :_))
|
||||
end
|
||||
|
||||
test "if `token.scopes` doesn't fulfill specified 'all of' conditions, " <>
|
||||
"clears `assigns[:user] and calls EnsurePublicOrAuthenticatedPlug",
|
||||
%{conn: conn} do
|
||||
token = insert(:oauth_token, scopes: ["read", "write"]) |> Repo.preload(:user)
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> assign(:user, token.user)
|
||||
|> assign(:token, token)
|
||||
|> OAuthScopesPlug.call(%{
|
||||
scopes: ["read", "follow"],
|
||||
op: :&,
|
||||
fallback: :proceed_unauthenticated
|
||||
})
|
||||
|
||||
refute conn.halted
|
||||
refute conn.assigns[:user]
|
||||
|
||||
assert called(EnsurePublicOrAuthenticatedPlug.call(conn, :_))
|
||||
end
|
||||
|
||||
test "with :skip_instance_privacy_check option, " <>
|
||||
"if `token.scopes` doesn't fulfill specified conditions, " <>
|
||||
"clears `assigns[:user]` and does not call EnsurePublicOrAuthenticatedPlug",
|
||||
%{conn: conn} do
|
||||
token = insert(:oauth_token, scopes: ["read:statuses", "write"]) |> Repo.preload(:user)
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> assign(:user, token.user)
|
||||
|> assign(:token, token)
|
||||
|> OAuthScopesPlug.call(%{
|
||||
scopes: ["read"],
|
||||
fallback: :proceed_unauthenticated,
|
||||
skip_instance_privacy_check: true
|
||||
})
|
||||
|
||||
refute conn.halted
|
||||
refute conn.assigns[:user]
|
||||
|
||||
refute called(EnsurePublicOrAuthenticatedPlug.call(conn, :_))
|
||||
end
|
||||
end
|
||||
|
||||
test "proceeds with cleared `assigns[:user]` if `token.scopes` doesn't fulfill specified 'all of' conditions " <>
|
||||
"and `fallback: :proceed_unauthenticated` option is specified",
|
||||
%{conn: conn} do
|
||||
token = insert(:oauth_token, scopes: ["read", "write"]) |> Repo.preload(:user)
|
||||
describe "without :fallback option, " do
|
||||
test "if `token.scopes` does not fulfill specified 'any of' conditions, " <>
|
||||
"returns 403 and halts",
|
||||
%{conn: conn} do
|
||||
token = insert(:oauth_token, scopes: ["read", "write"])
|
||||
any_of_scopes = ["follow"]
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> assign(:user, token.user)
|
||||
|> assign(:token, token)
|
||||
|> OAuthScopesPlug.call(%{
|
||||
scopes: ["read", "follow"],
|
||||
op: :&,
|
||||
fallback: :proceed_unauthenticated
|
||||
})
|
||||
conn =
|
||||
conn
|
||||
|> assign(:token, token)
|
||||
|> OAuthScopesPlug.call(%{scopes: any_of_scopes})
|
||||
|
||||
refute conn.halted
|
||||
refute conn.assigns[:user]
|
||||
assert conn.halted
|
||||
assert 403 == conn.status
|
||||
|
||||
expected_error = "Insufficient permissions: #{Enum.join(any_of_scopes, ", ")}."
|
||||
assert Jason.encode!(%{error: expected_error}) == conn.resp_body
|
||||
end
|
||||
|
||||
test "if `token.scopes` does not fulfill specified 'all of' conditions, " <>
|
||||
"returns 403 and halts",
|
||||
%{conn: conn} do
|
||||
token = insert(:oauth_token, scopes: ["read", "write"])
|
||||
all_of_scopes = ["write", "follow"]
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> assign(:token, token)
|
||||
|> OAuthScopesPlug.call(%{scopes: all_of_scopes, op: :&})
|
||||
|
||||
assert conn.halted
|
||||
assert 403 == conn.status
|
||||
|
||||
expected_error =
|
||||
"Insufficient permissions: #{Enum.join(all_of_scopes -- token.scopes, ", ")}."
|
||||
|
||||
assert Jason.encode!(%{error: expected_error}) == conn.resp_body
|
||||
end
|
||||
end
|
||||
|
||||
test "returns 403 and halts in case of no :fallback option and `token.scopes` not fulfilling specified 'any of' conditions",
|
||||
%{conn: conn} do
|
||||
token = insert(:oauth_token, scopes: ["read", "write"])
|
||||
any_of_scopes = ["follow"]
|
||||
describe "with hierarchical scopes, " do
|
||||
test "if `token.scopes` fulfills specified 'any of' conditions, " <>
|
||||
"proceeds with no op",
|
||||
%{conn: conn} do
|
||||
token = insert(:oauth_token, scopes: ["read", "write"]) |> Repo.preload(:user)
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> assign(:token, token)
|
||||
|> OAuthScopesPlug.call(%{scopes: any_of_scopes})
|
||||
conn =
|
||||
conn
|
||||
|> assign(:user, token.user)
|
||||
|> assign(:token, token)
|
||||
|> OAuthScopesPlug.call(%{scopes: ["read:something"]})
|
||||
|
||||
assert conn.halted
|
||||
assert 403 == conn.status
|
||||
refute conn.halted
|
||||
assert conn.assigns[:user]
|
||||
end
|
||||
|
||||
expected_error = "Insufficient permissions: #{Enum.join(any_of_scopes, ", ")}."
|
||||
assert Jason.encode!(%{error: expected_error}) == conn.resp_body
|
||||
test "if `token.scopes` fulfills specified 'all of' conditions, " <>
|
||||
"proceeds with no op",
|
||||
%{conn: conn} do
|
||||
token = insert(:oauth_token, scopes: ["scope1", "scope2", "scope3"]) |> Repo.preload(:user)
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> assign(:user, token.user)
|
||||
|> assign(:token, token)
|
||||
|> OAuthScopesPlug.call(%{scopes: ["scope1:subscope", "scope2:subscope"], op: :&})
|
||||
|
||||
refute conn.halted
|
||||
assert conn.assigns[:user]
|
||||
end
|
||||
end
|
||||
|
||||
test "returns 403 and halts in case of no :fallback option and `token.scopes` not fulfilling specified 'all of' conditions",
|
||||
%{conn: conn} do
|
||||
token = insert(:oauth_token, scopes: ["read", "write"])
|
||||
all_of_scopes = ["write", "follow"]
|
||||
describe "filter_descendants/2" do
|
||||
test "filters scopes which directly match or are ancestors of supported scopes" do
|
||||
f = fn scopes, supported_scopes ->
|
||||
OAuthScopesPlug.filter_descendants(scopes, supported_scopes)
|
||||
end
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> assign(:token, token)
|
||||
|> OAuthScopesPlug.call(%{scopes: all_of_scopes, op: :&})
|
||||
assert f.(["read", "follow"], ["write", "read"]) == ["read"]
|
||||
|
||||
assert conn.halted
|
||||
assert 403 == conn.status
|
||||
assert f.(["read", "write:something", "follow"], ["write", "read"]) ==
|
||||
["read", "write:something"]
|
||||
|
||||
expected_error =
|
||||
"Insufficient permissions: #{Enum.join(all_of_scopes -- token.scopes, ", ")}."
|
||||
assert f.(["admin:read"], ["write", "read"]) == []
|
||||
|
||||
assert Jason.encode!(%{error: expected_error}) == conn.resp_body
|
||||
assert f.(["admin:read"], ["write", "admin"]) == ["admin:read"]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ defmodule Pleroma.SignatureTest do
|
|||
user =
|
||||
insert(:user, %{
|
||||
ap_id: "https://mastodon.social/users/lambadalambda",
|
||||
info: %{keys: @private_key}
|
||||
keys: @private_key
|
||||
})
|
||||
|
||||
assert Signature.sign(
|
||||
|
|
@ -94,8 +94,7 @@ defmodule Pleroma.SignatureTest do
|
|||
end
|
||||
|
||||
test "it returns error" do
|
||||
user =
|
||||
insert(:user, %{ap_id: "https://mastodon.social/users/lambadalambda", info: %{keys: ""}})
|
||||
user = insert(:user, %{ap_id: "https://mastodon.social/users/lambadalambda", keys: ""})
|
||||
|
||||
assert Signature.sign(
|
||||
user,
|
||||
|
|
|
|||
|
|
@ -324,6 +324,7 @@ defmodule Pleroma.Factory do
|
|||
|
||||
%Pleroma.Web.OAuth.Token{
|
||||
token: :crypto.strong_rand_bytes(32) |> Base.url_encode64(),
|
||||
scopes: ["read"],
|
||||
refresh_token: :crypto.strong_rand_bytes(32) |> Base.url_encode64(),
|
||||
user: build(:user),
|
||||
app_id: oauth_app.id,
|
||||
|
|
|
|||
|
|
@ -1457,15 +1457,15 @@ defmodule Pleroma.UserTest do
|
|||
describe "ensure_keys_present" do
|
||||
test "it creates keys for a user and stores them in info" do
|
||||
user = insert(:user)
|
||||
refute is_binary(user.info.keys)
|
||||
refute is_binary(user.keys)
|
||||
{:ok, user} = User.ensure_keys_present(user)
|
||||
assert is_binary(user.info.keys)
|
||||
assert is_binary(user.keys)
|
||||
end
|
||||
|
||||
test "it doesn't create keys if there already are some" do
|
||||
user = insert(:user, %{info: %{keys: "xxx"}})
|
||||
user = insert(:user, keys: "xxx")
|
||||
{:ok, user} = User.ensure_keys_present(user)
|
||||
assert user.info.keys == "xxx"
|
||||
assert user.keys == "xxx"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
|
||||
end
|
||||
|
||||
test "has a matching host" do
|
||||
test "activity has a matching host" do
|
||||
Config.put([:mrf_simple, :reject], ["remote.instance"])
|
||||
|
||||
remote_message = build_remote_message()
|
||||
|
|
@ -244,13 +244,21 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
assert SimplePolicy.filter(remote_message) == {:reject, nil}
|
||||
end
|
||||
|
||||
test "match with wildcard domain" do
|
||||
test "activity matches with wildcard domain" do
|
||||
Config.put([:mrf_simple, :reject], ["*.remote.instance"])
|
||||
|
||||
remote_message = build_remote_message()
|
||||
|
||||
assert SimplePolicy.filter(remote_message) == {:reject, nil}
|
||||
end
|
||||
|
||||
test "actor has a matching host" do
|
||||
Config.put([:mrf_simple, :reject], ["remote.instance"])
|
||||
|
||||
remote_user = build_remote_user()
|
||||
|
||||
assert SimplePolicy.filter(remote_user) == {:reject, nil}
|
||||
end
|
||||
end
|
||||
|
||||
describe "when :accept" do
|
||||
|
|
@ -264,7 +272,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
|
||||
end
|
||||
|
||||
test "is not empty but it doesn't have a matching host" do
|
||||
test "is not empty but activity doesn't have a matching host" do
|
||||
Config.put([:mrf_simple, :accept], ["non.matching.remote"])
|
||||
|
||||
local_message = build_local_message()
|
||||
|
|
@ -274,7 +282,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
assert SimplePolicy.filter(remote_message) == {:reject, nil}
|
||||
end
|
||||
|
||||
test "has a matching host" do
|
||||
test "activity has a matching host" do
|
||||
Config.put([:mrf_simple, :accept], ["remote.instance"])
|
||||
|
||||
local_message = build_local_message()
|
||||
|
|
@ -284,7 +292,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
|
||||
end
|
||||
|
||||
test "match with wildcard domain" do
|
||||
test "activity matches with wildcard domain" do
|
||||
Config.put([:mrf_simple, :accept], ["*.remote.instance"])
|
||||
|
||||
local_message = build_local_message()
|
||||
|
|
@ -293,6 +301,14 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|
|||
assert SimplePolicy.filter(local_message) == {:ok, local_message}
|
||||
assert SimplePolicy.filter(remote_message) == {:ok, remote_message}
|
||||
end
|
||||
|
||||
test "actor has a matching host" do
|
||||
Config.put([:mrf_simple, :accept], ["remote.instance"])
|
||||
|
||||
remote_user = build_remote_user()
|
||||
|
||||
assert SimplePolicy.filter(remote_user) == {:ok, remote_user}
|
||||
end
|
||||
end
|
||||
|
||||
describe "when :avatar_removal" do
|
||||
|
|
|
|||
|
|
@ -272,7 +272,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do
|
|||
assert user_response["pleroma"]["background_image"]
|
||||
end
|
||||
|
||||
test "requires 'write' permission", %{conn: conn} do
|
||||
test "requires 'write:accounts' permission", %{conn: conn} do
|
||||
token1 = insert(:oauth_token, scopes: ["read"])
|
||||
token2 = insert(:oauth_token, scopes: ["write", "follow"])
|
||||
|
||||
|
|
@ -283,7 +283,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do
|
|||
|> patch("/api/v1/accounts/update_credentials", %{})
|
||||
|
||||
if token == token1 do
|
||||
assert %{"error" => "Insufficient permissions: write."} == json_response(conn, 403)
|
||||
assert %{"error" => "Insufficient permissions: write:accounts."} ==
|
||||
json_response(conn, 403)
|
||||
else
|
||||
assert json_response(conn, 200)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -557,7 +557,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
|
|||
"password" => "test",
|
||||
"client_id" => app.client_id,
|
||||
"redirect_uri" => redirect_uri,
|
||||
"scope" => "read write",
|
||||
"scope" => "read:subscope write",
|
||||
"state" => "statepassed"
|
||||
}
|
||||
})
|
||||
|
|
@ -570,7 +570,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
|
|||
assert %{"state" => "statepassed", "code" => code} = query
|
||||
auth = Repo.get_by(Authorization, token: code)
|
||||
assert auth
|
||||
assert auth.scopes == ["read", "write"]
|
||||
assert auth.scopes == ["read:subscope", "write"]
|
||||
end
|
||||
|
||||
test "returns 401 for wrong credentials", %{conn: conn} do
|
||||
|
|
@ -627,7 +627,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
|
|||
assert result =~ "This action is outside the authorized scopes"
|
||||
end
|
||||
|
||||
test "returns 401 for scopes beyond app scopes", %{conn: conn} do
|
||||
test "returns 401 for scopes beyond app scopes hierarchy", %{conn: conn} do
|
||||
user = insert(:user)
|
||||
app = insert(:oauth_app, scopes: ["read", "write"])
|
||||
redirect_uri = OAuthController.default_redirect_uri(app)
|
||||
|
|
|
|||
|
|
@ -81,19 +81,21 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
|
|||
assert response == "job started"
|
||||
end
|
||||
|
||||
test "requires 'follow' permission", %{conn: conn} do
|
||||
test "requires 'follow' or 'write:follows' permissions", %{conn: conn} do
|
||||
token1 = insert(:oauth_token, scopes: ["read", "write"])
|
||||
token2 = insert(:oauth_token, scopes: ["follow"])
|
||||
token3 = insert(:oauth_token, scopes: ["something"])
|
||||
another_user = insert(:user)
|
||||
|
||||
for token <- [token1, token2] do
|
||||
for token <- [token1, token2, token3] do
|
||||
conn =
|
||||
conn
|
||||
|> put_req_header("authorization", "Bearer #{token.token}")
|
||||
|> post("/api/pleroma/follow_import", %{"list" => "#{another_user.ap_id}"})
|
||||
|
||||
if token == token1 do
|
||||
assert %{"error" => "Insufficient permissions: follow."} == json_response(conn, 403)
|
||||
if token == token3 do
|
||||
assert %{"error" => "Insufficient permissions: follow | write:follows."} ==
|
||||
json_response(conn, 403)
|
||||
else
|
||||
assert json_response(conn, 200)
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue