Merge branch 'develop' of git.pleroma.social:pleroma/pleroma into pleroma-double_mentions

This commit is contained in:
Lain Soykaf 2023-06-11 16:31:20 +04:00
commit 55dd8ef1c7
59 changed files with 400 additions and 238 deletions

View File

@ -18,6 +18,26 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Removed ### Removed
- BREAKING: Support for passwords generated with `crypt(3)` (Gnu Social migration artifact) - BREAKING: Support for passwords generated with `crypt(3)` (Gnu Social migration artifact)
## 2.5.2
### Security
- `/proxy` endpoint now sets a Content-Security-Policy (sandbox)
- WebSocket endpoint now respects unauthenticated restrictions for streams of public posts
- OEmbed HTML tags are now filtered
### Changed
- docs: Be more explicit about the level of compatibility of OTP releases
- Set default background worker timeout to 15 minutes
### Fixed
- Atom/RSS formatting (HTML truncation, published, missing summary)
- Remove `static_fe` pipeline for `/users/:nickname/feed`
- Stop oban from retrying if validating errors occur when processing incoming data
- Make sure object refetching as used by already received polls follows MRF rules
### Removed
- BREAKING: Support for passwords generated with `crypt(3)` (Gnu Social migration artifact)
## 2.5.1 ## 2.5.1
### Added ### Added

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

@ -0,0 +1 @@
MediaProxy responses now return a sandbox CSP header

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

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/3891.fix Normal file
View File

@ -0,0 +1 @@
OEmbed HTML tags are now filtered

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

1
changelog.d/3896.add Normal file
View File

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

1
changelog.d/3897.add Normal file
View File

@ -0,0 +1 @@
OnlyMedia Upload Filter

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

View File

@ -0,0 +1 @@
Preload: Make generated JSON html-safe. It already was html safe because it only consists of config data that is base64 encoded, but this will keep it safe it that ever changes.

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

View File

View File

@ -671,6 +671,12 @@ This filter reads the ImageDescription and iptc:Caption-Abstract fields with Exi
No specific configuration. No specific configuration.
#### Pleroma.Upload.Filter.OnlyMedia
This filter rejects uploads that are not identified with Content-Type matching audio/\*, image/\*, or video/\*
No specific configuration.
#### Pleroma.Upload.Filter.Mogrify #### Pleroma.Upload.Filter.Mogrify
* `args`: List of actions for the `mogrify` command like `"strip"` or `["strip", "auto-orient", {"implode", "1"}]`. * `args`: List of actions for the `mogrify` command like `"strip"` or `["strip", "auto-orient", {"implode", "1"}]`.

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

@ -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

@ -38,9 +38,9 @@ def filter([filter | rest], upload) do
{:ok, :noop} -> {:ok, :noop} ->
filter(rest, upload) filter(rest, upload)
error -> {:error, e} ->
Logger.error("#{__MODULE__}: Filter #{filter} failed: #{inspect(error)}") Logger.error("#{__MODULE__}: Filter #{filter} failed: #{inspect(e)}")
error {:error, e}
end end
end end
end end

View File

@ -0,0 +1,20 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2023 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Upload.Filter.OnlyMedia do
@behaviour Pleroma.Upload.Filter
alias Pleroma.Upload
def filter(%Upload{content_type: content_type}) do
[type, _subtype] = String.split(content_type, "/")
if type in ["image", "video", "audio"] do
{:ok, :noop}
else
{:error, "Disallowed content-type: #{content_type}"}
end
end
def filter(_), do: {:ok, :noop}
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 @@ def remote_user_changeset(struct \\ %User{local: false}, params) 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 @@ def maybe_direct_follow(%User{} = follower, %User{local: true} = followed) 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 @@ def purge_user_changeset(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 @@ def get_public_key_for_ap_id(ap_id) 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 @@ defp object_to_user_data(data, additional) 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 @@ def user_data_from_user_object(data, additional \\ []) 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 @@ def pinned_fetch_task(%{pinned_objects: pins}) 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

@ -73,6 +73,7 @@ defp maybe_refetch_user(%User{featured_address: address} = user) when is_binary(
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 @@ defmacro status_object_fields 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 @@ def publish(%User{} = actor, %{data: %{"bcc" => bcc}} = activity)
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 @@ def publish(%User{} = actor, %Activity{} = activity) 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 @@ defp strip_internal_tags(%{"tag" => tags} = object) 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

@ -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 @@ def perform(:incoming_ap_doc, params) 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 @@ def perform(:incoming_ap_doc, params) 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,6 +12,8 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyController do
alias Pleroma.Web.MediaProxy alias Pleroma.Web.MediaProxy
alias Plug.Conn alias Plug.Conn
plug(:sandbox)
def remote(conn, %{"sig" => sig64, "url" => url64}) do def remote(conn, %{"sig" => sig64, "url" => url64}) do
with {_, true} <- {:enabled, MediaProxy.enabled?()}, with {_, true} <- {:enabled, MediaProxy.enabled?()},
{:ok, url} <- MediaProxy.decode_url(sig64, url64), {:ok, url} <- MediaProxy.decode_url(sig64, url64),
@ -202,4 +204,9 @@ defp media_preview_proxy_config do
defp media_proxy_opts do defp media_proxy_opts do
Config.get([:media_proxy, :proxy_opts], []) Config.get([:media_proxy, :proxy_opts], [])
end end
defp sandbox(conn, _params) do
conn
|> merge_resp_headers([{"content-security-policy", "sandbox;"}])
end
end end

View File

@ -76,9 +76,10 @@ defp build_attachments(id, %{data: %{"attachment" => attachments}}) 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 @@ defp maybe_add_dimensions(metadata, url) 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

@ -46,12 +46,32 @@ def call(%{request_path: <<"/", @path, "/", file::binary>>} = conn, opts) do
config = Pleroma.Config.get(Pleroma.Upload) config = Pleroma.Config.get(Pleroma.Upload)
with uploader <- Keyword.fetch!(config, :uploader), %{scheme: media_scheme, host: media_host, port: media_port} =
Pleroma.Upload.base_url() |> URI.parse()
with {:valid_host, true} <- {:valid_host, match?(^media_host, conn.host)},
uploader <- Keyword.fetch!(config, :uploader),
proxy_remote = Keyword.get(config, :proxy_remote, false), proxy_remote = Keyword.get(config, :proxy_remote, false),
{:ok, get_method} <- uploader.get_file(file), {:ok, get_method} <- uploader.get_file(file),
false <- media_is_banned(conn, get_method) do false <- media_is_banned(conn, get_method) do
get_media(conn, get_method, proxy_remote, opts) get_media(conn, get_method, proxy_remote, opts)
else else
{:valid_host, false} ->
redirect_url =
%URI{
scheme: media_scheme,
host: media_host,
port: media_port,
path: conn.request_path,
query: conn.query_string
}
|> URI.to_string()
|> String.trim_trailing("?")
conn
|> Phoenix.Controller.redirect(external: redirect_url)
|> halt()
_ -> _ ->
conn conn
|> send_resp(:internal_server_error, dgettext("errors", "Failed")) |> send_resp(:internal_server_error, dgettext("errors", "Failed"))

View File

@ -11,7 +11,7 @@ def build_tags(_conn, params) do
terms = terms =
params params
|> parser.generate_terms() |> parser.generate_terms()
|> Enum.map(fn {k, v} -> {k, Base.encode64(Jason.encode!(v))} end) |> Enum.map(fn {k, v} -> {k, Base.encode64(Jason.encode!(v, escape: :html_safe))} end)
|> Enum.into(%{}) |> Enum.into(%{})
Map.merge(acc, terms) Map.merge(acc, terms)
@ -19,7 +19,7 @@ def build_tags(_conn, params) do
rendered_html = rendered_html =
preload_data preload_data
|> Jason.encode!() |> Jason.encode!(escape: :html_safe)
|> build_script_tag() |> build_script_tag()
|> HTML.safe_to_string() |> HTML.safe_to_string()

View File

@ -6,8 +6,8 @@ defmodule Pleroma.Web.RichMedia.Parsers.OEmbed do
def parse(html, _data) do def parse(html, _data) do
with elements = [_ | _] <- get_discovery_data(html), with elements = [_ | _] <- get_discovery_data(html),
oembed_url when is_binary(oembed_url) <- get_oembed_url(elements), oembed_url when is_binary(oembed_url) <- get_oembed_url(elements),
{:ok, oembed_data} <- get_oembed_data(oembed_url) do {:ok, oembed_data = %{"html" => html}} <- get_oembed_data(oembed_url) do
oembed_data %{oembed_data | "html" => Pleroma.HTML.filter_tags(html)}
else else
_e -> %{} _e -> %{}
end end

View File

@ -25,7 +25,15 @@ def show(%{assigns: %{notice_id: notice_id}} = conn, _params) 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

@ -25,6 +25,7 @@ defmodule Pleroma.Web.Streamer do
def registry, do: @registry def registry, do: @registry
@public_streams ["public", "public:local", "public:media", "public:local:media"] @public_streams ["public", "public:local", "public:media", "public:local:media"]
@local_streams ["public:local", "public:local:media"]
@user_streams ["user", "user:notification", "direct", "user:pleroma_chat"] @user_streams ["user", "user:notification", "direct", "user:pleroma_chat"]
@doc "Expands and authorizes a stream, and registers the process for streaming." @doc "Expands and authorizes a stream, and registers the process for streaming."
@ -41,14 +42,37 @@ def get_topic_and_add_socket(stream, user, oauth_token, params \\ %{}) do
end end
end end
defp can_access_stream(user, oauth_token, kind) do
with {_, true} <- {:restrict?, Config.restrict_unauthenticated_access?(:timelines, kind)},
{_, %User{id: user_id}, %Token{user_id: user_id}} <- {:user, user, oauth_token},
{_, true} <-
{:scopes,
OAuthScopesPlug.filter_descendants(["read:statuses"], oauth_token.scopes) != []} do
true
else
{:restrict?, _} ->
true
_ ->
false
end
end
@doc "Expand and authorizes a stream" @doc "Expand and authorizes a stream"
@spec get_topic(stream :: String.t(), User.t() | nil, Token.t() | nil, Map.t()) :: @spec get_topic(stream :: String.t(), User.t() | nil, Token.t() | nil, Map.t()) ::
{:ok, topic :: String.t()} | {:error, :bad_topic} {:ok, topic :: String.t()} | {:error, :bad_topic}
def get_topic(stream, user, oauth_token, params \\ %{}) def get_topic(stream, user, oauth_token, params \\ %{})
# Allow all public steams. # Allow all public steams if the instance allows unauthenticated access.
def get_topic(stream, _user, _oauth_token, _params) when stream in @public_streams do # Otherwise, only allow users with valid oauth tokens.
{:ok, stream} def get_topic(stream, user, oauth_token, _params) when stream in @public_streams do
kind = if stream in @local_streams, do: :local, else: :federated
if can_access_stream(user, oauth_token, kind) do
{:ok, stream}
else
{:error, :unauthorized}
end
end end
# Allow all hashtags streams. # Allow all hashtags streams.
@ -57,12 +81,20 @@ def get_topic("hashtag", _user, _oauth_token, %{"tag" => tag} = _params) do
end end
# Allow remote instance streams. # Allow remote instance streams.
def get_topic("public:remote", _user, _oauth_token, %{"instance" => instance} = _params) do def get_topic("public:remote", user, oauth_token, %{"instance" => instance} = _params) do
{:ok, "public:remote:" <> instance} if can_access_stream(user, oauth_token, :federated) do
{:ok, "public:remote:" <> instance}
else
{:error, :unauthorized}
end
end end
def get_topic("public:remote:media", _user, _oauth_token, %{"instance" => instance} = _params) do def get_topic("public:remote:media", user, oauth_token, %{"instance" => instance} = _params) do
{:ok, "public:remote:media:" <> instance} if can_access_stream(user, oauth_token, :federated) do
{:ok, "public:remote:media:" <> instance}
else
{:error, :unauthorized}
end
end end
# Expand user streams. # Expand user streams.

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

@ -4,10 +4,10 @@ defmodule Pleroma.Mixfile do
def project do def project do
[ [
app: :pleroma, app: :pleroma,
version: version("2.5.51"), version: version("2.5.52"),
elixir: "~> 1.11", elixir: "~> 1.11",
elixirc_paths: elixirc_paths(Mix.env()), elixirc_paths: elixirc_paths(Mix.env()),
compilers: [:phoenix, :gettext] ++ Mix.compilers(), compilers: [:phoenix] ++ Mix.compilers(),
elixirc_options: [warnings_as_errors: warnings_as_errors()], elixirc_options: [warnings_as_errors: warnings_as_errors()],
xref: [exclude: [:eldap]], xref: [exclude: [:eldap]],
start_permanent: Mix.env() == :prod, start_permanent: Mix.env() == :prod,
@ -127,10 +127,7 @@ defp deps do
{:plug_cowboy, "~> 2.3"}, {:plug_cowboy, "~> 2.3"},
# oban 2.14 requires Elixir 1.12+ # oban 2.14 requires Elixir 1.12+
{:oban, "~> 2.13.4"}, {:oban, "~> 2.13.4"},
{:gettext, {:gettext, "~> 0.20"},
git: "https://github.com/tusooa/gettext.git",
ref: "72fb2496b6c5280ed911bdc3756890e7f38a4808",
override: true},
{:bcrypt_elixir, "~> 2.2"}, {:bcrypt_elixir, "~> 2.2"},
{:trailing_format_plug, "~> 0.0.7"}, {:trailing_format_plug, "~> 0.0.7"},
{:fast_sanitize, "~> 0.2.0"}, {:fast_sanitize, "~> 0.2.0"},

View File

@ -42,6 +42,7 @@
"ex_doc": {:hex, :ex_doc, "0.29.4", "6257ecbb20c7396b1fe5accd55b7b0d23f44b6aa18017b415cb4c2b91d997729", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "2c6699a737ae46cb61e4ed012af931b57b699643b24dabe2400a8168414bc4f5"}, "ex_doc": {:hex, :ex_doc, "0.29.4", "6257ecbb20c7396b1fe5accd55b7b0d23f44b6aa18017b415cb4c2b91d997729", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "2c6699a737ae46cb61e4ed012af931b57b699643b24dabe2400a8168414bc4f5"},
"ex_machina": {:hex, :ex_machina, "2.7.0", "b792cc3127fd0680fecdb6299235b4727a4944a09ff0fa904cc639272cd92dc7", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "419aa7a39bde11894c87a615c4ecaa52d8f107bbdd81d810465186f783245bf8"}, "ex_machina": {:hex, :ex_machina, "2.7.0", "b792cc3127fd0680fecdb6299235b4727a4944a09ff0fa904cc639272cd92dc7", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "419aa7a39bde11894c87a615c4ecaa52d8f107bbdd81d810465186f783245bf8"},
"ex_syslogger": {:hex, :ex_syslogger, "1.5.2", "72b6aa2d47a236e999171f2e1ec18698740f40af0bd02c8c650bf5f1fd1bac79", [:mix], [{:poison, ">= 1.5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:syslog, "~> 1.1.0", [hex: :syslog, repo: "hexpm", optional: false]}], "hexpm", "ab9fab4136dbc62651ec6f16fa4842f10cf02ab4433fa3d0976c01be99398399"}, "ex_syslogger": {:hex, :ex_syslogger, "1.5.2", "72b6aa2d47a236e999171f2e1ec18698740f40af0bd02c8c650bf5f1fd1bac79", [:mix], [{:poison, ">= 1.5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:syslog, "~> 1.1.0", [hex: :syslog, repo: "hexpm", optional: false]}], "hexpm", "ab9fab4136dbc62651ec6f16fa4842f10cf02ab4433fa3d0976c01be99398399"},
"expo": {:hex, :expo, "0.4.1", "1c61d18a5df197dfda38861673d392e642649a9cef7694d2f97a587b2cfb319b", [:mix], [], "hexpm", "2ff7ba7a798c8c543c12550fa0e2cbc81b95d4974c65855d8d15ba7b37a1ce47"},
"fast_html": {:hex, :fast_html, "2.0.5", "c61760340606c1077ff1f196f17834056cb1dd3d5cb92a9f2cabf28bc6221c3c", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}], "hexpm", "605f4f4829443c14127694ebabb681778712ceecb4470ec32aa31012330e6506"}, "fast_html": {:hex, :fast_html, "2.0.5", "c61760340606c1077ff1f196f17834056cb1dd3d5cb92a9f2cabf28bc6221c3c", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}], "hexpm", "605f4f4829443c14127694ebabb681778712ceecb4470ec32aa31012330e6506"},
"fast_sanitize": {:hex, :fast_sanitize, "0.2.3", "67b93dfb34e302bef49fec3aaab74951e0f0602fd9fa99085987af05bd91c7a5", [:mix], [{:fast_html, "~> 2.0", [hex: :fast_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "e8ad286d10d0386e15d67d0ee125245ebcfbc7d7290b08712ba9013c8c5e56e2"}, "fast_sanitize": {:hex, :fast_sanitize, "0.2.3", "67b93dfb34e302bef49fec3aaab74951e0f0602fd9fa99085987af05bd91c7a5", [:mix], [{:fast_html, "~> 2.0", [hex: :fast_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "e8ad286d10d0386e15d67d0ee125245ebcfbc7d7290b08712ba9013c8c5e56e2"},
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
@ -49,7 +50,7 @@
"flake_id": {:hex, :flake_id, "0.1.0", "7716b086d2e405d09b647121a166498a0d93d1a623bead243e1f74216079ccb3", [:mix], [{:base62, "~> 1.2", [hex: :base62, repo: "hexpm", optional: false]}, {:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "31fc8090fde1acd267c07c36ea7365b8604055f897d3a53dd967658c691bd827"}, "flake_id": {:hex, :flake_id, "0.1.0", "7716b086d2e405d09b647121a166498a0d93d1a623bead243e1f74216079ccb3", [:mix], [{:base62, "~> 1.2", [hex: :base62, repo: "hexpm", optional: false]}, {:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "31fc8090fde1acd267c07c36ea7365b8604055f897d3a53dd967658c691bd827"},
"floki": {:hex, :floki, "0.34.2", "5fad07ef153b3b8ec110b6b155ec3780c4b2c4906297d0b4be1a7162d04a7e02", [:mix], [], "hexpm", "26b9d50f0f01796bc6be611ca815c5e0de034d2128e39cc9702eee6b66a4d1c8"}, "floki": {:hex, :floki, "0.34.2", "5fad07ef153b3b8ec110b6b155ec3780c4b2c4906297d0b4be1a7162d04a7e02", [:mix], [], "hexpm", "26b9d50f0f01796bc6be611ca815c5e0de034d2128e39cc9702eee6b66a4d1c8"},
"gen_smtp": {:hex, :gen_smtp, "0.15.0", "9f51960c17769b26833b50df0b96123605a8024738b62db747fece14eb2fbfcc", [:rebar3], [], "hexpm", "29bd14a88030980849c7ed2447b8db6d6c9278a28b11a44cafe41b791205440f"}, "gen_smtp": {:hex, :gen_smtp, "0.15.0", "9f51960c17769b26833b50df0b96123605a8024738b62db747fece14eb2fbfcc", [:rebar3], [], "hexpm", "29bd14a88030980849c7ed2447b8db6d6c9278a28b11a44cafe41b791205440f"},
"gettext": {:git, "https://github.com/tusooa/gettext.git", "72fb2496b6c5280ed911bdc3756890e7f38a4808", [ref: "72fb2496b6c5280ed911bdc3756890e7f38a4808"]}, "gettext": {:hex, :gettext, "0.22.2", "6bfca374de34ecc913a28ba391ca184d88d77810a3e427afa8454a71a51341ac", [:mix], [{:expo, "~> 0.4.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "8a2d389673aea82d7eae387e6a2ccc12660610080ae7beb19452cfdc1ec30f60"},
"gun": {:hex, :gun, "2.0.0", "2326bc0fd6d9cf628419708270d6fe8b02b8d002cf992e4165a77d997b1defd0", [:make, :rebar3], [{:cowlib, "2.12.0", [hex: :cowlib, repo: "hexpm", optional: false]}], "hexpm", "6613cb7c62930dc8d58263c44dda72f8556346ba88358fc929dcbc5f76d04569"}, "gun": {:hex, :gun, "2.0.0", "2326bc0fd6d9cf628419708270d6fe8b02b8d002cf992e4165a77d997b1defd0", [:make, :rebar3], [{:cowlib, "2.12.0", [hex: :cowlib, repo: "hexpm", optional: false]}], "hexpm", "6613cb7c62930dc8d58263c44dda72f8556346ba88358fc929dcbc5f76d04569"},
"hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~>2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"}, "hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~>2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"},
"hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"}, "hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"},

View File

@ -9,7 +9,6 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Language: en_test\n" "Language: en_test\n"
"Plural-Forms: nplurals=2\n"
#, elixir-format #, elixir-format
#: lib/pleroma/web/api_spec/render_error.ex:122 #: lib/pleroma/web/api_spec/render_error.ex:122

View File

@ -9,7 +9,6 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Language: en_test\n" "Language: en_test\n"
"Plural-Forms: nplurals=2\n"
msgid "can't be blank" msgid "can't be blank"
msgstr "" msgstr ""

View File

@ -9,7 +9,6 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Language: en_test\n" "Language: en_test\n"
"Plural-Forms: nplurals=2\n"
msgid "eperm" msgid "eperm"
msgstr "" msgstr ""

View File

@ -21,10 +21,6 @@ msgstr ""
#~ ## #~ ##
#~ ## Use "mix gettext.extract --merge" or "mix gettext.merge" #~ ## Use "mix gettext.extract --merge" or "mix gettext.merge"
#~ ## to merge POT files into PO files. #~ ## to merge POT files into PO files.
#~ msgid ""
#~ msgstr ""
#~ "Language: en_test\n"
#~ "Plural-Forms: nplurals=2\n"
#, elixir-format #, elixir-format
#: lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex:9 #: lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex:9

View File

@ -9,7 +9,6 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Language: ru\n" "Language: ru\n"
"Plural-Forms: nplurals=3\n"
msgid "can't be blank" msgid "can't be blank"
msgstr "не может быть пустым" msgstr "не может быть пустым"

View File

@ -24,10 +24,6 @@ msgstr ""
## ##
## Use "mix gettext.extract --merge" or "mix gettext.merge" ## Use "mix gettext.extract --merge" or "mix gettext.merge"
## to merge POT files into PO files. ## to merge POT files into PO files.
#~ msgid ""
#~ msgstr ""
#~ "Language: zh_Hans\n"
#~ "Plural-Forms: nplurals=1\n"
#: lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex:9 #: lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex:9
#, elixir-format #, elixir-format

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

@ -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

@ -0,0 +1,32 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2023 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Upload.Filter.OnlyMediaTest do
use Pleroma.DataCase, async: true
alias Pleroma.Upload
alias Pleroma.Upload.Filter.OnlyMedia
test "Allows media Content-Type" do
["audio/mpeg", "image/jpeg", "video/mp4"]
|> Enum.each(fn type ->
upload = %Upload{
content_type: type
}
assert {:ok, :noop} = OnlyMedia.filter(upload)
end)
end
test "Disallows non-media Content-Type" do
["application/javascript", "application/pdf", "text/html"]
|> Enum.each(fn type ->
upload = %Upload{
content_type: type
}
assert {:error, _} = OnlyMedia.filter(upload)
end)
end
end

View File

@ -1844,7 +1844,6 @@ test "delete/1 purges a user when they wouldn't be fully deleted" 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 @@ test "delete/1 purges a user when they wouldn't be fully deleted" 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 @@ test "updates the counters normally on following/getting a follow when disabled"
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 @@ test "synchronizes the counters with the remote instance for the followed when e
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 @@ test "synchronizes the counters with the remote instance for the follower when e
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 @@ test "it inserts an incoming activity into the database" <>
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 @@ test "it returns a user" 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

@ -276,8 +276,7 @@ test "publish to url with with different ports" 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 @@ test "publish to url with with different ports" 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 @@ test "publish to url with with different ports" 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 @@ test "publish to url with with different ports" 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 @@ test "Updates of Notes are handled" 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

@ -1339,7 +1339,7 @@ test "cancels a pending follow for a local user" 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 @@ test "it federates only to reachable instances via AP" 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

@ -6,7 +6,9 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do
use Pleroma.Web.ConnCase use Pleroma.Web.ConnCase
import Mock import Mock
import Mox
alias Pleroma.ReverseProxy.ClientMock
alias Pleroma.Web.MediaProxy alias Pleroma.Web.MediaProxy
alias Plug.Conn alias Plug.Conn
@ -74,6 +76,20 @@ test "it returns 404 when url is in banned_urls cache", %{conn: conn, url: url}
assert %Conn{status: 404, resp_body: "Not Found"} = get(conn, url) assert %Conn{status: 404, resp_body: "Not Found"} = get(conn, url)
end end
end end
test "it applies sandbox CSP to MediaProxy requests", %{conn: conn} do
media_url = "https://lain.com/image.png"
media_proxy_url = MediaProxy.encode_url(media_url)
ClientMock
|> expect(:request, fn :get, ^media_url, _, _, _ ->
{:ok, 200, [{"content-type", "image/png"}]}
end)
%Conn{resp_headers: headers} = get(conn, media_proxy_url)
assert {"content-security-policy", "sandbox;"} in headers
end
end end
describe "Media Preview Proxy" do describe "Media Preview Proxy" do

View File

@ -182,7 +182,8 @@ test "it renders supported types of attachments and skips unknown types" 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

@ -40,4 +40,30 @@ test "sends Content-Disposition header when name param is set", %{
&(&1 == {"content-disposition", ~s[inline; filename="\\"cofe\\".gif"]}) &(&1 == {"content-disposition", ~s[inline; filename="\\"cofe\\".gif"]})
) )
end end
test "denies access to media if wrong Host", %{
attachment_url: attachment_url
} do
conn = get(build_conn(), attachment_url)
assert conn.status == 200
new_media_base = "http://media.localhost:8080"
%{scheme: new_media_scheme, host: new_media_host, port: new_media_port} =
URI.parse(new_media_base)
clear_config([Pleroma.Upload, :base_url], new_media_base)
conn = get(build_conn(), attachment_url)
expected_url =
URI.parse(attachment_url)
|> Map.put(:host, new_media_host)
|> Map.put(:port, new_media_port)
|> Map.put(:scheme, new_media_scheme)
|> URI.to_string()
assert redirected_to(conn, 302) == expected_url
end
end end

View File

@ -129,7 +129,7 @@ test "parses twitter card" do
}} }}
end end
test "parses OEmbed" do test "parses OEmbed and filters HTML tags" do
assert Parser.parse("http://example.com/oembed") == assert Parser.parse("http://example.com/oembed") ==
{:ok, {:ok,
%{ %{
@ -139,7 +139,7 @@ test "parses OEmbed" do
"flickr_type" => "photo", "flickr_type" => "photo",
"height" => "768", "height" => "768",
"html" => "html" =>
"<a data-flickr-embed=\"true\" href=\"https://www.flickr.com/photos/bees/2362225867/\" title=\"Bacon Lollys by \u202E\u202D\u202Cbees\u202C, on Flickr\"><img src=\"https://farm4.staticflickr.com/3040/2362225867_4a87ab8baf_b.jpg\" width=\"1024\" height=\"768\" alt=\"Bacon Lollys\"></a><script async src=\"https://embedr.flickr.com/assets/client-code.js\" charset=\"utf-8\"></script>", "<a href=\"https://www.flickr.com/photos/bees/2362225867/\" title=\"Bacon Lollys by \u202E\u202D\u202Cbees\u202C, on Flickr\"><img src=\"https://farm4.staticflickr.com/3040/2362225867_4a87ab8baf_b.jpg\" width=\"1024\" height=\"768\" alt=\"Bacon Lollys\"/></a>",
"license" => "All Rights Reserved", "license" => "All Rights Reserved",
"license_id" => 0, "license_id" => 0,
"provider_name" => "Flickr", "provider_name" => "Flickr",

View File

@ -29,6 +29,26 @@ test "allows public" do
assert {:ok, "public:local:media"} = Streamer.get_topic("public:local:media", nil, nil) assert {:ok, "public:local:media"} = Streamer.get_topic("public:local:media", nil, nil)
end end
test "rejects local public streams if restricted_unauthenticated is on" do
clear_config([:restrict_unauthenticated, :timelines, :local], true)
assert {:error, :unauthorized} = Streamer.get_topic("public:local", nil, nil)
assert {:error, :unauthorized} = Streamer.get_topic("public:local:media", nil, nil)
end
test "rejects remote public streams if restricted_unauthenticated is on" do
clear_config([:restrict_unauthenticated, :timelines, :federated], true)
assert {:error, :unauthorized} = Streamer.get_topic("public", nil, nil)
assert {:error, :unauthorized} = Streamer.get_topic("public:media", nil, nil)
assert {:error, :unauthorized} =
Streamer.get_topic("public:remote", nil, nil, %{"instance" => "lain.com"})
assert {:error, :unauthorized} =
Streamer.get_topic("public:remote:media", nil, nil, %{"instance" => "lain.com"})
end
test "allows instance streams" do test "allows instance streams" do
assert {:ok, "public:remote:lain.com"} = assert {:ok, "public:remote:lain.com"} =
Streamer.get_topic("public:remote", nil, nil, %{"instance" => "lain.com"}) Streamer.get_topic("public:remote", nil, nil, %{"instance" => "lain.com"})
@ -69,6 +89,63 @@ test "allows public streams (regardless of OAuth token scopes)", %{
end end
end end
test "allows local public streams if restricted_unauthenticated is on", %{
user: user,
token: oauth_token
} do
clear_config([:restrict_unauthenticated, :timelines, :local], true)
%{token: read_notifications_token} = oauth_access(["read:notifications"], user: user)
%{token: badly_scoped_token} = oauth_access(["irrelevant:scope"], user: user)
assert {:ok, "public:local"} = Streamer.get_topic("public:local", user, oauth_token)
assert {:ok, "public:local:media"} =
Streamer.get_topic("public:local:media", user, oauth_token)
for token <- [read_notifications_token, badly_scoped_token] do
assert {:error, :unauthorized} = Streamer.get_topic("public:local", user, token)
assert {:error, :unauthorized} = Streamer.get_topic("public:local:media", user, token)
end
end
test "allows remote public streams if restricted_unauthenticated is on", %{
user: user,
token: oauth_token
} do
clear_config([:restrict_unauthenticated, :timelines, :federated], true)
%{token: read_notifications_token} = oauth_access(["read:notifications"], user: user)
%{token: badly_scoped_token} = oauth_access(["irrelevant:scope"], user: user)
assert {:ok, "public"} = Streamer.get_topic("public", user, oauth_token)
assert {:ok, "public:media"} = Streamer.get_topic("public:media", user, oauth_token)
assert {:ok, "public:remote:lain.com"} =
Streamer.get_topic("public:remote", user, oauth_token, %{"instance" => "lain.com"})
assert {:ok, "public:remote:media:lain.com"} =
Streamer.get_topic("public:remote:media", user, oauth_token, %{
"instance" => "lain.com"
})
for token <- [read_notifications_token, badly_scoped_token] do
assert {:error, :unauthorized} = Streamer.get_topic("public", user, token)
assert {:error, :unauthorized} = Streamer.get_topic("public:media", user, token)
assert {:error, :unauthorized} =
Streamer.get_topic("public:remote", user, token, %{
"instance" => "lain.com"
})
assert {:error, :unauthorized} =
Streamer.get_topic("public:remote:media", user, token, %{
"instance" => "lain.com"
})
end
end
test "allows user streams (with proper OAuth token scopes)", %{ test "allows user streams (with proper OAuth token scopes)", %{
user: user, user: user,
token: read_oauth_token token: read_oauth_token

View File

@ -50,7 +50,6 @@ def user_factory(attrs \\ %{}) 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
} }