aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/mix/pleroma.ex35
-rw-r--r--lib/mix/tasks/pleroma/user.ex4
-rw-r--r--lib/pleroma/application.ex3
-rw-r--r--lib/pleroma/config/transfer_task.ex4
-rw-r--r--lib/pleroma/reverse_proxy/reverse_proxy.ex56
-rw-r--r--lib/pleroma/user.ex11
-rw-r--r--lib/pleroma/user/search.ex18
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub.ex5
-rw-r--r--lib/pleroma/web/activity_pub/object_validators/chat_message_validator.ex6
-rw-r--r--lib/pleroma/web/activity_pub/views/user_view.ex12
-rw-r--r--lib/pleroma/web/admin_api/controllers/admin_api_controller.ex10
-rw-r--r--lib/pleroma/web/api_spec/operations/account_operation.ex9
-rw-r--r--lib/pleroma/web/api_spec/schemas/account.ex2
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/account_controller.ex3
-rw-r--r--lib/pleroma/web/mastodon_api/views/account_view.ex1
15 files changed, 138 insertions, 41 deletions
diff --git a/lib/mix/pleroma.ex b/lib/mix/pleroma.ex
index 3ad6edbfb..9f0bf6ecb 100644
--- a/lib/mix/pleroma.ex
+++ b/lib/mix/pleroma.ex
@@ -3,15 +3,48 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.Pleroma do
+ @apps [
+ :restarter,
+ :ecto,
+ :ecto_sql,
+ :postgrex,
+ :db_connection,
+ :cachex,
+ :flake_id,
+ :swoosh,
+ :timex
+ ]
+ @cachex_children ["object", "user"]
@doc "Common functions to be reused in mix tasks"
def start_pleroma do
+ Pleroma.Config.Holder.save_default()
Application.put_env(:phoenix, :serve_endpoints, false, persistent: true)
if Pleroma.Config.get(:env) != :test do
Application.put_env(:logger, :console, level: :debug)
end
- {:ok, _} = Application.ensure_all_started(:pleroma)
+ apps =
+ if Application.get_env(:tesla, :adapter) == Tesla.Adapter.Gun do
+ [:gun | @apps]
+ else
+ [:hackney | @apps]
+ end
+
+ Enum.each(apps, &Application.ensure_all_started/1)
+
+ children = [
+ Pleroma.Repo,
+ {Pleroma.Config.TransferTask, false},
+ Pleroma.Web.Endpoint
+ ]
+
+ cachex_children = Enum.map(@cachex_children, &Pleroma.Application.build_cachex(&1, []))
+
+ Supervisor.start_link(children ++ cachex_children,
+ strategy: :one_for_one,
+ name: Pleroma.Supervisor
+ )
if Pleroma.Config.get(:env) not in [:test, :benchmark] do
pleroma_rebooted?()
diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex
index bca7e87bf..01824aa18 100644
--- a/lib/mix/tasks/pleroma/user.ex
+++ b/lib/mix/tasks/pleroma/user.ex
@@ -232,7 +232,7 @@ defmodule Mix.Tasks.Pleroma.User do
with %User{} = user <- User.get_cached_by_nickname(nickname) do
user = user |> User.tag(tags)
- shell_info("Tags of #{user.nickname}: #{inspect(tags)}")
+ shell_info("Tags of #{user.nickname}: #{inspect(user.tags)}")
else
_ ->
shell_error("Could not change user tags for #{nickname}")
@@ -245,7 +245,7 @@ defmodule Mix.Tasks.Pleroma.User do
with %User{} = user <- User.get_cached_by_nickname(nickname) do
user = user |> User.untag(tags)
- shell_info("Tags of #{user.nickname}: #{inspect(tags)}")
+ shell_info("Tags of #{user.nickname}: #{inspect(user.tags)}")
else
_ ->
shell_error("Could not change user tags for #{nickname}")
diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex
index 32773d3c9..84f3aa82d 100644
--- a/lib/pleroma/application.ex
+++ b/lib/pleroma/application.ex
@@ -162,7 +162,8 @@ defmodule Pleroma.Application do
defp seconds_valid_interval,
do: :timer.seconds(Config.get!([Pleroma.Captcha, :seconds_valid]))
- defp build_cachex(type, opts),
+ @spec build_cachex(String.t(), keyword()) :: map()
+ def build_cachex(type, opts),
do: %{
id: String.to_atom("cachex_" <> type),
start: {Cachex, :start_link, [String.to_atom(type <> "_cache"), opts]},
diff --git a/lib/pleroma/config/transfer_task.ex b/lib/pleroma/config/transfer_task.ex
index eb86b8ff4..a0d7b7d71 100644
--- a/lib/pleroma/config/transfer_task.ex
+++ b/lib/pleroma/config/transfer_task.ex
@@ -31,8 +31,8 @@ defmodule Pleroma.Config.TransferTask do
{:pleroma, :gopher, [:enabled]}
]
- def start_link(_) do
- load_and_update_env()
+ def start_link(restart_pleroma? \\ true) do
+ load_and_update_env([], restart_pleroma?)
if Config.get(:env) == :test, do: Ecto.Adapters.SQL.Sandbox.checkin(Repo)
:ignore
end
diff --git a/lib/pleroma/reverse_proxy/reverse_proxy.ex b/lib/pleroma/reverse_proxy/reverse_proxy.ex
index 4bbeb493c..28ad4c846 100644
--- a/lib/pleroma/reverse_proxy/reverse_proxy.ex
+++ b/lib/pleroma/reverse_proxy/reverse_proxy.ex
@@ -3,12 +3,13 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.ReverseProxy do
+ @range_headers ~w(range if-range)
@keep_req_headers ~w(accept user-agent accept-encoding cache-control if-modified-since) ++
- ~w(if-unmodified-since if-none-match if-range range)
+ ~w(if-unmodified-since if-none-match) ++ @range_headers
@resp_cache_headers ~w(etag date last-modified)
@keep_resp_headers @resp_cache_headers ++
- ~w(content-type content-disposition content-encoding content-range) ++
- ~w(accept-ranges vary)
+ ~w(content-length content-type content-disposition content-encoding) ++
+ ~w(content-range accept-ranges vary)
@default_cache_control_header "public, max-age=1209600"
@valid_resp_codes [200, 206, 304]
@max_read_duration :timer.seconds(30)
@@ -170,6 +171,8 @@ defmodule Pleroma.ReverseProxy do
end
defp response(conn, client, url, status, headers, opts) do
+ Logger.debug("#{__MODULE__} #{status} #{url} #{inspect(headers)}")
+
result =
conn
|> put_resp_headers(build_resp_headers(headers, opts))
@@ -220,7 +223,9 @@ defmodule Pleroma.ReverseProxy do
end
end
- defp head_response(conn, _url, code, headers, opts) do
+ defp head_response(conn, url, code, headers, opts) do
+ Logger.debug("#{__MODULE__} #{code} #{url} #{inspect(headers)}")
+
conn
|> put_resp_headers(build_resp_headers(headers, opts))
|> send_resp(code, "")
@@ -262,20 +267,33 @@ defmodule Pleroma.ReverseProxy do
headers
|> downcase_headers()
|> Enum.filter(fn {k, _} -> k in @keep_req_headers end)
- |> (fn headers ->
- headers = headers ++ Keyword.get(opts, :req_headers, [])
-
- if Keyword.get(opts, :keep_user_agent, false) do
- List.keystore(
- headers,
- "user-agent",
- 0,
- {"user-agent", Pleroma.Application.user_agent()}
- )
- else
- headers
- end
- end).()
+ |> build_req_range_or_encoding_header(opts)
+ |> build_req_user_agent_header(opts)
+ |> Keyword.merge(Keyword.get(opts, :req_headers, []))
+ end
+
+ # Disable content-encoding if any @range_headers are requested (see #1823).
+ defp build_req_range_or_encoding_header(headers, _opts) do
+ range? = Enum.any?(headers, fn {header, _} -> Enum.member?(@range_headers, header) end)
+
+ if range? && List.keymember?(headers, "accept-encoding", 0) do
+ List.keydelete(headers, "accept-encoding", 0)
+ else
+ headers
+ end
+ end
+
+ defp build_req_user_agent_header(headers, opts) do
+ if Keyword.get(opts, :keep_user_agent, false) do
+ List.keystore(
+ headers,
+ "user-agent",
+ 0,
+ {"user-agent", Pleroma.Application.user_agent()}
+ )
+ else
+ headers
+ end
end
defp build_resp_headers(headers, opts) do
@@ -283,7 +301,7 @@ defmodule Pleroma.ReverseProxy do
|> Enum.filter(fn {k, _} -> k in @keep_resp_headers end)
|> build_resp_cache_headers(opts)
|> build_resp_content_disposition_header(opts)
- |> (fn headers -> headers ++ Keyword.get(opts, :resp_headers, []) end).()
+ |> Keyword.merge(Keyword.get(opts, :resp_headers, []))
end
defp build_resp_cache_headers(headers, _opts) do
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 0078f9831..b9989f901 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -138,6 +138,7 @@ defmodule Pleroma.User do
field(:also_known_as, {:array, :string}, default: [])
field(:inbox, :string)
field(:shared_inbox, :string)
+ field(:accepts_chat_messages, :boolean, default: nil)
embeds_one(
:notification_settings,
@@ -436,7 +437,8 @@ defmodule Pleroma.User do
:discoverable,
:invisible,
:actor_type,
- :also_known_as
+ :also_known_as,
+ :accepts_chat_messages
]
)
|> validate_required([:name, :ap_id])
@@ -481,7 +483,8 @@ defmodule Pleroma.User do
:pleroma_settings_store,
:discoverable,
:actor_type,
- :also_known_as
+ :also_known_as,
+ :accepts_chat_messages
]
)
|> unique_constraint(:nickname)
@@ -620,6 +623,7 @@ defmodule Pleroma.User do
def register_changeset(struct, params \\ %{}, opts \\ []) do
bio_limit = Config.get([:instance, :user_bio_length], 5000)
name_limit = Config.get([:instance, :user_name_length], 100)
+ params = Map.put_new(params, :accepts_chat_messages, true)
need_confirmation? =
if is_nil(opts[:need_confirmation]) do
@@ -638,7 +642,8 @@ defmodule Pleroma.User do
:nickname,
:password,
:password_confirmation,
- :emoji
+ :emoji,
+ :accepts_chat_messages
])
|> validate_required([:name, :nickname, :password, :password_confirmation])
|> validate_confirmation(:password)
diff --git a/lib/pleroma/user/search.ex b/lib/pleroma/user/search.ex
index 42ff1de78..d4fd31069 100644
--- a/lib/pleroma/user/search.ex
+++ b/lib/pleroma/user/search.ex
@@ -69,11 +69,15 @@ defmodule Pleroma.User.Search do
u in query,
where:
fragment(
+ # The fragment must _exactly_ match `users_fts_index`, otherwise the index won't work
"""
- (to_tsvector('simple', ?) || to_tsvector('simple', ?)) @@ to_tsquery('simple', ?)
+ (
+ setweight(to_tsvector('simple', regexp_replace(?, '\\W', ' ', 'g')), 'A') ||
+ setweight(to_tsvector('simple', regexp_replace(coalesce(?, ''), '\\W', ' ', 'g')), 'B')
+ ) @@ to_tsquery('simple', ?)
""",
- u.name,
u.nickname,
+ u.name,
^query_string
)
)
@@ -88,15 +92,23 @@ defmodule Pleroma.User.Search do
|> Enum.join(" | ")
end
+ # Considers nickname match, localized nickname match, name match; preferences nickname match
defp trigram_rank(query, query_string) do
from(
u in query,
select_merge: %{
search_rank:
fragment(
- "similarity(?, trim(? || ' ' || coalesce(?, '')))",
+ """
+ similarity(?, ?) +
+ similarity(?, regexp_replace(?, '@.+', '')) +
+ similarity(?, trim(coalesce(?, '')))
+ """,
^query_string,
u.nickname,
+ ^query_string,
+ u.nickname,
+ ^query_string,
u.name
)
}
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 1c2908805..8da5cf938 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -1226,6 +1226,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end)
locked = data["manuallyApprovesFollowers"] || false
+ capabilities = data["capabilities"] || %{}
+ accepts_chat_messages = capabilities["acceptsChatMessages"]
data = Transmogrifier.maybe_fix_user_object(data)
discoverable = data["discoverable"] || false
invisible = data["invisible"] || false
@@ -1264,7 +1266,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
also_known_as: Map.get(data, "alsoKnownAs", []),
public_key: public_key,
inbox: data["inbox"],
- shared_inbox: shared_inbox
+ shared_inbox: shared_inbox,
+ accepts_chat_messages: accepts_chat_messages
}
# nickname can be nil because of virtual actors
diff --git a/lib/pleroma/web/activity_pub/object_validators/chat_message_validator.ex b/lib/pleroma/web/activity_pub/object_validators/chat_message_validator.ex
index c481d79e0..91b475393 100644
--- a/lib/pleroma/web/activity_pub/object_validators/chat_message_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/chat_message_validator.ex
@@ -93,12 +93,14 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ChatMessageValidator do
- If both users are in our system
- If at least one of the users in this ChatMessage is a local user
- If the recipient is not blocking the actor
+ - If the recipient is explicitly not accepting chat messages
"""
def validate_local_concern(cng) do
with actor_ap <- get_field(cng, :actor),
{_, %User{} = actor} <- {:find_actor, User.get_cached_by_ap_id(actor_ap)},
{_, %User{} = recipient} <-
{:find_recipient, User.get_cached_by_ap_id(get_field(cng, :to) |> hd())},
+ {_, false} <- {:not_accepting_chats?, recipient.accepts_chat_messages == false},
{_, false} <- {:blocking_actor?, User.blocks?(recipient, actor)},
{_, true} <- {:local?, Enum.any?([actor, recipient], & &1.local)} do
cng
@@ -107,6 +109,10 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ChatMessageValidator do
cng
|> add_error(:actor, "actor is blocked by recipient")
+ {:not_accepting_chats?, true} ->
+ cng
+ |> add_error(:to, "recipient does not accept chat messages")
+
{:local?, false} ->
cng
|> add_error(:actor, "actor and recipient are both remote")
diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex
index 4a02b09a1..3a4564912 100644
--- a/lib/pleroma/web/activity_pub/views/user_view.ex
+++ b/lib/pleroma/web/activity_pub/views/user_view.ex
@@ -81,6 +81,15 @@ defmodule Pleroma.Web.ActivityPub.UserView do
fields = Enum.map(user.fields, &Map.put(&1, "type", "PropertyValue"))
+ capabilities =
+ if is_boolean(user.accepts_chat_messages) do
+ %{
+ "acceptsChatMessages" => user.accepts_chat_messages
+ }
+ else
+ %{}
+ end
+
%{
"id" => user.ap_id,
"type" => user.actor_type,
@@ -101,7 +110,8 @@ defmodule Pleroma.Web.ActivityPub.UserView do
"endpoints" => endpoints,
"attachment" => fields,
"tag" => emoji_tags,
- "discoverable" => user.discoverable
+ "discoverable" => user.discoverable,
+ "capabilities" => capabilities
}
|> Map.merge(maybe_make_image(&User.avatar_url/2, "icon", user))
|> Map.merge(maybe_make_image(&User.banner_url/2, "image", user))
diff --git a/lib/pleroma/web/admin_api/controllers/admin_api_controller.ex b/lib/pleroma/web/admin_api/controllers/admin_api_controller.ex
index f9545d895..e5f14269a 100644
--- a/lib/pleroma/web/admin_api/controllers/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/controllers/admin_api_controller.ex
@@ -206,8 +206,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
end
end
- def user_show(conn, %{"nickname" => nickname}) do
- with %User{} = user <- User.get_cached_by_nickname_or_id(nickname) do
+ def user_show(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do
+ with %User{} = user <- User.get_cached_by_nickname_or_id(nickname, for: admin) do
conn
|> put_view(AccountView)
|> render("show.json", %{user: user})
@@ -233,11 +233,11 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|> render("index.json", %{activities: activities, as: :activity})
end
- def list_user_statuses(conn, %{"nickname" => nickname} = params) do
+ def list_user_statuses(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname} = params) do
with_reblogs = params["with_reblogs"] == "true" || params["with_reblogs"] == true
godmode = params["godmode"] == "true" || params["godmode"] == true
- with %User{} = user <- User.get_cached_by_nickname_or_id(nickname) do
+ with %User{} = user <- User.get_cached_by_nickname_or_id(nickname, for: admin) do
{_, page_size} = page_params(params)
activities =
@@ -526,7 +526,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
@doc "Show a given user's credentials"
def show_user_credentials(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do
- with %User{} = user <- User.get_cached_by_nickname_or_id(nickname) do
+ with %User{} = user <- User.get_cached_by_nickname_or_id(nickname, for: admin) do
conn
|> put_view(AccountView)
|> render("credentials.json", %{user: user, for: admin})
diff --git a/lib/pleroma/web/api_spec/operations/account_operation.ex b/lib/pleroma/web/api_spec/operations/account_operation.ex
index b8c527606..952d9347b 100644
--- a/lib/pleroma/web/api_spec/operations/account_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/account_operation.ex
@@ -61,7 +61,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
description: "Update the user's display and preferences.",
operationId: "AccountController.update_credentials",
security: [%{"oAuth" => ["write:accounts"]}],
- requestBody: request_body("Parameters", update_creadentials_request(), required: true),
+ requestBody: request_body("Parameters", update_credentials_request(), required: true),
responses: %{
200 => Operation.response("Account", "application/json", Account),
403 => Operation.response("Error", "application/json", ApiError)
@@ -474,7 +474,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
}
end
- defp update_creadentials_request do
+ defp update_credentials_request do
%Schema{
title: "AccountUpdateCredentialsRequest",
description: "POST body for creating an account",
@@ -508,6 +508,11 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
nullable: true,
description: "Whether manual approval of follow requests is required."
},
+ accepts_chat_messages: %Schema{
+ allOf: [BooleanLike],
+ nullable: true,
+ description: "Whether the user accepts receiving chat messages."
+ },
fields_attributes: %Schema{
nullable: true,
oneOf: [
diff --git a/lib/pleroma/web/api_spec/schemas/account.ex b/lib/pleroma/web/api_spec/schemas/account.ex
index e6f163cb7..cf148bc9d 100644
--- a/lib/pleroma/web/api_spec/schemas/account.ex
+++ b/lib/pleroma/web/api_spec/schemas/account.ex
@@ -103,6 +103,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do
description:
"A generic map of settings for frontends. Opaque to the backend. Only returned in `verify_credentials` and `update_credentials`"
},
+ accepts_chat_messages: %Schema{type: :boolean, nullable: true},
favicon: %Schema{
type: :string,
format: :uri,
@@ -175,6 +176,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Account do
"is_admin" => false,
"is_moderator" => false,
"skip_thread_containment" => false,
+ "accepts_chat_messages" => true,
"chat_token" =>
"SFMyNTY.g3QAAAACZAAEZGF0YW0AAAASOXRLaTNlc2JHN09RZ1oyOTIwZAAGc2lnbmVkbgYARNplS3EB.Mb_Iaqew2bN1I1o79B_iP7encmVCpTKC4OtHZRxdjKc",
"unread_conversation_count" => 0,
diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
index 743442855..fe5d022f5 100644
--- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
@@ -163,7 +163,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
:show_role,
:skip_thread_containment,
:allow_following_move,
- :discoverable
+ :discoverable,
+ :accepts_chat_messages
]
|> Enum.reduce(%{}, fn key, acc ->
Maps.put_if_present(acc, key, params[key], &{:ok, truthy_param?(&1)})
diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex
index 2feba4778..bc9745044 100644
--- a/lib/pleroma/web/mastodon_api/views/account_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/account_view.ex
@@ -258,6 +258,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
relationship: relationship,
skip_thread_containment: user.skip_thread_containment,
background_image: image_url(user.background) |> MediaProxy.url(),
+ accepts_chat_messages: user.accepts_chat_messages,
favicon: favicon
}
}