Merge branch 'develop' into gun

This commit is contained in:
Alexander Strizhakov 2020-02-29 11:34:50 +03:00
commit 814b275af7
No known key found for this signature in database
GPG key ID: 022896A53AEF1381
208 changed files with 1946 additions and 2688 deletions

View file

@ -1,17 +1,20 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.CaptchaTest do
use ExUnit.Case
use Pleroma.DataCase
import Tesla.Mock
alias Pleroma.Captcha
alias Pleroma.Captcha.Kocaptcha
alias Pleroma.Captcha.Native
@ets_options [:ordered_set, :private, :named_table, {:read_concurrency, true}]
clear_config([Pleroma.Captcha, :enabled])
describe "Kocaptcha" do
setup do
ets_name = Kocaptcha.Ets
@ -31,17 +34,18 @@ defmodule Pleroma.CaptchaTest do
test "new and validate" do
new = Kocaptcha.new()
assert new[:type] == :kocaptcha
assert new[:token] == "afa1815e14e29355e6c8f6b143a39fa2"
assert new[:url] ==
"https://captcha.kotobank.ch/captchas/afa1815e14e29355e6c8f6b143a39fa2.png"
token = "afa1815e14e29355e6c8f6b143a39fa2"
url = "https://captcha.kotobank.ch/captchas/afa1815e14e29355e6c8f6b143a39fa2.png"
assert Kocaptcha.validate(
new[:token],
"7oEy8c",
new[:answer_data]
) == :ok
assert %{
answer_data: answer,
token: ^token,
url: ^url,
type: :kocaptcha
} = new
assert Kocaptcha.validate(token, "7oEy8c", answer) == :ok
end
end
@ -61,4 +65,52 @@ defmodule Pleroma.CaptchaTest do
assert {:error, "Invalid CAPTCHA"} == Native.validate(token, answer, answer <> "foobar")
end
end
describe "Captcha Wrapper" do
test "validate" do
Pleroma.Config.put([Pleroma.Captcha, :enabled], true)
new = Captcha.new()
assert %{
answer_data: answer,
token: token
} = new
assert is_binary(answer)
assert :ok = Captcha.validate(token, "63615261b77f5354fb8c4e4986477555", answer)
end
test "doesn't validate invalid answer" do
Pleroma.Config.put([Pleroma.Captcha, :enabled], true)
new = Captcha.new()
assert %{
answer_data: answer,
token: token
} = new
assert is_binary(answer)
assert {:error, "Invalid answer data"} =
Captcha.validate(token, "63615261b77f5354fb8c4e4986477555", answer <> "foobar")
end
test "nil answer_data" do
Pleroma.Config.put([Pleroma.Captcha, :enabled], true)
new = Captcha.new()
assert %{
answer_data: answer,
token: token
} = new
assert is_binary(answer)
assert {:error, "Invalid answer data"} =
Captcha.validate(token, "63615261b77f5354fb8c4e4986477555", nil)
end
end
end

View file

@ -35,6 +35,19 @@
"inReplyTo": null,
"inReplyToAtomUri": null,
"published": "2018-02-12T14:08:20Z",
"replies": {
"id": "http://mastodon.example.org/users/admin/statuses/99512778738411822/replies",
"type": "Collection",
"first": {
"type": "CollectionPage",
"next": "http://mastodon.example.org/users/admin/statuses/99512778738411822/replies?min_id=99512778738411824&page=true",
"partOf": "http://mastodon.example.org/users/admin/statuses/99512778738411822/replies",
"items": [
"http://mastodon.example.org/users/admin/statuses/99512778738411823",
"http://mastodon.example.org/users/admin/statuses/99512778738411824"
]
}
},
"sensitive": true,
"summary": "cw",
"tag": [

View file

@ -26,6 +26,31 @@ defmodule Pleroma.Object.FetcherTest do
:ok
end
describe "max thread distance restriction" do
@ap_id "http://mastodon.example.org/@admin/99541947525187367"
clear_config([:instance, :federation_incoming_replies_max_depth])
test "it returns thread depth exceeded error if thread depth is exceeded" do
Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 0)
assert {:error, "Max thread distance exceeded."} =
Fetcher.fetch_object_from_id(@ap_id, depth: 1)
end
test "it fetches object if max thread depth is restricted to 0 and depth is not specified" do
Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 0)
assert {:ok, _} = Fetcher.fetch_object_from_id(@ap_id)
end
test "it fetches object if requested depth does not exceed max thread depth" do
Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 10)
assert {:ok, _} = Fetcher.fetch_object_from_id(@ap_id, depth: 10)
end
end
describe "actor origin containment" do
test "it rejects objects with a bogus origin" do
{:error, _} = Fetcher.fetch_object_from_id("https://info.pleroma.site/activity.json")

70
test/stat_test.exs Normal file
View file

@ -0,0 +1,70 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.StateTest do
use Pleroma.DataCase
import Pleroma.Factory
alias Pleroma.Web.CommonAPI
describe "status visibility count" do
test "on new status" do
user = insert(:user)
other_user = insert(:user)
CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"})
Enum.each(0..1, fn _ ->
CommonAPI.post(user, %{
"visibility" => "unlisted",
"status" => "hey"
})
end)
Enum.each(0..2, fn _ ->
CommonAPI.post(user, %{
"visibility" => "direct",
"status" => "hey @#{other_user.nickname}"
})
end)
Enum.each(0..3, fn _ ->
CommonAPI.post(user, %{
"visibility" => "private",
"status" => "hey"
})
end)
assert %{direct: 3, private: 4, public: 1, unlisted: 2} =
Pleroma.Stats.get_status_visibility_count()
end
test "on status delete" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"})
assert %{public: 1} = Pleroma.Stats.get_status_visibility_count()
CommonAPI.delete(activity.id, user)
assert %{public: 0} = Pleroma.Stats.get_status_visibility_count()
end
test "on status visibility update" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"})
assert %{public: 1, private: 0} = Pleroma.Stats.get_status_visibility_count()
{:ok, _} = CommonAPI.update_activity_scope(activity.id, %{"visibility" => "private"})
assert %{public: 0, private: 1} = Pleroma.Stats.get_status_visibility_count()
end
test "doesn't count unrelated activities" do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"})
_ = CommonAPI.follow(user, other_user)
CommonAPI.favorite(activity.id, other_user)
CommonAPI.repeat(activity.id, other_user)
assert %{direct: 0, private: 0, public: 1, unlisted: 0} =
Pleroma.Stats.get_status_visibility_count()
end
end
end

View file

@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Captcha.Mock do
@ -7,8 +7,17 @@ defmodule Pleroma.Captcha.Mock do
@behaviour Service
@impl Service
def new, do: %{type: :mock}
def new,
do: %{
type: :mock,
token: "afa1815e14e29355e6c8f6b143a39fa2",
answer_data: "63615261b77f5354fb8c4e4986477555",
url: "https://example.org/captcha.png"
}
@impl Service
def validate(_token, _captcha, _data), do: :ok
def validate(_token, captcha, captcha) when not is_nil(captcha), do: :ok
def validate(_token, captcha, answer),
do: {:error, "Invalid CAPTCHA captcha: #{inspect(captcha)} ; answer: #{inspect(answer)}"}
end

View file

@ -9,6 +9,10 @@ defmodule Pleroma.Tests.ObanHelpers do
alias Pleroma.Repo
def wipe_all do
Repo.delete_all(Oban.Job)
end
def perform_all do
Oban.Job
|> Repo.all()

View file

@ -3,7 +3,7 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.InstanceTest do
use ExUnit.Case, async: true
use ExUnit.Case
setup do
File.mkdir_p!(tmp_path())
@ -15,6 +15,8 @@ defmodule Pleroma.InstanceTest do
if File.exists?(static_dir) do
File.rm_rf(Path.join(static_dir, "robots.txt"))
end
Pleroma.Config.put([:instance, :static_dir], static_dir)
end)
:ok

View file

@ -0,0 +1,43 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.Tasks.Pleroma.RefreshCounterCacheTest do
use Pleroma.DataCase
alias Pleroma.Web.CommonAPI
import ExUnit.CaptureIO, only: [capture_io: 1]
import Pleroma.Factory
test "counts statuses" do
user = insert(:user)
other_user = insert(:user)
CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"})
Enum.each(0..1, fn _ ->
CommonAPI.post(user, %{
"visibility" => "unlisted",
"status" => "hey"
})
end)
Enum.each(0..2, fn _ ->
CommonAPI.post(user, %{
"visibility" => "direct",
"status" => "hey @#{other_user.nickname}"
})
end)
Enum.each(0..3, fn _ ->
CommonAPI.post(user, %{
"visibility" => "private",
"status" => "hey"
})
end)
assert capture_io(fn -> Mix.Tasks.Pleroma.RefreshCounterCache.run([]) end) =~ "Done\n"
assert %{direct: 3, private: 4, public: 1, unlisted: 2} =
Pleroma.Stats.get_status_visibility_count()
end
end

View file

@ -3,7 +3,9 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
use Oban.Testing, repo: Pleroma.Repo
use Pleroma.DataCase
alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.Object.Fetcher
@ -40,7 +42,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
end
@tag capture_log: true
test "it fetches replied-to activities if we don't have them" do
test "it fetches reply-to activities if we don't have them" do
data =
File.read!("test/fixtures/mastodon-post-activity.json")
|> Poison.decode!()
@ -61,7 +63,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
assert returned_object.data["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873"
end
test "it does not fetch replied-to activities beyond max_replies_depth" do
test "it does not fetch reply-to activities beyond max replies depth limit" do
data =
File.read!("test/fixtures/mastodon-post-activity.json")
|> Poison.decode!()
@ -73,7 +75,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
data = Map.put(data, "object", object)
with_mock Pleroma.Web.Federator,
allowed_incoming_reply_depth?: fn _ -> false end do
allowed_thread_distance?: fn _ -> false end do
{:ok, returned_activity} = Transmogrifier.handle_incoming(data)
returned_object = Object.normalize(returned_activity, false)
@ -1348,6 +1350,101 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
end
end
describe "`handle_incoming/2`, Mastodon format `replies` handling" do
clear_config([:activitypub, :note_replies_output_limit]) do
Pleroma.Config.put([:activitypub, :note_replies_output_limit], 5)
end
clear_config([:instance, :federation_incoming_replies_max_depth])
setup do
data =
"test/fixtures/mastodon-post-activity.json"
|> File.read!()
|> Poison.decode!()
items = get_in(data, ["object", "replies", "first", "items"])
assert length(items) > 0
%{data: data, items: items}
end
test "schedules background fetching of `replies` items if max thread depth limit allows", %{
data: data,
items: items
} do
Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 10)
{:ok, _activity} = Transmogrifier.handle_incoming(data)
for id <- items do
job_args = %{"op" => "fetch_remote", "id" => id, "depth" => 1}
assert_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker, args: job_args)
end
end
test "does NOT schedule background fetching of `replies` beyond max thread depth limit allows",
%{data: data} do
Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 0)
{:ok, _activity} = Transmogrifier.handle_incoming(data)
assert all_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker) == []
end
end
describe "`handle_incoming/2`, Pleroma format `replies` handling" do
clear_config([:activitypub, :note_replies_output_limit]) do
Pleroma.Config.put([:activitypub, :note_replies_output_limit], 5)
end
clear_config([:instance, :federation_incoming_replies_max_depth])
setup do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "post1"})
{:ok, reply1} =
CommonAPI.post(user, %{"status" => "reply1", "in_reply_to_status_id" => activity.id})
{:ok, reply2} =
CommonAPI.post(user, %{"status" => "reply2", "in_reply_to_status_id" => activity.id})
replies_uris = Enum.map([reply1, reply2], fn a -> a.object.data["id"] end)
{:ok, federation_output} = Transmogrifier.prepare_outgoing(activity.data)
Repo.delete(activity.object)
Repo.delete(activity)
%{federation_output: federation_output, replies_uris: replies_uris}
end
test "schedules background fetching of `replies` items if max thread depth limit allows", %{
federation_output: federation_output,
replies_uris: replies_uris
} do
Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 1)
{:ok, _activity} = Transmogrifier.handle_incoming(federation_output)
for id <- replies_uris do
job_args = %{"op" => "fetch_remote", "id" => id, "depth" => 1}
assert_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker, args: job_args)
end
end
test "does NOT schedule background fetching of `replies` beyond max thread depth limit allows",
%{federation_output: federation_output} do
Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 0)
{:ok, _activity} = Transmogrifier.handle_incoming(federation_output)
assert all_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker) == []
end
end
describe "prepare outgoing" do
test "it inlines private announced objects" do
user = insert(:user)
@ -2046,4 +2143,49 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
}
end
end
describe "set_replies/1" do
clear_config([:activitypub, :note_replies_output_limit]) do
Pleroma.Config.put([:activitypub, :note_replies_output_limit], 2)
end
test "returns unmodified object if activity doesn't have self-replies" do
data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json"))
assert Transmogrifier.set_replies(data) == data
end
test "sets `replies` collection with a limited number of self-replies" do
[user, another_user] = insert_list(2, :user)
{:ok, %{id: id1} = activity} = CommonAPI.post(user, %{"status" => "1"})
{:ok, %{id: id2} = self_reply1} =
CommonAPI.post(user, %{"status" => "self-reply 1", "in_reply_to_status_id" => id1})
{:ok, self_reply2} =
CommonAPI.post(user, %{"status" => "self-reply 2", "in_reply_to_status_id" => id1})
# Assuming to _not_ be present in `replies` due to :note_replies_output_limit is set to 2
{:ok, _} =
CommonAPI.post(user, %{"status" => "self-reply 3", "in_reply_to_status_id" => id1})
{:ok, _} =
CommonAPI.post(user, %{
"status" => "self-reply to self-reply",
"in_reply_to_status_id" => id2
})
{:ok, _} =
CommonAPI.post(another_user, %{
"status" => "another user's reply",
"in_reply_to_status_id" => id1
})
object = Object.normalize(activity)
replies_uris = Enum.map([self_reply1, self_reply2], fn a -> a.object.data["id"] end)
assert %{"type" => "Collection", "items" => ^replies_uris} =
Transmogrifier.set_replies(object.data)["replies"]
end
end
end

View file

@ -36,6 +36,26 @@ defmodule Pleroma.Web.ActivityPub.ObjectViewTest do
assert result["@context"]
end
describe "note activity's `replies` collection rendering" do
clear_config([:activitypub, :note_replies_output_limit]) do
Pleroma.Config.put([:activitypub, :note_replies_output_limit], 5)
end
test "renders `replies` collection for a note activity" do
user = insert(:user)
activity = insert(:note_activity, user: user)
{:ok, self_reply1} =
CommonAPI.post(user, %{"status" => "self-reply 1", "in_reply_to_status_id" => activity.id})
replies_uris = [self_reply1.object.data["id"]]
result = ObjectView.render("object.json", %{object: refresh_record(activity)})
assert %{"type" => "Collection", "items" => ^replies_uris} =
get_in(result, ["object", "replies"])
end
end
test "renders a like activity" do
note = insert(:note_activity)
object = Object.normalize(note)

View file

@ -3064,6 +3064,52 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
end
end
describe "GET /api/pleroma/admin/statuses" do
test "returns all public, unlisted, and direct statuses", %{conn: conn, admin: admin} do
blocked = insert(:user)
user = insert(:user)
User.block(admin, blocked)
{:ok, _} =
CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"})
{:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "unlisted"})
{:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
{:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
{:ok, _} = CommonAPI.post(blocked, %{"status" => ".", "visibility" => "public"})
response =
conn
|> get("/api/pleroma/admin/statuses")
|> json_response(200)
refute "private" in Enum.map(response, & &1["visibility"])
assert length(response) == 4
end
test "returns only local statuses with local_only on", %{conn: conn} do
user = insert(:user)
remote_user = insert(:user, local: false, nickname: "archaeme@archae.me")
insert(:note_activity, user: user, local: true)
insert(:note_activity, user: remote_user, local: false)
response =
conn
|> get("/api/pleroma/admin/statuses?local_only=true")
|> json_response(200)
assert length(response) == 1
end
test "returns private statuses with godmode on", %{conn: conn} do
user = insert(:user)
{:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
{:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
conn = get(conn, "/api/pleroma/admin/statuses?godmode=true")
assert json_response(conn, 200) |> length() == 2
end
end
describe "GET /api/pleroma/admin/users/:nickname/statuses" do
setup do
user = insert(:user)
@ -3114,6 +3160,20 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
assert json_response(conn, 200) |> length() == 5
end
test "excludes reblogs by default", %{conn: conn, user: user} do
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "."})
{:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, other_user)
conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
assert json_response(conn_res, 200) |> length() == 0
conn_res =
get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")
assert json_response(conn_res, 200) |> length() == 1
end
end
describe "GET /api/pleroma/admin/moderation_log" do
@ -3396,7 +3456,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
user = insert(:user, local: false, nickname: "archaeme@archae.me")
user2 = insert(:user, local: false, nickname: "test@test.com")
insert_pair(:note_activity, user: user)
insert(:note_activity, user: user2)
activity = insert(:note_activity, user: user2)
ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
@ -3415,6 +3475,16 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
response = json_response(ret_conn, 200)
assert Enum.empty?(response)
CommonAPI.repeat(activity.id, user)
ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
response = json_response(ret_conn, 200)
assert length(response) == 2
ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
response = json_response(ret_conn, 200)
assert length(response) == 3
end
end
@ -3544,6 +3614,25 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
assert String.starts_with?(child["group"], ":")
assert child["description"]
end
describe "/api/pleroma/admin/stats" do
test "status visibility count", %{conn: conn} do
admin = insert(:user, is_admin: true)
user = insert(:user)
CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"})
CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"})
CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"})
response =
conn
|> assign(:user, admin)
|> get("/api/pleroma/admin/stats")
|> json_response(200)
assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
response["status_visibility"]
end
end
end
# Needed for testing

View file

@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Push.ImplTest do
@ -98,6 +98,14 @@ defmodule Pleroma.Web.Push.ImplTest do
refute Pleroma.Repo.get(Subscription, subscription.id)
end
test "deletes subscription when token has been deleted" do
subscription = insert(:push_subscription)
Pleroma.Repo.delete(subscription.token)
refute Pleroma.Repo.get(Subscription, subscription.id)
end
test "renders title and body for create activity" do
user = insert(:user, nickname: "Bob")