Merge branch 'develop' into pleroma-token-view-scopes
This commit is contained in:
commit
2baa9b0072
67 changed files with 825 additions and 278 deletions
|
|
@ -1542,16 +1542,23 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
|||
|
||||
defp get_actor_url(_url), do: nil
|
||||
|
||||
defp normalize_image(%{"url" => url}) do
|
||||
defp normalize_image(%{"url" => url} = data) do
|
||||
%{
|
||||
"type" => "Image",
|
||||
"url" => [%{"href" => url}]
|
||||
}
|
||||
|> maybe_put_description(data)
|
||||
end
|
||||
|
||||
defp normalize_image(urls) when is_list(urls), do: urls |> List.first() |> normalize_image()
|
||||
defp normalize_image(_), do: nil
|
||||
|
||||
defp maybe_put_description(map, %{"name" => description}) when is_binary(description) do
|
||||
Map.put(map, "name", description)
|
||||
end
|
||||
|
||||
defp maybe_put_description(map, _), do: map
|
||||
|
||||
defp object_to_user_data(data, additional) do
|
||||
fields =
|
||||
data
|
||||
|
|
|
|||
|
|
@ -108,6 +108,14 @@ defmodule Pleroma.Web.ActivityPub.MRF do
|
|||
|
||||
def filter(%{} = object), do: get_policies() |> filter(object)
|
||||
|
||||
def id_filter(policies, id) when is_binary(id) do
|
||||
policies
|
||||
|> Enum.filter(&function_exported?(&1, :id_filter, 1))
|
||||
|> Enum.all?(& &1.id_filter(id))
|
||||
end
|
||||
|
||||
def id_filter(id) when is_binary(id), do: get_policies() |> id_filter(id)
|
||||
|
||||
@impl true
|
||||
def pipeline_filter(%{} = message, meta) do
|
||||
object = meta[:object_data]
|
||||
|
|
|
|||
|
|
@ -13,6 +13,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.DropPolicy do
|
|||
{:reject, activity}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def id_filter(id) do
|
||||
Logger.debug("REJECTING #{id}")
|
||||
false
|
||||
end
|
||||
|
||||
@impl true
|
||||
def describe, do: {:ok, %{}}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
defmodule Pleroma.Web.ActivityPub.MRF.Policy do
|
||||
@callback filter(Pleroma.Activity.t()) :: {:ok | :reject, Pleroma.Activity.t()}
|
||||
@callback id_filter(String.t()) :: boolean()
|
||||
@callback describe() :: {:ok | :error, map()}
|
||||
@callback config_description() :: %{
|
||||
optional(:children) => [map()],
|
||||
|
|
@ -13,5 +14,5 @@ defmodule Pleroma.Web.ActivityPub.MRF.Policy do
|
|||
description: String.t()
|
||||
}
|
||||
@callback history_awareness() :: :auto | :manual
|
||||
@optional_callbacks config_description: 0, history_awareness: 0
|
||||
@optional_callbacks config_description: 0, history_awareness: 0, id_filter: 1
|
||||
end
|
||||
|
|
|
|||
118
lib/pleroma/web/activity_pub/mrf/remote_report_policy.ex
Normal file
118
lib/pleroma/web/activity_pub/mrf/remote_report_policy.ex
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
defmodule Pleroma.Web.ActivityPub.MRF.RemoteReportPolicy do
|
||||
@moduledoc "Drop remote reports if they don't contain enough information."
|
||||
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
|
||||
|
||||
alias Pleroma.Config
|
||||
|
||||
@impl true
|
||||
def filter(%{"type" => "Flag"} = object) do
|
||||
with {_, false} <- {:local, local?(object)},
|
||||
{:ok, _} <- maybe_reject_all(object),
|
||||
{:ok, _} <- maybe_reject_anonymous(object),
|
||||
{:ok, _} <- maybe_reject_third_party(object),
|
||||
{:ok, _} <- maybe_reject_empty_message(object) do
|
||||
{:ok, object}
|
||||
else
|
||||
{:local, true} -> {:ok, object}
|
||||
{:reject, message} -> {:reject, message}
|
||||
error -> {:reject, error}
|
||||
end
|
||||
end
|
||||
|
||||
def filter(object), do: {:ok, object}
|
||||
|
||||
defp maybe_reject_all(object) do
|
||||
if Config.get([:mrf_remote_report, :reject_all]) do
|
||||
{:reject, "[RemoteReportPolicy] Remote report"}
|
||||
else
|
||||
{:ok, object}
|
||||
end
|
||||
end
|
||||
|
||||
defp maybe_reject_anonymous(%{"actor" => actor} = object) do
|
||||
with true <- Config.get([:mrf_remote_report, :reject_anonymous]),
|
||||
%URI{path: "/actor"} <- URI.parse(actor) do
|
||||
{:reject, "[RemoteReportPolicy] Anonymous: #{actor}"}
|
||||
else
|
||||
_ -> {:ok, object}
|
||||
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)
|
||||
when is_binary(content) and content != "" do
|
||||
{:ok, object}
|
||||
end
|
||||
|
||||
defp maybe_reject_empty_message(object) do
|
||||
if Config.get([:mrf_remote_report, :reject_empty_message]) do
|
||||
{:reject, ["RemoteReportPolicy] No content"]}
|
||||
else
|
||||
{:ok, object}
|
||||
end
|
||||
end
|
||||
|
||||
defp local?(%{"actor" => actor}) do
|
||||
String.starts_with?(actor, Pleroma.Web.Endpoint.url())
|
||||
end
|
||||
|
||||
@impl true
|
||||
def describe do
|
||||
mrf_remote_report =
|
||||
Config.get(:mrf_remote_report)
|
||||
|> Enum.into(%{})
|
||||
|
||||
{:ok, %{mrf_remote_report: mrf_remote_report}}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def config_description do
|
||||
%{
|
||||
key: :mrf_remote_report,
|
||||
related_policy: "Pleroma.Web.ActivityPub.MRF.RemoteReportPolicy",
|
||||
label: "MRF Remote Report",
|
||||
description: "Drop remote reports if they don't contain enough information.",
|
||||
children: [
|
||||
%{
|
||||
key: :reject_all,
|
||||
type: :boolean,
|
||||
description: "Reject all remote reports? (this option takes precedence)",
|
||||
suggestions: [false]
|
||||
},
|
||||
%{
|
||||
key: :reject_anonymous,
|
||||
type: :boolean,
|
||||
description: "Reject anonymous remote reports?",
|
||||
suggestions: [true]
|
||||
},
|
||||
%{
|
||||
key: :reject_third_party,
|
||||
type: :boolean,
|
||||
description: "Reject reports on users from third-party instances?",
|
||||
suggestions: [true]
|
||||
},
|
||||
%{
|
||||
key: :reject_empty_message,
|
||||
type: :boolean,
|
||||
description: "Reject remote reports with no message?",
|
||||
suggestions: [true]
|
||||
}
|
||||
]
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
@ -191,6 +191,18 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
|
|||
|> MRF.instance_list_from_tuples()
|
||||
end
|
||||
|
||||
@impl true
|
||||
def id_filter(id) do
|
||||
host_info = URI.parse(id)
|
||||
|
||||
with {:ok, _} <- check_accept(host_info, %{}),
|
||||
{:ok, _} <- check_reject(host_info, %{}) do
|
||||
true
|
||||
else
|
||||
_ -> false
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def filter(%{"type" => "Delete", "actor" => actor} = activity) do
|
||||
%{host: actor_host} = URI.parse(actor)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
|
|||
|
||||
@behaviour Pleroma.Web.ActivityPub.ObjectValidator.Validating
|
||||
|
||||
import Pleroma.Constants, only: [activity_types: 0, object_types: 0]
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
||||
alias Pleroma.Object
|
||||
|
|
@ -38,6 +40,16 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
|
|||
@impl true
|
||||
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
|
||||
with {:ok, block_activity} <-
|
||||
block_activity
|
||||
|
|
|
|||
|
|
@ -129,8 +129,22 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
"vcard:bday" => birthday,
|
||||
"webfinger" => "acct:#{User.full_nickname(user)}"
|
||||
}
|
||||
|> Map.merge(maybe_make_image(&User.avatar_url/2, "icon", user))
|
||||
|> Map.merge(maybe_make_image(&User.banner_url/2, "image", user))
|
||||
|> Map.merge(
|
||||
maybe_make_image(
|
||||
&User.avatar_url/2,
|
||||
User.image_description(user.avatar, nil),
|
||||
"icon",
|
||||
user
|
||||
)
|
||||
)
|
||||
|> Map.merge(
|
||||
maybe_make_image(
|
||||
&User.banner_url/2,
|
||||
User.image_description(user.banner, nil),
|
||||
"image",
|
||||
user
|
||||
)
|
||||
)
|
||||
|> Map.merge(Utils.make_json_ld_header())
|
||||
end
|
||||
|
||||
|
|
@ -305,16 +319,24 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
end
|
||||
end
|
||||
|
||||
defp maybe_make_image(func, key, user) do
|
||||
defp maybe_make_image(func, description, key, user) do
|
||||
if image = func.(user, no_default: true) do
|
||||
%{
|
||||
key => %{
|
||||
"type" => "Image",
|
||||
"url" => image
|
||||
}
|
||||
key =>
|
||||
%{
|
||||
"type" => "Image",
|
||||
"url" => image
|
||||
}
|
||||
|> maybe_put_description(description)
|
||||
}
|
||||
else
|
||||
%{}
|
||||
end
|
||||
end
|
||||
|
||||
defp maybe_put_description(map, description) when is_binary(description) do
|
||||
Map.put(map, "name", description)
|
||||
end
|
||||
|
||||
defp maybe_put_description(map, _description), do: map
|
||||
end
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ defmodule Pleroma.Web.ApiSpec.MediaOperation do
|
|||
security: [%{"oAuth" => ["write:media"]}],
|
||||
requestBody: Helpers.request_body("Parameters", create_request()),
|
||||
responses: %{
|
||||
202 => Operation.response("Media", "application/json", Attachment),
|
||||
200 => Operation.response("Media", "application/json", Attachment),
|
||||
400 => Operation.response("Media", "application/json", ApiError),
|
||||
422 => Operation.response("Media", "application/json", ApiError),
|
||||
500 => Operation.response("Media", "application/json", ApiError)
|
||||
|
|
|
|||
|
|
@ -10,4 +10,9 @@ defmodule Pleroma.Web.Auth.Authenticator do
|
|||
@callback handle_error(Plug.Conn.t(), any()) :: any()
|
||||
@callback auth_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
|
||||
|
|
|
|||
|
|
@ -30,4 +30,13 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do
|
|||
error
|
||||
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
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do
|
|||
alias Pleroma.Registration
|
||||
alias Pleroma.Repo
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.CommonAPI
|
||||
alias Pleroma.Web.Plugs.AuthenticationPlug
|
||||
|
||||
import Pleroma.Web.Auth.Helpers, only: [fetch_credentials: 1, fetch_user: 1]
|
||||
|
|
@ -101,4 +102,23 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do
|
|||
def auth_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
|
||||
|
|
|
|||
|
|
@ -39,4 +39,8 @@ defmodule Pleroma.Web.Auth.WrapperAuthenticator do
|
|||
implementation().oauth_consumer_template() ||
|
||||
Pleroma.Config.get([:auth, :oauth_consumer_template], "consumer.html")
|
||||
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
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ defmodule Pleroma.Web.Feed.TagController do
|
|||
alias Pleroma.Web.Feed.FeedView
|
||||
|
||||
def feed(conn, params) do
|
||||
if Config.get!([:instance, :public]) do
|
||||
if not Config.restrict_unauthenticated_access?(:timelines, :local) do
|
||||
render_feed(conn, params)
|
||||
else
|
||||
render_error(conn, :not_found, "Not found")
|
||||
|
|
@ -18,10 +18,12 @@ defmodule Pleroma.Web.Feed.TagController do
|
|||
end
|
||||
|
||||
defp render_feed(conn, %{"tag" => raw_tag} = params) do
|
||||
local_only = Config.restrict_unauthenticated_access?(:timelines, :federated)
|
||||
|
||||
{format, tag} = parse_tag(raw_tag)
|
||||
|
||||
activities =
|
||||
%{type: ["Create"], tag: tag}
|
||||
%{type: ["Create"], tag: tag, local_only: local_only}
|
||||
|> Pleroma.Maps.put_if_present(:max_id, params["max_id"])
|
||||
|> ActivityPub.fetch_public_activities()
|
||||
|
||||
|
|
|
|||
|
|
@ -53,9 +53,7 @@ defmodule Pleroma.Web.MastodonAPI.MediaController do
|
|||
) do
|
||||
attachment_data = Map.put(object.data, "id", object.id)
|
||||
|
||||
conn
|
||||
|> put_status(202)
|
||||
|> render("attachment.json", %{attachment: attachment_data})
|
||||
render(conn, "attachment.json", %{attachment: attachment_data})
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ defmodule Pleroma.Web.MastodonAPI.PollController do
|
|||
alias Pleroma.Web.ActivityPub.Visibility
|
||||
alias Pleroma.Web.CommonAPI
|
||||
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
||||
alias Pleroma.Workers.PollWorker
|
||||
|
||||
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
|
||||
|
||||
|
|
@ -27,12 +28,16 @@ defmodule Pleroma.Web.MastodonAPI.PollController do
|
|||
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.PollOperation
|
||||
|
||||
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
|
||||
@poll_refresh_interval 120
|
||||
|
||||
@doc "GET /api/v1/polls/:id"
|
||||
def show(%{assigns: %{user: user}, private: %{open_api_spex: %{params: %{id: id}}}} = conn, _) do
|
||||
with %Object{} = object <- Object.get_by_id_and_maybe_refetch(id, interval: 60),
|
||||
%Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]),
|
||||
with %Object{} = object <- Object.get_by_id(id),
|
||||
%Activity{} = activity <-
|
||||
Activity.get_create_by_object_ap_id_with_object(object.data["id"]),
|
||||
true <- Visibility.visible_for_user?(activity, user) do
|
||||
maybe_refresh_poll(activity)
|
||||
|
||||
try_render(conn, "show.json", %{object: object, for: user})
|
||||
else
|
||||
error when is_nil(error) or error == false ->
|
||||
|
|
@ -70,4 +75,13 @@ defmodule Pleroma.Web.MastodonAPI.PollController do
|
|||
end
|
||||
end)
|
||||
end
|
||||
|
||||
defp maybe_refresh_poll(%Activity{object: %Object{} = object} = activity) do
|
||||
with false <- activity.local,
|
||||
{:ok, end_time} <- NaiveDateTime.from_iso8601(object.data["closed"]),
|
||||
{_, :lt} <- {:closed_compare, NaiveDateTime.compare(object.updated_at, end_time)} do
|
||||
PollWorker.new(%{"op" => "refresh", "activity_id" => activity.id})
|
||||
|> Oban.insert(unique: [period: @poll_refresh_interval])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -219,10 +219,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
|||
|
||||
avatar = User.avatar_url(user) |> MediaProxy.url()
|
||||
avatar_static = User.avatar_url(user) |> MediaProxy.preview_url(static: true)
|
||||
avatar_description = image_description(user.avatar)
|
||||
avatar_description = User.image_description(user.avatar)
|
||||
header = User.banner_url(user) |> MediaProxy.url()
|
||||
header_static = User.banner_url(user) |> MediaProxy.preview_url(static: true)
|
||||
header_description = image_description(user.banner)
|
||||
header_description = User.image_description(user.banner)
|
||||
|
||||
following_count =
|
||||
if !user.hide_follows_count or !user.hide_follows or self,
|
||||
|
|
@ -349,10 +349,6 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
|||
|
||||
defp username_from_nickname(_), do: nil
|
||||
|
||||
defp image_description(%{"name" => name}), do: name
|
||||
|
||||
defp image_description(_), do: ""
|
||||
|
||||
defp maybe_put_follow_requests_count(
|
||||
data,
|
||||
%User{id: user_id} = user,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|
|||
alias Pleroma.Healthcheck
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
alias Pleroma.Web.Auth.WrapperAuthenticator, as: Authenticator
|
||||
alias Pleroma.Web.CommonAPI
|
||||
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
||||
alias Pleroma.Web.WebFinger
|
||||
|
|
@ -195,19 +196,21 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|
|||
%{assigns: %{user: user}, private: %{open_api_spex: %{body_params: body_params}}} = conn,
|
||||
_
|
||||
) do
|
||||
case CommonAPI.Utils.confirm_current_password(user, body_params.password) do
|
||||
{:ok, user} ->
|
||||
with {:ok, _user} <-
|
||||
User.reset_password(user, %{
|
||||
password: body_params.new_password,
|
||||
password_confirmation: body_params.new_password_confirmation
|
||||
}) do
|
||||
json(conn, %{status: "success"})
|
||||
else
|
||||
{:error, changeset} ->
|
||||
{_, {error, _}} = Enum.at(changeset.errors, 0)
|
||||
json(conn, %{error: "New password #{error}."})
|
||||
end
|
||||
with {:ok, %User{}} <-
|
||||
Authenticator.change_password(
|
||||
user,
|
||||
body_params.password,
|
||||
body_params.new_password,
|
||||
body_params.new_password_confirmation
|
||||
) do
|
||||
json(conn, %{status: "success"})
|
||||
else
|
||||
{:error, %Ecto.Changeset{} = changeset} ->
|
||||
{_, {error, _}} = Enum.at(changeset.errors, 0)
|
||||
json(conn, %{error: "New password #{error}."})
|
||||
|
||||
{:error, :password_confirmation} ->
|
||||
json(conn, %{error: "New password does not match confirmation."})
|
||||
|
||||
{:error, msg} ->
|
||||
json(conn, %{error: msg})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue