Merge remote-tracking branch 'upstream/develop' into neckbeard

This commit is contained in:
Your New SJW Waifu 2023-06-20 16:34:56 -05:00
commit 3e3cd4e453
46 changed files with 303 additions and 278 deletions

1
changelog.d/3874.remove Normal file
View File

@ -0,0 +1 @@
Remove a few unused indexes.

1
changelog.d/3880.remove Normal file
View File

@ -0,0 +1 @@
Cleanup OStatus-era user upgrades and ap_enabled indicator

1
changelog.d/3884.fix Normal file
View File

@ -0,0 +1 @@
Allow non-HTTP(s) URIs in "url" fields for compatibility with "FEP-fffd: Proxy Objects"

1
changelog.d/3885.fix Normal file
View File

@ -0,0 +1 @@
Fix opengraph and twitter card meta tags

1
changelog.d/3888.fix Normal file
View File

@ -0,0 +1 @@
ForceMentionsInContent: fix double mentions for Mastodon/Misskey posts

View File

@ -1 +1 @@
Validate Host header for MediaProxy and Uploads and return a 302 if the base_url has changed Validate Host header for Uploads and return a 302 if the base_url has changed

0
changelog.d/3902.skip Normal file
View File

View File

@ -0,0 +1 @@
Fix error 404 when deleting status of a banned user

View File

View File

@ -0,0 +1 @@
(hardening) Add no_new_privs=yes to OpenRC service files

View File

@ -4,7 +4,7 @@
## Installation ## Installation
This guide will assume you are on Debian 11 (“bullseye”) or later. This guide should also work with Ubuntu 18.04 (“Bionic Beaver”) and later. It also assumes that you have administrative rights, either as root or a user with [sudo permissions](https://www.digitalocean.com/community/tutorials/how-to-add-delete-and-grant-sudo-privileges-to-users-on-a-debian-vps). If you want to run this guide with root, ignore the `sudo` at the beginning of the lines, unless it calls a user like `sudo -Hu pleroma`; in this case, use `su <username> -s $SHELL -c 'command'` instead. This guide will assume you are on Debian 12 (“bookworm”) or later. This guide should also work with Ubuntu 22.04 (“jammy”) and later. It also assumes that you have administrative rights, either as root or a user with [sudo permissions](https://www.digitalocean.com/community/tutorials/how-to-add-delete-and-grant-sudo-privileges-to-users-on-a-debian-vps). If you want to run this guide with root, ignore the `sudo` at the beginning of the lines, unless it calls a user like `sudo -Hu pleroma`; in this case, use `su <username> -s $SHELL -c 'command'` instead.
{! backend/installation/generic_dependencies.include !} {! backend/installation/generic_dependencies.include !}

View File

@ -5,7 +5,7 @@
## インストール ## インストール
このガイドはDebian Stretchを利用することを想定しています。Ubuntu 16.04や18.04でもおそらく動作します。また、ユーザはrootもしくはsudoにより管理者権限を持っていることを前提とします。もし、以下の操作をrootユーザで行う場合は、 `sudo` を無視してください。ただし、`sudo -Hu pleroma` のようにユーザを指定している場合には `su <username> -s $SHELL -c 'command'` を代わりに使ってください。 このガイドはDebian Bookwormを利用することを想定しています。Ubuntu 22.04でもおそらく動作します。また、ユーザはrootもしくはsudoにより管理者権限を持っていることを前提とします。もし、以下の操作をrootユーザで行う場合は、 `sudo` を無視してください。ただし、`sudo -Hu pleroma` のようにユーザを指定している場合には `su <username> -s $SHELL -c 'command'` を代わりに使ってください。
### 必要なソフトウェア ### 必要なソフトウェア

View File

@ -86,26 +86,26 @@ export FLAVOUR="amd64-musl"
# Clone the release build into a temporary directory and unpack it # Clone the release build into a temporary directory and unpack it
# Replace `stable` with `unstable` if you want to run the unstable branch # Replace `stable` with `unstable` if you want to run the unstable branch
su pleroma -s $SHELL -lc " sudo -Hu pleroma "
curl 'https://git.pleroma.social/api/v4/projects/2/jobs/artifacts/stable/download?job=$FLAVOUR' -o /tmp/pleroma.zip curl 'https://git.pleroma.social/api/v4/projects/2/jobs/artifacts/stable/download?job=$FLAVOUR' -o /tmp/pleroma.zip
unzip /tmp/pleroma.zip -d /tmp/ unzip /tmp/pleroma.zip -d /tmp/
" "
# Move the release to the home directory and delete temporary files # Move the release to the home directory and delete temporary files
su pleroma -s $SHELL -lc " sudo -Hu pleroma "
mv /tmp/release/* ~pleroma/ mv /tmp/release/* ~pleroma/
rmdir /tmp/release rmdir /tmp/release
rm /tmp/pleroma.zip rm /tmp/pleroma.zip
" "
# Start the instance to verify that everything is working as expected # Start the instance to verify that everything is working as expected
su pleroma -s $SHELL -lc "./bin/pleroma daemon" sudo -Hu pleroma "./bin/pleroma daemon"
# Wait for about 20 seconds and query the instance endpoint, if it shows your uri, name and email correctly, you are configured correctly # Wait for about 20 seconds and query the instance endpoint, if it shows your uri, name and email correctly, you are configured correctly
sleep 20 && curl http://localhost:4000/api/v1/instance sleep 20 && curl http://localhost:4000/api/v1/instance
# Stop the instance # Stop the instance
su pleroma -s $SHELL -lc "./bin/pleroma stop" sudo -Hu pleroma "./bin/pleroma stop"
``` ```
## Setting up a system service ## Setting up a system service

View File

@ -115,13 +115,13 @@ adduser --system --shell /bin/false --home /opt/pleroma pleroma
export FLAVOUR="amd64-musl" export FLAVOUR="amd64-musl"
# Clone the release build into a temporary directory and unpack it # Clone the release build into a temporary directory and unpack it
su pleroma -s $SHELL -lc " sudo -Hu pleroma "
curl 'https://git.pleroma.social/api/v4/projects/2/jobs/artifacts/stable/download?job=$FLAVOUR' -o /tmp/pleroma.zip curl 'https://git.pleroma.social/api/v4/projects/2/jobs/artifacts/stable/download?job=$FLAVOUR' -o /tmp/pleroma.zip
unzip /tmp/pleroma.zip -d /tmp/ unzip /tmp/pleroma.zip -d /tmp/
" "
# Move the release to the home directory and delete temporary files # Move the release to the home directory and delete temporary files
su pleroma -s $SHELL -lc " sudo -Hu pleroma "
mv /tmp/release/* /opt/pleroma mv /tmp/release/* /opt/pleroma
rmdir /tmp/release rmdir /tmp/release
rm /tmp/pleroma.zip rm /tmp/pleroma.zip
@ -142,25 +142,25 @@ mkdir -p /etc/pleroma
chown -R pleroma /etc/pleroma chown -R pleroma /etc/pleroma
# Run the config generator # Run the config generator
su pleroma -s $SHELL -lc "./bin/pleroma_ctl instance gen --output /etc/pleroma/config.exs --output-psql /tmp/setup_db.psql" sudo -Hu pleroma "./bin/pleroma_ctl instance gen --output /etc/pleroma/config.exs --output-psql /tmp/setup_db.psql"
# Create the postgres database # Create the postgres database
su postgres -s $SHELL -lc "psql -f /tmp/setup_db.psql" sudo -u postgres -s $SHELL -lc "psql -f /tmp/setup_db.psql"
# Create the database schema # Create the database schema
su pleroma -s $SHELL -lc "./bin/pleroma_ctl migrate" sudo -Hu pleroma "./bin/pleroma_ctl migrate"
# If you have installed RUM indexes uncommend and run # If you have installed RUM indexes uncommend and run
# su pleroma -s $SHELL -lc "./bin/pleroma_ctl migrate --migrations-path priv/repo/optional_migrations/rum_indexing/" # sudo -Hu pleroma "./bin/pleroma_ctl migrate --migrations-path priv/repo/optional_migrations/rum_indexing/"
# Start the instance to verify that everything is working as expected # Start the instance to verify that everything is working as expected
su pleroma -s $SHELL -lc "./bin/pleroma daemon" sudo -Hu pleroma "./bin/pleroma daemon"
# Wait for about 20 seconds and query the instance endpoint, if it shows your uri, name and email correctly, you are configured correctly # Wait for about 20 seconds and query the instance endpoint, if it shows your uri, name and email correctly, you are configured correctly
sleep 20 && curl http://localhost:4000/api/v1/instance sleep 20 && curl http://localhost:4000/api/v1/instance
# Stop the instance # Stop the instance
su pleroma -s $SHELL -lc "./bin/pleroma stop" sudo -Hu pleroma "./bin/pleroma stop"
``` ```
### Setting up nginx and getting Let's Encrypt SSL certificaties ### Setting up nginx and getting Let's Encrypt SSL certificaties

View File

@ -8,6 +8,7 @@ pidfile="/var/run/pleroma.pid"
directory=/opt/pleroma directory=/opt/pleroma
healthcheck_delay=60 healthcheck_delay=60
healthcheck_timer=30 healthcheck_timer=30
no_new_privs="yes"
: ${pleroma_port:-4000} : ${pleroma_port:-4000}

View File

@ -0,0 +1,23 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2023 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.BareUri do
use Ecto.Type
def type, do: :string
def cast(uri) when is_binary(uri) do
case URI.parse(uri) do
%URI{scheme: nil} -> :error
%URI{} -> {:ok, uri}
_ -> :error
end
end
def cast(_), do: :error
def dump(data), do: {:ok, data}
def load(data), do: {:ok, data}
end

View File

@ -124,7 +124,6 @@ defmodule Pleroma.User do
field(:domain_blocks, {:array, :string}, default: []) field(:domain_blocks, {:array, :string}, default: [])
field(:is_active, :boolean, default: true) field(:is_active, :boolean, default: true)
field(:no_rich_text, :boolean, default: false) field(:no_rich_text, :boolean, default: false)
field(:ap_enabled, :boolean, default: false)
field(:is_moderator, :boolean, default: false) field(:is_moderator, :boolean, default: false)
field(:is_admin, :boolean, default: false) field(:is_admin, :boolean, default: false)
field(:show_role, :boolean, default: true) field(:show_role, :boolean, default: true)
@ -488,7 +487,6 @@ defmodule Pleroma.User do
:nickname, :nickname,
:public_key, :public_key,
:avatar, :avatar,
:ap_enabled,
:banner, :banner,
:is_locked, :is_locked,
:last_refreshed_at, :last_refreshed_at,
@ -1061,11 +1059,7 @@ defmodule Pleroma.User do
end end
def maybe_direct_follow(%User{} = follower, %User{} = followed) do def maybe_direct_follow(%User{} = follower, %User{} = followed) do
if not ap_enabled?(followed) do {:ok, follower, followed}
follow(follower, followed)
else
{:ok, follower, followed}
end
end end
@doc "A mass follow for local users. Respects blocks in both directions but does not create activities." @doc "A mass follow for local users. Respects blocks in both directions but does not create activities."
@ -1898,7 +1892,6 @@ defmodule Pleroma.User do
confirmation_token: nil, confirmation_token: nil,
domain_blocks: [], domain_blocks: [],
is_active: false, is_active: false,
ap_enabled: false,
is_moderator: false, is_moderator: false,
is_admin: false, is_admin: false,
mascot: nil, mascot: nil,
@ -2151,10 +2144,6 @@ defmodule Pleroma.User do
end end
end end
def ap_enabled?(%User{local: true}), do: true
def ap_enabled?(%User{ap_enabled: ap_enabled}), do: ap_enabled
def ap_enabled?(_), do: false
@doc "Gets or fetch a user by uri or nickname." @doc "Gets or fetch a user by uri or nickname."
@spec get_or_fetch(String.t()) :: {:ok, User.t()} | {:error, String.t()} @spec get_or_fetch(String.t()) :: {:ok, User.t()} | {:error, String.t()}
def get_or_fetch("http://" <> _host = uri), do: get_or_fetch_by_ap_id(uri) def get_or_fetch("http://" <> _host = uri), do: get_or_fetch_by_ap_id(uri)

View File

@ -1547,7 +1547,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
%{ %{
ap_id: data["id"], ap_id: data["id"],
uri: get_actor_url(data["url"]), uri: get_actor_url(data["url"]),
ap_enabled: true,
banner: normalize_image(data["image"]), banner: normalize_image(data["image"]),
fields: fields, fields: fields,
emoji: emojis, emoji: emojis,
@ -1668,7 +1667,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end end
end end
def fetch_and_prepare_user_from_ap_id(ap_id, additional \\ []) do defp fetch_and_prepare_user_from_ap_id(ap_id, additional) do
with {:ok, data} <- Fetcher.fetch_and_contain_remote_object_from_id(ap_id), with {:ok, data} <- Fetcher.fetch_and_contain_remote_object_from_id(ap_id),
{:ok, data} <- user_data_from_user_object(data, additional) do {:ok, data} <- user_data_from_user_object(data, additional) do
{:ok, maybe_update_follow_information(data)} {:ok, maybe_update_follow_information(data)}
@ -1751,24 +1750,20 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
def make_user_from_ap_id(ap_id, additional \\ []) do def make_user_from_ap_id(ap_id, additional \\ []) do
user = User.get_cached_by_ap_id(ap_id) user = User.get_cached_by_ap_id(ap_id)
if user && !User.ap_enabled?(user) do with {:ok, data} <- fetch_and_prepare_user_from_ap_id(ap_id, additional) do
Transmogrifier.upgrade_user_from_ap_id(ap_id) {:ok, _pid} = Task.start(fn -> pinned_fetch_task(data) end)
else
with {:ok, data} <- fetch_and_prepare_user_from_ap_id(ap_id, additional) do
{:ok, _pid} = Task.start(fn -> pinned_fetch_task(data) end)
if user do if user do
user user
|> User.remote_user_changeset(data) |> User.remote_user_changeset(data)
|> User.update_and_set_cache() |> User.update_and_set_cache()
else else
maybe_handle_clashing_nickname(data) maybe_handle_clashing_nickname(data)
data data
|> User.remote_user_changeset() |> User.remote_user_changeset()
|> Repo.insert() |> Repo.insert()
|> User.set_cache() |> User.set_cache()
end
end end
end end
end end

View File

@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server # Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/> # Copyright © 2017-2023 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only # SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.ForceMentionsInContent do defmodule Pleroma.Web.ActivityPub.MRF.ForceMentionsInContent do
@ -95,11 +95,13 @@ defmodule Pleroma.Web.ActivityPub.MRF.ForceMentionsInContent do
|> Enum.reject(&is_nil/1) |> Enum.reject(&is_nil/1)
|> sort_replied_user(replied_to_user) |> sort_replied_user(replied_to_user)
explicitly_mentioned_uris = extract_mention_uris_from_content(content) explicitly_mentioned_uris =
extract_mention_uris_from_content(content)
|> MapSet.new()
added_mentions = added_mentions =
Enum.reduce(mention_users, "", fn %User{ap_id: uri} = user, acc -> Enum.reduce(mention_users, "", fn %User{ap_id: ap_id, uri: uri} = user, acc ->
unless uri in explicitly_mentioned_uris do if MapSet.disjoint?(MapSet.new([ap_id, uri]), explicitly_mentioned_uris) do
acc <> Formatter.mention_from_user(user, %{mentions_format: :compact}) <> " " acc <> Formatter.mention_from_user(user, %{mentions_format: :compact}) <> " "
else else
acc acc

View File

@ -73,6 +73,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AddRemoveValidator do
end end
defp maybe_refetch_user(%User{ap_id: ap_id}) do defp maybe_refetch_user(%User{ap_id: ap_id}) do
Pleroma.Web.ActivityPub.Transmogrifier.upgrade_user_from_ap_id(ap_id) # Maybe it could use User.get_or_fetch_by_ap_id to avoid refreshing too often
User.fetch_by_ap_id(ap_id)
end end
end end

View File

@ -58,7 +58,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFields do
field(:like_count, :integer, default: 0) field(:like_count, :integer, default: 0)
field(:announcement_count, :integer, default: 0) field(:announcement_count, :integer, default: 0)
field(:inReplyTo, ObjectValidators.ObjectID) field(:inReplyTo, ObjectValidators.ObjectID)
field(:url, ObjectValidators.Uri) field(:url, ObjectValidators.BareUri)
field(:likes, {:array, ObjectValidators.ObjectID}, default: []) field(:likes, {:array, ObjectValidators.ObjectID}, default: [])
field(:announcements, {:array, ObjectValidators.ObjectID}, default: []) field(:announcements, {:array, ObjectValidators.ObjectID}, default: [])

View File

@ -199,7 +199,6 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
inboxes = inboxes =
recipients recipients
|> Enum.filter(&User.ap_enabled?/1)
|> Enum.map(fn actor -> actor.inbox end) |> Enum.map(fn actor -> actor.inbox end)
|> Enum.filter(fn inbox -> should_federate?(inbox, public) end) |> Enum.filter(fn inbox -> should_federate?(inbox, public) end)
|> Instances.filter_reachable() |> Instances.filter_reachable()
@ -241,7 +240,6 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
json = Jason.encode!(data) json = Jason.encode!(data)
recipients(actor, activity) recipients(actor, activity)
|> Enum.filter(fn user -> User.ap_enabled?(user) end)
|> Enum.map(fn %User{} = user -> |> Enum.map(fn %User{} = user ->
determine_inbox(activity, user) determine_inbox(activity, user)
end) end)

View File

@ -20,7 +20,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.Federator alias Pleroma.Web.Federator
alias Pleroma.Workers.TransmogrifierWorker
import Ecto.Query import Ecto.Query
@ -946,47 +945,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
defp strip_internal_tags(object), do: object defp strip_internal_tags(object), do: object
def perform(:user_upgrade, user) do
# we pass a fake user so that the followers collection is stripped away
old_follower_address = User.ap_followers(%User{nickname: user.nickname})
from(
a in Activity,
where: ^old_follower_address in a.recipients,
update: [
set: [
recipients:
fragment(
"array_replace(?,?,?)",
a.recipients,
^old_follower_address,
^user.follower_address
)
]
]
)
|> Repo.update_all([])
end
def upgrade_user_from_ap_id(ap_id) do
with %User{local: false} = user <- User.get_cached_by_ap_id(ap_id),
{:ok, data} <- ActivityPub.fetch_and_prepare_user_from_ap_id(ap_id),
{:ok, user} <- update_user(user, data) do
{:ok, _pid} = Task.start(fn -> ActivityPub.pinned_fetch_task(user) end)
TransmogrifierWorker.enqueue("user_upgrade", %{"user_id" => user.id})
{:ok, user}
else
%User{} = user -> {:ok, user}
e -> e
end
end
defp update_user(user, data) do
user
|> User.remote_user_changeset(data)
|> User.update_and_set_cache()
end
def maybe_fix_user_url(%{"url" => url} = data) when is_map(url) do def maybe_fix_user_url(%{"url" => url} = data) when is_map(url) do
Map.put(data, "url", url["href"]) Map.put(data, "url", url["href"])
end end

View File

@ -142,7 +142,7 @@ defmodule Pleroma.Web.CommonAPI do
def delete(activity_id, user) do def delete(activity_id, user) do
with {_, %Activity{data: %{"object" => _, "type" => "Create"}} = activity} <- with {_, %Activity{data: %{"object" => _, "type" => "Create"}} = activity} <-
{:find_activity, Activity.get_by_id(activity_id)}, {:find_activity, Activity.get_by_id(activity_id, filter: [])},
{_, %Object{} = object, _} <- {_, %Object{} = object, _} <-
{:find_object, Object.normalize(activity, fetch: false), activity}, {:find_object, Object.normalize(activity, fetch: false), activity},
true <- User.privileged?(user, :messages_delete) || user.ap_id == object.data["actor"], true <- User.privileged?(user, :messages_delete) || user.ap_id == object.data["actor"],

View File

@ -6,7 +6,6 @@ defmodule Pleroma.Web.Federator do
alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.Object.Containment alias Pleroma.Object.Containment
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Transmogrifier alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.Federator.Publisher alias Pleroma.Web.Federator.Publisher
@ -80,7 +79,7 @@ defmodule Pleroma.Web.Federator do
# NOTE: we use the actor ID to do the containment, this is fine because an # NOTE: we use the actor ID to do the containment, this is fine because an
# actor shouldn't be acting on objects outside their own AP server. # actor shouldn't be acting on objects outside their own AP server.
with {_, {:ok, _user}} <- {:actor, ap_enabled_actor(actor)}, with {_, {:ok, _user}} <- {:actor, User.get_or_fetch_by_ap_id(actor)},
nil <- Activity.normalize(params["id"]), nil <- Activity.normalize(params["id"]),
{_, :ok} <- {_, :ok} <-
{:correct_origin?, Containment.contain_origin_from_id(actor, params)}, {:correct_origin?, Containment.contain_origin_from_id(actor, params)},
@ -110,14 +109,4 @@ defmodule Pleroma.Web.Federator do
{:error, e} {:error, e}
end end
end end
def ap_enabled_actor(id) do
user = User.get_cached_by_ap_id(id)
if User.ap_enabled?(user) do
{:ok, user}
else
ActivityPub.make_user_from_ap_id(id)
end
end
end end

View File

@ -12,7 +12,6 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyController do
alias Pleroma.Web.MediaProxy alias Pleroma.Web.MediaProxy
alias Plug.Conn alias Plug.Conn
plug(:validate_host)
plug(:sandbox) plug(:sandbox)
def remote(conn, %{"sig" => sig64, "url" => url64}) do def remote(conn, %{"sig" => sig64, "url" => url64}) do
@ -206,30 +205,6 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyController do
Config.get([:media_proxy, :proxy_opts], []) Config.get([:media_proxy, :proxy_opts], [])
end end
defp validate_host(conn, _params) do
%{scheme: proxy_scheme, host: proxy_host, port: proxy_port} =
MediaProxy.base_url() |> URI.parse()
if match?(^proxy_host, conn.host) do
conn
else
redirect_url =
%URI{
scheme: proxy_scheme,
host: proxy_host,
port: proxy_port,
path: conn.request_path,
query: conn.query_string
}
|> URI.to_string()
|> String.trim_trailing("?")
conn
|> Phoenix.Controller.redirect(external: redirect_url)
|> halt()
end
end
defp sandbox(conn, _params) do defp sandbox(conn, _params) do
conn conn
|> merge_resp_headers([{"content-security-policy", "sandbox;"}]) |> merge_resp_headers([{"content-security-policy", "sandbox;"}])

View File

@ -76,9 +76,10 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCard do
{:meta, [name: "twitter:card", content: "summary_large_image"], []}, {:meta, [name: "twitter:card", content: "summary_large_image"], []},
{:meta, {:meta,
[ [
name: "twitter:player", name: "twitter:image",
content: MediaProxy.url(url["href"]) content: MediaProxy.url(url["href"])
], []} ], []},
{:meta, [name: "twitter:image:alt", content: truncate(attachment["name"])], []}
| acc | acc
] ]
|> maybe_add_dimensions(url) |> maybe_add_dimensions(url)
@ -130,4 +131,12 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCard do
metadata metadata
end end
end end
defp truncate(nil), do: ""
defp truncate(text) do
# truncate to 420 characters
# see https://developer.twitter.com/en/docs/twitter-for-websites/cards/overview/markup
Pleroma.Formatter.truncate(text, 420)
end
end end

View File

@ -25,7 +25,15 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do
true <- Visibility.is_public?(activity.object), true <- Visibility.is_public?(activity.object),
{_, true} <- {:visible?, Visibility.visible_for_user?(activity, _reading_user = nil)}, {_, true} <- {:visible?, Visibility.visible_for_user?(activity, _reading_user = nil)},
%User{} = user <- User.get_by_ap_id(activity.object.data["actor"]) do %User{} = user <- User.get_by_ap_id(activity.object.data["actor"]) do
meta = Metadata.build_tags(%{activity_id: notice_id, object: activity.object, user: user}) url = Helpers.url(conn) <> conn.request_path
meta =
Metadata.build_tags(%{
activity_id: notice_id,
object: activity.object,
user: user,
url: url
})
timeline = timeline =
activity.object.data["context"] activity.object.data["context"]

View File

@ -1,18 +0,0 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Workers.TransmogrifierWorker do
alias Pleroma.User
use Pleroma.Workers.WorkerHelper, queue: "transmogrifier"
@impl Oban.Worker
def perform(%Job{args: %{"op" => "user_upgrade", "user_id" => user_id}}) do
user = User.get_cached_by_id(user_id)
Pleroma.Web.ActivityPub.Transmogrifier.perform(:user_upgrade, user)
end
@impl Oban.Worker
def timeout(_job), do: :timer.seconds(5)
end

View File

@ -0,0 +1,73 @@
defmodule Pleroma.Repo.Migrations.DropUnusedIndexes do
use Ecto.Migration
@disable_ddl_transaction true
@disable_migration_lock true
def up do
drop_if_exists(
index(:activities, ["(data->>'actor')", "inserted_at desc"], name: :activities_actor_index)
)
drop_if_exists(index(:activities, ["(data->'to')"], name: :activities_to_index))
drop_if_exists(index(:activities, ["(data->'cc')"], name: :activities_cc_index))
drop_if_exists(index(:activities, ["(split_part(actor, '/', 3))"], name: :activities_hosts))
drop_if_exists(
index(:activities, ["(data->'object'->>'inReplyTo')"], name: :activities_in_reply_to)
)
drop_if_exists(
index(:activities, ["((data #> '{\"object\",\"likes\"}'))"], name: :activities_likes)
)
end
def down do
create_if_not_exists(
index(:activities, ["(data->>'actor')", "inserted_at desc"],
name: :activities_actor_index,
concurrently: true
)
)
create_if_not_exists(
index(:activities, ["(data->'to')"],
name: :activities_to_index,
using: :gin,
concurrently: true
)
)
create_if_not_exists(
index(:activities, ["(data->'cc')"],
name: :activities_cc_index,
using: :gin,
concurrently: true
)
)
create_if_not_exists(
index(:activities, ["(split_part(actor, '/', 3))"],
name: :activities_hosts,
concurrently: true
)
)
create_if_not_exists(
index(:activities, ["(data->'object'->>'inReplyTo')"],
name: :activities_in_reply_to,
concurrently: true
)
)
create_if_not_exists(
index(:activities, ["((data #> '{\"object\",\"likes\"}'))"],
name: :activities_likes,
using: :gin,
concurrently: true
)
)
end
end

View File

@ -0,0 +1,13 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2023 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Repo.Migrations.RemoveUserApEnabled do
use Ecto.Migration
def change do
alter table(:users) do
remove(:ap_enabled, :boolean, default: false, null: false)
end
end
end

View File

@ -9,6 +9,7 @@ command=/opt/pleroma/bin/pleroma
command_args="start" command_args="start"
command_user=pleroma command_user=pleroma
command_background=1 command_background=1
no_new_privs="yes"
# Ask process to terminate within 30 seconds, otherwise kill it # Ask process to terminate within 30 seconds, otherwise kill it
retry="SIGTERM/30/SIGKILL/5" retry="SIGTERM/30/SIGKILL/5"

View File

@ -0,0 +1,25 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2023 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.BareUriTest do
use Pleroma.DataCase, async: true
alias Pleroma.EctoType.ActivityPub.ObjectValidators.BareUri
test "diaspora://" do
text = "diaspora://alice@fediverse.example/post/deadbeefdeadbeefdeadbeefdeadbeef"
assert {:ok, text} = BareUri.cast(text)
end
test "nostr:" do
text = "nostr:note1gwdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
assert {:ok, text} = BareUri.cast(text)
end
test "errors for non-URIs" do
assert :error == SafeText.cast(1)
assert :error == SafeText.cast("foo")
assert :error == SafeText.cast("foo bar")
end
end

View File

@ -1844,7 +1844,6 @@ defmodule Pleroma.UserTest do
confirmation_token: "qqqq", confirmation_token: "qqqq",
domain_blocks: ["lain.com"], domain_blocks: ["lain.com"],
is_active: false, is_active: false,
ap_enabled: true,
is_moderator: true, is_moderator: true,
is_admin: true, is_admin: true,
mascot: %{"a" => "b"}, mascot: %{"a" => "b"},
@ -1885,7 +1884,6 @@ defmodule Pleroma.UserTest do
confirmation_token: nil, confirmation_token: nil,
domain_blocks: [], domain_blocks: [],
is_active: false, is_active: false,
ap_enabled: false,
is_moderator: false, is_moderator: false,
is_admin: false, is_admin: false,
mascot: nil, mascot: nil,
@ -2473,8 +2471,7 @@ defmodule Pleroma.UserTest do
insert(:user, insert(:user,
local: false, local: false,
follower_address: "http://localhost:4001/users/masto_closed/followers", follower_address: "http://localhost:4001/users/masto_closed/followers",
following_address: "http://localhost:4001/users/masto_closed/following", following_address: "http://localhost:4001/users/masto_closed/following"
ap_enabled: true
) )
assert other_user.following_count == 0 assert other_user.following_count == 0
@ -2495,8 +2492,7 @@ defmodule Pleroma.UserTest do
insert(:user, insert(:user,
local: false, local: false,
follower_address: "http://localhost:4001/users/masto_closed/followers", follower_address: "http://localhost:4001/users/masto_closed/followers",
following_address: "http://localhost:4001/users/masto_closed/following", following_address: "http://localhost:4001/users/masto_closed/following"
ap_enabled: true
) )
assert other_user.following_count == 0 assert other_user.following_count == 0
@ -2517,8 +2513,7 @@ defmodule Pleroma.UserTest do
insert(:user, insert(:user,
local: false, local: false,
follower_address: "http://localhost:4001/users/masto_closed/followers", follower_address: "http://localhost:4001/users/masto_closed/followers",
following_address: "http://localhost:4001/users/masto_closed/following", following_address: "http://localhost:4001/users/masto_closed/following"
ap_enabled: true
) )
assert other_user.following_count == 0 assert other_user.following_count == 0

View File

@ -575,7 +575,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
user = user =
insert(:user, insert(:user,
ap_id: "https://mastodon.example.org/users/raymoo", ap_id: "https://mastodon.example.org/users/raymoo",
ap_enabled: true,
local: false, local: false,
last_refreshed_at: nil last_refreshed_at: nil
) )

View File

@ -174,7 +174,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
{:ok, user} = ActivityPub.make_user_from_ap_id(user_id) {:ok, user} = ActivityPub.make_user_from_ap_id(user_id)
assert user.ap_id == user_id assert user.ap_id == user_id
assert user.nickname == "admin@mastodon.example.org" assert user.nickname == "admin@mastodon.example.org"
assert user.ap_enabled
assert user.follower_address == "http://mastodon.example.org/users/admin/followers" assert user.follower_address == "http://mastodon.example.org/users/admin/followers"
end end

View File

@ -256,4 +256,55 @@ defmodule Pleroma.Web.ActivityPub.MRF.ForceMentionsInContentTest do
} }
}} = MRF.filter_one(ForceMentionsInContent, activity) }} = MRF.filter_one(ForceMentionsInContent, activity)
end end
test "don't add duplicate mentions for mastodon or misskey posts" do
[zero, rogerick, greg] = [
insert(:user,
ap_id: "https://pleroma.example.com/users/zero",
uri: "https://pleroma.example.com/users/zero",
nickname: "zero@pleroma.example.com",
local: false
),
insert(:user,
ap_id: "https://misskey.example.com/users/104ab42f11",
uri: "https://misskey.example.com/@rogerick",
nickname: "rogerick@misskey.example.com",
local: false
),
insert(:user,
ap_id: "https://mastodon.example.com/users/greg",
uri: "https://mastodon.example.com/@greg",
nickname: "greg@mastodon.example.com",
local: false
)
]
{:ok, post} = CommonAPI.post(rogerick, %{status: "eugh"})
inline_mentions = [
"<span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{rogerick.id}\" href=\"#{rogerick.ap_id}\" rel=\"ugc\">@<span>rogerick</span></a></span>",
"<span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{greg.id}\" href=\"#{greg.uri}\" rel=\"ugc\">@<span>greg</span></a></span>"
]
activity = %{
"type" => "Create",
"actor" => zero.ap_id,
"object" => %{
"type" => "Note",
"actor" => zero.ap_id,
"content" => "#{Enum.at(inline_mentions, 0)} #{Enum.at(inline_mentions, 1)} erm",
"to" => [
rogerick.ap_id,
greg.ap_id,
Constants.as_public()
],
"inReplyTo" => Object.normalize(post).data["id"]
}
}
{:ok, %{"object" => %{"content" => filtered}}} = ForceMentionsInContent.filter(activity)
assert filtered ==
"#{Enum.at(inline_mentions, 0)} #{Enum.at(inline_mentions, 1)} erm"
end
end end

View File

@ -276,8 +276,7 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
follower = follower =
insert(:user, %{ insert(:user, %{
local: false, local: false,
inbox: "https://domain.com/users/nick1/inbox", inbox: "https://domain.com/users/nick1/inbox"
ap_enabled: true
}) })
actor = insert(:user, follower_address: follower.ap_id) actor = insert(:user, follower_address: follower.ap_id)
@ -313,8 +312,7 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
follower = follower =
insert(:user, %{ insert(:user, %{
local: false, local: false,
inbox: "https://domain.com/users/nick1/inbox", inbox: "https://domain.com/users/nick1/inbox"
ap_enabled: true
}) })
actor = insert(:user, follower_address: follower.ap_id) actor = insert(:user, follower_address: follower.ap_id)
@ -348,8 +346,7 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
follower = follower =
insert(:user, %{ insert(:user, %{
local: false, local: false,
inbox: "https://domain.com/users/nick1/inbox", inbox: "https://domain.com/users/nick1/inbox"
ap_enabled: true
}) })
actor = insert(:user, follower_address: follower.ap_id) actor = insert(:user, follower_address: follower.ap_id)
@ -382,15 +379,13 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
fetcher = fetcher =
insert(:user, insert(:user,
local: false, local: false,
inbox: "https://domain.com/users/nick1/inbox", inbox: "https://domain.com/users/nick1/inbox"
ap_enabled: true
) )
another_fetcher = another_fetcher =
insert(:user, insert(:user,
local: false, local: false,
inbox: "https://domain2.com/users/nick1/inbox", inbox: "https://domain2.com/users/nick1/inbox"
ap_enabled: true
) )
actor = insert(:user) actor = insert(:user)

View File

@ -8,7 +8,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.Tests.ObanHelpers
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.ActivityPub.Transmogrifier alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Utils
@ -353,69 +352,6 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
end end
end end
describe "user upgrade" do
test "it upgrades a user to activitypub" do
user =
insert(:user, %{
nickname: "rye@niu.moe",
local: false,
ap_id: "https://niu.moe/users/rye",
follower_address: User.ap_followers(%User{nickname: "rye@niu.moe"})
})
user_two = insert(:user)
Pleroma.FollowingRelationship.follow(user_two, user, :follow_accept)
{:ok, activity} = CommonAPI.post(user, %{status: "test"})
{:ok, unrelated_activity} = CommonAPI.post(user_two, %{status: "test"})
assert "http://localhost:4001/users/rye@niu.moe/followers" in activity.recipients
user = User.get_cached_by_id(user.id)
assert user.note_count == 1
{:ok, user} = Transmogrifier.upgrade_user_from_ap_id("https://niu.moe/users/rye")
ObanHelpers.perform_all()
assert user.ap_enabled
assert user.note_count == 1
assert user.follower_address == "https://niu.moe/users/rye/followers"
assert user.following_address == "https://niu.moe/users/rye/following"
user = User.get_cached_by_id(user.id)
assert user.note_count == 1
activity = Activity.get_by_id(activity.id)
assert user.follower_address in activity.recipients
assert %{
"url" => [
%{
"href" =>
"https://cdn.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg"
}
]
} = user.avatar
assert %{
"url" => [
%{
"href" =>
"https://cdn.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png"
}
]
} = user.banner
refute "..." in activity.recipients
unrelated_activity = Activity.get_by_id(unrelated_activity.id)
refute user.follower_address in unrelated_activity.recipients
user_two = User.get_cached_by_id(user_two.id)
assert User.following?(user_two, user)
refute "..." in User.following(user_two)
end
end
describe "actor rewriting" do describe "actor rewriting" do
test "it fixes the actor URL property to be a proper URI" do test "it fixes the actor URL property to be a proper URI" do
data = %{ data = %{

View File

@ -393,6 +393,20 @@ defmodule Pleroma.Web.CommonAPITest do
refute Activity.get_by_id(post.id) refute Activity.get_by_id(post.id)
end end
test "it allows privileged users to delete banned user's posts" do
clear_config([:instance, :moderator_privileges], [:messages_delete])
user = insert(:user)
moderator = insert(:user, is_moderator: true)
{:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"})
User.set_activation(user, false)
assert {:ok, delete} = CommonAPI.delete(post.id, moderator)
assert delete.local
refute Activity.get_by_id(post.id)
end
end end
test "favoriting race condition" do test "favoriting race condition" do
@ -1339,7 +1353,7 @@ defmodule Pleroma.Web.CommonAPITest do
test "cancels a pending follow for a remote user" do test "cancels a pending follow for a remote user" do
follower = insert(:user) follower = insert(:user)
followed = insert(:user, is_locked: true, local: false, ap_enabled: true) followed = insert(:user, is_locked: true, local: false)
assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} = assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} =
CommonAPI.follow(follower, followed) CommonAPI.follow(follower, followed)

View File

@ -78,16 +78,14 @@ defmodule Pleroma.Web.FederatorTest do
local: false, local: false,
nickname: "nick1@domain.com", nickname: "nick1@domain.com",
ap_id: "https://domain.com/users/nick1", ap_id: "https://domain.com/users/nick1",
inbox: inbox1, inbox: inbox1
ap_enabled: true
}) })
insert(:user, %{ insert(:user, %{
local: false, local: false,
nickname: "nick2@domain2.com", nickname: "nick2@domain2.com",
ap_id: "https://domain2.com/users/nick2", ap_id: "https://domain2.com/users/nick2",
inbox: inbox2, inbox: inbox2
ap_enabled: true
}) })
dt = NaiveDateTime.utc_now() dt = NaiveDateTime.utc_now()

View File

@ -1018,6 +1018,27 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
refute Activity.get_by_id(activity.id) refute Activity.get_by_id(activity.id)
end end
test "when you're privileged and the user is banned", %{conn: conn} do
clear_config([:instance, :moderator_privileges], [:messages_delete])
posting_user = insert(:user, is_active: false)
refute posting_user.is_active
activity = insert(:note_activity, user: posting_user)
user = insert(:user, is_moderator: true)
res_conn =
conn
|> assign(:user, user)
|> assign(:token, insert(:oauth_token, user: user, scopes: ["write:statuses"]))
|> delete("/api/v1/statuses/#{activity.id}")
assert %{} = json_response_and_validate_schema(res_conn, 200)
assert ModerationLog |> Repo.one() |> ModerationLog.get_log_entry_message() ==
"@#{user.nickname} deleted status ##{activity.id}"
refute Activity.get_by_id(activity.id)
end
end end
describe "reblogging" do describe "reblogging" do

View File

@ -54,35 +54,6 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do
} = get(conn, "/proxy/hhgfh/eeee/fff") } = get(conn, "/proxy/hhgfh/eeee/fff")
end end
test "it returns a 302 for invalid host", %{conn: conn} do
new_proxy_base = "http://mp.localhost/"
%{scheme: new_proxy_scheme, host: new_proxy_host, port: new_proxy_port} =
URI.parse(new_proxy_base)
clear_config([:media_proxy, :base_url], new_proxy_base)
proxy_url =
MediaProxy.encode_url("https://pleroma.social/logo.jpeg")
|> URI.parse()
|> Map.put(:host, "wronghost")
|> URI.to_string()
expected_url =
URI.parse(proxy_url)
|> Map.put(:host, new_proxy_host)
|> Map.put(:port, new_proxy_port)
|> Map.put(:scheme, new_proxy_scheme)
|> URI.to_string()
with_mock Pleroma.ReverseProxy,
call: fn _conn, _url, _opts -> %Conn{status: :success} end do
conn = get(conn, proxy_url)
assert redirected_to(conn, 302) == expected_url
end
end
test "redirects to valid url when filename is invalidated", %{conn: conn, url: url} do test "redirects to valid url when filename is invalidated", %{conn: conn, url: url} do
invalid_url = String.replace(url, "test.png", "test-file.png") invalid_url = String.replace(url, "test.png", "test-file.png")
response = get(conn, invalid_url) response = get(conn, invalid_url)

View File

@ -182,7 +182,8 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do
{:meta, [name: "twitter:title", content: Utils.user_name_string(user)], []}, {:meta, [name: "twitter:title", content: Utils.user_name_string(user)], []},
{:meta, [name: "twitter:description", content: "pleroma in a nutshell"], []}, {:meta, [name: "twitter:description", content: "pleroma in a nutshell"], []},
{:meta, [name: "twitter:card", content: "summary_large_image"], []}, {:meta, [name: "twitter:card", content: "summary_large_image"], []},
{:meta, [name: "twitter:player", content: "https://pleroma.gov/tenshi.png"], []}, {:meta, [name: "twitter:image", content: "https://pleroma.gov/tenshi.png"], []},
{:meta, [name: "twitter:image:alt", content: ""], []},
{:meta, [name: "twitter:player:width", content: "1280"], []}, {:meta, [name: "twitter:player:width", content: "1280"], []},
{:meta, [name: "twitter:player:height", content: "1024"], []}, {:meta, [name: "twitter:player:height", content: "1024"], []},
{:meta, [name: "twitter:card", content: "player"], []}, {:meta, [name: "twitter:card", content: "player"], []},

View File

@ -120,9 +120,6 @@ defmodule Pleroma.Web.ConnCase do
Mox.verify_on_exit!() Mox.verify_on_exit!()
{:ok, {:ok, conn: Phoenix.ConnTest.build_conn()}
conn:
Phoenix.ConnTest.build_conn()
|> Map.put(:host, Pleroma.Web.Endpoint.host())}
end end
end end

View File

@ -50,7 +50,6 @@ defmodule Pleroma.Factory do
last_refreshed_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{}, multi_factor_authentication_settings: %Pleroma.MFA.Settings{},
ap_enabled: true,
keys: pem keys: pem
} }