Merge branch 'release/2.4.5' into 'stable'

Release 2.4.5

See merge request pleroma/pleroma!3793
This commit is contained in:
Haelwenn 2022-11-27 21:24:19 +00:00
commit 76bdb01c18
26 changed files with 371 additions and 48 deletions

View File

@ -14,6 +14,20 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Removed ### Removed
## 2.4.5 - 2022-08-27
## Fixed
- Image `class` attributes not being scrubbed, allowing to exploit frontend special classes [!3792](https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3792)
- Delete report notifs when demoting from superuser [!3642](https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3642)
- Validate `mediaType` only by it's format rather than using a list [!3597](https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3597)
- Pagination: Make mutes and blocks lists behave the same as other lists [!3693](https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3693)
- Compatibility with Elixir 1.14 [!3740](https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3740)
- Frontend installer: FediFE build URL [!3736](https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3736)
- Streaming: Don't stream ChatMessage into the home timeline [!3738](https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3738)
- Streaming: Stream local-only posts in the local timeline [!3738](https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3738)
- Signatures: Fix `keyId` lookup for GoToSocial [!3725](https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3725)
- Validator: Fix `replies` handling for GoToSocial [!3725](https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3725)
## 2.4.4 - 2022-08-19 ## 2.4.4 - 2022-08-19
### Security ### Security

View File

@ -734,7 +734,7 @@
"name" => "fedi-fe", "name" => "fedi-fe",
"git" => "https://git.pleroma.social/pleroma/fedi-fe", "git" => "https://git.pleroma.social/pleroma/fedi-fe",
"build_url" => "build_url" =>
"https://git.pleroma.social/pleroma/fedi-fe/-/jobs/artifacts/${ref}/download?job=build", "https://git.pleroma.social/pleroma/fedi-fe/-/jobs/artifacts/${ref}/download?job=build_release",
"ref" => "master", "ref" => "master",
"custom-http-headers" => [ "custom-http-headers" => [
{"service-worker-allowed", "/"} {"service-worker-allowed", "/"}

View File

@ -13,6 +13,14 @@ def get_activity_topics(activity) do
|> List.flatten() |> List.flatten()
end end
defp generate_topics(%{data: %{"type" => "ChatMessage"}}, %{data: %{"type" => "Delete"}}) do
["user", "user:pleroma_chat"]
end
defp generate_topics(%{data: %{"type" => "ChatMessage"}}, %{data: %{"type" => "Create"}}) do
[]
end
defp generate_topics(%{data: %{"type" => "Answer"}}, _) do defp generate_topics(%{data: %{"type" => "Answer"}}, _) do
[] []
end end
@ -31,6 +39,10 @@ defp visibility_tags(object, activity) do
end end
|> item_creation_tags(object, activity) |> item_creation_tags(object, activity)
"local" ->
["public:local"]
|> item_creation_tags(object, activity)
"direct" -> "direct" ->
["direct"] ["direct"]
@ -63,7 +75,18 @@ defp remote_topics(_), do: []
defp attachment_topics(%{data: %{"attachment" => []}}, _act), do: [] defp attachment_topics(%{data: %{"attachment" => []}}, _act), do: []
defp attachment_topics(_object, %{local: true}), do: ["public:media", "public:local:media"] defp attachment_topics(_object, %{local: true} = activity) do
case Visibility.get_visibility(activity) do
"public" ->
["public:media", "public:local:media"]
"local" ->
["public:local:media"]
_ ->
[]
end
end
defp attachment_topics(_object, %{actor: actor}) when is_binary(actor), defp attachment_topics(_object, %{actor: actor}) when is_binary(actor),
do: ["public:media", "public:remote:media:" <> URI.parse(actor).host] do: ["public:media", "public:remote:media:" <> URI.parse(actor).host]

View File

@ -27,4 +27,10 @@ defmodule Pleroma.Constants do
do: do:
~w(index.html robots.txt static static-fe finmoji emoji packs sounds images instance sw.js sw-pleroma.js favicon.png schemas doc embed.js embed.css) ~w(index.html robots.txt static static-fe finmoji emoji packs sounds images instance sw.js sw-pleroma.js favicon.png schemas doc embed.js embed.css)
) )
# basic regex, just there to weed out potential mistakes
# https://datatracker.ietf.org/doc/html/rfc2045#section-5.1
const(mime_regex,
do: ~r/^[^[:cntrl:] ()<>@,;:\\"\/\[\]?=]+\/[^[:cntrl:] ()<>@,;:\\"\/\[\]?=]+(; .*)?$/
)
end end

View File

@ -0,0 +1,25 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.MIME do
use Ecto.Type
require Pleroma.Constants
def type, do: :string
def cast(mime) when is_binary(mime) do
if mime =~ Pleroma.Constants.mime_regex() do
{:ok, mime}
else
{:ok, "application/octet-stream"}
end
end
def cast(_), do: :error
def dump(data), do: {:ok, data}
def load(data), do: {:ok, data}
end

View File

@ -328,6 +328,14 @@ def destroy_multiple(%{id: user_id} = _user, ids) do
|> Repo.delete_all() |> Repo.delete_all()
end end
def destroy_multiple_from_types(%{id: user_id}, types) do
from(n in Notification,
where: n.user_id == ^user_id,
where: n.type in ^types
)
|> Repo.delete_all()
end
def dismiss(%Pleroma.Activity{} = activity) do def dismiss(%Pleroma.Activity{} = activity) do
Notification Notification
|> where([n], n.activity_id == ^activity.id) |> where([n], n.activity_id == ^activity.id)

View File

@ -10,17 +10,14 @@ defmodule Pleroma.Signature do
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ActivityPub
@known_suffixes ["/publickey", "/main-key"]
def key_id_to_actor_id(key_id) do def key_id_to_actor_id(key_id) do
uri = uri =
URI.parse(key_id) key_id
|> URI.parse()
|> Map.put(:fragment, nil) |> Map.put(:fragment, nil)
|> remove_suffix(@known_suffixes)
uri =
if not is_nil(uri.path) and String.ends_with?(uri.path, "/publickey") do
Map.put(uri, :path, String.replace(uri.path, "/publickey", ""))
else
uri
end
maybe_ap_id = URI.to_string(uri) maybe_ap_id = URI.to_string(uri)
@ -36,6 +33,16 @@ def key_id_to_actor_id(key_id) do
end end
end end
defp remove_suffix(uri, [test | rest]) do
if not is_nil(uri.path) and String.ends_with?(uri.path, test) do
Map.put(uri, :path, String.replace(uri.path, test, ""))
else
remove_suffix(uri, rest)
end
end
defp remove_suffix(uri, []), do: uri
def fetch_public_key(conn) do def fetch_public_key(conn) do
with %{"keyId" => kid} <- HTTPSignatures.signature_for_conn(conn), with %{"keyId" => kid} <- HTTPSignatures.signature_for_conn(conn),
{:ok, actor_id} <- key_id_to_actor_id(kid), {:ok, actor_id} <- key_id_to_actor_id(kid),

View File

@ -1087,10 +1087,24 @@ def update_and_set_cache(struct, params) do
|> update_and_set_cache() |> update_and_set_cache()
end end
def update_and_set_cache(changeset) do def update_and_set_cache(%{data: %Pleroma.User{} = user} = changeset) do
was_superuser_before_update = User.superuser?(user)
with {:ok, user} <- Repo.update(changeset, stale_error_field: :id) do with {:ok, user} <- Repo.update(changeset, stale_error_field: :id) do
set_cache(user) set_cache(user)
end end
|> maybe_remove_report_notifications(was_superuser_before_update)
end
defp maybe_remove_report_notifications({:ok, %Pleroma.User{} = user} = result, true) do
if not User.superuser?(user),
do: user |> Notification.destroy_multiple_from_types(["pleroma:report"])
result
end
defp maybe_remove_report_notifications(result, _) do
result
end end
def get_user_friends_ap_ids(user) do def get_user_friends_ap_ids(user) do

View File

@ -86,7 +86,10 @@ defp fix_replies(%{"replies" => %{"first" => %{"items" => replies}}} = data)
defp fix_replies(%{"replies" => %{"items" => replies}} = data) when is_list(replies), defp fix_replies(%{"replies" => %{"items" => replies}} = data) when is_list(replies),
do: Map.put(data, "replies", replies) do: Map.put(data, "replies", replies)
defp fix_replies(%{"replies" => replies} = data) when is_bitstring(replies), # TODO: Pleroma does not have any support for Collections at the moment.
# If the `replies` field is not something the ObjectID validator can handle,
# the activity/object would be rejected, which is bad behavior.
defp fix_replies(%{"replies" => replies} = data) when not is_list(replies),
do: Map.drop(data, ["replies"]) do: Map.drop(data, ["replies"])
defp fix_replies(data), do: data defp fix_replies(data), do: data

View File

@ -12,14 +12,14 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator do
@primary_key false @primary_key false
embedded_schema do embedded_schema do
field(:type, :string) field(:type, :string)
field(:mediaType, :string, default: "application/octet-stream") field(:mediaType, ObjectValidators.MIME, default: "application/octet-stream")
field(:name, :string) field(:name, :string)
field(:blurhash, :string) field(:blurhash, :string)
embeds_many :url, UrlObjectValidator, primary_key: false do embeds_many :url, UrlObjectValidator, primary_key: false do
field(:type, :string) field(:type, :string)
field(:href, ObjectValidators.Uri) field(:href, ObjectValidators.Uri)
field(:mediaType, :string, default: "application/octet-stream") field(:mediaType, ObjectValidators.MIME, default: "application/octet-stream")
field(:width, :integer) field(:width, :integer)
field(:height, :integer) field(:height, :integer)
end end
@ -59,13 +59,7 @@ def url_changeset(struct, data) do
end end
def fix_media_type(data) do def fix_media_type(data) do
data = Map.put_new(data, "mediaType", data["mimeType"]) Map.put_new(data, "mediaType", data["mimeType"])
if is_bitstring(data["mediaType"]) && MIME.extensions(data["mediaType"]) != [] do
data
else
Map.put(data, "mediaType", "application/octet-stream")
end
end end
defp handle_href(href, mediaType) do defp handle_href(href, mediaType) do

View File

@ -203,13 +203,13 @@ def fix_attachments(%{"attachment" => attachment} = object) when is_list(attachm
media_type = media_type =
cond do cond do
is_map(url) && MIME.extensions(url["mediaType"]) != [] -> is_map(url) && url =~ Pleroma.Constants.mime_regex() ->
url["mediaType"] url["mediaType"]
is_bitstring(data["mediaType"]) && MIME.extensions(data["mediaType"]) != [] -> is_bitstring(data["mediaType"]) && data["mediaType"] =~ Pleroma.Constants.mime_regex() ->
data["mediaType"] data["mediaType"]
is_bitstring(data["mimeType"]) && MIME.extensions(data["mimeType"]) != [] -> is_bitstring(data["mimeType"]) && data["mimeType"] =~ Pleroma.Constants.mime_regex() ->
data["mimeType"] data["mimeType"]
true -> true ->

View File

@ -453,7 +453,7 @@ def mutes(%{assigns: %{user: user}} = conn, params) do
users = users =
user user
|> User.muted_users_relation(_restrict_deactivated = true) |> User.muted_users_relation(_restrict_deactivated = true)
|> Pleroma.Pagination.fetch_paginated(Map.put(params, :skip_order, true)) |> Pleroma.Pagination.fetch_paginated(params)
conn conn
|> add_link_headers(users) |> add_link_headers(users)
@ -470,7 +470,7 @@ def blocks(%{assigns: %{user: user}} = conn, params) do
users = users =
user user
|> User.blocked_users_relation(_restrict_deactivated = true) |> User.blocked_users_relation(_restrict_deactivated = true)
|> Pleroma.Pagination.fetch_paginated(Map.put(params, :skip_order, true)) |> Pleroma.Pagination.fetch_paginated(params)
conn conn
|> add_link_headers(users) |> add_link_headers(users)

View File

@ -4,7 +4,7 @@ defmodule Pleroma.Mixfile do
def project do def project do
[ [
app: :pleroma, app: :pleroma,
version: version("2.4.4"), version: version("2.4.5"),
elixir: "~> 1.9", elixir: "~> 1.9",
elixirc_paths: elixirc_paths(Mix.env()), elixirc_paths: elixirc_paths(Mix.env()),
compilers: [:phoenix, :gettext] ++ Mix.compilers(), compilers: [:phoenix, :gettext] ++ Mix.compilers(),
@ -163,8 +163,8 @@ defp deps do
{:poolboy, "~> 1.5"}, {:poolboy, "~> 1.5"},
{:prometheus, "~> 4.6"}, {:prometheus, "~> 4.6"},
{:prometheus_ex, {:prometheus_ex,
git: "https://git.pleroma.social/pleroma/elixir-libraries/prometheus.ex.git", git: "https://github.com/lanodan/prometheus.ex.git",
ref: "a4e9beb3c1c479d14b352fd9d6dd7b1f6d7deee5", branch: "fix/elixir-1.14",
override: true}, override: true},
{:prometheus_plugs, "~> 1.1"}, {:prometheus_plugs, "~> 1.1"},
{:prometheus_phoenix, "~> 1.3"}, {:prometheus_phoenix, "~> 1.3"},

View File

@ -104,7 +104,7 @@
"pot": {:hex, :pot, "1.0.1", "81b511b1fa7c3123171c265cb7065a1528cebd7277b0cbc94257c50a8b2e4c17", [:rebar3], [], "hexpm", "ed87f5976531d91528452faa1138a5328db7f9f20d8feaae15f5051f79bcfb6d"}, "pot": {:hex, :pot, "1.0.1", "81b511b1fa7c3123171c265cb7065a1528cebd7277b0cbc94257c50a8b2e4c17", [:rebar3], [], "hexpm", "ed87f5976531d91528452faa1138a5328db7f9f20d8feaae15f5051f79bcfb6d"},
"prometheus": {:hex, :prometheus, "4.8.0", "1ce1e1002b173c336d61f186b56263346536e76814edd9a142e12aeb2d6c1ad2", [:mix, :rebar3], [], "hexpm", "0fc2e17103073edb3758a46a5d44b006191bf25b73cbaa2b779109de396afcb5"}, "prometheus": {:hex, :prometheus, "4.8.0", "1ce1e1002b173c336d61f186b56263346536e76814edd9a142e12aeb2d6c1ad2", [:mix, :rebar3], [], "hexpm", "0fc2e17103073edb3758a46a5d44b006191bf25b73cbaa2b779109de396afcb5"},
"prometheus_ecto": {:hex, :prometheus_ecto, "1.4.3", "3dd4da1812b8e0dbee81ea58bb3b62ed7588f2eae0c9e97e434c46807ff82311", [:mix], [{:ecto, "~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm", "8d66289f77f913b37eda81fd287340c17e61a447549deb28efc254532b2bed82"}, "prometheus_ecto": {:hex, :prometheus_ecto, "1.4.3", "3dd4da1812b8e0dbee81ea58bb3b62ed7588f2eae0c9e97e434c46807ff82311", [:mix], [{:ecto, "~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm", "8d66289f77f913b37eda81fd287340c17e61a447549deb28efc254532b2bed82"},
"prometheus_ex": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/prometheus.ex.git", "a4e9beb3c1c479d14b352fd9d6dd7b1f6d7deee5", [ref: "a4e9beb3c1c479d14b352fd9d6dd7b1f6d7deee5"]}, "prometheus_ex": {:git, "https://github.com/lanodan/prometheus.ex.git", "31f7fbe4b71b79ba27efc2a5085746c4011ceb8f", [branch: "fix/elixir-1.14"]},
"prometheus_phoenix": {:hex, :prometheus_phoenix, "1.3.0", "c4b527e0b3a9ef1af26bdcfbfad3998f37795b9185d475ca610fe4388fdd3bb5", [:mix], [{:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.3 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm", "c4d1404ac4e9d3d963da601db2a7d8ea31194f0017057fabf0cfb9bf5a6c8c75"}, "prometheus_phoenix": {:hex, :prometheus_phoenix, "1.3.0", "c4b527e0b3a9ef1af26bdcfbfad3998f37795b9185d475ca610fe4388fdd3bb5", [:mix], [{:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.3 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm", "c4d1404ac4e9d3d963da601db2a7d8ea31194f0017057fabf0cfb9bf5a6c8c75"},
"prometheus_phx": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/prometheus-phx.git", "9cd8f248c9381ffedc799905050abce194a97514", [branch: "no-logging"]}, "prometheus_phx": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/prometheus-phx.git", "9cd8f248c9381ffedc799905050abce194a97514", [branch: "no-logging"]},
"prometheus_plugs": {:hex, :prometheus_plugs, "1.1.5", "25933d48f8af3a5941dd7b621c889749894d8a1082a6ff7c67cc99dec26377c5", [:mix], [{:accept, "~> 0.1", [hex: :accept, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}, {:prometheus_process_collector, "~> 1.1", [hex: :prometheus_process_collector, repo: "hexpm", optional: true]}], "hexpm", "0273a6483ccb936d79ca19b0ab629aef0dba958697c94782bb728b920dfc6a79"}, "prometheus_plugs": {:hex, :prometheus_plugs, "1.1.5", "25933d48f8af3a5941dd7b621c889749894d8a1082a6ff7c67cc99dec26377c5", [:mix], [{:accept, "~> 0.1", [hex: :accept, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}, {:prometheus_process_collector, "~> 1.1", [hex: :prometheus_process_collector, repo: "hexpm", optional: true]}], "hexpm", "0273a6483ccb936d79ca19b0ab629aef0dba958697c94782bb728b920dfc6a79"},

View File

@ -64,13 +64,14 @@ defmodule Pleroma.HTML.Scrubber.Default do
@allow_inline_images Pleroma.Config.get([:markup, :allow_inline_images]) @allow_inline_images Pleroma.Config.get([:markup, :allow_inline_images])
if @allow_inline_images do if @allow_inline_images do
Meta.allow_tag_with_this_attribute_values(:img, "class", ["emoji"])
# restrict img tags to http/https only, because of MediaProxy. # restrict img tags to http/https only, because of MediaProxy.
Meta.allow_tag_with_uri_attributes(:img, ["src"], ["http", "https"]) Meta.allow_tag_with_uri_attributes(:img, ["src"], ["http", "https"])
Meta.allow_tag_with_these_attributes(:img, [ Meta.allow_tag_with_these_attributes(:img, [
"width", "width",
"height", "height",
"class",
"title", "title",
"alt" "alt"
]) ])

View File

@ -41,13 +41,14 @@ defmodule Pleroma.HTML.Scrubber.TwitterText do
# allow inline images for custom emoji # allow inline images for custom emoji
if Pleroma.Config.get([:markup, :allow_inline_images]) do if Pleroma.Config.get([:markup, :allow_inline_images]) do
Meta.allow_tag_with_this_attribute_values(:img, "class", ["emoji"])
# restrict img tags to http/https only, because of MediaProxy. # restrict img tags to http/https only, because of MediaProxy.
Meta.allow_tag_with_uri_attributes(:img, ["src"], ["http", "https"]) Meta.allow_tag_with_uri_attributes(:img, ["src"], ["http", "https"])
Meta.allow_tag_with_these_attributes(:img, [ Meta.allow_tag_with_these_attributes(:img, [
"width", "width",
"height", "height",
"class",
"title", "title",
"alt" "alt"
]) ])

View File

@ -13,6 +13,29 @@ defmodule Pleroma.Activity.Ir.TopicsTest do
import Mock import Mock
describe "chat message" do
test "Create produces no topics" do
activity = %Activity{
object: %Object{data: %{"type" => "ChatMessage"}},
data: %{"type" => "Create"}
}
assert [] == Topics.get_activity_topics(activity)
end
test "Delete produces user and user:pleroma_chat" do
activity = %Activity{
object: %Object{data: %{"type" => "ChatMessage"}},
data: %{"type" => "Delete"}
}
topics = Topics.get_activity_topics(activity)
assert [_, _] = topics
assert "user" in topics
assert "user:pleroma_chat" in topics
end
end
describe "poll answer" do describe "poll answer" do
test "produce no topics" do test "produce no topics" do
activity = %Activity{object: %Object{data: %{"type" => "Answer"}}} activity = %Activity{object: %Object{data: %{"type" => "Answer"}}}
@ -114,6 +137,36 @@ test "local action doesn't produce public:remote topic", %{activity: activity} d
end end
end end
describe "local-public visibility create events" do
setup do
activity = %Activity{
object: %Object{data: %{"attachment" => []}},
data: %{"type" => "Create", "to" => [Pleroma.Web.ActivityPub.Utils.as_local_public()]}
}
{:ok, activity: activity}
end
test "doesn't produce public topics", %{activity: activity} do
topics = Topics.get_activity_topics(activity)
refute Enum.member?(topics, "public")
end
test "produces public:local topics", %{activity: activity} do
topics = Topics.get_activity_topics(activity)
assert Enum.member?(topics, "public:local")
end
test "with no attachments doesn't produce public:media topics", %{activity: activity} do
topics = Topics.get_activity_topics(activity)
refute Enum.member?(topics, "public:media")
refute Enum.member?(topics, "public:local:media")
end
end
describe "public visibility create events with attachments" do describe "public visibility create events with attachments" do
setup do setup do
activity = %Activity{ activity = %Activity{
@ -152,6 +205,29 @@ test "non-local action produces public:remote:media topic", %{activity: activity
end end
end end
describe "local-public visibility create events with attachments" do
setup do
activity = %Activity{
object: %Object{data: %{"attachment" => ["foo"]}},
data: %{"type" => "Create", "to" => [Pleroma.Web.ActivityPub.Utils.as_local_public()]}
}
{:ok, activity: activity}
end
test "do not produce public:media topics", %{activity: activity} do
topics = Topics.get_activity_topics(activity)
refute Enum.member?(topics, "public:media")
end
test "produces public:local:media topics", %{activity: activity} do
topics = Topics.get_activity_topics(activity)
assert Enum.member?(topics, "public:local:media")
end
end
describe "non-public visibility" do describe "non-public visibility" do
test "produces direct topic" do test "produces direct topic" do
activity = %Activity{object: %Object{data: %{"type" => "Note"}}, data: %{"to" => []}} activity = %Activity{object: %Object{data: %{"type" => "Note"}}, data: %{"to" => []}}

View File

@ -17,6 +17,7 @@ defmodule Pleroma.HTMLTest do
this is a link with allowed "rel" attribute: <a href="http://example.com/" rel="tag">example.com</a> this is a link with allowed "rel" attribute: <a href="http://example.com/" rel="tag">example.com</a>
this is a link with not allowed "rel" attribute: <a href="http://example.com/" rel="tag noallowed">example.com</a> this is a link with not allowed "rel" attribute: <a href="http://example.com/" rel="tag noallowed">example.com</a>
this is an image: <img src="http://example.com/image.jpg"><br /> this is an image: <img src="http://example.com/image.jpg"><br />
this is an inline emoji: <img class="emoji" src="http://example.com/image.jpg"><br />
<script>alert('hacked')</script> <script>alert('hacked')</script>
""" """
@ -24,6 +25,10 @@ defmodule Pleroma.HTMLTest do
<img src="http://example.com/image.jpg" onerror="alert('hacked')"> <img src="http://example.com/image.jpg" onerror="alert('hacked')">
""" """
@html_stillimage_sample """
<img class="still-image" src="http://example.com/image.jpg">
"""
@html_span_class_sample """ @html_span_class_sample """
<span class="animate-spin">hi</span> <span class="animate-spin">hi</span>
""" """
@ -45,6 +50,7 @@ test "works as expected" do
this is a link with allowed &quot;rel&quot; attribute: example.com this is a link with allowed &quot;rel&quot; attribute: example.com
this is a link with not allowed &quot;rel&quot; attribute: example.com this is a link with not allowed &quot;rel&quot; attribute: example.com
this is an image: this is an image:
this is an inline emoji:
alert(&#39;hacked&#39;) alert(&#39;hacked&#39;)
""" """
@ -67,6 +73,7 @@ test "normalizes HTML as expected" do
this is a link with allowed &quot;rel&quot; attribute: <a href="http://example.com/" rel="tag">example.com</a> this is a link with allowed &quot;rel&quot; attribute: <a href="http://example.com/" rel="tag">example.com</a>
this is a link with not allowed &quot;rel&quot; attribute: <a href="http://example.com/">example.com</a> this is a link with not allowed &quot;rel&quot; attribute: <a href="http://example.com/">example.com</a>
this is an image: <img src="http://example.com/image.jpg"/><br/> this is an image: <img src="http://example.com/image.jpg"/><br/>
this is an inline emoji: <img class="emoji" src="http://example.com/image.jpg"/><br/>
alert(&#39;hacked&#39;) alert(&#39;hacked&#39;)
""" """
@ -90,6 +97,15 @@ test "does not allow spans with invalid classes" do
HTML.filter_tags(@html_span_class_sample, Pleroma.HTML.Scrubber.TwitterText) HTML.filter_tags(@html_span_class_sample, Pleroma.HTML.Scrubber.TwitterText)
end end
test "does not allow images with invalid classes" do
expected = """
<img src="http://example.com/image.jpg"/>
"""
assert expected ==
HTML.filter_tags(@html_stillimage_sample, Pleroma.HTML.Scrubber.TwitterText)
end
test "does allow microformats" do test "does allow microformats" do
expected = """ expected = """
<span class="h-card"><a class="u-url mention">@<span>foo</span></a></span> <span class="h-card"><a class="u-url mention">@<span>foo</span></a></span>
@ -121,6 +137,7 @@ test "normalizes HTML as expected" do
this is a link with allowed &quot;rel&quot; attribute: <a href="http://example.com/" rel="tag">example.com</a> this is a link with allowed &quot;rel&quot; attribute: <a href="http://example.com/" rel="tag">example.com</a>
this is a link with not allowed &quot;rel&quot; attribute: <a href="http://example.com/">example.com</a> this is a link with not allowed &quot;rel&quot; attribute: <a href="http://example.com/">example.com</a>
this is an image: <img src="http://example.com/image.jpg"/><br/> this is an image: <img src="http://example.com/image.jpg"/><br/>
this is an inline emoji: <img class="emoji" src="http://example.com/image.jpg"/><br/>
alert(&#39;hacked&#39;) alert(&#39;hacked&#39;)
""" """
@ -143,6 +160,15 @@ test "does not allow spans with invalid classes" do
assert expected == HTML.filter_tags(@html_span_class_sample, Pleroma.HTML.Scrubber.Default) assert expected == HTML.filter_tags(@html_span_class_sample, Pleroma.HTML.Scrubber.Default)
end end
test "does not allow images with invalid classes" do
expected = """
<img src="http://example.com/image.jpg"/>
"""
assert expected ==
HTML.filter_tags(@html_stillimage_sample, Pleroma.HTML.Scrubber.TwitterText)
end
test "does allow microformats" do test "does allow microformats" do
expected = """ expected = """
<span class="h-card"><a class="u-url mention">@<span>foo</span></a></span> <span class="h-card"><a class="u-url mention">@<span>foo</span></a></span>

View File

@ -507,6 +507,25 @@ test "it clears all notifications belonging to the user" do
end end
end end
describe "destroy_multiple_from_types/2" do
test "clears all notifications of a certain type for a given user" do
report_activity = insert(:report_activity)
user1 = insert(:user, is_moderator: true, is_admin: true)
user2 = insert(:user, is_moderator: true, is_admin: true)
{:ok, _} = Notification.create_notifications(report_activity)
{:ok, _} =
CommonAPI.post(user2, %{
status: "hey @#{user1.nickname} !"
})
Notification.destroy_multiple_from_types(user1, ["pleroma:report"])
assert [%Pleroma.Notification{type: "mention"}] = Notification.for_user(user1)
assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user2)
end
end
describe "set_read_up_to()" do describe "set_read_up_to()" do
test "it sets all notifications as read up to a specified notification ID" do test "it sets all notifications as read up to a specified notification ID" do
user = insert(:user) user = insert(:user)

View File

@ -109,6 +109,11 @@ test "it properly deduces the actor id for mastodon and pleroma" do
{:ok, "https://example.com/users/1234"} {:ok, "https://example.com/users/1234"}
end end
test "it deduces the actor id for gotoSocial" do
assert Signature.key_id_to_actor_id("https://example.com/users/1234/main-key") ==
{:ok, "https://example.com/users/1234"}
end
test "it calls webfinger for 'acct:' accounts" do test "it calls webfinger for 'acct:' accounts" do
with_mock(Pleroma.Web.WebFinger, with_mock(Pleroma.Web.WebFinger,
finger: fn _ -> %{"ap_id" => "https://gensokyo.2hu/users/raymoo"} end finger: fn _ -> %{"ap_id" => "https://gensokyo.2hu/users/raymoo"} end

View File

@ -5,6 +5,7 @@
defmodule Pleroma.UserTest do defmodule Pleroma.UserTest do
alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.Builders.UserBuilder alias Pleroma.Builders.UserBuilder
alias Pleroma.Notification
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.Repo alias Pleroma.Repo
alias Pleroma.Tests.ObanHelpers alias Pleroma.Tests.ObanHelpers
@ -2123,6 +2124,26 @@ test "performs update cache if user updated" do
assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}") assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id) assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
end end
test "removes report notifs when user isn't superuser any more" do
report_activity = insert(:report_activity)
user = insert(:user, is_moderator: true, is_admin: true)
{:ok, _} = Notification.create_notifications(report_activity)
assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user)
{:ok, user} = user |> User.admin_api_update(%{is_moderator: false})
# is still superuser because still admin
assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user)
{:ok, user} = user |> User.admin_api_update(%{is_moderator: true, is_admin: false})
# is still superuser because still moderator
assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user)
{:ok, user} = user |> User.admin_api_update(%{is_moderator: false})
# is not a superuser any more
assert [] = Notification.for_user(user)
end
end end
describe "following/followers synchronization" do describe "following/followers synchronization" do

View File

@ -32,4 +32,17 @@ test "a basic note validates", %{note: note} do
%{valid?: true} = ArticleNotePageValidator.cast_and_validate(note) %{valid?: true} = ArticleNotePageValidator.cast_and_validate(note)
end end
end end
test "a Note without replies/first/items validates" do
insert(:user, ap_id: "https://mastodon.social/users/emelie")
note =
"test/fixtures/tesla_mock/status.emelie.json"
|> File.read!()
|> Jason.decode!()
|> pop_in(["replies", "first", "items"])
|> elem(1)
%{valid?: true} = ArticleNotePageValidator.cast_and_validate(note)
end
end end

View File

@ -27,6 +27,46 @@ test "works with honkerific attachments" do
assert attachment.mediaType == "application/octet-stream" assert attachment.mediaType == "application/octet-stream"
end end
test "works with an unknown but valid mime type" do
attachment = %{
"mediaType" => "x-custom/x-type",
"type" => "Document",
"url" => "https://example.org"
}
assert {:ok, attachment} =
AttachmentValidator.cast_and_validate(attachment)
|> Ecto.Changeset.apply_action(:insert)
assert attachment.mediaType == "x-custom/x-type"
end
test "works with invalid mime types" do
attachment = %{
"mediaType" => "x-customx-type",
"type" => "Document",
"url" => "https://example.org"
}
assert {:ok, attachment} =
AttachmentValidator.cast_and_validate(attachment)
|> Ecto.Changeset.apply_action(:insert)
assert attachment.mediaType == "application/octet-stream"
attachment = %{
"mediaType" => "https://example.org",
"type" => "Document",
"url" => "https://example.org"
}
assert {:ok, attachment} =
AttachmentValidator.cast_and_validate(attachment)
|> Ecto.Changeset.apply_action(:insert)
assert attachment.mediaType == "application/octet-stream"
end
test "it turns mastodon attachments into our attachments" do test "it turns mastodon attachments into our attachments" do
attachment = %{ attachment = %{
"url" => "url" =>

View File

@ -1664,21 +1664,21 @@ test "getting a list of mutes" do
|> get("/api/v1/mutes") |> get("/api/v1/mutes")
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)
assert [id1, id2, id3] == Enum.map(result, & &1["id"]) assert [id3, id2, id1] == Enum.map(result, & &1["id"])
result = result =
conn conn
|> get("/api/v1/mutes?limit=1") |> get("/api/v1/mutes?limit=1")
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)
assert [%{"id" => ^id1}] = result assert [%{"id" => ^id3}] = result
result = result =
conn conn
|> get("/api/v1/mutes?since_id=#{id1}") |> get("/api/v1/mutes?since_id=#{id1}")
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)
assert [%{"id" => ^id2}, %{"id" => ^id3}] = result assert [%{"id" => ^id3}, %{"id" => ^id2}] = result
result = result =
conn conn
@ -1692,7 +1692,7 @@ test "getting a list of mutes" do
|> get("/api/v1/mutes?since_id=#{id1}&limit=1") |> get("/api/v1/mutes?since_id=#{id1}&limit=1")
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)
assert [%{"id" => ^id2}] = result assert [%{"id" => ^id3}] = result
end end
test "list of mutes with with_relationships parameter" do test "list of mutes with with_relationships parameter" do
@ -1711,7 +1711,7 @@ test "list of mutes with with_relationships parameter" do
assert [ assert [
%{ %{
"id" => ^id1, "id" => ^id3,
"pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}} "pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}}
}, },
%{ %{
@ -1719,7 +1719,7 @@ test "list of mutes with with_relationships parameter" do
"pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}} "pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}}
}, },
%{ %{
"id" => ^id3, "id" => ^id1,
"pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}} "pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}}
} }
] = ] =
@ -1744,7 +1744,7 @@ test "getting a list of blocks" do
|> get("/api/v1/blocks") |> get("/api/v1/blocks")
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)
assert [id1, id2, id3] == Enum.map(result, & &1["id"]) assert [id3, id2, id1] == Enum.map(result, & &1["id"])
result = result =
conn conn
@ -1752,7 +1752,7 @@ test "getting a list of blocks" do
|> get("/api/v1/blocks?limit=1") |> get("/api/v1/blocks?limit=1")
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)
assert [%{"id" => ^id1}] = result assert [%{"id" => ^id3}] = result
result = result =
conn conn
@ -1760,7 +1760,7 @@ test "getting a list of blocks" do
|> get("/api/v1/blocks?since_id=#{id1}") |> get("/api/v1/blocks?since_id=#{id1}")
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)
assert [%{"id" => ^id2}, %{"id" => ^id3}] = result assert [%{"id" => ^id3}, %{"id" => ^id2}] = result
result = result =
conn conn
@ -1776,6 +1776,30 @@ test "getting a list of blocks" do
|> get("/api/v1/blocks?since_id=#{id1}&limit=1") |> get("/api/v1/blocks?since_id=#{id1}&limit=1")
|> json_response_and_validate_schema(200) |> json_response_and_validate_schema(200)
assert [%{"id" => ^id2}] = result assert [%{"id" => ^id3}] = result
conn_res =
conn
|> assign(:user, user)
|> get("/api/v1/blocks?limit=2")
next_url =
~r{<.+?(?<link>/api[^>]+)>; rel=\"next\"}
|> Regex.named_captures(get_resp_header(conn_res, "link") |> Enum.at(0))
|> Map.get("link")
result =
conn_res
|> json_response_and_validate_schema(200)
assert [%{"id" => ^id3}, %{"id" => ^id2}] = result
result =
conn
|> assign(:user, user)
|> get(next_url)
|> json_response_and_validate_schema(200)
assert [%{"id" => ^id1}] = result
end end
end end

View File

@ -885,7 +885,7 @@ test "muted emotions", %{conn: conn} do
end end
end end
describe "hashtag timeline handling of :restrict_unauthenticated setting" do describe "hashtag timeline handling of restrict_unauthenticated setting" do
setup do setup do
user = insert(:user) user = insert(:user)
{:ok, activity1} = CommonAPI.post(user, %{status: "test #tag1"}) {:ok, activity1} = CommonAPI.post(user, %{status: "test #tag1"})

View File

@ -10,11 +10,14 @@ defmodule Pleroma.Web.MediaProxy.Invalidation.ScriptTest do
test "it logs error when script is not found" do test "it logs error when script is not found" do
assert capture_log(fn -> assert capture_log(fn ->
assert Invalidation.Script.purge( assert {:error, msg} =
Invalidation.Script.purge(
["http://example.com/media/example.jpg"], ["http://example.com/media/example.jpg"],
script_path: "./example" script_path: "./example"
) == {:error, "%ErlangError{original: :enoent}"} )
end) =~ "Error while cache purge: %ErlangError{original: :enoent}"
assert msg =~ ~r/%ErlangError{original: :enoent(, reason: nil)?}/
end) =~ ~r/Error while cache purge: %ErlangError{original: :enoent(, reason: nil)?}/
capture_log(fn -> capture_log(fn ->
assert Invalidation.Script.purge( assert Invalidation.Script.purge(