Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into feature/undo-validator-reduced

This commit is contained in:
lain 2020-05-07 14:45:20 +02:00
commit f0c22df226
157 changed files with 5707 additions and 1650 deletions

View file

@ -141,17 +141,15 @@ defmodule Pleroma.FilterTest do
context: ["home"]
}
query_two = %Pleroma.Filter{
user_id: user.id,
filter_id: 1,
changes = %{
phrase: "who",
context: ["home", "timeline"]
}
{:ok, filter_one} = Pleroma.Filter.create(query_one)
{:ok, filter_two} = Pleroma.Filter.update(query_two)
{:ok, filter_two} = Pleroma.Filter.update(filter_one, changes)
assert filter_one != filter_two
assert filter_two.phrase == query_two.phrase
assert filter_two.context == query_two.context
assert filter_two.phrase == changes.phrase
assert filter_two.context == changes.context
end
end

View file

@ -12,17 +12,14 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.OAuth
@moduletag needs_streamer: true, capture_log: true
@path Pleroma.Web.Endpoint.url()
|> URI.parse()
|> Map.put(:scheme, "ws")
|> Map.put(:path, "/api/v1/streaming")
|> URI.to_string()
setup_all do
start_supervised(Pleroma.Web.Streamer.supervisor())
:ok
end
def start_socket(qs \\ nil, headers \\ []) do
path =
case qs do

View file

@ -0,0 +1,11 @@
defmodule Pleroma.MFA.BackupCodesTest do
use Pleroma.DataCase
alias Pleroma.MFA.BackupCodes
test "generate backup codes" do
codes = BackupCodes.generate(number_of_codes: 2, length: 4)
assert [<<_::bytes-size(4)>>, <<_::bytes-size(4)>>] = codes
end
end

17
test/mfa/totp_test.exs Normal file
View file

@ -0,0 +1,17 @@
defmodule Pleroma.MFA.TOTPTest do
use Pleroma.DataCase
alias Pleroma.MFA.TOTP
test "create provisioning_uri to generate qrcode" do
uri =
TOTP.provisioning_uri("test-secrcet", "test@example.com",
issuer: "Plerome-42",
digits: 8,
period: 60
)
assert uri ==
"otpauth://totp/test@example.com?digits=8&issuer=Plerome-42&period=60&secret=test-secrcet"
end
end

53
test/mfa_test.exs Normal file
View file

@ -0,0 +1,53 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.MFATest do
use Pleroma.DataCase
import Pleroma.Factory
alias Comeonin.Pbkdf2
alias Pleroma.MFA
describe "mfa_settings" do
test "returns settings user's" do
user =
insert(:user,
multi_factor_authentication_settings: %MFA.Settings{
enabled: true,
totp: %MFA.Settings.TOTP{secret: "xx", confirmed: true}
}
)
settings = MFA.mfa_settings(user)
assert match?(^settings, %{enabled: true, totp: true})
end
end
describe "generate backup codes" do
test "returns backup codes" do
user = insert(:user)
{:ok, [code1, code2]} = MFA.generate_backup_codes(user)
updated_user = refresh_record(user)
[hash1, hash2] = updated_user.multi_factor_authentication_settings.backup_codes
assert Pbkdf2.checkpw(code1, hash1)
assert Pbkdf2.checkpw(code2, hash2)
end
end
describe "invalidate_backup_code" do
test "invalid used code" do
user = insert(:user)
{:ok, _} = MFA.generate_backup_codes(user)
user = refresh_record(user)
assert length(user.multi_factor_authentication_settings.backup_codes) == 2
[hash_code | _] = user.multi_factor_authentication_settings.backup_codes
{:ok, user} = MFA.invalidate_backup_code(user, hash_code)
assert length(user.multi_factor_authentication_settings.backup_codes) == 1
end
end
end

View file

@ -162,14 +162,18 @@ defmodule Pleroma.NotificationTest do
@tag needs_streamer: true
test "it creates a notification for user and send to the 'user' and the 'user:notification' stream" do
user = insert(:user)
task = Task.async(fn -> assert_receive {:text, _}, 4_000 end)
task_user_notification = Task.async(fn -> assert_receive {:text, _}, 4_000 end)
Streamer.add_socket("user", %{transport_pid: task.pid, assigns: %{user: user}})
Streamer.add_socket(
"user:notification",
%{transport_pid: task_user_notification.pid, assigns: %{user: user}}
)
task =
Task.async(fn ->
Streamer.add_socket("user", user)
assert_receive {:render_with_user, _, _, _}, 4_000
end)
task_user_notification =
Task.async(fn ->
Streamer.add_socket("user:notification", user)
assert_receive {:render_with_user, _, _, _}, 4_000
end)
activity = insert(:note_activity)

View file

@ -24,11 +24,36 @@ defmodule Pleroma.Plugs.EnsureAuthenticatedPlugTest do
end
end
test "it halts if user is assigned and MFA enabled", %{conn: conn} do
conn =
conn
|> assign(:user, %User{multi_factor_authentication_settings: %{enabled: true}})
|> assign(:auth_credentials, %{password: "xd-42"})
|> EnsureAuthenticatedPlug.call(%{})
assert conn.status == 403
assert conn.halted == true
assert conn.resp_body ==
"{\"error\":\"Two-factor authentication enabled, you must use a access token.\"}"
end
test "it continues if user is assigned and MFA disabled", %{conn: conn} do
conn =
conn
|> assign(:user, %User{multi_factor_authentication_settings: %{enabled: false}})
|> assign(:auth_credentials, %{password: "xd-42"})
|> EnsureAuthenticatedPlug.call(%{})
refute conn.status == 403
refute conn.halted
end
describe "with :if_func / :unless_func options" do
setup do
%{
true_fn: fn -> true end,
false_fn: fn -> false end
true_fn: fn _conn -> true end,
false_fn: fn _conn -> false end
}
end

View file

@ -21,7 +21,15 @@ defmodule Pleroma.Builders.ActivityBuilder do
def insert(data \\ %{}, opts \\ %{}) do
activity = build(data, opts)
ActivityPub.insert(activity)
case ActivityPub.insert(activity) do
ok = {:ok, activity} ->
ActivityPub.notify_and_stream(activity)
ok
error ->
error
end
end
def insert_list(times, data \\ %{}, opts \\ %{}) do

View file

@ -11,6 +11,7 @@ defmodule Pleroma.Builders.UserBuilder do
bio: "A tester.",
ap_id: "some id",
last_digest_emailed_at: NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
multi_factor_authentication_settings: %Pleroma.MFA.Settings{},
notification_settings: %Pleroma.User.NotificationSetting{}
}

View file

@ -74,7 +74,7 @@ defmodule Pleroma.Web.ConnCase do
status = Plug.Conn.Status.code(status)
unless lookup[op_id].responses[status] do
err = "Response schema not found for #{conn.status} #{conn.method} #{conn.request_path}"
err = "Response schema not found for #{status} #{conn.method} #{conn.request_path}"
flunk(err)
end
@ -139,7 +139,11 @@ defmodule Pleroma.Web.ConnCase do
end
if tags[:needs_streamer] do
start_supervised(Pleroma.Web.Streamer.supervisor())
start_supervised(%{
id: Pleroma.Web.Streamer.registry(),
start:
{Registry, :start_link, [[keys: :duplicate, name: Pleroma.Web.Streamer.registry()]]}
})
end
{:ok, conn: Phoenix.ConnTest.build_conn()}

View file

@ -40,7 +40,11 @@ defmodule Pleroma.DataCase do
end
if tags[:needs_streamer] do
start_supervised(Pleroma.Web.Streamer.supervisor())
start_supervised(%{
id: Pleroma.Web.Streamer.registry(),
start:
{Registry, :start_link, [[keys: :duplicate, name: Pleroma.Web.Streamer.registry()]]}
})
end
:ok

View file

@ -33,7 +33,8 @@ defmodule Pleroma.Factory do
bio: sequence(:bio, &"Tester Number #{&1}"),
last_digest_emailed_at: NaiveDateTime.utc_now(),
last_refreshed_at: NaiveDateTime.utc_now(),
notification_settings: %Pleroma.User.NotificationSetting{}
notification_settings: %Pleroma.User.NotificationSetting{},
multi_factor_authentication_settings: %Pleroma.MFA.Settings{}
}
%{
@ -422,4 +423,13 @@ defmodule Pleroma.Factory do
last_read_id: "1"
}
end
def mfa_token_factory do
%Pleroma.MFA.Token{
token: :crypto.strong_rand_bytes(32) |> Base.url_encode64(padding: false),
authorization: build(:oauth_authorization),
valid_until: NaiveDateTime.add(NaiveDateTime.utc_now(), 60 * 10),
user: build(:user)
}
end
end

View file

@ -40,12 +40,18 @@ defmodule Pleroma.Tests.Helpers do
clear_config: 2
]
def to_datetime(naive_datetime) do
def to_datetime(%NaiveDateTime{} = naive_datetime) do
naive_datetime
|> DateTime.from_naive!("Etc/UTC")
|> DateTime.truncate(:second)
end
def to_datetime(datetime) when is_binary(datetime) do
datetime
|> NaiveDateTime.from_iso8601!()
|> to_datetime()
end
def collect_ids(collection) do
collection
|> Enum.map(& &1.id)

View file

@ -211,7 +211,7 @@ defmodule HttpRequestMock do
end
def get(
"https://squeet.me/xrd/?uri=lain@squeet.me",
"https://squeet.me/xrd/?uri=acct:lain@squeet.me",
_,
_,
[{"accept", "application/xrd+xml,application/jrd+json"}]
@ -870,7 +870,7 @@ defmodule HttpRequestMock do
end
def get(
"https://social.heldscal.la/.well-known/webfinger?resource=shp@social.heldscal.la",
"https://social.heldscal.la/.well-known/webfinger?resource=acct:shp@social.heldscal.la",
_,
_,
[{"accept", "application/xrd+xml,application/jrd+json"}]
@ -883,7 +883,7 @@ defmodule HttpRequestMock do
end
def get(
"https://social.heldscal.la/.well-known/webfinger?resource=invalid_content@social.heldscal.la",
"https://social.heldscal.la/.well-known/webfinger?resource=acct:invalid_content@social.heldscal.la",
_,
_,
[{"accept", "application/xrd+xml,application/jrd+json"}]
@ -900,7 +900,7 @@ defmodule HttpRequestMock do
end
def get(
"http://framatube.org/main/xrd?uri=framasoft@framatube.org",
"http://framatube.org/main/xrd?uri=acct:framasoft@framatube.org",
_,
_,
[{"accept", "application/xrd+xml,application/jrd+json"}]
@ -959,7 +959,7 @@ defmodule HttpRequestMock do
end
def get(
"https://gerzilla.de/xrd/?uri=kaniini@gerzilla.de",
"https://gerzilla.de/xrd/?uri=acct:kaniini@gerzilla.de",
_,
_,
[{"accept", "application/xrd+xml,application/jrd+json"}]
@ -1155,7 +1155,7 @@ defmodule HttpRequestMock do
end
def get(
"https://zetsubou.xn--q9jyb4c/.well-known/webfinger?resource=lain@zetsubou.xn--q9jyb4c",
"https://zetsubou.xn--q9jyb4c/.well-known/webfinger?resource=acct:lain@zetsubou.xn--q9jyb4c",
_,
_,
[{"accept", "application/xrd+xml,application/jrd+json"}]
@ -1168,7 +1168,7 @@ defmodule HttpRequestMock do
end
def get(
"https://zetsubou.xn--q9jyb4c/.well-known/webfinger?resource=https://zetsubou.xn--q9jyb4c/users/lain",
"https://zetsubou.xn--q9jyb4c/.well-known/webfinger?resource=acct:https://zetsubou.xn--q9jyb4c/users/lain",
_,
_,
[{"accept", "application/xrd+xml,application/jrd+json"}]

View file

@ -4,14 +4,17 @@
defmodule Mix.Tasks.Pleroma.UserTest do
alias Pleroma.Repo
alias Pleroma.Tests.ObanHelpers
alias Pleroma.User
alias Pleroma.Web.OAuth.Authorization
alias Pleroma.Web.OAuth.Token
use Pleroma.DataCase
use Oban.Testing, repo: Pleroma.Repo
import Pleroma.Factory
import ExUnit.CaptureIO
import Mock
import Pleroma.Factory
setup_all do
Mix.shell(Mix.Shell.Process)
@ -87,12 +90,17 @@ defmodule Mix.Tasks.Pleroma.UserTest do
test "user is deleted" do
user = insert(:user)
Mix.Tasks.Pleroma.User.run(["rm", user.nickname])
with_mock Pleroma.Web.Federator,
publish: fn _ -> nil end do
Mix.Tasks.Pleroma.User.run(["rm", user.nickname])
ObanHelpers.perform_all()
assert_received {:mix_shell, :info, [message]}
assert message =~ " deleted"
assert_received {:mix_shell, :info, [message]}
assert message =~ " deleted"
assert %{deactivated: true} = User.get_by_nickname(user.nickname)
assert %{deactivated: true} = User.get_by_nickname(user.nickname)
assert called(Pleroma.Web.Federator.publish(:_))
end
end
test "no user to delete" do

View file

@ -172,6 +172,7 @@ defmodule Pleroma.UserSearchTest do
|> Map.put(:search_rank, nil)
|> Map.put(:search_type, nil)
|> Map.put(:last_digest_emailed_at, nil)
|> Map.put(:multi_factor_authentication_settings, nil)
|> Map.put(:notification_settings, nil)
assert user == expected

View file

@ -15,7 +15,6 @@ defmodule Pleroma.UserTest do
use Pleroma.DataCase
use Oban.Testing, repo: Pleroma.Repo
import Mock
import Pleroma.Factory
import ExUnit.CaptureLog
@ -1131,7 +1130,7 @@ defmodule Pleroma.UserTest do
User.delete_user_activities(user)
# TODO: Remove favorites, repeats, delete activities.
# TODO: Test removal favorites, repeats, delete activities.
refute Activity.get_by_id(activity.id)
end
@ -1170,31 +1169,6 @@ defmodule Pleroma.UserTest do
refute Activity.get_by_id(like_two.id)
refute Activity.get_by_id(repeat.id)
end
test_with_mock "it sends out User Delete activity",
%{user: user},
Pleroma.Web.ActivityPub.Publisher,
[:passthrough],
[] do
Pleroma.Config.put([:instance, :federating], true)
{:ok, follower} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
{:ok, _} = User.follow(follower, user)
{:ok, job} = User.delete(user)
{:ok, _user} = ObanHelpers.perform(job)
assert ObanHelpers.member?(
%{
"op" => "publish_one",
"params" => %{
"inbox" => "http://mastodon.example.org/inbox",
"id" => "pleroma:fakeid"
}
},
all_enqueued(worker: Pleroma.Workers.PublisherWorker)
)
end
end
test "get_public_key_for_ap_id fetches a user that's not in the db" do

View file

@ -820,21 +820,29 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
activity: activity
} do
user = insert(:user)
conn = assign(conn, :user, user)
object = Map.put(activity["object"], "sensitive", true)
activity = Map.put(activity, "object", object)
result =
response =
conn
|> assign(:user, user)
|> put_req_header("content-type", "application/activity+json")
|> post("/users/#{user.nickname}/outbox", activity)
|> json_response(201)
assert Activity.get_by_ap_id(result["id"])
assert result["object"]
assert %Object{data: object} = Object.normalize(result["object"])
assert object["sensitive"] == activity["object"]["sensitive"]
assert object["content"] == activity["object"]["content"]
assert Activity.get_by_ap_id(response["id"])
assert response["object"]
assert %Object{data: response_object} = Object.normalize(response["object"])
assert response_object["sensitive"] == true
assert response_object["content"] == activity["object"]["content"]
representation =
conn
|> put_req_header("accept", "application/activity+json")
|> get(response["id"])
|> json_response(200)
assert representation["object"]["sensitive"] == true
end
test "it rejects an incoming activity with bogus type", %{conn: conn, activity: activity} do

View file

@ -1138,143 +1138,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
end
end
describe "deletion" do
setup do: clear_config([:instance, :rewrite_policy])
test "it reverts deletion on error" do
note = insert(:note_activity)
object = Object.normalize(note)
with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do
assert {:error, :reverted} = ActivityPub.delete(object)
end
assert Repo.aggregate(Activity, :count, :id) == 1
assert Repo.get(Object, object.id) == object
assert Activity.get_by_id(note.id) == note
end
test "it creates a delete activity and deletes the original object" do
note = insert(:note_activity)
object = Object.normalize(note)
{:ok, delete} = ActivityPub.delete(object)
assert delete.data["type"] == "Delete"
assert delete.data["actor"] == note.data["actor"]
assert delete.data["object"] == object.data["id"]
assert Activity.get_by_id(delete.id) != nil
assert Repo.get(Object, object.id).data["type"] == "Tombstone"
end
test "it doesn't fail when an activity was already deleted" do
{:ok, delete} = insert(:note_activity) |> Object.normalize() |> ActivityPub.delete()
assert {:ok, ^delete} = delete |> Object.normalize() |> ActivityPub.delete()
end
test "decrements user note count only for public activities" do
user = insert(:user, note_count: 10)
{:ok, a1} =
CommonAPI.post(User.get_cached_by_id(user.id), %{
"status" => "yeah",
"visibility" => "public"
})
{:ok, a2} =
CommonAPI.post(User.get_cached_by_id(user.id), %{
"status" => "yeah",
"visibility" => "unlisted"
})
{:ok, a3} =
CommonAPI.post(User.get_cached_by_id(user.id), %{
"status" => "yeah",
"visibility" => "private"
})
{:ok, a4} =
CommonAPI.post(User.get_cached_by_id(user.id), %{
"status" => "yeah",
"visibility" => "direct"
})
{:ok, _} = Object.normalize(a1) |> ActivityPub.delete()
{:ok, _} = Object.normalize(a2) |> ActivityPub.delete()
{:ok, _} = Object.normalize(a3) |> ActivityPub.delete()
{:ok, _} = Object.normalize(a4) |> ActivityPub.delete()
user = User.get_cached_by_id(user.id)
assert user.note_count == 10
end
test "it creates a delete activity and checks that it is also sent to users mentioned by the deleted object" do
user = insert(:user)
note = insert(:note_activity)
object = Object.normalize(note)
{:ok, object} =
object
|> Object.change(%{
data: %{
"actor" => object.data["actor"],
"id" => object.data["id"],
"to" => [user.ap_id],
"type" => "Note"
}
})
|> Object.update_and_set_cache()
{:ok, delete} = ActivityPub.delete(object)
assert user.ap_id in delete.data["to"]
end
test "decreases reply count" do
user = insert(:user)
user2 = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "1", "visibility" => "public"})
reply_data = %{"status" => "1", "in_reply_to_status_id" => activity.id}
ap_id = activity.data["id"]
{:ok, public_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "public"))
{:ok, unlisted_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "unlisted"))
{:ok, private_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "private"))
{:ok, direct_reply} = CommonAPI.post(user2, Map.put(reply_data, "visibility", "direct"))
_ = CommonAPI.delete(direct_reply.id, user2)
assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
assert object.data["repliesCount"] == 2
_ = CommonAPI.delete(private_reply.id, user2)
assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
assert object.data["repliesCount"] == 2
_ = CommonAPI.delete(public_reply.id, user2)
assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
assert object.data["repliesCount"] == 1
_ = CommonAPI.delete(unlisted_reply.id, user2)
assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
assert object.data["repliesCount"] == 0
end
test "it passes delete activity through MRF before deleting the object" do
Pleroma.Config.put([:instance, :rewrite_policy], Pleroma.Web.ActivityPub.MRF.DropPolicy)
note = insert(:note_activity)
object = Object.normalize(note)
{:error, {:reject, _}} = ActivityPub.delete(object)
assert Activity.get_by_id(note.id)
assert Repo.get(Object, object.id).data["type"] == object.data["type"]
end
end
describe "timeline post-processing" do
test "it filters broken threads" do
user1 = insert(:user)

View file

@ -1,6 +1,7 @@
defmodule Pleroma.Web.ActivityPub.ObjectValidatorTest do
use Pleroma.DataCase
alias Pleroma.Object
alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.ObjectValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
@ -49,6 +50,99 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidatorTest do
end
end
describe "deletes" do
setup do
user = insert(:user)
{:ok, post_activity} = CommonAPI.post(user, %{"status" => "cancel me daddy"})
{:ok, valid_post_delete, _} = Builder.delete(user, post_activity.data["object"])
{:ok, valid_user_delete, _} = Builder.delete(user, user.ap_id)
%{user: user, valid_post_delete: valid_post_delete, valid_user_delete: valid_user_delete}
end
test "it is valid for a post deletion", %{valid_post_delete: valid_post_delete} do
{:ok, valid_post_delete, _} = ObjectValidator.validate(valid_post_delete, [])
assert valid_post_delete["deleted_activity_id"]
end
test "it is invalid if the object isn't in a list of certain types", %{
valid_post_delete: valid_post_delete
} do
object = Object.get_by_ap_id(valid_post_delete["object"])
data =
object.data
|> Map.put("type", "Like")
{:ok, _object} =
object
|> Ecto.Changeset.change(%{data: data})
|> Object.update_and_set_cache()
{:error, cng} = ObjectValidator.validate(valid_post_delete, [])
assert {:object, {"object not in allowed types", []}} in cng.errors
end
test "it is valid for a user deletion", %{valid_user_delete: valid_user_delete} do
assert match?({:ok, _, _}, ObjectValidator.validate(valid_user_delete, []))
end
test "it's invalid if the id is missing", %{valid_post_delete: valid_post_delete} do
no_id =
valid_post_delete
|> Map.delete("id")
{:error, cng} = ObjectValidator.validate(no_id, [])
assert {:id, {"can't be blank", [validation: :required]}} in cng.errors
end
test "it's invalid if the object doesn't exist", %{valid_post_delete: valid_post_delete} do
missing_object =
valid_post_delete
|> Map.put("object", "http://does.not/exist")
{:error, cng} = ObjectValidator.validate(missing_object, [])
assert {:object, {"can't find object", []}} in cng.errors
assert length(cng.errors) == 1
end
test "it's invalid if the actor of the object and the actor of delete are from different domains",
%{valid_post_delete: valid_post_delete} do
valid_user = insert(:user)
valid_other_actor =
valid_post_delete
|> Map.put("actor", valid_user.ap_id)
assert match?({:ok, _, _}, ObjectValidator.validate(valid_other_actor, []))
invalid_other_actor =
valid_post_delete
|> Map.put("actor", "https://gensokyo.2hu/users/raymoo")
{:error, cng} = ObjectValidator.validate(invalid_other_actor, [])
assert {:actor, {"is not allowed to delete object", []}} in cng.errors
end
test "it's valid if the actor of the object is a local superuser",
%{valid_post_delete: valid_post_delete} do
user =
insert(:user, local: true, is_moderator: true, ap_id: "https://gensokyo.2hu/users/raymoo")
valid_other_actor =
valid_post_delete
|> Map.put("actor", user.ap_id)
{:ok, _, meta} = ObjectValidator.validate(valid_other_actor, [])
assert meta[:do_not_federate]
end
end
describe "likes" do
setup do
user = insert(:user)

View file

@ -0,0 +1,27 @@
defmodule Pleroma.Web.ObjectValidators.Types.RecipientsTest do
alias Pleroma.Web.ActivityPub.ObjectValidators.Types.Recipients
use Pleroma.DataCase
test "it asserts that all elements of the list are object ids" do
list = ["https://lain.com/users/lain", "invalid"]
assert :error == Recipients.cast(list)
end
test "it works with a list" do
list = ["https://lain.com/users/lain"]
assert {:ok, list} == Recipients.cast(list)
end
test "it works with a list with whole objects" do
list = ["https://lain.com/users/lain", %{"id" => "https://gensokyo.2hu/users/raymoo"}]
resulting_list = ["https://gensokyo.2hu/users/raymoo", "https://lain.com/users/lain"]
assert {:ok, resulting_list} == Recipients.cast(list)
end
test "it turns a single string into a list" do
recipient = "https://lain.com/users/lain"
assert {:ok, [recipient]} == Recipients.cast(recipient)
end
end

View file

@ -3,12 +3,14 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
use Oban.Testing, repo: Pleroma.Repo
use Pleroma.DataCase
alias Pleroma.Activity
alias Pleroma.Notification
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.Tests.ObanHelpers
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Builder
@ -16,6 +18,59 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
alias Pleroma.Web.CommonAPI
import Pleroma.Factory
import Mock
describe "delete objects" do
setup do
user = insert(:user)
other_user = insert(:user)
{:ok, op} = CommonAPI.post(other_user, %{"status" => "big oof"})
{:ok, post} = CommonAPI.post(user, %{"status" => "hey", "in_reply_to_id" => op})
object = Object.normalize(post)
{:ok, delete_data, _meta} = Builder.delete(user, object.data["id"])
{:ok, delete_user_data, _meta} = Builder.delete(user, user.ap_id)
{:ok, delete, _meta} = ActivityPub.persist(delete_data, local: true)
{:ok, delete_user, _meta} = ActivityPub.persist(delete_user_data, local: true)
%{user: user, delete: delete, post: post, object: object, delete_user: delete_user, op: op}
end
test "it handles object deletions", %{
delete: delete,
post: post,
object: object,
user: user,
op: op
} do
with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough],
stream_out: fn _ -> nil end,
stream_out_participations: fn _, _ -> nil end do
{:ok, delete, _} = SideEffects.handle(delete)
user = User.get_cached_by_ap_id(object.data["actor"])
assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(delete))
assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out_participations(object, user))
end
object = Object.get_by_id(object.id)
assert object.data["type"] == "Tombstone"
refute Activity.get_by_id(post.id)
user = User.get_by_id(user.id)
assert user.note_count == 0
object = Object.normalize(op.data["object"], false)
assert object.data["repliesCount"] == 0
end
test "it handles user deletions", %{delete_user: delete, user: user} do
{:ok, _delete, _} = SideEffects.handle(delete)
ObanHelpers.perform_all()
assert User.get_cached_by_ap_id(user.ap_id).deactivated
end
end
describe "Undo objects" do
setup do

View file

@ -0,0 +1,86 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.Transmogrifier.DeleteHandlingTest do
use Oban.Testing, repo: Pleroma.Repo
use Pleroma.DataCase
alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.Tests.ObanHelpers
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Transmogrifier
import Pleroma.Factory
setup_all do
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
:ok
end
test "it works for incoming deletes" do
activity = insert(:note_activity)
deleting_user = insert(:user)
data =
File.read!("test/fixtures/mastodon-delete.json")
|> Poison.decode!()
|> Map.put("actor", deleting_user.ap_id)
|> put_in(["object", "id"], activity.data["object"])
{:ok, %Activity{actor: actor, local: false, data: %{"id" => id}}} =
Transmogrifier.handle_incoming(data)
assert id == data["id"]
# We delete the Create activity because we base our timelines on it.
# This should be changed after we unify objects and activities
refute Activity.get_by_id(activity.id)
assert actor == deleting_user.ap_id
# Objects are replaced by a tombstone object.
object = Object.normalize(activity.data["object"])
assert object.data["type"] == "Tombstone"
end
test "it fails for incoming deletes with spoofed origin" do
activity = insert(:note_activity)
%{ap_id: ap_id} = insert(:user, ap_id: "https://gensokyo.2hu/users/raymoo")
data =
File.read!("test/fixtures/mastodon-delete.json")
|> Poison.decode!()
|> Map.put("actor", ap_id)
|> put_in(["object", "id"], activity.data["object"])
assert match?({:error, _}, Transmogrifier.handle_incoming(data))
end
@tag capture_log: true
test "it works for incoming user deletes" do
%{ap_id: ap_id} = insert(:user, ap_id: "http://mastodon.example.org/users/admin")
data =
File.read!("test/fixtures/mastodon-delete-user.json")
|> Poison.decode!()
{:ok, _} = Transmogrifier.handle_incoming(data)
ObanHelpers.perform_all()
assert User.get_cached_by_ap_id(ap_id).deactivated
end
test "it fails for incoming user deletes with spoofed origin" do
%{ap_id: ap_id} = insert(:user)
data =
File.read!("test/fixtures/mastodon-delete-user.json")
|> Poison.decode!()
|> Map.put("actor", ap_id)
assert match?({:error, _}, Transmogrifier.handle_incoming(data))
assert User.get_cached_by_ap_id(ap_id)
end
end

View file

@ -763,6 +763,60 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
assert User.get_cached_by_ap_id(ap_id)
end
test "it works for incoming unannounces with an existing notice" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "hey"})
announce_data =
File.read!("test/fixtures/mastodon-announce.json")
|> Poison.decode!()
|> Map.put("object", activity.data["object"])
{:ok, %Activity{data: announce_data, local: false}} =
Transmogrifier.handle_incoming(announce_data)
data =
File.read!("test/fixtures/mastodon-undo-announce.json")
|> Poison.decode!()
|> Map.put("object", announce_data)
|> Map.put("actor", announce_data["actor"])
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert data["type"] == "Undo"
assert object_data = data["object"]
assert object_data["type"] == "Announce"
assert object_data["object"] == activity.data["object"]
assert object_data["id"] ==
"http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
end
test "it works for incomming unfollows with an existing follow" do
user = insert(:user)
follow_data =
File.read!("test/fixtures/mastodon-follow-activity.json")
|> Poison.decode!()
|> Map.put("object", user.ap_id)
{:ok, %Activity{data: _, local: false}} = Transmogrifier.handle_incoming(follow_data)
data =
File.read!("test/fixtures/mastodon-unfollow-activity.json")
|> Poison.decode!()
|> Map.put("object", follow_data)
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
assert data["type"] == "Undo"
assert data["object"]["type"] == "Follow"
assert data["object"]["object"] == user.ap_id
assert data["actor"] == "http://mastodon.example.org/users/admin"
refute User.following?(User.get_cached_by_ap_id(data["actor"]), user)
end
test "it works for incoming follows to locked account" do
pending_follower = insert(:user, ap_id: "http://mastodon.example.org/users/admin")
user = insert(:user, locked: true)

View file

@ -6,19 +6,22 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
use Pleroma.Web.ConnCase
use Oban.Testing, repo: Pleroma.Repo
import Pleroma.Factory
import ExUnit.CaptureLog
import Mock
import Pleroma.Factory
alias Pleroma.Activity
alias Pleroma.Config
alias Pleroma.ConfigDB
alias Pleroma.HTML
alias Pleroma.MFA
alias Pleroma.ModerationLog
alias Pleroma.Repo
alias Pleroma.ReportNote
alias Pleroma.Tests.ObanHelpers
alias Pleroma.User
alias Pleroma.UserInviteToken
alias Pleroma.Web
alias Pleroma.Web.ActivityPub.Relay
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.MediaProxy
@ -146,17 +149,26 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
test "single user", %{admin: admin, conn: conn} do
user = insert(:user)
conn =
conn
|> put_req_header("accept", "application/json")
|> delete("/api/pleroma/admin/users?nickname=#{user.nickname}")
with_mock Pleroma.Web.Federator,
publish: fn _ -> nil end do
conn =
conn
|> put_req_header("accept", "application/json")
|> delete("/api/pleroma/admin/users?nickname=#{user.nickname}")
log_entry = Repo.one(ModerationLog)
ObanHelpers.perform_all()
assert ModerationLog.get_log_entry_message(log_entry) ==
"@#{admin.nickname} deleted users: @#{user.nickname}"
assert User.get_by_nickname(user.nickname).deactivated
assert json_response(conn, 200) == user.nickname
log_entry = Repo.one(ModerationLog)
assert ModerationLog.get_log_entry_message(log_entry) ==
"@#{admin.nickname} deleted users: @#{user.nickname}"
assert json_response(conn, 200) == [user.nickname]
assert called(Pleroma.Web.Federator.publish(:_))
end
end
test "multiple users", %{admin: admin, conn: conn} do
@ -737,6 +749,39 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
}
end
test "pagination works correctly with service users", %{conn: conn} do
service1 = insert(:user, ap_id: Web.base_url() <> "/relay")
service2 = insert(:user, ap_id: Web.base_url() <> "/internal/fetch")
insert_list(25, :user)
assert %{"count" => 26, "page_size" => 10, "users" => users1} =
conn
|> get("/api/pleroma/admin/users?page=1&filters=", %{page_size: "10"})
|> json_response(200)
assert Enum.count(users1) == 10
assert service1 not in [users1]
assert service2 not in [users1]
assert %{"count" => 26, "page_size" => 10, "users" => users2} =
conn
|> get("/api/pleroma/admin/users?page=2&filters=", %{page_size: "10"})
|> json_response(200)
assert Enum.count(users2) == 10
assert service1 not in [users2]
assert service2 not in [users2]
assert %{"count" => 26, "page_size" => 10, "users" => users3} =
conn
|> get("/api/pleroma/admin/users?page=3&filters=", %{page_size: "10"})
|> json_response(200)
assert Enum.count(users3) == 6
assert service1 not in [users3]
assert service2 not in [users3]
end
test "renders empty array for the second page", %{conn: conn} do
insert(:user)
@ -1234,6 +1279,38 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
"@#{admin.nickname} deactivated users: @#{user.nickname}"
end
describe "PUT disable_mfa" do
test "returns 200 and disable 2fa", %{conn: conn} do
user =
insert(:user,
multi_factor_authentication_settings: %MFA.Settings{
enabled: true,
totp: %MFA.Settings.TOTP{secret: "otp_secret", confirmed: true}
}
)
response =
conn
|> put("/api/pleroma/admin/users/disable_mfa", %{nickname: user.nickname})
|> json_response(200)
assert response == user.nickname
mfa_settings = refresh_record(user).multi_factor_authentication_settings
refute mfa_settings.enabled
refute mfa_settings.totp.confirmed
end
test "returns 404 if user not found", %{conn: conn} do
response =
conn
|> put("/api/pleroma/admin/users/disable_mfa", %{nickname: "nickname"})
|> json_response(404)
assert response == "Not found"
end
end
describe "POST /api/pleroma/admin/users/invite_token" do
test "without options", %{conn: conn} do
conn = post(conn, "/api/pleroma/admin/users/invite_token")
@ -1620,6 +1697,25 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
end
end
describe "GET /api/pleroma/admin/statuses/:id" do
test "not found", %{conn: conn} do
assert conn
|> get("/api/pleroma/admin/statuses/not_found")
|> json_response(:not_found)
end
test "shows activity", %{conn: conn} do
activity = insert(:note_activity)
response =
conn
|> get("/api/pleroma/admin/statuses/#{activity.id}")
|> json_response(200)
assert response["id"] == activity.id
end
end
describe "PUT /api/pleroma/admin/statuses/:id" do
setup do
activity = insert(:note_activity)
@ -3526,7 +3622,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
end
test "success", %{conn: conn} do
base_url = Pleroma.Web.base_url()
base_url = Web.base_url()
app_name = "Trusted app"
response =
@ -3547,7 +3643,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
end
test "with trusted", %{conn: conn} do
base_url = Pleroma.Web.base_url()
base_url = Web.base_url()
app_name = "Trusted app"
response =

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 Pleroma.Web.Auth.PleromaAuthenticatorTest do
use Pleroma.Web.ConnCase
alias Pleroma.Web.Auth.PleromaAuthenticator
import Pleroma.Factory
setup do
password = "testpassword"
name = "AgentSmith"
user = insert(:user, nickname: name, password_hash: Comeonin.Pbkdf2.hashpwsalt(password))
{:ok, [user: user, name: name, password: password]}
end
test "get_user/authorization", %{user: user, name: name, password: password} do
params = %{"authorization" => %{"name" => name, "password" => password}}
res = PleromaAuthenticator.get_user(%Plug.Conn{params: params})
assert {:ok, user} == res
end
test "get_user/authorization with invalid password", %{name: name} do
params = %{"authorization" => %{"name" => name, "password" => "password"}}
res = PleromaAuthenticator.get_user(%Plug.Conn{params: params})
assert {:error, {:checkpw, false}} == res
end
test "get_user/grant_type_password", %{user: user, name: name, password: password} do
params = %{"grant_type" => "password", "username" => name, "password" => password}
res = PleromaAuthenticator.get_user(%Plug.Conn{params: params})
assert {:ok, user} == res
end
test "error credintails" do
res = PleromaAuthenticator.get_user(%Plug.Conn{params: %{}})
assert {:error, :invalid_credentials} == res
end
end

View file

@ -0,0 +1,51 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Auth.TOTPAuthenticatorTest do
use Pleroma.Web.ConnCase
alias Pleroma.MFA
alias Pleroma.MFA.BackupCodes
alias Pleroma.MFA.TOTP
alias Pleroma.Web.Auth.TOTPAuthenticator
import Pleroma.Factory
test "verify token" do
otp_secret = TOTP.generate_secret()
otp_token = TOTP.generate_token(otp_secret)
user =
insert(:user,
multi_factor_authentication_settings: %MFA.Settings{
enabled: true,
totp: %MFA.Settings.TOTP{secret: otp_secret, confirmed: true}
}
)
assert TOTPAuthenticator.verify(otp_token, user) == {:ok, :pass}
assert TOTPAuthenticator.verify(nil, user) == {:error, :invalid_token}
assert TOTPAuthenticator.verify("", user) == {:error, :invalid_token}
end
test "checks backup codes" do
[code | _] = backup_codes = BackupCodes.generate()
hashed_codes =
backup_codes
|> Enum.map(&Comeonin.Pbkdf2.hashpwsalt(&1))
user =
insert(:user,
multi_factor_authentication_settings: %MFA.Settings{
enabled: true,
backup_codes: hashed_codes,
totp: %MFA.Settings.TOTP{secret: "otp_secret", confirmed: true}
}
)
assert TOTPAuthenticator.verify_recovery_code(user, code) == {:ok, :pass}
refute TOTPAuthenticator.verify_recovery_code(code, refresh_record(user)) == {:ok, :pass}
end
end

View file

@ -9,11 +9,13 @@ defmodule Pleroma.Web.CommonAPITest do
alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.AdminAPI.AccountView
alias Pleroma.Web.CommonAPI
import Pleroma.Factory
import Mock
require Pleroma.Constants
@ -21,6 +23,84 @@ defmodule Pleroma.Web.CommonAPITest do
setup do: clear_config([:instance, :limit])
setup do: clear_config([:instance, :max_pinned_statuses])
describe "deletion" do
test "it allows users to delete their posts" do
user = insert(:user)
{:ok, post} = CommonAPI.post(user, %{"status" => "namu amida butsu"})
with_mock Pleroma.Web.Federator,
publish: fn _ -> nil end do
assert {:ok, delete} = CommonAPI.delete(post.id, user)
assert delete.local
assert called(Pleroma.Web.Federator.publish(delete))
end
refute Activity.get_by_id(post.id)
end
test "it does not allow a user to delete their posts" do
user = insert(:user)
other_user = insert(:user)
{:ok, post} = CommonAPI.post(user, %{"status" => "namu amida butsu"})
assert {:error, "Could not delete"} = CommonAPI.delete(post.id, other_user)
assert Activity.get_by_id(post.id)
end
test "it allows moderators to delete other user's posts" do
user = insert(:user)
moderator = insert(:user, is_moderator: true)
{:ok, post} = CommonAPI.post(user, %{"status" => "namu amida butsu"})
assert {:ok, delete} = CommonAPI.delete(post.id, moderator)
assert delete.local
refute Activity.get_by_id(post.id)
end
test "it allows admins to delete other user's posts" do
user = insert(:user)
moderator = insert(:user, is_admin: true)
{:ok, post} = CommonAPI.post(user, %{"status" => "namu amida butsu"})
assert {:ok, delete} = CommonAPI.delete(post.id, moderator)
assert delete.local
refute Activity.get_by_id(post.id)
end
test "superusers deleting non-local posts won't federate the delete" do
# This is the user of the ingested activity
_user =
insert(:user,
local: false,
ap_id: "http://mastodon.example.org/users/admin",
last_refreshed_at: NaiveDateTime.utc_now()
)
moderator = insert(:user, is_admin: true)
data =
File.read!("test/fixtures/mastodon-post-activity.json")
|> Jason.decode!()
{:ok, post} = Transmogrifier.handle_incoming(data)
with_mock Pleroma.Web.Federator,
publish: fn _ -> nil end do
assert {:ok, delete} = CommonAPI.delete(post.id, moderator)
assert delete.local
refute called(Pleroma.Web.Federator.publish(:_))
end
refute Activity.get_by_id(post.id)
end
end
test "favoriting race condition" do
user = insert(:user)
users_serial = insert_list(10, :user)

View file

@ -36,7 +36,7 @@ defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do
res_conn = get(conn, "/api/v1/conversations")
assert response = json_response(res_conn, 200)
assert response = json_response_and_validate_schema(res_conn, 200)
assert [
%{
@ -91,18 +91,18 @@ defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do
"visibility" => "direct"
})
[conversation1, conversation2] =
conn
|> get("/api/v1/conversations", %{"recipients" => [user_two.id]})
|> json_response(200)
assert [conversation1, conversation2] =
conn
|> get("/api/v1/conversations?recipients[]=#{user_two.id}")
|> json_response_and_validate_schema(200)
assert conversation1["last_status"]["id"] == direct5.id
assert conversation2["last_status"]["id"] == direct1.id
[conversation1] =
conn
|> get("/api/v1/conversations", %{"recipients" => [user_two.id, user_three.id]})
|> json_response(200)
|> get("/api/v1/conversations?recipients[]=#{user_two.id}&recipients[]=#{user_three.id}")
|> json_response_and_validate_schema(200)
assert conversation1["last_status"]["id"] == direct3.id
end
@ -126,7 +126,7 @@ defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do
[%{"last_status" => res_last_status}] =
conn
|> get("/api/v1/conversations")
|> json_response(200)
|> json_response_and_validate_schema(200)
assert res_last_status["id"] == direct_reply.id
end
@ -154,12 +154,12 @@ defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do
[%{"id" => direct_conversation_id, "unread" => true}] =
user_two_conn
|> get("/api/v1/conversations")
|> json_response(200)
|> json_response_and_validate_schema(200)
%{"unread" => false} =
user_two_conn
|> post("/api/v1/conversations/#{direct_conversation_id}/read")
|> json_response(200)
|> json_response_and_validate_schema(200)
assert User.get_cached_by_id(user_one.id).unread_conversation_count == 0
assert User.get_cached_by_id(user_two.id).unread_conversation_count == 0
@ -175,7 +175,7 @@ defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do
[%{"unread" => true}] =
conn
|> get("/api/v1/conversations")
|> json_response(200)
|> json_response_and_validate_schema(200)
assert User.get_cached_by_id(user_one.id).unread_conversation_count == 1
assert User.get_cached_by_id(user_two.id).unread_conversation_count == 0

View file

@ -15,9 +15,12 @@ defmodule Pleroma.Web.MastodonAPI.FilterControllerTest do
context: ["home"]
}
conn = post(conn, "/api/v1/filters", %{"phrase" => filter.phrase, context: filter.context})
conn =
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/filters", %{"phrase" => filter.phrase, context: filter.context})
assert response = json_response(conn, 200)
assert response = json_response_and_validate_schema(conn, 200)
assert response["phrase"] == filter.phrase
assert response["context"] == filter.context
assert response["irreversible"] == false
@ -48,12 +51,12 @@ defmodule Pleroma.Web.MastodonAPI.FilterControllerTest do
response =
conn
|> get("/api/v1/filters")
|> json_response(200)
|> json_response_and_validate_schema(200)
assert response ==
render_json(
FilterView,
"filters.json",
"index.json",
filters: [filter_two, filter_one]
)
end
@ -72,7 +75,7 @@ defmodule Pleroma.Web.MastodonAPI.FilterControllerTest do
conn = get(conn, "/api/v1/filters/#{filter.filter_id}")
assert _response = json_response(conn, 200)
assert response = json_response_and_validate_schema(conn, 200)
end
test "update a filter" do
@ -82,7 +85,8 @@ defmodule Pleroma.Web.MastodonAPI.FilterControllerTest do
user_id: user.id,
filter_id: 2,
phrase: "knight",
context: ["home"]
context: ["home"],
hide: true
}
{:ok, _filter} = Pleroma.Filter.create(query)
@ -93,14 +97,17 @@ defmodule Pleroma.Web.MastodonAPI.FilterControllerTest do
}
conn =
put(conn, "/api/v1/filters/#{query.filter_id}", %{
conn
|> put_req_header("content-type", "application/json")
|> put("/api/v1/filters/#{query.filter_id}", %{
phrase: new.phrase,
context: new.context
})
assert response = json_response(conn, 200)
assert response = json_response_and_validate_schema(conn, 200)
assert response["phrase"] == new.phrase
assert response["context"] == new.context
assert response["irreversible"] == true
end
test "delete a filter" do
@ -117,7 +124,6 @@ defmodule Pleroma.Web.MastodonAPI.FilterControllerTest do
conn = delete(conn, "/api/v1/filters/#{filter.filter_id}")
assert response = json_response(conn, 200)
assert response == %{}
assert json_response_and_validate_schema(conn, 200) == %{}
end
end

View file

@ -27,7 +27,7 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do
conn = get(conn, "/api/v1/follow_requests")
assert [relationship] = json_response(conn, 200)
assert [relationship] = json_response_and_validate_schema(conn, 200)
assert to_string(other_user.id) == relationship["id"]
end
@ -44,7 +44,7 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do
conn = post(conn, "/api/v1/follow_requests/#{other_user.id}/authorize")
assert relationship = json_response(conn, 200)
assert relationship = json_response_and_validate_schema(conn, 200)
assert to_string(other_user.id) == relationship["id"]
user = User.get_cached_by_id(user.id)
@ -62,7 +62,7 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do
conn = post(conn, "/api/v1/follow_requests/#{other_user.id}/reject")
assert relationship = json_response(conn, 200)
assert relationship = json_response_and_validate_schema(conn, 200)
assert to_string(other_user.id) == relationship["id"]
user = User.get_cached_by_id(user.id)

View file

@ -10,7 +10,7 @@ defmodule Pleroma.Web.MastodonAPI.InstanceControllerTest do
test "get instance information", %{conn: conn} do
conn = get(conn, "/api/v1/instance")
assert result = json_response(conn, 200)
assert result = json_response_and_validate_schema(conn, 200)
email = Pleroma.Config.get([:instance, :email])
# Note: not checking for "max_toot_chars" since it's optional
@ -56,7 +56,7 @@ defmodule Pleroma.Web.MastodonAPI.InstanceControllerTest do
conn = get(conn, "/api/v1/instance")
assert result = json_response(conn, 200)
assert result = json_response_and_validate_schema(conn, 200)
stats = result["stats"]
@ -74,7 +74,7 @@ defmodule Pleroma.Web.MastodonAPI.InstanceControllerTest do
conn = get(conn, "/api/v1/instance/peers")
assert result = json_response(conn, 200)
assert result = json_response_and_validate_schema(conn, 200)
assert ["peer1.com", "peer2.com"] == Enum.sort(result)
end

View file

@ -12,37 +12,44 @@ defmodule Pleroma.Web.MastodonAPI.ListControllerTest do
test "creating a list" do
%{conn: conn} = oauth_access(["write:lists"])
conn = post(conn, "/api/v1/lists", %{"title" => "cuties"})
assert %{"title" => title} = json_response(conn, 200)
assert title == "cuties"
assert %{"title" => "cuties"} =
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/lists", %{"title" => "cuties"})
|> json_response_and_validate_schema(:ok)
end
test "renders error for invalid params" do
%{conn: conn} = oauth_access(["write:lists"])
conn = post(conn, "/api/v1/lists", %{"title" => nil})
conn =
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/lists", %{"title" => nil})
assert %{"error" => "can't be blank"} == json_response(conn, :unprocessable_entity)
assert %{"error" => "title - null value where string expected."} =
json_response_and_validate_schema(conn, 400)
end
test "listing a user's lists" do
%{conn: conn} = oauth_access(["read:lists", "write:lists"])
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/lists", %{"title" => "cuties"})
|> json_response(:ok)
|> json_response_and_validate_schema(:ok)
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/lists", %{"title" => "cofe"})
|> json_response(:ok)
|> json_response_and_validate_schema(:ok)
conn = get(conn, "/api/v1/lists")
assert [
%{"id" => _, "title" => "cofe"},
%{"id" => _, "title" => "cuties"}
] = json_response(conn, :ok)
] = json_response_and_validate_schema(conn, :ok)
end
test "adding users to a list" do
@ -50,9 +57,12 @@ defmodule Pleroma.Web.MastodonAPI.ListControllerTest do
other_user = insert(:user)
{:ok, list} = Pleroma.List.create("name", user)
conn = post(conn, "/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
assert %{} ==
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
|> json_response_and_validate_schema(:ok)
assert %{} == json_response(conn, 200)
%Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
assert following == [other_user.follower_address]
end
@ -65,9 +75,12 @@ defmodule Pleroma.Web.MastodonAPI.ListControllerTest do
{:ok, list} = Pleroma.List.follow(list, other_user)
{:ok, list} = Pleroma.List.follow(list, third_user)
conn = delete(conn, "/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
assert %{} ==
conn
|> put_req_header("content-type", "application/json")
|> delete("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
|> json_response_and_validate_schema(:ok)
assert %{} == json_response(conn, 200)
%Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
assert following == [third_user.follower_address]
end
@ -83,7 +96,7 @@ defmodule Pleroma.Web.MastodonAPI.ListControllerTest do
|> assign(:user, user)
|> get("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
assert [%{"id" => id}] = json_response(conn, 200)
assert [%{"id" => id}] = json_response_and_validate_schema(conn, 200)
assert id == to_string(other_user.id)
end
@ -96,7 +109,7 @@ defmodule Pleroma.Web.MastodonAPI.ListControllerTest do
|> assign(:user, user)
|> get("/api/v1/lists/#{list.id}")
assert %{"id" => id} = json_response(conn, 200)
assert %{"id" => id} = json_response_and_validate_schema(conn, 200)
assert id == to_string(list.id)
end
@ -105,17 +118,18 @@ defmodule Pleroma.Web.MastodonAPI.ListControllerTest do
conn = get(conn, "/api/v1/lists/666")
assert %{"error" => "List not found"} = json_response(conn, :not_found)
assert %{"error" => "List not found"} = json_response_and_validate_schema(conn, :not_found)
end
test "renaming a list" do
%{user: user, conn: conn} = oauth_access(["write:lists"])
{:ok, list} = Pleroma.List.create("name", user)
conn = put(conn, "/api/v1/lists/#{list.id}", %{"title" => "newname"})
assert %{"title" => name} = json_response(conn, 200)
assert name == "newname"
assert %{"title" => "newname"} =
conn
|> put_req_header("content-type", "application/json")
|> put("/api/v1/lists/#{list.id}", %{"title" => "newname"})
|> json_response_and_validate_schema(:ok)
end
test "validates title when renaming a list" do
@ -125,9 +139,11 @@ defmodule Pleroma.Web.MastodonAPI.ListControllerTest do
conn =
conn
|> assign(:user, user)
|> put_req_header("content-type", "application/json")
|> put("/api/v1/lists/#{list.id}", %{"title" => " "})
assert %{"error" => "can't be blank"} == json_response(conn, :unprocessable_entity)
assert %{"error" => "can't be blank"} ==
json_response_and_validate_schema(conn, :unprocessable_entity)
end
test "deleting a list" do
@ -136,7 +152,7 @@ defmodule Pleroma.Web.MastodonAPI.ListControllerTest do
conn = delete(conn, "/api/v1/lists/#{list.id}")
assert %{} = json_response(conn, 200)
assert %{} = json_response_and_validate_schema(conn, 200)
assert is_nil(Repo.get(Pleroma.List, list.id))
end
end

View file

@ -22,8 +22,8 @@ defmodule Pleroma.Web.MastodonAPI.MarkerControllerTest do
conn
|> assign(:user, user)
|> assign(:token, token)
|> get("/api/v1/markers", %{timeline: ["notifications"]})
|> json_response(200)
|> get("/api/v1/markers?timeline[]=notifications")
|> json_response_and_validate_schema(200)
assert response == %{
"notifications" => %{
@ -45,7 +45,7 @@ defmodule Pleroma.Web.MastodonAPI.MarkerControllerTest do
|> assign(:user, user)
|> assign(:token, token)
|> get("/api/v1/markers", %{timeline: ["notifications"]})
|> json_response(403)
|> json_response_and_validate_schema(403)
assert response == %{"error" => "Insufficient permissions: read:statuses."}
end
@ -60,11 +60,12 @@ defmodule Pleroma.Web.MastodonAPI.MarkerControllerTest do
conn
|> assign(:user, user)
|> assign(:token, token)
|> put_req_header("content-type", "application/json")
|> post("/api/v1/markers", %{
home: %{last_read_id: "777"},
notifications: %{"last_read_id" => "69420"}
})
|> json_response(200)
|> json_response_and_validate_schema(200)
assert %{
"notifications" => %{
@ -89,11 +90,12 @@ defmodule Pleroma.Web.MastodonAPI.MarkerControllerTest do
conn
|> assign(:user, user)
|> assign(:token, token)
|> put_req_header("content-type", "application/json")
|> post("/api/v1/markers", %{
home: %{last_read_id: "777"},
notifications: %{"last_read_id" => "69888"}
})
|> json_response(200)
|> json_response_and_validate_schema(200)
assert response == %{
"notifications" => %{
@ -112,11 +114,12 @@ defmodule Pleroma.Web.MastodonAPI.MarkerControllerTest do
conn
|> assign(:user, user)
|> assign(:token, token)
|> put_req_header("content-type", "application/json")
|> post("/api/v1/markers", %{
home: %{last_read_id: "777"},
notifications: %{"last_read_id" => "69420"}
})
|> json_response(403)
|> json_response_and_validate_schema(403)
assert response == %{"error" => "Insufficient permissions: write:statuses."}
end

View file

@ -24,7 +24,7 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do
conn = get(conn, "/api/v1/polls/#{object.id}")
response = json_response(conn, 200)
response = json_response_and_validate_schema(conn, 200)
id = to_string(object.id)
assert %{"id" => ^id, "expired" => false, "multiple" => false} = response
end
@ -43,7 +43,7 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do
conn = get(conn, "/api/v1/polls/#{object.id}")
assert json_response(conn, 404)
assert json_response_and_validate_schema(conn, 404)
end
end
@ -65,9 +65,12 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do
object = Object.normalize(activity)
conn = post(conn, "/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1, 2]})
conn =
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1, 2]})
assert json_response(conn, 200)
assert json_response_and_validate_schema(conn, 200)
object = Object.get_by_id(object.id)
assert Enum.all?(object.data["anyOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
@ -85,8 +88,9 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do
object = Object.normalize(activity)
assert conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [1]})
|> json_response(422) == %{"error" => "Poll's author can't vote"}
|> json_response_and_validate_schema(422) == %{"error" => "Poll's author can't vote"}
object = Object.get_by_id(object.id)
@ -105,8 +109,9 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do
object = Object.normalize(activity)
assert conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1]})
|> json_response(422) == %{"error" => "Too many choices"}
|> json_response_and_validate_schema(422) == %{"error" => "Too many choices"}
object = Object.get_by_id(object.id)
@ -126,15 +131,21 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do
object = Object.normalize(activity)
conn = post(conn, "/api/v1/polls/#{object.id}/votes", %{"choices" => [2]})
conn =
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [2]})
assert json_response(conn, 422) == %{"error" => "Invalid indices"}
assert json_response_and_validate_schema(conn, 422) == %{"error" => "Invalid indices"}
end
test "returns 404 error when object is not exist", %{conn: conn} do
conn = post(conn, "/api/v1/polls/1/votes", %{"choices" => [0]})
conn =
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/polls/1/votes", %{"choices" => [0]})
assert json_response(conn, 404) == %{"error" => "Record not found"}
assert json_response_and_validate_schema(conn, 404) == %{"error" => "Record not found"}
end
test "returns 404 when poll is private and not available for user", %{conn: conn} do
@ -149,9 +160,12 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do
object = Object.normalize(activity)
conn = post(conn, "/api/v1/polls/#{object.id}/votes", %{"choices" => [0]})
conn =
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0]})
assert json_response(conn, 404) == %{"error" => "Record not found"}
assert json_response_and_validate_schema(conn, 404) == %{"error" => "Record not found"}
end
end
end

View file

@ -24,19 +24,19 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityControllerTest do
# min_id
conn_res = get(conn, "/api/v1/scheduled_statuses?limit=2&min_id=#{scheduled_activity_id1}")
result = json_response(conn_res, 200)
result = json_response_and_validate_schema(conn_res, 200)
assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
# since_id
conn_res = get(conn, "/api/v1/scheduled_statuses?limit=2&since_id=#{scheduled_activity_id1}")
result = json_response(conn_res, 200)
result = json_response_and_validate_schema(conn_res, 200)
assert [%{"id" => ^scheduled_activity_id4}, %{"id" => ^scheduled_activity_id3}] = result
# max_id
conn_res = get(conn, "/api/v1/scheduled_statuses?limit=2&max_id=#{scheduled_activity_id4}")
result = json_response(conn_res, 200)
result = json_response_and_validate_schema(conn_res, 200)
assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
end
@ -46,12 +46,12 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityControllerTest do
res_conn = get(conn, "/api/v1/scheduled_statuses/#{scheduled_activity.id}")
assert %{"id" => scheduled_activity_id} = json_response(res_conn, 200)
assert %{"id" => scheduled_activity_id} = json_response_and_validate_schema(res_conn, 200)
assert scheduled_activity_id == scheduled_activity.id |> to_string()
res_conn = get(conn, "/api/v1/scheduled_statuses/404")
assert %{"error" => "Record not found"} = json_response(res_conn, 404)
assert %{"error" => "Record not found"} = json_response_and_validate_schema(res_conn, 404)
end
test "updates a scheduled activity" do
@ -74,22 +74,32 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityControllerTest do
assert job.args == %{"activity_id" => scheduled_activity.id}
assert DateTime.truncate(job.scheduled_at, :second) == to_datetime(scheduled_at)
new_scheduled_at = Timex.shift(NaiveDateTime.utc_now(), minutes: 120)
new_scheduled_at =
NaiveDateTime.utc_now()
|> Timex.shift(minutes: 120)
|> Timex.format!("%Y-%m-%dT%H:%M:%S.%fZ", :strftime)
res_conn =
put(conn, "/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{
conn
|> put_req_header("content-type", "application/json")
|> put("/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{
scheduled_at: new_scheduled_at
})
assert %{"scheduled_at" => expected_scheduled_at} = json_response(res_conn, 200)
assert %{"scheduled_at" => expected_scheduled_at} =
json_response_and_validate_schema(res_conn, 200)
assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at)
job = refresh_record(job)
assert DateTime.truncate(job.scheduled_at, :second) == to_datetime(new_scheduled_at)
res_conn = put(conn, "/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at})
res_conn =
conn
|> put_req_header("content-type", "application/json")
|> put("/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at})
assert %{"error" => "Record not found"} = json_response(res_conn, 404)
assert %{"error" => "Record not found"} = json_response_and_validate_schema(res_conn, 404)
end
test "deletes a scheduled activity" do
@ -115,7 +125,7 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityControllerTest do
|> assign(:user, user)
|> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
assert %{} = json_response(res_conn, 200)
assert %{} = json_response_and_validate_schema(res_conn, 200)
refute Repo.get(ScheduledActivity, scheduled_activity.id)
refute Repo.get(Oban.Job, job.id)
@ -124,6 +134,6 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityControllerTest do
|> assign(:user, user)
|> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
assert %{"error" => "Record not found"} = json_response(res_conn, 404)
assert %{"error" => "Record not found"} = json_response_and_validate_schema(res_conn, 404)
end
end

View file

@ -6,6 +6,7 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionControllerTest do
use Pleroma.Web.ConnCase
import Pleroma.Factory
alias Pleroma.Web.Push
alias Pleroma.Web.Push.Subscription
@ -27,6 +28,7 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionControllerTest do
build_conn()
|> assign(:user, user)
|> assign(:token, token)
|> put_req_header("content-type", "application/json")
%{conn: conn, user: user, token: token}
end
@ -47,8 +49,8 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionControllerTest do
test "returns error when push disabled ", %{conn: conn} do
assert_error_when_disable_push do
conn
|> post("/api/v1/push/subscription", %{})
|> json_response(403)
|> post("/api/v1/push/subscription", %{subscription: @sub})
|> json_response_and_validate_schema(403)
end
end
@ -59,7 +61,7 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionControllerTest do
"data" => %{"alerts" => %{"mention" => true, "test" => true}},
"subscription" => @sub
})
|> json_response(200)
|> json_response_and_validate_schema(200)
[subscription] = Pleroma.Repo.all(Subscription)
@ -77,7 +79,7 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionControllerTest do
assert_error_when_disable_push do
conn
|> get("/api/v1/push/subscription", %{})
|> json_response(403)
|> json_response_and_validate_schema(403)
end
end
@ -85,9 +87,9 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionControllerTest do
res =
conn
|> get("/api/v1/push/subscription", %{})
|> json_response(404)
|> json_response_and_validate_schema(404)
assert "Not found" == res
assert %{"error" => "Record not found"} == res
end
test "returns a user subsciption", %{conn: conn, user: user, token: token} do
@ -101,7 +103,7 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionControllerTest do
res =
conn
|> get("/api/v1/push/subscription", %{})
|> json_response(200)
|> json_response_and_validate_schema(200)
expect = %{
"alerts" => %{"mention" => true},
@ -130,7 +132,7 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionControllerTest do
assert_error_when_disable_push do
conn
|> put("/api/v1/push/subscription", %{data: %{"alerts" => %{"mention" => false}}})
|> json_response(403)
|> json_response_and_validate_schema(403)
end
end
@ -140,7 +142,7 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionControllerTest do
|> put("/api/v1/push/subscription", %{
data: %{"alerts" => %{"mention" => false, "follow" => true}}
})
|> json_response(200)
|> json_response_and_validate_schema(200)
expect = %{
"alerts" => %{"follow" => true, "mention" => false},
@ -158,7 +160,7 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionControllerTest do
assert_error_when_disable_push do
conn
|> delete("/api/v1/push/subscription", %{})
|> json_response(403)
|> json_response_and_validate_schema(403)
end
end
@ -166,9 +168,9 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionControllerTest do
res =
conn
|> delete("/api/v1/push/subscription", %{})
|> json_response(404)
|> json_response_and_validate_schema(404)
assert "Not found" == res
assert %{"error" => "Record not found"} == res
end
test "returns empty result and delete user subsciption", %{
@ -186,7 +188,7 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionControllerTest do
res =
conn
|> delete("/api/v1/push/subscription", %{})
|> json_response(200)
|> json_response_and_validate_schema(200)
assert %{} == res
refute Pleroma.Repo.get(Subscription, subscription.id)

View file

@ -402,11 +402,17 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
pleroma: %{mime_type: "image/png"}
}
api_spec = Pleroma.Web.ApiSpec.spec()
assert expected == StatusView.render("attachment.json", %{attachment: object})
OpenApiSpex.TestAssertions.assert_schema(expected, "Attachment", api_spec)
# If theres a "id", use that instead of the generated one
object = Map.put(object, "id", 2)
assert %{id: "2"} = StatusView.render("attachment.json", %{attachment: object})
result = StatusView.render("attachment.json", %{attachment: object})
assert %{id: "2"} = result
OpenApiSpex.TestAssertions.assert_schema(result, "Attachment", api_spec)
end
test "put the url advertised in the Activity in to the url attribute" do

View file

@ -0,0 +1,306 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OAuth.MFAControllerTest do
use Pleroma.Web.ConnCase
import Pleroma.Factory
alias Pleroma.MFA
alias Pleroma.MFA.BackupCodes
alias Pleroma.MFA.TOTP
alias Pleroma.Repo
alias Pleroma.Web.OAuth.Authorization
alias Pleroma.Web.OAuth.OAuthController
setup %{conn: conn} do
otp_secret = TOTP.generate_secret()
user =
insert(:user,
multi_factor_authentication_settings: %MFA.Settings{
enabled: true,
backup_codes: [Comeonin.Pbkdf2.hashpwsalt("test-code")],
totp: %MFA.Settings.TOTP{secret: otp_secret, confirmed: true}
}
)
app = insert(:oauth_app)
{:ok, conn: conn, user: user, app: app}
end
describe "show" do
setup %{conn: conn, user: user, app: app} do
mfa_token =
insert(:mfa_token,
user: user,
authorization: build(:oauth_authorization, app: app, scopes: ["write"])
)
{:ok, conn: conn, mfa_token: mfa_token}
end
test "GET /oauth/mfa renders mfa forms", %{conn: conn, mfa_token: mfa_token} do
conn =
get(
conn,
"/oauth/mfa",
%{
"mfa_token" => mfa_token.token,
"state" => "a_state",
"redirect_uri" => "http://localhost:8080/callback"
}
)
assert response = html_response(conn, 200)
assert response =~ "Two-factor authentication"
assert response =~ mfa_token.token
assert response =~ "http://localhost:8080/callback"
end
test "GET /oauth/mfa renders mfa recovery forms", %{conn: conn, mfa_token: mfa_token} do
conn =
get(
conn,
"/oauth/mfa",
%{
"mfa_token" => mfa_token.token,
"state" => "a_state",
"redirect_uri" => "http://localhost:8080/callback",
"challenge_type" => "recovery"
}
)
assert response = html_response(conn, 200)
assert response =~ "Two-factor recovery"
assert response =~ mfa_token.token
assert response =~ "http://localhost:8080/callback"
end
end
describe "verify" do
setup %{conn: conn, user: user, app: app} do
mfa_token =
insert(:mfa_token,
user: user,
authorization: build(:oauth_authorization, app: app, scopes: ["write"])
)
{:ok, conn: conn, user: user, mfa_token: mfa_token, app: app}
end
test "POST /oauth/mfa/verify, verify totp code", %{
conn: conn,
user: user,
mfa_token: mfa_token,
app: app
} do
otp_token = TOTP.generate_token(user.multi_factor_authentication_settings.totp.secret)
conn =
conn
|> post("/oauth/mfa/verify", %{
"mfa" => %{
"mfa_token" => mfa_token.token,
"challenge_type" => "totp",
"code" => otp_token,
"state" => "a_state",
"redirect_uri" => OAuthController.default_redirect_uri(app)
}
})
target = redirected_to(conn)
target_url = %URI{URI.parse(target) | query: nil} |> URI.to_string()
query = URI.parse(target).query |> URI.query_decoder() |> Map.new()
assert %{"state" => "a_state", "code" => code} = query
assert target_url == OAuthController.default_redirect_uri(app)
auth = Repo.get_by(Authorization, token: code)
assert auth.scopes == ["write"]
end
test "POST /oauth/mfa/verify, verify recovery code", %{
conn: conn,
mfa_token: mfa_token,
app: app
} do
conn =
conn
|> post("/oauth/mfa/verify", %{
"mfa" => %{
"mfa_token" => mfa_token.token,
"challenge_type" => "recovery",
"code" => "test-code",
"state" => "a_state",
"redirect_uri" => OAuthController.default_redirect_uri(app)
}
})
target = redirected_to(conn)
target_url = %URI{URI.parse(target) | query: nil} |> URI.to_string()
query = URI.parse(target).query |> URI.query_decoder() |> Map.new()
assert %{"state" => "a_state", "code" => code} = query
assert target_url == OAuthController.default_redirect_uri(app)
auth = Repo.get_by(Authorization, token: code)
assert auth.scopes == ["write"]
end
end
describe "challenge/totp" do
test "returns access token with valid code", %{conn: conn, user: user, app: app} do
otp_token = TOTP.generate_token(user.multi_factor_authentication_settings.totp.secret)
mfa_token =
insert(:mfa_token,
user: user,
authorization: build(:oauth_authorization, app: app, scopes: ["write"])
)
response =
conn
|> post("/oauth/mfa/challenge", %{
"mfa_token" => mfa_token.token,
"challenge_type" => "totp",
"code" => otp_token,
"client_id" => app.client_id,
"client_secret" => app.client_secret
})
|> json_response(:ok)
ap_id = user.ap_id
assert match?(
%{
"access_token" => _,
"expires_in" => 600,
"me" => ^ap_id,
"refresh_token" => _,
"scope" => "write",
"token_type" => "Bearer"
},
response
)
end
test "returns errors when mfa token invalid", %{conn: conn, user: user, app: app} do
otp_token = TOTP.generate_token(user.multi_factor_authentication_settings.totp.secret)
response =
conn
|> post("/oauth/mfa/challenge", %{
"mfa_token" => "XXX",
"challenge_type" => "totp",
"code" => otp_token,
"client_id" => app.client_id,
"client_secret" => app.client_secret
})
|> json_response(400)
assert response == %{"error" => "Invalid code"}
end
test "returns error when otp code is invalid", %{conn: conn, user: user, app: app} do
mfa_token = insert(:mfa_token, user: user)
response =
conn
|> post("/oauth/mfa/challenge", %{
"mfa_token" => mfa_token.token,
"challenge_type" => "totp",
"code" => "XXX",
"client_id" => app.client_id,
"client_secret" => app.client_secret
})
|> json_response(400)
assert response == %{"error" => "Invalid code"}
end
test "returns error when client credentails is wrong ", %{conn: conn, user: user} do
otp_token = TOTP.generate_token(user.multi_factor_authentication_settings.totp.secret)
mfa_token = insert(:mfa_token, user: user)
response =
conn
|> post("/oauth/mfa/challenge", %{
"mfa_token" => mfa_token.token,
"challenge_type" => "totp",
"code" => otp_token,
"client_id" => "xxx",
"client_secret" => "xxx"
})
|> json_response(400)
assert response == %{"error" => "Invalid code"}
end
end
describe "challenge/recovery" do
setup %{conn: conn} do
app = insert(:oauth_app)
{:ok, conn: conn, app: app}
end
test "returns access token with valid code", %{conn: conn, app: app} do
otp_secret = TOTP.generate_secret()
[code | _] = backup_codes = BackupCodes.generate()
hashed_codes =
backup_codes
|> Enum.map(&Comeonin.Pbkdf2.hashpwsalt(&1))
user =
insert(:user,
multi_factor_authentication_settings: %MFA.Settings{
enabled: true,
backup_codes: hashed_codes,
totp: %MFA.Settings.TOTP{secret: otp_secret, confirmed: true}
}
)
mfa_token =
insert(:mfa_token,
user: user,
authorization: build(:oauth_authorization, app: app, scopes: ["write"])
)
response =
conn
|> post("/oauth/mfa/challenge", %{
"mfa_token" => mfa_token.token,
"challenge_type" => "recovery",
"code" => code,
"client_id" => app.client_id,
"client_secret" => app.client_secret
})
|> json_response(:ok)
ap_id = user.ap_id
assert match?(
%{
"access_token" => _,
"expires_in" => 600,
"me" => ^ap_id,
"refresh_token" => _,
"scope" => "write",
"token_type" => "Bearer"
},
response
)
error_response =
conn
|> post("/oauth/mfa/challenge", %{
"mfa_token" => mfa_token.token,
"challenge_type" => "recovery",
"code" => code,
"client_id" => app.client_id,
"client_secret" => app.client_secret
})
|> json_response(400)
assert error_response == %{"error" => "Invalid code"}
end
end
end

View file

@ -6,6 +6,8 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
use Pleroma.Web.ConnCase
import Pleroma.Factory
alias Pleroma.MFA
alias Pleroma.MFA.TOTP
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.OAuth.Authorization
@ -604,6 +606,41 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
end
end
test "redirect to on two-factor auth page" do
otp_secret = TOTP.generate_secret()
user =
insert(:user,
multi_factor_authentication_settings: %MFA.Settings{
enabled: true,
totp: %MFA.Settings.TOTP{secret: otp_secret, confirmed: true}
}
)
app = insert(:oauth_app, scopes: ["read", "write", "follow"])
conn =
build_conn()
|> post("/oauth/authorize", %{
"authorization" => %{
"name" => user.nickname,
"password" => "test",
"client_id" => app.client_id,
"redirect_uri" => app.redirect_uris,
"scope" => "read write",
"state" => "statepassed"
}
})
result = html_response(conn, 200)
mfa_token = Repo.get_by(MFA.Token, user_id: user.id)
assert result =~ app.redirect_uris
assert result =~ "statepassed"
assert result =~ mfa_token.token
assert result =~ "Two-factor authentication"
end
test "returns 401 for wrong credentials", %{conn: conn} do
user = insert(:user)
app = insert(:oauth_app)
@ -735,6 +772,46 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
assert token.scopes == app.scopes
end
test "issues a mfa token for `password` grant_type, when MFA enabled" do
password = "testpassword"
otp_secret = TOTP.generate_secret()
user =
insert(:user,
password_hash: Comeonin.Pbkdf2.hashpwsalt(password),
multi_factor_authentication_settings: %MFA.Settings{
enabled: true,
totp: %MFA.Settings.TOTP{secret: otp_secret, confirmed: true}
}
)
app = insert(:oauth_app, scopes: ["read", "write"])
response =
build_conn()
|> post("/oauth/token", %{
"grant_type" => "password",
"username" => user.nickname,
"password" => password,
"client_id" => app.client_id,
"client_secret" => app.client_secret
})
|> json_response(403)
assert match?(
%{
"supported_challenge_types" => "totp",
"mfa_token" => _,
"error" => "mfa_required"
},
response
)
token = Repo.get_by(MFA.Token, token: response["mfa_token"])
assert token.user_id == user.id
assert token.authorization_id
end
test "issues a token for request with HTTP basic auth client credentials" do
user = insert(:user)
app = insert(:oauth_app, scopes: ["scope1", "scope2", "scope3"])

View file

@ -0,0 +1,260 @@
defmodule Pleroma.Web.PleromaAPI.TwoFactorAuthenticationControllerTest do
use Pleroma.Web.ConnCase
import Pleroma.Factory
alias Pleroma.MFA.Settings
alias Pleroma.MFA.TOTP
describe "GET /api/pleroma/accounts/mfa/settings" do
test "returns user mfa settings for new user", %{conn: conn} do
token = insert(:oauth_token, scopes: ["read", "follow"])
token2 = insert(:oauth_token, scopes: ["write"])
assert conn
|> put_req_header("authorization", "Bearer #{token.token}")
|> get("/api/pleroma/accounts/mfa")
|> json_response(:ok) == %{
"settings" => %{"enabled" => false, "totp" => false}
}
assert conn
|> put_req_header("authorization", "Bearer #{token2.token}")
|> get("/api/pleroma/accounts/mfa")
|> json_response(403) == %{
"error" => "Insufficient permissions: read:security."
}
end
test "returns user mfa settings with enabled totp", %{conn: conn} do
user =
insert(:user,
multi_factor_authentication_settings: %Settings{
enabled: true,
totp: %Settings.TOTP{secret: "XXX", delivery_type: "app", confirmed: true}
}
)
token = insert(:oauth_token, scopes: ["read", "follow"], user: user)
assert conn
|> put_req_header("authorization", "Bearer #{token.token}")
|> get("/api/pleroma/accounts/mfa")
|> json_response(:ok) == %{
"settings" => %{"enabled" => true, "totp" => true}
}
end
end
describe "GET /api/pleroma/accounts/mfa/backup_codes" do
test "returns backup codes", %{conn: conn} do
user =
insert(:user,
multi_factor_authentication_settings: %Settings{
backup_codes: ["1", "2", "3"],
totp: %Settings.TOTP{secret: "secret"}
}
)
token = insert(:oauth_token, scopes: ["write", "follow"], user: user)
token2 = insert(:oauth_token, scopes: ["read"])
response =
conn
|> put_req_header("authorization", "Bearer #{token.token}")
|> get("/api/pleroma/accounts/mfa/backup_codes")
|> json_response(:ok)
assert [<<_::bytes-size(6)>>, <<_::bytes-size(6)>>] = response["codes"]
user = refresh_record(user)
mfa_settings = user.multi_factor_authentication_settings
assert mfa_settings.totp.secret == "secret"
refute mfa_settings.backup_codes == ["1", "2", "3"]
refute mfa_settings.backup_codes == []
assert conn
|> put_req_header("authorization", "Bearer #{token2.token}")
|> get("/api/pleroma/accounts/mfa/backup_codes")
|> json_response(403) == %{
"error" => "Insufficient permissions: write:security."
}
end
end
describe "GET /api/pleroma/accounts/mfa/setup/totp" do
test "return errors when method is invalid", %{conn: conn} do
user = insert(:user)
token = insert(:oauth_token, scopes: ["write", "follow"], user: user)
response =
conn
|> put_req_header("authorization", "Bearer #{token.token}")
|> get("/api/pleroma/accounts/mfa/setup/torf")
|> json_response(400)
assert response == %{"error" => "undefined method"}
end
test "returns key and provisioning_uri", %{conn: conn} do
user =
insert(:user,
multi_factor_authentication_settings: %Settings{backup_codes: ["1", "2", "3"]}
)
token = insert(:oauth_token, scopes: ["write", "follow"], user: user)
token2 = insert(:oauth_token, scopes: ["read"])
response =
conn
|> put_req_header("authorization", "Bearer #{token.token}")
|> get("/api/pleroma/accounts/mfa/setup/totp")
|> json_response(:ok)
user = refresh_record(user)
mfa_settings = user.multi_factor_authentication_settings
secret = mfa_settings.totp.secret
refute mfa_settings.enabled
assert mfa_settings.backup_codes == ["1", "2", "3"]
assert response == %{
"key" => secret,
"provisioning_uri" => TOTP.provisioning_uri(secret, "#{user.email}")
}
assert conn
|> put_req_header("authorization", "Bearer #{token2.token}")
|> get("/api/pleroma/accounts/mfa/setup/totp")
|> json_response(403) == %{
"error" => "Insufficient permissions: write:security."
}
end
end
describe "GET /api/pleroma/accounts/mfa/confirm/totp" do
test "returns success result", %{conn: conn} do
secret = TOTP.generate_secret()
code = TOTP.generate_token(secret)
user =
insert(:user,
multi_factor_authentication_settings: %Settings{
backup_codes: ["1", "2", "3"],
totp: %Settings.TOTP{secret: secret}
}
)
token = insert(:oauth_token, scopes: ["write", "follow"], user: user)
token2 = insert(:oauth_token, scopes: ["read"])
assert conn
|> put_req_header("authorization", "Bearer #{token.token}")
|> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "test", code: code})
|> json_response(:ok)
settings = refresh_record(user).multi_factor_authentication_settings
assert settings.enabled
assert settings.totp.secret == secret
assert settings.totp.confirmed
assert settings.backup_codes == ["1", "2", "3"]
assert conn
|> put_req_header("authorization", "Bearer #{token2.token}")
|> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "test", code: code})
|> json_response(403) == %{
"error" => "Insufficient permissions: write:security."
}
end
test "returns error if password incorrect", %{conn: conn} do
secret = TOTP.generate_secret()
code = TOTP.generate_token(secret)
user =
insert(:user,
multi_factor_authentication_settings: %Settings{
backup_codes: ["1", "2", "3"],
totp: %Settings.TOTP{secret: secret}
}
)
token = insert(:oauth_token, scopes: ["write", "follow"], user: user)
response =
conn
|> put_req_header("authorization", "Bearer #{token.token}")
|> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "xxx", code: code})
|> json_response(422)
settings = refresh_record(user).multi_factor_authentication_settings
refute settings.enabled
refute settings.totp.confirmed
assert settings.backup_codes == ["1", "2", "3"]
assert response == %{"error" => "Invalid password."}
end
test "returns error if code incorrect", %{conn: conn} do
secret = TOTP.generate_secret()
user =
insert(:user,
multi_factor_authentication_settings: %Settings{
backup_codes: ["1", "2", "3"],
totp: %Settings.TOTP{secret: secret}
}
)
token = insert(:oauth_token, scopes: ["write", "follow"], user: user)
token2 = insert(:oauth_token, scopes: ["read"])
response =
conn
|> put_req_header("authorization", "Bearer #{token.token}")
|> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "test", code: "code"})
|> json_response(422)
settings = refresh_record(user).multi_factor_authentication_settings
refute settings.enabled
refute settings.totp.confirmed
assert settings.backup_codes == ["1", "2", "3"]
assert response == %{"error" => "invalid_token"}
assert conn
|> put_req_header("authorization", "Bearer #{token2.token}")
|> post("/api/pleroma/accounts/mfa/confirm/totp", %{password: "test", code: "code"})
|> json_response(403) == %{
"error" => "Insufficient permissions: write:security."
}
end
end
describe "DELETE /api/pleroma/accounts/mfa/totp" do
test "returns success result", %{conn: conn} do
user =
insert(:user,
multi_factor_authentication_settings: %Settings{
backup_codes: ["1", "2", "3"],
totp: %Settings.TOTP{secret: "secret"}
}
)
token = insert(:oauth_token, scopes: ["write", "follow"], user: user)
token2 = insert(:oauth_token, scopes: ["read"])
assert conn
|> put_req_header("authorization", "Bearer #{token.token}")
|> delete("/api/pleroma/accounts/mfa/totp", %{password: "test"})
|> json_response(:ok)
settings = refresh_record(user).multi_factor_authentication_settings
refute settings.enabled
assert settings.totp.secret == nil
refute settings.totp.confirmed
assert conn
|> put_req_header("authorization", "Bearer #{token2.token}")
|> delete("/api/pleroma/accounts/mfa/totp", %{password: "test"})
|> json_response(403) == %{
"error" => "Insufficient permissions: write:security."
}
end
end
end

View file

@ -0,0 +1,91 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.PlugTest do
@moduledoc "Tests for the functionality added via `use Pleroma.Web, :plug`"
alias Pleroma.Plugs.ExpectAuthenticatedCheckPlug
alias Pleroma.Plugs.ExpectPublicOrAuthenticatedCheckPlug
alias Pleroma.Plugs.PlugHelper
import Mock
use Pleroma.Web.ConnCase
describe "when plug is skipped, " do
setup_with_mocks(
[
{ExpectPublicOrAuthenticatedCheckPlug, [:passthrough], []}
],
%{conn: conn}
) do
conn = ExpectPublicOrAuthenticatedCheckPlug.skip_plug(conn)
%{conn: conn}
end
test "it neither adds plug to called plugs list nor calls `perform/2`, " <>
"regardless of :if_func / :unless_func options",
%{conn: conn} do
for opts <- [%{}, %{if_func: fn _ -> true end}, %{unless_func: fn _ -> false end}] do
ret_conn = ExpectPublicOrAuthenticatedCheckPlug.call(conn, opts)
refute called(ExpectPublicOrAuthenticatedCheckPlug.perform(:_, :_))
refute PlugHelper.plug_called?(ret_conn, ExpectPublicOrAuthenticatedCheckPlug)
end
end
end
describe "when plug is NOT skipped, " do
setup_with_mocks([{ExpectAuthenticatedCheckPlug, [:passthrough], []}]) do
:ok
end
test "with no pre-run checks, adds plug to called plugs list and calls `perform/2`", %{
conn: conn
} do
ret_conn = ExpectAuthenticatedCheckPlug.call(conn, %{})
assert called(ExpectAuthenticatedCheckPlug.perform(ret_conn, :_))
assert PlugHelper.plug_called?(ret_conn, ExpectAuthenticatedCheckPlug)
end
test "when :if_func option is given, calls the plug only if provided function evals tru-ish",
%{conn: conn} do
ret_conn = ExpectAuthenticatedCheckPlug.call(conn, %{if_func: fn _ -> false end})
refute called(ExpectAuthenticatedCheckPlug.perform(:_, :_))
refute PlugHelper.plug_called?(ret_conn, ExpectAuthenticatedCheckPlug)
ret_conn = ExpectAuthenticatedCheckPlug.call(conn, %{if_func: fn _ -> true end})
assert called(ExpectAuthenticatedCheckPlug.perform(ret_conn, :_))
assert PlugHelper.plug_called?(ret_conn, ExpectAuthenticatedCheckPlug)
end
test "if :unless_func option is given, calls the plug only if provided function evals falsy",
%{conn: conn} do
ret_conn = ExpectAuthenticatedCheckPlug.call(conn, %{unless_func: fn _ -> true end})
refute called(ExpectAuthenticatedCheckPlug.perform(:_, :_))
refute PlugHelper.plug_called?(ret_conn, ExpectAuthenticatedCheckPlug)
ret_conn = ExpectAuthenticatedCheckPlug.call(conn, %{unless_func: fn _ -> false end})
assert called(ExpectAuthenticatedCheckPlug.perform(ret_conn, :_))
assert PlugHelper.plug_called?(ret_conn, ExpectAuthenticatedCheckPlug)
end
test "allows a plug to be called multiple times (even if it's in called plugs list)", %{
conn: conn
} do
conn = ExpectAuthenticatedCheckPlug.call(conn, %{an_option: :value1})
assert called(ExpectAuthenticatedCheckPlug.perform(conn, %{an_option: :value1}))
assert PlugHelper.plug_called?(conn, ExpectAuthenticatedCheckPlug)
conn = ExpectAuthenticatedCheckPlug.call(conn, %{an_option: :value2})
assert called(ExpectAuthenticatedCheckPlug.perform(conn, %{an_option: :value2}))
end
end
end

View file

@ -1,36 +0,0 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.PingTest do
use Pleroma.DataCase
import Pleroma.Factory
alias Pleroma.Web.Streamer
setup do
start_supervised({Streamer.supervisor(), [ping_interval: 30]})
:ok
end
describe "sockets" do
setup do
user = insert(:user)
{:ok, %{user: user}}
end
test "it sends pings", %{user: user} do
task =
Task.async(fn ->
assert_receive {:text, received_event}, 40
assert_receive {:text, received_event}, 40
assert_receive {:text, received_event}, 40
end)
Streamer.add_socket("public", %{transport_pid: task.pid, assigns: %{user: user}})
Task.await(task)
end
end
end

View file

@ -1,54 +0,0 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.StateTest do
use Pleroma.DataCase
import Pleroma.Factory
alias Pleroma.Web.Streamer
alias Pleroma.Web.Streamer.StreamerSocket
@moduletag needs_streamer: true
describe "sockets" do
setup do
user = insert(:user)
user2 = insert(:user)
{:ok, %{user: user, user2: user2}}
end
test "it can add a socket", %{user: user} do
Streamer.add_socket("public", %{transport_pid: 1, assigns: %{user: user}})
assert(%{"public" => [%StreamerSocket{transport_pid: 1}]} = Streamer.get_sockets())
end
test "it can add multiple sockets per user", %{user: user} do
Streamer.add_socket("public", %{transport_pid: 1, assigns: %{user: user}})
Streamer.add_socket("public", %{transport_pid: 2, assigns: %{user: user}})
assert(
%{
"public" => [
%StreamerSocket{transport_pid: 2},
%StreamerSocket{transport_pid: 1}
]
} = Streamer.get_sockets()
)
end
test "it will not add a duplicate socket", %{user: user} do
Streamer.add_socket("activity", %{transport_pid: 1, assigns: %{user: user}})
Streamer.add_socket("activity", %{transport_pid: 1, assigns: %{user: user}})
assert(
%{
"activity" => [
%StreamerSocket{transport_pid: 1}
]
} = Streamer.get_sockets()
)
end
end
end

View file

@ -12,13 +12,9 @@ defmodule Pleroma.Web.StreamerTest do
alias Pleroma.User
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.Streamer
alias Pleroma.Web.Streamer.StreamerSocket
alias Pleroma.Web.Streamer.Worker
@moduletag needs_streamer: true, capture_log: true
@streamer_timeout 150
@streamer_start_wait 10
setup do: clear_config([:instance, :skip_thread_containment])
describe "user streams" do
@ -29,69 +25,35 @@ defmodule Pleroma.Web.StreamerTest do
end
test "it streams the user's post in the 'user' stream", %{user: user} do
task =
Task.async(fn ->
assert_receive {:text, _}, @streamer_timeout
end)
Streamer.add_socket(
"user",
%{transport_pid: task.pid, assigns: %{user: user}}
)
Streamer.add_socket("user", user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "hey"})
Streamer.stream("user", activity)
Task.await(task)
assert_receive {:render_with_user, _, _, ^activity}
refute Streamer.filtered_by_user?(user, activity)
end
test "it streams boosts of the user in the 'user' stream", %{user: user} do
task =
Task.async(fn ->
assert_receive {:text, _}, @streamer_timeout
end)
Streamer.add_socket(
"user",
%{transport_pid: task.pid, assigns: %{user: user}}
)
Streamer.add_socket("user", user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(other_user, %{"status" => "hey"})
{:ok, announce, _} = CommonAPI.repeat(activity.id, user)
Streamer.stream("user", announce)
Task.await(task)
assert_receive {:render_with_user, Pleroma.Web.StreamerView, "update.json", ^announce}
refute Streamer.filtered_by_user?(user, announce)
end
test "it sends notify to in the 'user' stream", %{user: user, notify: notify} do
task =
Task.async(fn ->
assert_receive {:text, _}, @streamer_timeout
end)
Streamer.add_socket(
"user",
%{transport_pid: task.pid, assigns: %{user: user}}
)
Streamer.add_socket("user", user)
Streamer.stream("user", notify)
Task.await(task)
assert_receive {:render_with_user, _, _, ^notify}
refute Streamer.filtered_by_user?(user, notify)
end
test "it sends notify to in the 'user:notification' stream", %{user: user, notify: notify} do
task =
Task.async(fn ->
assert_receive {:text, _}, @streamer_timeout
end)
Streamer.add_socket(
"user:notification",
%{transport_pid: task.pid, assigns: %{user: user}}
)
Streamer.add_socket("user:notification", user)
Streamer.stream("user:notification", notify)
Task.await(task)
assert_receive {:render_with_user, _, _, ^notify}
refute Streamer.filtered_by_user?(user, notify)
end
test "it doesn't send notify to the 'user:notification' stream when a user is blocked", %{
@ -100,18 +62,12 @@ defmodule Pleroma.Web.StreamerTest do
blocked = insert(:user)
{:ok, _user_relationship} = User.block(user, blocked)
task = Task.async(fn -> refute_receive {:text, _}, @streamer_timeout end)
Streamer.add_socket(
"user:notification",
%{transport_pid: task.pid, assigns: %{user: user}}
)
Streamer.add_socket("user:notification", user)
{:ok, activity} = CommonAPI.post(user, %{"status" => ":("})
{:ok, notif} = CommonAPI.favorite(blocked, activity.id)
{:ok, _} = CommonAPI.favorite(blocked, activity.id)
Streamer.stream("user:notification", notif)
Task.await(task)
refute_receive _
end
test "it doesn't send notify to the 'user:notification' stream when a thread is muted", %{
@ -119,45 +75,50 @@ defmodule Pleroma.Web.StreamerTest do
} do
user2 = insert(:user)
task = Task.async(fn -> refute_receive {:text, _}, @streamer_timeout end)
Streamer.add_socket(
"user:notification",
%{transport_pid: task.pid, assigns: %{user: user}}
)
{:ok, activity} = CommonAPI.post(user, %{"status" => "super hot take"})
{:ok, activity} = CommonAPI.add_mute(user, activity)
{:ok, notif} = CommonAPI.favorite(user2, activity.id)
{:ok, _} = CommonAPI.add_mute(user, activity)
Streamer.stream("user:notification", notif)
Task.await(task)
Streamer.add_socket("user:notification", user)
{:ok, favorite_activity} = CommonAPI.favorite(user2, activity.id)
refute_receive _
assert Streamer.filtered_by_user?(user, favorite_activity)
end
test "it doesn't send notify to the 'user:notification' stream' when a domain is blocked", %{
test "it sends favorite to 'user:notification' stream'", %{
user: user
} do
user2 = insert(:user, %{ap_id: "https://hecking-lewd-place.com/user/meanie"})
task = Task.async(fn -> refute_receive {:text, _}, @streamer_timeout end)
{:ok, activity} = CommonAPI.post(user, %{"status" => "super hot take"})
Streamer.add_socket("user:notification", user)
{:ok, favorite_activity} = CommonAPI.favorite(user2, activity.id)
Streamer.add_socket(
"user:notification",
%{transport_pid: task.pid, assigns: %{user: user}}
)
assert_receive {:render_with_user, _, "notification.json", notif}
assert notif.activity.id == favorite_activity.id
refute Streamer.filtered_by_user?(user, notif)
end
test "it doesn't send the 'user:notification' stream' when a domain is blocked", %{
user: user
} do
user2 = insert(:user, %{ap_id: "https://hecking-lewd-place.com/user/meanie"})
{:ok, user} = User.block_domain(user, "hecking-lewd-place.com")
{:ok, activity} = CommonAPI.post(user, %{"status" => "super hot take"})
{:ok, notif} = CommonAPI.favorite(user2, activity.id)
Streamer.add_socket("user:notification", user)
{:ok, favorite_activity} = CommonAPI.favorite(user2, activity.id)
Streamer.stream("user:notification", notif)
Task.await(task)
refute_receive _
assert Streamer.filtered_by_user?(user, favorite_activity)
end
test "it sends follow activities to the 'user:notification' stream", %{
user: user
} do
user_url = user.ap_id
user2 = insert(:user)
body =
File.read!("test/fixtures/users_mock/localhost.json")
@ -169,79 +130,57 @@ defmodule Pleroma.Web.StreamerTest do
%Tesla.Env{status: 200, body: body}
end)
user2 = insert(:user)
task = Task.async(fn -> assert_receive {:text, _}, @streamer_timeout end)
Streamer.add_socket("user:notification", user)
{:ok, _follower, _followed, follow_activity} = CommonAPI.follow(user2, user)
Process.sleep(@streamer_start_wait)
Streamer.add_socket(
"user:notification",
%{transport_pid: task.pid, assigns: %{user: user}}
)
{:ok, _follower, _followed, _activity} = CommonAPI.follow(user2, user)
# We don't directly pipe the notification to the streamer as it's already
# generated as a side effect of CommonAPI.follow().
Task.await(task)
assert_receive {:render_with_user, _, "notification.json", notif}
assert notif.activity.id == follow_activity.id
refute Streamer.filtered_by_user?(user, notif)
end
end
test "it sends to public" do
test "it sends to public authenticated" do
user = insert(:user)
other_user = insert(:user)
task =
Task.async(fn ->
assert_receive {:text, _}, @streamer_timeout
end)
Streamer.add_socket("public", other_user)
fake_socket = %StreamerSocket{
transport_pid: task.pid,
user: user
}
{:ok, activity} = CommonAPI.post(user, %{"status" => "Test"})
assert_receive {:render_with_user, _, _, ^activity}
refute Streamer.filtered_by_user?(user, activity)
end
test "works for deletions" do
user = insert(:user)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(other_user, %{"status" => "Test"})
topics = %{
"public" => [fake_socket]
}
Streamer.add_socket("public", user)
Worker.push_to_socket(topics, "public", activity)
{:ok, _} = CommonAPI.delete(activity.id, other_user)
activity_id = activity.id
assert_receive {:text, event}
assert %{"event" => "delete", "payload" => ^activity_id} = Jason.decode!(event)
end
Task.await(task)
test "it sends to public unauthenticated" do
user = insert(:user)
task =
Task.async(fn ->
expected_event =
%{
"event" => "delete",
"payload" => activity.id
}
|> Jason.encode!()
Streamer.add_socket("public", nil)
assert_receive {:text, received_event}, @streamer_timeout
assert received_event == expected_event
end)
{:ok, activity} = CommonAPI.post(user, %{"status" => "Test"})
activity_id = activity.id
assert_receive {:text, event}
assert %{"event" => "update", "payload" => payload} = Jason.decode!(event)
assert %{"id" => ^activity_id} = Jason.decode!(payload)
fake_socket = %StreamerSocket{
transport_pid: task.pid,
user: user
}
{:ok, activity} = CommonAPI.delete(activity.id, other_user)
topics = %{
"public" => [fake_socket]
}
Worker.push_to_socket(topics, "public", activity)
Task.await(task)
{:ok, _} = CommonAPI.delete(activity.id, user)
assert_receive {:text, event}
assert %{"event" => "delete", "payload" => ^activity_id} = Jason.decode!(event)
end
describe "thread_containment" do
test "it doesn't send to user if recipients invalid and thread containment is enabled" do
test "it filters to user if recipients invalid and thread containment is enabled" do
Pleroma.Config.put([:instance, :skip_thread_containment], false)
author = insert(:user)
user = insert(:user)
@ -256,12 +195,10 @@ defmodule Pleroma.Web.StreamerTest do
)
)
task = Task.async(fn -> refute_receive {:text, _}, 1_000 end)
fake_socket = %StreamerSocket{transport_pid: task.pid, user: user}
topics = %{"public" => [fake_socket]}
Worker.push_to_socket(topics, "public", activity)
Task.await(task)
Streamer.add_socket("public", user)
Streamer.stream("public", activity)
assert_receive {:render_with_user, _, _, ^activity}
assert Streamer.filtered_by_user?(user, activity)
end
test "it sends message if recipients invalid and thread containment is disabled" do
@ -279,12 +216,11 @@ defmodule Pleroma.Web.StreamerTest do
)
)
task = Task.async(fn -> assert_receive {:text, _}, 1_000 end)
fake_socket = %StreamerSocket{transport_pid: task.pid, user: user}
topics = %{"public" => [fake_socket]}
Worker.push_to_socket(topics, "public", activity)
Streamer.add_socket("public", user)
Streamer.stream("public", activity)
Task.await(task)
assert_receive {:render_with_user, _, _, ^activity}
refute Streamer.filtered_by_user?(user, activity)
end
test "it sends message if recipients invalid and thread containment is enabled but user's thread containment is disabled" do
@ -302,255 +238,168 @@ defmodule Pleroma.Web.StreamerTest do
)
)
task = Task.async(fn -> assert_receive {:text, _}, 1_000 end)
fake_socket = %StreamerSocket{transport_pid: task.pid, user: user}
topics = %{"public" => [fake_socket]}
Worker.push_to_socket(topics, "public", activity)
Streamer.add_socket("public", user)
Streamer.stream("public", activity)
Task.await(task)
assert_receive {:render_with_user, _, _, ^activity}
refute Streamer.filtered_by_user?(user, activity)
end
end
describe "blocks" do
test "it doesn't send messages involving blocked users" do
test "it filters messages involving blocked users" do
user = insert(:user)
blocked_user = insert(:user)
{:ok, _user_relationship} = User.block(user, blocked_user)
Streamer.add_socket("public", user)
{:ok, activity} = CommonAPI.post(blocked_user, %{"status" => "Test"})
task =
Task.async(fn ->
refute_receive {:text, _}, 1_000
end)
fake_socket = %StreamerSocket{
transport_pid: task.pid,
user: user
}
topics = %{
"public" => [fake_socket]
}
Worker.push_to_socket(topics, "public", activity)
Task.await(task)
assert_receive {:render_with_user, _, _, ^activity}
assert Streamer.filtered_by_user?(user, activity)
end
test "it doesn't send messages transitively involving blocked users" do
test "it filters messages transitively involving blocked users" do
blocker = insert(:user)
blockee = insert(:user)
friend = insert(:user)
task =
Task.async(fn ->
refute_receive {:text, _}, 1_000
end)
fake_socket = %StreamerSocket{
transport_pid: task.pid,
user: blocker
}
topics = %{
"public" => [fake_socket]
}
Streamer.add_socket("public", blocker)
{:ok, _user_relationship} = User.block(blocker, blockee)
{:ok, activity_one} = CommonAPI.post(friend, %{"status" => "hey! @#{blockee.nickname}"})
Worker.push_to_socket(topics, "public", activity_one)
assert_receive {:render_with_user, _, _, ^activity_one}
assert Streamer.filtered_by_user?(blocker, activity_one)
{:ok, activity_two} = CommonAPI.post(blockee, %{"status" => "hey! @#{friend.nickname}"})
Worker.push_to_socket(topics, "public", activity_two)
assert_receive {:render_with_user, _, _, ^activity_two}
assert Streamer.filtered_by_user?(blocker, activity_two)
{:ok, activity_three} = CommonAPI.post(blockee, %{"status" => "hey! @#{blocker.nickname}"})
Worker.push_to_socket(topics, "public", activity_three)
Task.await(task)
assert_receive {:render_with_user, _, _, ^activity_three}
assert Streamer.filtered_by_user?(blocker, activity_three)
end
end
test "it doesn't send unwanted DMs to list" do
user_a = insert(:user)
user_b = insert(:user)
user_c = insert(:user)
describe "lists" do
test "it doesn't send unwanted DMs to list" do
user_a = insert(:user)
user_b = insert(:user)
user_c = insert(:user)
{:ok, user_a} = User.follow(user_a, user_b)
{:ok, user_a} = User.follow(user_a, user_b)
{:ok, list} = List.create("Test", user_a)
{:ok, list} = List.follow(list, user_b)
{:ok, list} = List.create("Test", user_a)
{:ok, list} = List.follow(list, user_b)
{:ok, activity} =
CommonAPI.post(user_b, %{
"status" => "@#{user_c.nickname} Test",
"visibility" => "direct"
})
Streamer.add_socket("list:#{list.id}", user_a)
task =
Task.async(fn ->
refute_receive {:text, _}, 1_000
end)
{:ok, _activity} =
CommonAPI.post(user_b, %{
"status" => "@#{user_c.nickname} Test",
"visibility" => "direct"
})
fake_socket = %StreamerSocket{
transport_pid: task.pid,
user: user_a
}
refute_receive _
end
topics = %{
"list:#{list.id}" => [fake_socket]
}
test "it doesn't send unwanted private posts to list" do
user_a = insert(:user)
user_b = insert(:user)
Worker.handle_call({:stream, "list", activity}, self(), topics)
{:ok, list} = List.create("Test", user_a)
{:ok, list} = List.follow(list, user_b)
Task.await(task)
Streamer.add_socket("list:#{list.id}", user_a)
{:ok, _activity} =
CommonAPI.post(user_b, %{
"status" => "Test",
"visibility" => "private"
})
refute_receive _
end
test "it sends wanted private posts to list" do
user_a = insert(:user)
user_b = insert(:user)
{:ok, user_a} = User.follow(user_a, user_b)
{:ok, list} = List.create("Test", user_a)
{:ok, list} = List.follow(list, user_b)
Streamer.add_socket("list:#{list.id}", user_a)
{:ok, activity} =
CommonAPI.post(user_b, %{
"status" => "Test",
"visibility" => "private"
})
assert_receive {:render_with_user, _, _, ^activity}
refute Streamer.filtered_by_user?(user_a, activity)
end
end
test "it doesn't send unwanted private posts to list" do
user_a = insert(:user)
user_b = insert(:user)
describe "muted reblogs" do
test "it filters muted reblogs" do
user1 = insert(:user)
user2 = insert(:user)
user3 = insert(:user)
CommonAPI.follow(user1, user2)
CommonAPI.hide_reblogs(user1, user2)
{:ok, list} = List.create("Test", user_a)
{:ok, list} = List.follow(list, user_b)
{:ok, create_activity} = CommonAPI.post(user3, %{"status" => "I'm kawen"})
{:ok, activity} =
CommonAPI.post(user_b, %{
"status" => "Test",
"visibility" => "private"
})
Streamer.add_socket("user", user1)
{:ok, announce_activity, _} = CommonAPI.repeat(create_activity.id, user2)
assert_receive {:render_with_user, _, _, ^announce_activity}
assert Streamer.filtered_by_user?(user1, announce_activity)
end
task =
Task.async(fn ->
refute_receive {:text, _}, 1_000
end)
test "it filters reblog notification for reblog-muted actors" do
user1 = insert(:user)
user2 = insert(:user)
CommonAPI.follow(user1, user2)
CommonAPI.hide_reblogs(user1, user2)
fake_socket = %StreamerSocket{
transport_pid: task.pid,
user: user_a
}
{:ok, create_activity} = CommonAPI.post(user1, %{"status" => "I'm kawen"})
Streamer.add_socket("user", user1)
{:ok, _favorite_activity, _} = CommonAPI.repeat(create_activity.id, user2)
topics = %{
"list:#{list.id}" => [fake_socket]
}
assert_receive {:render_with_user, _, "notification.json", notif}
assert Streamer.filtered_by_user?(user1, notif)
end
Worker.handle_call({:stream, "list", activity}, self(), topics)
test "it send non-reblog notification for reblog-muted actors" do
user1 = insert(:user)
user2 = insert(:user)
CommonAPI.follow(user1, user2)
CommonAPI.hide_reblogs(user1, user2)
Task.await(task)
{:ok, create_activity} = CommonAPI.post(user1, %{"status" => "I'm kawen"})
Streamer.add_socket("user", user1)
{:ok, _favorite_activity} = CommonAPI.favorite(user2, create_activity.id)
assert_receive {:render_with_user, _, "notification.json", notif}
refute Streamer.filtered_by_user?(user1, notif)
end
end
test "it sends wanted private posts to list" do
user_a = insert(:user)
user_b = insert(:user)
{:ok, user_a} = User.follow(user_a, user_b)
{:ok, list} = List.create("Test", user_a)
{:ok, list} = List.follow(list, user_b)
{:ok, activity} =
CommonAPI.post(user_b, %{
"status" => "Test",
"visibility" => "private"
})
task =
Task.async(fn ->
assert_receive {:text, _}, 1_000
end)
fake_socket = %StreamerSocket{
transport_pid: task.pid,
user: user_a
}
Streamer.add_socket(
"list:#{list.id}",
fake_socket
)
Worker.handle_call({:stream, "list", activity}, self(), %{})
Task.await(task)
end
test "it doesn't send muted reblogs" do
user1 = insert(:user)
user2 = insert(:user)
user3 = insert(:user)
CommonAPI.hide_reblogs(user1, user2)
{:ok, create_activity} = CommonAPI.post(user3, %{"status" => "I'm kawen"})
{:ok, announce_activity, _} = CommonAPI.repeat(create_activity.id, user2)
task =
Task.async(fn ->
refute_receive {:text, _}, 1_000
end)
fake_socket = %StreamerSocket{
transport_pid: task.pid,
user: user1
}
topics = %{
"public" => [fake_socket]
}
Worker.push_to_socket(topics, "public", announce_activity)
Task.await(task)
end
test "it does send non-reblog notification for reblog-muted actors" do
user1 = insert(:user)
user2 = insert(:user)
user3 = insert(:user)
CommonAPI.hide_reblogs(user1, user2)
{:ok, create_activity} = CommonAPI.post(user3, %{"status" => "I'm kawen"})
{:ok, favorite_activity} = CommonAPI.favorite(user2, create_activity.id)
task =
Task.async(fn ->
assert_receive {:text, _}, 1_000
end)
fake_socket = %StreamerSocket{
transport_pid: task.pid,
user: user1
}
topics = %{
"public" => [fake_socket]
}
Worker.push_to_socket(topics, "public", favorite_activity)
Task.await(task)
end
test "it doesn't send posts from muted threads" do
test "it filters posts from muted threads" do
user = insert(:user)
user2 = insert(:user)
Streamer.add_socket("user", user2)
{:ok, user2, user, _activity} = CommonAPI.follow(user2, user)
{:ok, activity} = CommonAPI.post(user, %{"status" => "super hot take"})
{:ok, activity} = CommonAPI.add_mute(user2, activity)
task = Task.async(fn -> refute_receive {:text, _}, @streamer_timeout end)
Streamer.add_socket(
"user",
%{transport_pid: task.pid, assigns: %{user: user2}}
)
Streamer.stream("user", activity)
Task.await(task)
{:ok, _} = CommonAPI.add_mute(user2, activity)
assert_receive {:render_with_user, _, _, ^activity}
assert Streamer.filtered_by_user?(user2, activity)
end
describe "direct streams" do
@ -562,22 +411,7 @@ defmodule Pleroma.Web.StreamerTest do
user = insert(:user)
another_user = insert(:user)
task =
Task.async(fn ->
assert_receive {:text, received_event}, @streamer_timeout
assert %{"event" => "conversation", "payload" => received_payload} =
Jason.decode!(received_event)
assert %{"last_status" => last_status} = Jason.decode!(received_payload)
[participation] = Participation.for_user(user)
assert last_status["pleroma"]["direct_conversation_id"] == participation.id
end)
Streamer.add_socket(
"direct",
%{transport_pid: task.pid, assigns: %{user: user}}
)
Streamer.add_socket("direct", user)
{:ok, _create_activity} =
CommonAPI.post(another_user, %{
@ -585,42 +419,47 @@ defmodule Pleroma.Web.StreamerTest do
"visibility" => "direct"
})
Task.await(task)
assert_receive {:text, received_event}
assert %{"event" => "conversation", "payload" => received_payload} =
Jason.decode!(received_event)
assert %{"last_status" => last_status} = Jason.decode!(received_payload)
[participation] = Participation.for_user(user)
assert last_status["pleroma"]["direct_conversation_id"] == participation.id
end
test "it doesn't send conversation update to the 'direct' stream when the last message in the conversation is deleted" do
user = insert(:user)
another_user = insert(:user)
Streamer.add_socket("direct", user)
{:ok, create_activity} =
CommonAPI.post(another_user, %{
"status" => "hi @#{user.nickname}",
"visibility" => "direct"
})
task =
Task.async(fn ->
assert_receive {:text, received_event}, @streamer_timeout
assert %{"event" => "delete", "payload" => _} = Jason.decode!(received_event)
create_activity_id = create_activity.id
assert_receive {:render_with_user, _, _, ^create_activity}
assert_receive {:text, received_conversation1}
assert %{"event" => "conversation", "payload" => _} = Jason.decode!(received_conversation1)
refute_receive {:text, _}, @streamer_timeout
end)
{:ok, _} = CommonAPI.delete(create_activity_id, another_user)
Process.sleep(@streamer_start_wait)
assert_receive {:text, received_event}
Streamer.add_socket(
"direct",
%{transport_pid: task.pid, assigns: %{user: user}}
)
assert %{"event" => "delete", "payload" => ^create_activity_id} =
Jason.decode!(received_event)
{:ok, _} = CommonAPI.delete(create_activity.id, another_user)
Task.await(task)
refute_receive _
end
test "it sends conversation update to the 'direct' stream when a message is deleted" do
user = insert(:user)
another_user = insert(:user)
Streamer.add_socket("direct", user)
{:ok, create_activity} =
CommonAPI.post(another_user, %{
@ -630,35 +469,30 @@ defmodule Pleroma.Web.StreamerTest do
{:ok, create_activity2} =
CommonAPI.post(another_user, %{
"status" => "hi @#{user.nickname}",
"status" => "hi @#{user.nickname} 2",
"in_reply_to_status_id" => create_activity.id,
"visibility" => "direct"
})
task =
Task.async(fn ->
assert_receive {:text, received_event}, @streamer_timeout
assert %{"event" => "delete", "payload" => _} = Jason.decode!(received_event)
assert_receive {:text, received_event}, @streamer_timeout
assert %{"event" => "conversation", "payload" => received_payload} =
Jason.decode!(received_event)
assert %{"last_status" => last_status} = Jason.decode!(received_payload)
assert last_status["id"] == to_string(create_activity.id)
end)
Process.sleep(@streamer_start_wait)
Streamer.add_socket(
"direct",
%{transport_pid: task.pid, assigns: %{user: user}}
)
assert_receive {:render_with_user, _, _, ^create_activity}
assert_receive {:render_with_user, _, _, ^create_activity2}
assert_receive {:text, received_conversation1}
assert %{"event" => "conversation", "payload" => _} = Jason.decode!(received_conversation1)
assert_receive {:text, received_conversation1}
assert %{"event" => "conversation", "payload" => _} = Jason.decode!(received_conversation1)
{:ok, _} = CommonAPI.delete(create_activity2.id, another_user)
Task.await(task)
assert_receive {:text, received_event}
assert %{"event" => "delete", "payload" => _} = Jason.decode!(received_event)
assert_receive {:text, received_event}
assert %{"event" => "conversation", "payload" => received_payload} =
Jason.decode!(received_event)
assert %{"last_status" => last_status} = Jason.decode!(received_payload)
assert last_status["id"] == to_string(create_activity.id)
end
end
end

View file

@ -6,11 +6,14 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do
use Pleroma.Web.ConnCase
alias Pleroma.Config
alias Pleroma.MFA
alias Pleroma.MFA.TOTP
alias Pleroma.User
alias Pleroma.Web.CommonAPI
import ExUnit.CaptureLog
import Pleroma.Factory
import Ecto.Query
setup do
Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
@ -160,6 +163,119 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do
end
end
describe "POST /ostatus_subscribe - follow/2 with enabled Two-Factor Auth " do
test "render the MFA login form", %{conn: conn} do
otp_secret = TOTP.generate_secret()
user =
insert(:user,
multi_factor_authentication_settings: %MFA.Settings{
enabled: true,
totp: %MFA.Settings.TOTP{secret: otp_secret, confirmed: true}
}
)
user2 = insert(:user)
response =
conn
|> post(remote_follow_path(conn, :do_follow), %{
"authorization" => %{"name" => user.nickname, "password" => "test", "id" => user2.id}
})
|> response(200)
mfa_token = Pleroma.Repo.one(from(q in Pleroma.MFA.Token, where: q.user_id == ^user.id))
assert response =~ "Two-factor authentication"
assert response =~ "Authentication code"
assert response =~ mfa_token.token
refute user2.follower_address in User.following(user)
end
test "returns error when password is incorrect", %{conn: conn} do
otp_secret = TOTP.generate_secret()
user =
insert(:user,
multi_factor_authentication_settings: %MFA.Settings{
enabled: true,
totp: %MFA.Settings.TOTP{secret: otp_secret, confirmed: true}
}
)
user2 = insert(:user)
response =
conn
|> post(remote_follow_path(conn, :do_follow), %{
"authorization" => %{"name" => user.nickname, "password" => "test1", "id" => user2.id}
})
|> response(200)
assert response =~ "Wrong username or password"
refute user2.follower_address in User.following(user)
end
test "follows", %{conn: conn} do
otp_secret = TOTP.generate_secret()
user =
insert(:user,
multi_factor_authentication_settings: %MFA.Settings{
enabled: true,
totp: %MFA.Settings.TOTP{secret: otp_secret, confirmed: true}
}
)
{:ok, %{token: token}} = MFA.Token.create_token(user)
user2 = insert(:user)
otp_token = TOTP.generate_token(otp_secret)
conn =
conn
|> post(
remote_follow_path(conn, :do_follow),
%{
"mfa" => %{"code" => otp_token, "token" => token, "id" => user2.id}
}
)
assert redirected_to(conn) == "/users/#{user2.id}"
assert user2.follower_address in User.following(user)
end
test "returns error when auth code is incorrect", %{conn: conn} do
otp_secret = TOTP.generate_secret()
user =
insert(:user,
multi_factor_authentication_settings: %MFA.Settings{
enabled: true,
totp: %MFA.Settings.TOTP{secret: otp_secret, confirmed: true}
}
)
{:ok, %{token: token}} = MFA.Token.create_token(user)
user2 = insert(:user)
otp_token = TOTP.generate_token(TOTP.generate_secret())
response =
conn
|> post(
remote_follow_path(conn, :do_follow),
%{
"mfa" => %{"code" => otp_token, "token" => token, "id" => user2.id}
}
)
|> response(200)
assert response =~ "Wrong authentication code"
refute user2.follower_address in User.following(user)
end
end
describe "POST /ostatus_subscribe - follow/2 without assigned user " do
test "follows", %{conn: conn} do
user = insert(:user)

View file

@ -67,7 +67,7 @@ defmodule Pleroma.Web.WebFingerTest do
assert data["magic_key"] == nil
assert data["salmon"] == nil
assert data["topic"] == "https://mstdn.jp/users/kPherox.atom"
assert data["topic"] == nil
assert data["subject"] == "acct:kPherox@mstdn.jp"
assert data["ap_id"] == "https://mstdn.jp/users/kPherox"
assert data["subscribe_address"] == "https://mstdn.jp/authorize_interaction?acct={uri}"