Merge remote-tracking branch 'origin/develop' into fork
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
commit
95edffdb19
21 changed files with 334 additions and 63 deletions
1
changelog.d/hashtag-feeds-restricted.add
Normal file
1
changelog.d/hashtag-feeds-restricted.add
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Repesct :restrict_unauthenticated for hashtag rss/atom feeds
|
1
changelog.d/incoming-blocks.fix
Normal file
1
changelog.d/incoming-blocks.fix
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Fix incoming Block activities being rejected
|
1
changelog.d/ldap-password-change.add
Normal file
1
changelog.d/ldap-password-change.add
Normal file
|
@ -0,0 +1 @@
|
||||||
|
LDAP now supports users changing their passwords
|
1
changelog.d/remote-report-policy.add
Normal file
1
changelog.d/remote-report-policy.add
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Added RemoteReportPolicy from Rebased for handling bogus federated reports
|
7
installation/openldap/pw_self_service.ldif
Normal file
7
installation/openldap/pw_self_service.ldif
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
dn: olcDatabase={1}mdb,cn=config
|
||||||
|
changetype: modify
|
||||||
|
add: olcAccess
|
||||||
|
olcAccess: {1}to attrs=userPassword
|
||||||
|
by self write
|
||||||
|
by anonymous auth
|
||||||
|
by * none
|
|
@ -102,6 +102,7 @@ defmodule Pleroma.Constants do
|
||||||
|
|
||||||
const(activity_types,
|
const(activity_types,
|
||||||
do: [
|
do: [
|
||||||
|
"Block",
|
||||||
"Create",
|
"Create",
|
||||||
"Update",
|
"Update",
|
||||||
"Delete",
|
"Delete",
|
||||||
|
@ -130,6 +131,10 @@ defmodule Pleroma.Constants do
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const(object_types,
|
||||||
|
do: ~w[Event Question Answer Audio Video Image Article Note Page ChatMessage]
|
||||||
|
)
|
||||||
|
|
||||||
# basic regex, just there to weed out potential mistakes
|
# basic regex, just there to weed out potential mistakes
|
||||||
# https://datatracker.ietf.org/doc/html/rfc2045#section-5.1
|
# https://datatracker.ietf.org/doc/html/rfc2045#section-5.1
|
||||||
const(mime_regex,
|
const(mime_regex,
|
||||||
|
|
|
@ -15,6 +15,14 @@ def start_link(_) do
|
||||||
GenServer.start_link(__MODULE__, [], name: __MODULE__)
|
GenServer.start_link(__MODULE__, [], name: __MODULE__)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def bind_user(name, password) do
|
||||||
|
GenServer.call(__MODULE__, {:bind_user, name, password})
|
||||||
|
end
|
||||||
|
|
||||||
|
def change_password(name, password, new_password) do
|
||||||
|
GenServer.call(__MODULE__, {:change_password, name, password, new_password})
|
||||||
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def init(state) do
|
def init(state) do
|
||||||
case {Config.get(Pleroma.Web.Auth.Authenticator), Config.get([:ldap, :enabled])} do
|
case {Config.get(Pleroma.Web.Auth.Authenticator), Config.get([:ldap, :enabled])} do
|
||||||
|
@ -47,13 +55,42 @@ def handle_continue(:connect, _state), do: do_handle_connect()
|
||||||
def handle_info(:connect, _state), do: do_handle_connect()
|
def handle_info(:connect, _state), do: do_handle_connect()
|
||||||
|
|
||||||
def handle_info({:bind_after_reconnect, name, password, from}, state) do
|
def handle_info({:bind_after_reconnect, name, password, from}, state) do
|
||||||
result = bind_user(state[:handle], name, password)
|
result = do_bind_user(state[:handle], name, password)
|
||||||
|
|
||||||
GenServer.reply(from, result)
|
GenServer.reply(from, result)
|
||||||
|
|
||||||
{:noreply, state}
|
{:noreply, state}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def handle_call({:bind_user, name, password}, from, state) do
|
||||||
|
case do_bind_user(state[:handle], name, password) do
|
||||||
|
:needs_reconnect ->
|
||||||
|
Process.send(self(), {:bind_after_reconnect, name, password, from}, [])
|
||||||
|
{:noreply, state, {:continue, :connect}}
|
||||||
|
|
||||||
|
result ->
|
||||||
|
{:reply, result, state, :hibernate}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_call({:change_password, name, password, new_password}, _from, state) do
|
||||||
|
result = change_password(state[:handle], name, password, new_password)
|
||||||
|
|
||||||
|
{:reply, result, state, :hibernate}
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def terminate(_, state) do
|
||||||
|
handle = Keyword.get(state, :handle)
|
||||||
|
|
||||||
|
if not is_nil(handle) do
|
||||||
|
:eldap.close(handle)
|
||||||
|
end
|
||||||
|
|
||||||
|
:ok
|
||||||
|
end
|
||||||
|
|
||||||
defp do_handle_connect do
|
defp do_handle_connect do
|
||||||
state =
|
state =
|
||||||
case connect() do
|
case connect() do
|
||||||
|
@ -71,33 +108,6 @@ defp do_handle_connect do
|
||||||
{:noreply, state}
|
{:noreply, state}
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
|
||||||
def handle_call({:bind_user, name, password}, from, state) do
|
|
||||||
case bind_user(state[:handle], name, password) do
|
|
||||||
:needs_reconnect ->
|
|
||||||
Process.send(self(), {:bind_after_reconnect, name, password, from}, [])
|
|
||||||
{:noreply, state, {:continue, :connect}}
|
|
||||||
|
|
||||||
result ->
|
|
||||||
{:reply, result, state, :hibernate}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@impl true
|
|
||||||
def terminate(_, state) do
|
|
||||||
handle = Keyword.get(state, :handle)
|
|
||||||
|
|
||||||
if not is_nil(handle) do
|
|
||||||
:eldap.close(handle)
|
|
||||||
end
|
|
||||||
|
|
||||||
:ok
|
|
||||||
end
|
|
||||||
|
|
||||||
def bind_user(name, password) do
|
|
||||||
GenServer.call(__MODULE__, {:bind_user, name, password})
|
|
||||||
end
|
|
||||||
|
|
||||||
defp connect do
|
defp connect do
|
||||||
ldap = Config.get(:ldap, [])
|
ldap = Config.get(:ldap, [])
|
||||||
host = Keyword.get(ldap, :host, "localhost")
|
host = Keyword.get(ldap, :host, "localhost")
|
||||||
|
@ -161,18 +171,17 @@ defp connect do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp bind_user(handle, name, password) do
|
defp do_bind_user(handle, name, password) do
|
||||||
uid = Config.get([:ldap, :uid], "cn")
|
dn = make_dn(name)
|
||||||
base = Config.get([:ldap, :base])
|
|
||||||
|
|
||||||
case :eldap.simple_bind(handle, "#{uid}=#{name},#{base}", password) do
|
case :eldap.simple_bind(handle, dn, password) do
|
||||||
:ok ->
|
:ok ->
|
||||||
case fetch_user(name) do
|
case fetch_user(name) do
|
||||||
%User{} = user ->
|
%User{} = user ->
|
||||||
user
|
user
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
register_user(handle, base, uid, name)
|
register_user(handle, ldap_base(), ldap_uid(), name)
|
||||||
end
|
end
|
||||||
|
|
||||||
# eldap does not inform us of socket closure
|
# eldap does not inform us of socket closure
|
||||||
|
@ -231,6 +240,14 @@ defp try_register(name, attributes) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp change_password(handle, name, password, new_password) do
|
||||||
|
dn = make_dn(name)
|
||||||
|
|
||||||
|
with :ok <- :eldap.simple_bind(handle, dn, password) do
|
||||||
|
:eldap.modify_password(handle, dn, to_charlist(new_password), to_charlist(password))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
defp decode_certfile(file) do
|
defp decode_certfile(file) do
|
||||||
with {:ok, data} <- File.read(file) do
|
with {:ok, data} <- File.read(file) do
|
||||||
data
|
data
|
||||||
|
@ -242,4 +259,13 @@ defp decode_certfile(file) do
|
||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp ldap_uid, do: to_charlist(Config.get([:ldap, :uid], "cn"))
|
||||||
|
defp ldap_base, do: to_charlist(Config.get([:ldap, :base]))
|
||||||
|
|
||||||
|
defp make_dn(name) do
|
||||||
|
uid = ldap_uid()
|
||||||
|
base = ldap_base()
|
||||||
|
~c"#{uid}=#{name},#{base}"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,6 +9,7 @@ def filter(%{"type" => "Flag"} = object) do
|
||||||
with {_, false} <- {:local, local?(object)},
|
with {_, false} <- {:local, local?(object)},
|
||||||
{:ok, _} <- maybe_reject_all(object),
|
{:ok, _} <- maybe_reject_all(object),
|
||||||
{:ok, _} <- maybe_reject_anonymous(object),
|
{:ok, _} <- maybe_reject_anonymous(object),
|
||||||
|
{:ok, _} <- maybe_reject_third_party(object),
|
||||||
{:ok, _} <- maybe_reject_empty_message(object) do
|
{:ok, _} <- maybe_reject_empty_message(object) do
|
||||||
{:ok, object}
|
{:ok, object}
|
||||||
else
|
else
|
||||||
|
@ -37,6 +38,22 @@ defp maybe_reject_anonymous(%{"actor" => actor} = object) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp maybe_reject_third_party(%{"object" => objects} = object) do
|
||||||
|
{_, to} =
|
||||||
|
case objects do
|
||||||
|
[head | tail] when is_binary(head) -> {tail, head}
|
||||||
|
s when is_binary(s) -> {[], s}
|
||||||
|
_ -> {[], ""}
|
||||||
|
end
|
||||||
|
|
||||||
|
with true <- Config.get([:mrf_remote_report, :reject_third_party]),
|
||||||
|
false <- String.starts_with?(to, Pleroma.Web.Endpoint.url()) do
|
||||||
|
{:reject, "[RemoteReportPolicy] Third-party: #{to}"}
|
||||||
|
else
|
||||||
|
_ -> {:ok, object}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
defp maybe_reject_empty_message(%{"content" => content} = object)
|
defp maybe_reject_empty_message(%{"content" => content} = object)
|
||||||
when is_binary(content) and content != "" do
|
when is_binary(content) and content != "" do
|
||||||
{:ok, object}
|
{:ok, object}
|
||||||
|
@ -83,6 +100,12 @@ def config_description do
|
||||||
description: "Reject anonymous remote reports?",
|
description: "Reject anonymous remote reports?",
|
||||||
suggestions: [true]
|
suggestions: [true]
|
||||||
},
|
},
|
||||||
|
%{
|
||||||
|
key: :reject_third_party,
|
||||||
|
type: :boolean,
|
||||||
|
description: "Reject reports on users from third-party instances?",
|
||||||
|
suggestions: [true]
|
||||||
|
},
|
||||||
%{
|
%{
|
||||||
key: :reject_empty_message,
|
key: :reject_empty_message,
|
||||||
type: :boolean,
|
type: :boolean,
|
||||||
|
|
|
@ -11,6 +11,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
|
||||||
|
|
||||||
@behaviour Pleroma.Web.ActivityPub.ObjectValidator.Validating
|
@behaviour Pleroma.Web.ActivityPub.ObjectValidator.Validating
|
||||||
|
|
||||||
|
import Pleroma.Constants, only: [activity_types: 0, object_types: 0]
|
||||||
|
|
||||||
alias Pleroma.Activity
|
alias Pleroma.Activity
|
||||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
|
@ -42,6 +44,16 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
|
||||||
@impl true
|
@impl true
|
||||||
def validate(object, meta)
|
def validate(object, meta)
|
||||||
|
|
||||||
|
# This overload works together with the InboxGuardPlug
|
||||||
|
# and ensures that we are not accepting any activity type
|
||||||
|
# that cannot pass InboxGuardPlug.
|
||||||
|
# If we want to support any more activity types, make sure to
|
||||||
|
# add it in Pleroma.Constants's activity_types or object_types,
|
||||||
|
# and, if applicable, allowed_activity_types_from_strangers.
|
||||||
|
def validate(%{"type" => type}, _meta)
|
||||||
|
when type not in activity_types() and type not in object_types(),
|
||||||
|
do: {:error, :not_allowed_object_type}
|
||||||
|
|
||||||
def validate(%{"type" => "Block"} = block_activity, meta) do
|
def validate(%{"type" => "Block"} = block_activity, meta) do
|
||||||
with {:ok, block_activity} <-
|
with {:ok, block_activity} <-
|
||||||
block_activity
|
block_activity
|
||||||
|
|
|
@ -10,4 +10,9 @@ defmodule Pleroma.Web.Auth.Authenticator do
|
||||||
@callback handle_error(Plug.Conn.t(), any()) :: any()
|
@callback handle_error(Plug.Conn.t(), any()) :: any()
|
||||||
@callback auth_template() :: String.t() | nil
|
@callback auth_template() :: String.t() | nil
|
||||||
@callback oauth_consumer_template() :: String.t() | nil
|
@callback oauth_consumer_template() :: String.t() | nil
|
||||||
|
|
||||||
|
@callback change_password(Pleroma.User.t(), String.t(), String.t(), String.t()) ::
|
||||||
|
{:ok, Pleroma.User.t()} | {:error, term()}
|
||||||
|
|
||||||
|
@optional_callbacks change_password: 4
|
||||||
end
|
end
|
||||||
|
|
|
@ -30,4 +30,13 @@ def get_user(%Plug.Conn{} = conn) do
|
||||||
error
|
error
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def change_password(user, password, new_password, new_password) do
|
||||||
|
case LDAP.change_password(user.nickname, password, new_password) do
|
||||||
|
:ok -> {:ok, user}
|
||||||
|
e -> e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def change_password(_, _, _, _), do: {:error, :password_confirmation}
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,6 +6,7 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do
|
||||||
alias Pleroma.Registration
|
alias Pleroma.Registration
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
alias Pleroma.Web.CommonAPI
|
||||||
alias Pleroma.Web.Plugs.AuthenticationPlug
|
alias Pleroma.Web.Plugs.AuthenticationPlug
|
||||||
|
|
||||||
import Pleroma.Web.Auth.Helpers, only: [fetch_credentials: 1, fetch_user: 1]
|
import Pleroma.Web.Auth.Helpers, only: [fetch_credentials: 1, fetch_user: 1]
|
||||||
|
@ -101,4 +102,23 @@ def handle_error(%Plug.Conn{} = _conn, error) do
|
||||||
def auth_template, do: nil
|
def auth_template, do: nil
|
||||||
|
|
||||||
def oauth_consumer_template, do: nil
|
def oauth_consumer_template, do: nil
|
||||||
|
|
||||||
|
@doc "Changes Pleroma.User password in the database"
|
||||||
|
def change_password(user, password, new_password, new_password) do
|
||||||
|
case CommonAPI.Utils.confirm_current_password(user, password) do
|
||||||
|
{:ok, user} ->
|
||||||
|
with {:ok, _user} <-
|
||||||
|
User.reset_password(user, %{
|
||||||
|
password: new_password,
|
||||||
|
password_confirmation: new_password
|
||||||
|
}) do
|
||||||
|
{:ok, user}
|
||||||
|
end
|
||||||
|
|
||||||
|
error ->
|
||||||
|
error
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def change_password(_, _, _, _), do: {:error, :password_confirmation}
|
||||||
end
|
end
|
||||||
|
|
|
@ -39,4 +39,8 @@ def oauth_consumer_template do
|
||||||
implementation().oauth_consumer_template() ||
|
implementation().oauth_consumer_template() ||
|
||||||
Pleroma.Config.get([:auth, :oauth_consumer_template], "consumer.html")
|
Pleroma.Config.get([:auth, :oauth_consumer_template], "consumer.html")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def change_password(user, password, new_password, new_password_confirmation),
|
||||||
|
do: implementation().change_password(user, password, new_password, new_password_confirmation)
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,7 +10,7 @@ defmodule Pleroma.Web.Feed.TagController do
|
||||||
alias Pleroma.Web.Feed.FeedView
|
alias Pleroma.Web.Feed.FeedView
|
||||||
|
|
||||||
def feed(conn, params) do
|
def feed(conn, params) do
|
||||||
if Config.get!([:instance, :public]) do
|
if not Config.restrict_unauthenticated_access?(:timelines, :local) do
|
||||||
render_feed(conn, params)
|
render_feed(conn, params)
|
||||||
else
|
else
|
||||||
render_error(conn, :not_found, "Not found")
|
render_error(conn, :not_found, "Not found")
|
||||||
|
@ -18,10 +18,12 @@ def feed(conn, params) do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp render_feed(conn, %{"tag" => raw_tag} = params) do
|
defp render_feed(conn, %{"tag" => raw_tag} = params) do
|
||||||
|
local_only = Config.restrict_unauthenticated_access?(:timelines, :federated)
|
||||||
|
|
||||||
{format, tag} = parse_tag(raw_tag)
|
{format, tag} = parse_tag(raw_tag)
|
||||||
|
|
||||||
activities =
|
activities =
|
||||||
%{type: ["Create"], tag: tag}
|
%{type: ["Create"], tag: tag, local_only: local_only}
|
||||||
|> Pleroma.Maps.put_if_present(:max_id, params["max_id"])
|
|> Pleroma.Maps.put_if_present(:max_id, params["max_id"])
|
||||||
|> ActivityPub.fetch_public_activities()
|
|> ActivityPub.fetch_public_activities()
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|
||||||
alias Pleroma.Healthcheck
|
alias Pleroma.Healthcheck
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
|
alias Pleroma.Web.Auth.WrapperAuthenticator, as: Authenticator
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
||||||
alias Pleroma.Web.WebFinger
|
alias Pleroma.Web.WebFinger
|
||||||
|
@ -195,19 +196,21 @@ def change_password(
|
||||||
%{assigns: %{user: user}, private: %{open_api_spex: %{body_params: body_params}}} = conn,
|
%{assigns: %{user: user}, private: %{open_api_spex: %{body_params: body_params}}} = conn,
|
||||||
_
|
_
|
||||||
) do
|
) do
|
||||||
case CommonAPI.Utils.confirm_current_password(user, body_params.password) do
|
with {:ok, %User{}} <-
|
||||||
{:ok, user} ->
|
Authenticator.change_password(
|
||||||
with {:ok, _user} <-
|
user,
|
||||||
User.reset_password(user, %{
|
body_params.password,
|
||||||
password: body_params.new_password,
|
body_params.new_password,
|
||||||
password_confirmation: body_params.new_password_confirmation
|
body_params.new_password_confirmation
|
||||||
}) do
|
) do
|
||||||
json(conn, %{status: "success"})
|
json(conn, %{status: "success"})
|
||||||
else
|
else
|
||||||
{:error, changeset} ->
|
{:error, %Ecto.Changeset{} = changeset} ->
|
||||||
{_, {error, _}} = Enum.at(changeset.errors, 0)
|
{_, {error, _}} = Enum.at(changeset.errors, 0)
|
||||||
json(conn, %{error: "New password #{error}."})
|
json(conn, %{error: "New password #{error}."})
|
||||||
end
|
|
||||||
|
{:error, :password_confirmation} ->
|
||||||
|
json(conn, %{error: "New password does not match confirmation."})
|
||||||
|
|
||||||
{:error, msg} ->
|
{:error, msg} ->
|
||||||
json(conn, %{error: msg})
|
json(conn, %{error: msg})
|
||||||
|
|
|
@ -22,9 +22,11 @@ defmodule Pleroma.Workers.PollWorker do
|
||||||
def perform(%Job{args: %{"op" => "poll_end", "activity_id" => activity_id}}) do
|
def perform(%Job{args: %{"op" => "poll_end", "activity_id" => activity_id}}) do
|
||||||
with {_, %Activity{} = activity} <- {:activity, Activity.get_by_id(activity_id)},
|
with {_, %Activity{} = activity} <- {:activity, Activity.get_by_id(activity_id)},
|
||||||
{:ok, notifications} <- Notification.create_poll_notifications(activity) do
|
{:ok, notifications} <- Notification.create_poll_notifications(activity) do
|
||||||
# Schedule a final refresh
|
unless activity.local do
|
||||||
__MODULE__.new(%{"op" => "refresh", "activity_id" => activity_id})
|
# Schedule a final refresh
|
||||||
|> Oban.insert()
|
__MODULE__.new(%{"op" => "refresh", "activity_id" => activity_id})
|
||||||
|
|> Oban.insert()
|
||||||
|
end
|
||||||
|
|
||||||
Notification.stream(notifications)
|
Notification.stream(notifications)
|
||||||
else
|
else
|
||||||
|
|
|
@ -1338,6 +1338,27 @@ test "forwarded report from mastodon", %{conn: conn} do
|
||||||
html_body: ~r/#{note.data["object"]}/i
|
html_body: ~r/#{note.data["object"]}/i
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "it accepts an incoming Block", %{conn: conn, data: data} do
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
data =
|
||||||
|
data
|
||||||
|
|> Map.put("type", "Block")
|
||||||
|
|> Map.put("to", [user.ap_id])
|
||||||
|
|> Map.put("cc", [])
|
||||||
|
|> Map.put("object", user.ap_id)
|
||||||
|
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> assign(:valid_signature, true)
|
||||||
|
|> put_req_header("content-type", "application/activity+json")
|
||||||
|
|> post("/users/#{user.nickname}/inbox", data)
|
||||||
|
|
||||||
|
assert "ok" == json_response(conn, 200)
|
||||||
|
ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
|
||||||
|
assert Activity.get_by_ap_id(data["id"])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "GET /users/:nickname/outbox" do
|
describe "GET /users/:nickname/outbox" do
|
||||||
|
|
|
@ -13,7 +13,8 @@ test "doesn't impact local report" do
|
||||||
|
|
||||||
activity = %{
|
activity = %{
|
||||||
"type" => "Flag",
|
"type" => "Flag",
|
||||||
"actor" => "http://localhost:4001/actor"
|
"actor" => "http://localhost:4001/actor",
|
||||||
|
"object" => ["https://mastodon.online/users/Gargron"]
|
||||||
}
|
}
|
||||||
|
|
||||||
assert {:ok, _} = RemoteReportPolicy.filter(activity)
|
assert {:ok, _} = RemoteReportPolicy.filter(activity)
|
||||||
|
@ -25,7 +26,8 @@ test "rejects anonymous report if `reject_anonymous: true`" do
|
||||||
|
|
||||||
activity = %{
|
activity = %{
|
||||||
"type" => "Flag",
|
"type" => "Flag",
|
||||||
"actor" => "https://mastodon.social/actor"
|
"actor" => "https://mastodon.social/actor",
|
||||||
|
"object" => ["https://mastodon.online/users/Gargron"]
|
||||||
}
|
}
|
||||||
|
|
||||||
assert {:reject, _} = RemoteReportPolicy.filter(activity)
|
assert {:reject, _} = RemoteReportPolicy.filter(activity)
|
||||||
|
@ -37,7 +39,47 @@ test "preserves anonymous report if `reject_anonymous: false`" do
|
||||||
|
|
||||||
activity = %{
|
activity = %{
|
||||||
"type" => "Flag",
|
"type" => "Flag",
|
||||||
"actor" => "https://mastodon.social/actor"
|
"actor" => "https://mastodon.social/actor",
|
||||||
|
"object" => ["https://mastodon.online/users/Gargron"]
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {:ok, _} = RemoteReportPolicy.filter(activity)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "rejects report on third party if `reject_third_party: true`" do
|
||||||
|
clear_config([:mrf_remote_report, :reject_third_party], true)
|
||||||
|
clear_config([:mrf_remote_report, :reject_empty_message], false)
|
||||||
|
|
||||||
|
activity = %{
|
||||||
|
"type" => "Flag",
|
||||||
|
"actor" => "https://mastodon.social/users/Gargron",
|
||||||
|
"object" => ["https://mastodon.online/users/Gargron"]
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {:reject, _} = RemoteReportPolicy.filter(activity)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "preserves report on first party if `reject_third_party: true`" do
|
||||||
|
clear_config([:mrf_remote_report, :reject_third_party], true)
|
||||||
|
clear_config([:mrf_remote_report, :reject_empty_message], false)
|
||||||
|
|
||||||
|
activity = %{
|
||||||
|
"type" => "Flag",
|
||||||
|
"actor" => "https://mastodon.social/users/Gargron",
|
||||||
|
"object" => ["http://localhost:4001/actor"]
|
||||||
|
}
|
||||||
|
|
||||||
|
assert {:ok, _} = RemoteReportPolicy.filter(activity)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "preserves report on third party if `reject_third_party: false`" do
|
||||||
|
clear_config([:mrf_remote_report, :reject_third_party], false)
|
||||||
|
clear_config([:mrf_remote_report, :reject_empty_message], false)
|
||||||
|
|
||||||
|
activity = %{
|
||||||
|
"type" => "Flag",
|
||||||
|
"actor" => "https://mastodon.social/users/Gargron",
|
||||||
|
"object" => ["https://mastodon.online/users/Gargron"]
|
||||||
}
|
}
|
||||||
|
|
||||||
assert {:ok, _} = RemoteReportPolicy.filter(activity)
|
assert {:ok, _} = RemoteReportPolicy.filter(activity)
|
||||||
|
@ -49,7 +91,8 @@ test "rejects empty message report if `reject_empty_message: true`" do
|
||||||
|
|
||||||
activity = %{
|
activity = %{
|
||||||
"type" => "Flag",
|
"type" => "Flag",
|
||||||
"actor" => "https://mastodon.social/users/Gargron"
|
"actor" => "https://mastodon.social/users/Gargron",
|
||||||
|
"object" => ["https://mastodon.online/users/Gargron"]
|
||||||
}
|
}
|
||||||
|
|
||||||
assert {:reject, _} = RemoteReportPolicy.filter(activity)
|
assert {:reject, _} = RemoteReportPolicy.filter(activity)
|
||||||
|
@ -62,6 +105,7 @@ test "rejects empty message report (\"\") if `reject_empty_message: true`" do
|
||||||
activity = %{
|
activity = %{
|
||||||
"type" => "Flag",
|
"type" => "Flag",
|
||||||
"actor" => "https://mastodon.social/users/Gargron",
|
"actor" => "https://mastodon.social/users/Gargron",
|
||||||
|
"object" => ["https://mastodon.online/users/Gargron"],
|
||||||
"content" => ""
|
"content" => ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +118,8 @@ test "preserves empty message report if `reject_empty_message: false`" do
|
||||||
|
|
||||||
activity = %{
|
activity = %{
|
||||||
"type" => "Flag",
|
"type" => "Flag",
|
||||||
"actor" => "https://mastodon.social/users/Gargron"
|
"actor" => "https://mastodon.social/users/Gargron",
|
||||||
|
"object" => ["https://mastodon.online/users/Gargron"]
|
||||||
}
|
}
|
||||||
|
|
||||||
assert {:ok, _} = RemoteReportPolicy.filter(activity)
|
assert {:ok, _} = RemoteReportPolicy.filter(activity)
|
||||||
|
@ -86,7 +131,8 @@ test "preserves anonymous, empty message report with all settings disabled" do
|
||||||
|
|
||||||
activity = %{
|
activity = %{
|
||||||
"type" => "Flag",
|
"type" => "Flag",
|
||||||
"actor" => "https://mastodon.social/actor"
|
"actor" => "https://mastodon.social/actor",
|
||||||
|
"object" => ["https://mastodon.online/users/Gargron"]
|
||||||
}
|
}
|
||||||
|
|
||||||
assert {:ok, _} = RemoteReportPolicy.filter(activity)
|
assert {:ok, _} = RemoteReportPolicy.filter(activity)
|
||||||
|
@ -100,7 +146,8 @@ test "reject remote report if `reject_all: true`" do
|
||||||
activity = %{
|
activity = %{
|
||||||
"type" => "Flag",
|
"type" => "Flag",
|
||||||
"actor" => "https://mastodon.social/users/Gargron",
|
"actor" => "https://mastodon.social/users/Gargron",
|
||||||
"content" => "Transphobia"
|
"content" => "Transphobia",
|
||||||
|
"object" => ["https://mastodon.online/users/Gargron"]
|
||||||
}
|
}
|
||||||
|
|
||||||
assert {:reject, _} = RemoteReportPolicy.filter(activity)
|
assert {:reject, _} = RemoteReportPolicy.filter(activity)
|
||||||
|
|
|
@ -191,4 +191,60 @@ test "returns 404 for tags feed", %{conn: conn} do
|
||||||
|> response(404)
|
|> response(404)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "restricted for unauthenticated" do
|
||||||
|
test "returns 404 when local timeline is disabled", %{conn: conn} do
|
||||||
|
clear_config([:restrict_unauthenticated, :timelines], %{local: true, federated: false})
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> put_req_header("accept", "application/rss+xml")
|
||||||
|
|> get(tag_feed_path(conn, :feed, "pleromaart.rss"))
|
||||||
|
|> response(404)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns local posts only when federated timeline is disabled", %{conn: conn} do
|
||||||
|
clear_config([:restrict_unauthenticated, :timelines], %{local: false, federated: true})
|
||||||
|
|
||||||
|
local_user = insert(:user)
|
||||||
|
remote_user = insert(:user, local: false)
|
||||||
|
|
||||||
|
local_note =
|
||||||
|
insert(:note,
|
||||||
|
user: local_user,
|
||||||
|
data: %{
|
||||||
|
"content" => "local post #PleromaArt",
|
||||||
|
"summary" => "",
|
||||||
|
"tag" => ["pleromaart"]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
remote_note =
|
||||||
|
insert(:note,
|
||||||
|
user: remote_user,
|
||||||
|
data: %{
|
||||||
|
"content" => "remote post #PleromaArt",
|
||||||
|
"summary" => "",
|
||||||
|
"tag" => ["pleromaart"]
|
||||||
|
},
|
||||||
|
local: false
|
||||||
|
)
|
||||||
|
|
||||||
|
insert(:note_activity, user: local_user, note: local_note)
|
||||||
|
insert(:note_activity, user: remote_user, note: remote_note, local: false)
|
||||||
|
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> put_req_header("accept", "application/rss+xml")
|
||||||
|
|> get(tag_feed_path(conn, :feed, "pleromaart.rss"))
|
||||||
|
|> response(200)
|
||||||
|
|
||||||
|
xml = parse(response)
|
||||||
|
|
||||||
|
assert xpath(xml, ~x"//channel/title/text()") == ~c"#pleromaart"
|
||||||
|
|
||||||
|
assert xpath(xml, ~x"//channel/item/title/text()"l) == [
|
||||||
|
~c"local post #PleromaArt"
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,10 +11,10 @@ defmodule Pleroma.Workers.PollWorkerTest do
|
||||||
|
|
||||||
alias Pleroma.Workers.PollWorker
|
alias Pleroma.Workers.PollWorker
|
||||||
|
|
||||||
test "poll notification job" do
|
test "local poll ending notification job" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
question = insert(:question, user: user)
|
question = insert(:question, user: user)
|
||||||
activity = insert(:question_activity, question: question)
|
activity = insert(:question_activity, question: question, user: user)
|
||||||
|
|
||||||
PollWorker.schedule_poll_end(activity)
|
PollWorker.schedule_poll_end(activity)
|
||||||
|
|
||||||
|
@ -45,14 +45,38 @@ test "poll notification job" do
|
||||||
assert called(Pleroma.Web.Streamer.stream(["user", "user:notification"], :_))
|
assert called(Pleroma.Web.Streamer.stream(["user", "user:notification"], :_))
|
||||||
assert called(Pleroma.Web.Push.send(:_))
|
assert called(Pleroma.Web.Push.send(:_))
|
||||||
|
|
||||||
# Ensure we scheduled a final refresh of the poll
|
# Skip refreshing polls for local activities
|
||||||
assert_enqueued(
|
assert activity.local
|
||||||
|
|
||||||
|
refute_enqueued(
|
||||||
worker: PollWorker,
|
worker: PollWorker,
|
||||||
args: %{"op" => "refresh", "activity_id" => activity.id}
|
args: %{"op" => "refresh", "activity_id" => activity.id}
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "remote poll ending notification job schedules refresh" do
|
||||||
|
user = insert(:user, local: false)
|
||||||
|
question = insert(:question, user: user)
|
||||||
|
activity = insert(:question_activity, question: question, user: user)
|
||||||
|
|
||||||
|
PollWorker.schedule_poll_end(activity)
|
||||||
|
|
||||||
|
expected_job_args = %{"activity_id" => activity.id, "op" => "poll_end"}
|
||||||
|
|
||||||
|
assert_enqueued(args: expected_job_args)
|
||||||
|
|
||||||
|
[job] = all_enqueued(worker: PollWorker)
|
||||||
|
PollWorker.perform(job)
|
||||||
|
|
||||||
|
refute activity.local
|
||||||
|
|
||||||
|
assert_enqueued(
|
||||||
|
worker: PollWorker,
|
||||||
|
args: %{"op" => "refresh", "activity_id" => activity.id}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
test "poll refresh" do
|
test "poll refresh" do
|
||||||
user = insert(:user, local: false)
|
user = insert(:user, local: false)
|
||||||
question = insert(:question, user: user)
|
question = insert(:question, user: user)
|
||||||
|
|
|
@ -510,7 +510,8 @@ def question_activity_factory(attrs \\ %{}) do
|
||||||
%Pleroma.Activity{
|
%Pleroma.Activity{
|
||||||
data: data,
|
data: data,
|
||||||
actor: data["actor"],
|
actor: data["actor"],
|
||||||
recipients: data["to"]
|
recipients: data["to"],
|
||||||
|
local: user.local
|
||||||
}
|
}
|
||||||
|> Map.merge(attrs)
|
|> Map.merge(attrs)
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue