diff --git a/CHANGELOG.md b/CHANGELOG.md
index 92635f6d0..2f85cc302 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,28 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
+## [2.1.2] - 2020-09-17
+
+### Security
+
+- Fix most MRF rules either crashing or not being applied to objects passed into the Common Pipeline (ChatMessage, Question, Answer, Audio, Event).
+
+### Fixed
+
+- Welcome Chat messages preventing user registration with MRF Simple Policy applied to the local instance.
+- Mastodon API: the public timeline returning an error when the `reply_visibility` parameter is set to `self` for an unauthenticated user.
+- Mastodon Streaming API: Handler crashes on authentication failures, resulting in error logs.
+- Mastodon Streaming API: Error logs on client pings.
+- Rich media: Log spam on failures. Now the error is only logged once per attempt.
+
+### Changed
+
+- Rich Media: A HEAD request is now done to the url, to ensure it has the appropriate content type and size before proceeding with a GET.
+
+### Upgrade notes
+
+1. Restart Pleroma
+
## [2.1.1] - 2020-09-08
### Security
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 624a508ae..e4eafc8ac 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -744,7 +744,7 @@ defp restrict_replies(query, %{exclude_replies: true}) do
end
defp restrict_replies(query, %{
- reply_filtering_user: user,
+ reply_filtering_user: %User{} = user,
reply_visibility: "self"
}) do
from(
@@ -760,7 +760,7 @@ defp restrict_replies(query, %{
end
defp restrict_replies(query, %{
- reply_filtering_user: user,
+ reply_filtering_user: %User{} = user,
reply_visibility: "following"
}) do
from(
diff --git a/lib/pleroma/web/activity_pub/mrf.ex b/lib/pleroma/web/activity_pub/mrf.ex
index 206d6af52..5e5361082 100644
--- a/lib/pleroma/web/activity_pub/mrf.ex
+++ b/lib/pleroma/web/activity_pub/mrf.ex
@@ -5,16 +5,34 @@
defmodule Pleroma.Web.ActivityPub.MRF do
@callback filter(Map.t()) :: {:ok | :reject, Map.t()}
- def filter(policies, %{} = object) do
+ def filter(policies, %{} = message) do
policies
- |> Enum.reduce({:ok, object}, fn
- policy, {:ok, object} -> policy.filter(object)
+ |> Enum.reduce({:ok, message}, fn
+ policy, {:ok, message} -> policy.filter(message)
_, error -> error
end)
end
def filter(%{} = object), do: get_policies() |> filter(object)
+ def pipeline_filter(%{} = message, meta) do
+ object = meta[:object_data]
+ ap_id = message["object"]
+
+ if object && ap_id do
+ with {:ok, message} <- filter(Map.put(message, "object", object)) do
+ meta = Keyword.put(meta, :object_data, message["object"])
+ {:ok, Map.put(message, "object", ap_id), meta}
+ else
+ {err, message} -> {err, message, meta}
+ end
+ else
+ {err, message} = filter(message)
+
+ {err, message, meta}
+ end
+ end
+
def get_policies do
Pleroma.Config.get([:mrf, :policies], []) |> get_policies()
end
diff --git a/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex b/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex
index 15e09dcf0..db66cfa3e 100644
--- a/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex
@@ -20,9 +20,17 @@ defp string_matches?(string, pattern) do
String.match?(string, pattern)
end
- defp check_reject(%{"object" => %{"content" => content, "summary" => summary}} = message) do
+ defp object_payload(%{} = object) do
+ [object["content"], object["summary"], object["name"]]
+ |> Enum.filter(& &1)
+ |> Enum.join("\n")
+ end
+
+ defp check_reject(%{"object" => %{} = object} = message) do
+ payload = object_payload(object)
+
if Enum.any?(Pleroma.Config.get([:mrf_keyword, :reject]), fn pattern ->
- string_matches?(content, pattern) or string_matches?(summary, pattern)
+ string_matches?(payload, pattern)
end) do
{:reject, "[KeywordPolicy] Matches with rejected keyword"}
else
@@ -30,12 +38,12 @@ defp check_reject(%{"object" => %{"content" => content, "summary" => summary}} =
end
end
- defp check_ftl_removal(
- %{"to" => to, "object" => %{"content" => content, "summary" => summary}} = message
- ) do
+ defp check_ftl_removal(%{"to" => to, "object" => %{} = object} = message) do
+ payload = object_payload(object)
+
if Pleroma.Constants.as_public() in to and
Enum.any?(Pleroma.Config.get([:mrf_keyword, :federated_timeline_removal]), fn pattern ->
- string_matches?(content, pattern) or string_matches?(summary, pattern)
+ string_matches?(payload, pattern)
end) do
to = List.delete(to, Pleroma.Constants.as_public())
cc = [Pleroma.Constants.as_public() | message["cc"] || []]
@@ -51,35 +59,24 @@ defp check_ftl_removal(
end
end
- defp check_replace(%{"object" => %{"content" => content, "summary" => summary}} = message) do
- content =
- if is_binary(content) do
- content
- else
- ""
- end
+ defp check_replace(%{"object" => %{} = object} = message) do
+ object =
+ ["content", "name", "summary"]
+ |> Enum.filter(fn field -> Map.has_key?(object, field) && object[field] end)
+ |> Enum.reduce(object, fn field, object ->
+ data =
+ Enum.reduce(
+ Pleroma.Config.get([:mrf_keyword, :replace]),
+ object[field],
+ fn {pat, repl}, acc -> String.replace(acc, pat, repl) end
+ )
- summary =
- if is_binary(summary) do
- summary
- else
- ""
- end
+ Map.put(object, field, data)
+ end)
- {content, summary} =
- Enum.reduce(
- Pleroma.Config.get([:mrf_keyword, :replace]),
- {content, summary},
- fn {pattern, replacement}, {content_acc, summary_acc} ->
- {String.replace(content_acc, pattern, replacement),
- String.replace(summary_acc, pattern, replacement)}
- end
- )
+ message = Map.put(message, "object", object)
- {:ok,
- message
- |> put_in(["object", "content"], content)
- |> put_in(["object", "summary"], summary)}
+ {:ok, message}
end
@impl true
diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex
index bb193475a..161177727 100644
--- a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex
@@ -66,7 +66,8 @@ defp check_media_nsfw(
"type" => "Create",
"object" => child_object
} = object
- ) do
+ )
+ when is_map(child_object) do
media_nsfw =
Config.get([:mrf_simple, :media_nsfw])
|> MRF.subdomains_regex()
diff --git a/lib/pleroma/web/activity_pub/mrf/subchain_policy.ex b/lib/pleroma/web/activity_pub/mrf/subchain_policy.ex
index c9f20571f..048052da6 100644
--- a/lib/pleroma/web/activity_pub/mrf/subchain_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/subchain_policy.ex
@@ -28,8 +28,7 @@ def filter(%{"actor" => actor} = message) do
}"
)
- subchain
- |> MRF.filter(message)
+ MRF.filter(subchain, message)
else
_e -> {:ok, message}
end
diff --git a/lib/pleroma/web/activity_pub/pipeline.ex b/lib/pleroma/web/activity_pub/pipeline.ex
index 36e325c37..2db86f116 100644
--- a/lib/pleroma/web/activity_pub/pipeline.ex
+++ b/lib/pleroma/web/activity_pub/pipeline.ex
@@ -26,13 +26,17 @@ def common_pipeline(object, meta) do
{:error, e} ->
{:error, e}
+
+ {:reject, e} ->
+ {:reject, e}
end
end
def do_common_pipeline(object, meta) do
with {_, {:ok, validated_object, meta}} <-
{:validate_object, ObjectValidator.validate(object, meta)},
- {_, {:ok, mrfd_object}} <- {:mrf_object, MRF.filter(validated_object)},
+ {_, {:ok, mrfd_object, meta}} <-
+ {:mrf_object, MRF.pipeline_filter(validated_object, meta)},
{_, {:ok, activity, meta}} <-
{:persist_object, ActivityPub.persist(mrfd_object, meta)},
{_, {:ok, activity, meta}} <-
@@ -40,7 +44,7 @@ def do_common_pipeline(object, meta) do
{_, {:ok, _}} <- {:federation, maybe_federate(activity, meta)} do
{:ok, activity, meta}
else
- {:mrf_object, {:reject, _}} -> {:ok, nil, meta}
+ {:mrf_object, {:reject, message, _}} -> {:reject, message}
e -> {:error, e}
end
end
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index 76298c4a0..63dd227c1 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -311,7 +311,7 @@ def fix_url(object), do: object
def fix_emoji(%{"tag" => tags} = object) when is_list(tags) do
emoji =
tags
- |> Enum.filter(fn data -> data["type"] == "Emoji" and data["icon"] end)
+ |> Enum.filter(fn data -> is_map(data) and data["type"] == "Emoji" and data["icon"] end)
|> Enum.reduce(%{}, fn data, mapping ->
name = String.trim(data["name"], ":")
diff --git a/lib/pleroma/web/api_spec/operations/chat_operation.ex b/lib/pleroma/web/api_spec/operations/chat_operation.ex
index b1a0d26ab..56554d5b4 100644
--- a/lib/pleroma/web/api_spec/operations/chat_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/chat_operation.ex
@@ -184,7 +184,8 @@ def post_chat_message_operation do
"application/json",
ChatMessage
),
- 400 => Operation.response("Bad Request", "application/json", ApiError)
+ 400 => Operation.response("Bad Request", "application/json", ApiError),
+ 422 => Operation.response("MRF Rejection", "application/json", ApiError)
},
security: [
%{
diff --git a/lib/pleroma/web/api_spec/operations/status_operation.ex b/lib/pleroma/web/api_spec/operations/status_operation.ex
index 5bd4619d5..d7ebde6f6 100644
--- a/lib/pleroma/web/api_spec/operations/status_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/status_operation.ex
@@ -55,7 +55,7 @@ def create_operation do
"application/json",
%Schema{oneOf: [Status, ScheduledStatus]}
),
- 422 => Operation.response("Bad Request", "application/json", ApiError)
+ 422 => Operation.response("Bad Request / MRF Rejection", "application/json", ApiError)
}
}
end
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index 5ad2b91c2..3c7b9e794 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -49,6 +49,9 @@ def post_chat_message(%User{} = user, %User{} = recipient, content, opts \\ [])
local: true
)} do
{:ok, activity}
+ else
+ {:common_pipeline, {:reject, _} = e} -> e
+ e -> e
end
end
diff --git a/lib/pleroma/web/mastodon_api/websocket_handler.ex b/lib/pleroma/web/mastodon_api/websocket_handler.ex
index 94e4595d8..cf923ded8 100644
--- a/lib/pleroma/web/mastodon_api/websocket_handler.ex
+++ b/lib/pleroma/web/mastodon_api/websocket_handler.ex
@@ -37,12 +37,12 @@ def init(%{qs: qs} = req, state) do
else
{:error, :bad_topic} ->
Logger.debug("#{__MODULE__} bad topic #{inspect(req)}")
- {:ok, req} = :cowboy_req.reply(404, req)
+ req = :cowboy_req.reply(404, req)
{:ok, req, state}
{:error, :unauthorized} ->
Logger.debug("#{__MODULE__} authentication error: #{inspect(req)}")
- {:ok, req} = :cowboy_req.reply(401, req)
+ req = :cowboy_req.reply(401, req)
{:ok, req, state}
end
end
@@ -64,7 +64,9 @@ def websocket_handle(:pong, state) do
{:ok, %{state | timer: timer()}}
end
- # We never receive messages.
+ # We only receive pings for now
+ def websocket_handle(:ping, state), do: {:ok, state}
+
def websocket_handle(frame, state) do
Logger.error("#{__MODULE__} received frame: #{inspect(frame)}")
{:ok, state}
@@ -98,6 +100,10 @@ def websocket_info(:tick, state) do
{:reply, :ping, %{state | timer: nil, count: 0}, :hibernate}
end
+ # State can be `[]` only in case we terminate before switching to websocket,
+ # we already log errors for these cases in `init/1`, so just do nothing here
+ def terminate(_reason, _req, []), do: :ok
+
def terminate(reason, _req, state) do
Logger.debug(
"#{__MODULE__} terminating websocket connection for user #{
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index dd00600ea..06b116368 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -145,7 +145,10 @@ def create_authorization(
def after_create_authorization(%Plug.Conn{} = conn, %Authorization{} = auth, %{
"authorization" => %{"redirect_uri" => @oob_token_redirect_uri}
}) do
- render(conn, "oob_authorization_created.html", %{auth: auth})
+ # Enforcing the view to reuse the template when calling from other controllers
+ conn
+ |> put_view(OAuthView)
+ |> render("oob_authorization_created.html", %{auth: auth})
end
def after_create_authorization(%Plug.Conn{} = conn, %Authorization{} = auth, %{
diff --git a/lib/pleroma/web/pleroma_api/controllers/chat_controller.ex b/lib/pleroma/web/pleroma_api/controllers/chat_controller.ex
index 1f2e953f7..ea0921c77 100644
--- a/lib/pleroma/web/pleroma_api/controllers/chat_controller.ex
+++ b/lib/pleroma/web/pleroma_api/controllers/chat_controller.ex
@@ -90,6 +90,16 @@ def post_chat_message(
conn
|> put_view(MessageReferenceView)
|> render("show.json", chat_message_reference: cm_ref)
+ else
+ {:reject, message} ->
+ conn
+ |> put_status(:unprocessable_entity)
+ |> json(%{error: message})
+
+ {:error, message} ->
+ conn
+ |> put_status(:bad_request)
+ |> json(%{error: message})
end
end
diff --git a/lib/pleroma/web/rich_media/helpers.ex b/lib/pleroma/web/rich_media/helpers.ex
index 752ca9f81..b7852c6e3 100644
--- a/lib/pleroma/web/rich_media/helpers.ex
+++ b/lib/pleroma/web/rich_media/helpers.ex
@@ -96,6 +96,50 @@ def rich_media_get(url) do
@rich_media_options
end
- Pleroma.HTTP.get(url, headers, adapter: options)
+ head_check =
+ case Pleroma.HTTP.head(url, headers, adapter: options) do
+ # If the HEAD request didn't reach the server for whatever reason,
+ # we assume the GET that comes right after won't either
+ {:error, _} = e ->
+ e
+
+ {:ok, %Tesla.Env{status: 200, headers: headers}} ->
+ with :ok <- check_content_type(headers),
+ :ok <- check_content_length(headers),
+ do: :ok
+
+ _ ->
+ :ok
+ end
+
+ with :ok <- head_check, do: Pleroma.HTTP.get(url, headers, adapter: options)
+ end
+
+ defp check_content_type(headers) do
+ case List.keyfind(headers, "content-type", 0) do
+ {_, content_type} ->
+ case Plug.Conn.Utils.media_type(content_type) do
+ {:ok, "text", "html", _} -> :ok
+ _ -> {:error, {:content_type, content_type}}
+ end
+
+ _ ->
+ :ok
+ end
+ end
+
+ @max_body @rich_media_options[:max_body]
+ defp check_content_length(headers) do
+ case List.keyfind(headers, "content-length", 0) do
+ {_, maybe_content_length} ->
+ case Integer.parse(maybe_content_length) do
+ {content_length, ""} when content_length <= @max_body -> :ok
+ {_, ""} -> {:error, :body_too_large}
+ _ -> :ok
+ end
+
+ _ ->
+ :ok
+ end
end
end
diff --git a/lib/pleroma/web/rich_media/parser.ex b/lib/pleroma/web/rich_media/parser.ex
index e98c743ca..569249f51 100644
--- a/lib/pleroma/web/rich_media/parser.ex
+++ b/lib/pleroma/web/rich_media/parser.ex
@@ -31,6 +31,14 @@ defp get_cached_or_parse(url) do
{:ok, _data} = res ->
res
+ {:error, :body_too_large} = e ->
+ e
+
+ {:error, {:content_type, _}} = e ->
+ e
+
+ # The TTL is not set for the errors above, since they are unlikely to change
+ # with time
{:error, _} = e ->
ttl = Pleroma.Config.get([:rich_media, :failure_backoff], 60_000)
Cachex.expire(:rich_media_cache, url, ttl)
diff --git a/lib/pleroma/web/templates/o_auth/o_auth/oob_authorization_created.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/oob_authorization_created.html.eex
index 8443d906b..ffabe29a6 100644
--- a/lib/pleroma/web/templates/o_auth/o_auth/oob_authorization_created.html.eex
+++ b/lib/pleroma/web/templates/o_auth/o_auth/oob_authorization_created.html.eex
@@ -1,2 +1,2 @@
Successfully authorized
-Token code is <%= @auth.token %>
+Token code is
<%= @auth.token %>
diff --git a/lib/pleroma/web/templates/o_auth/o_auth/oob_token_exists.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/oob_token_exists.html.eex
index 961aad976..82785c4b9 100644
--- a/lib/pleroma/web/templates/o_auth/o_auth/oob_token_exists.html.eex
+++ b/lib/pleroma/web/templates/o_auth/o_auth/oob_token_exists.html.eex
@@ -1,2 +1,2 @@
Authorization exists
-Access token is <%= @token.token %>
+Access token is
<%= @token.token %>
diff --git a/mix.exs b/mix.exs
index 51e05965e..c88bf392d 100644
--- a/mix.exs
+++ b/mix.exs
@@ -4,7 +4,7 @@ defmodule Pleroma.Mixfile do
def project do
[
app: :pleroma,
- version: version("2.1.1"),
+ version: version("2.1.2"),
elixir: "~> 1.9",
elixirc_paths: elixirc_paths(Mix.env()),
compilers: [:phoenix, :gettext] ++ Mix.compilers(),
diff --git a/priv/static/index.html b/priv/static/index.html
index 6fa237768..f5690a8d6 100644
--- a/priv/static/index.html
+++ b/priv/static/index.html
@@ -1 +1 @@
-Pleroma
\ No newline at end of file
+Pleroma
\ No newline at end of file
diff --git a/priv/static/static/font/fontello.1599568314856.woff b/priv/static/static/font/fontello.1599568314856.woff
deleted file mode 100644
index 64f566383..000000000
Binary files a/priv/static/static/font/fontello.1599568314856.woff and /dev/null differ
diff --git a/priv/static/static/font/fontello.1599568314856.woff2 b/priv/static/static/font/fontello.1599568314856.woff2
deleted file mode 100644
index 972e70831..000000000
Binary files a/priv/static/static/font/fontello.1599568314856.woff2 and /dev/null differ
diff --git a/priv/static/static/font/fontello.1599568314856.eot b/priv/static/static/font/fontello.1600365488745.eot
similarity index 89%
rename from priv/static/static/font/fontello.1599568314856.eot
rename to priv/static/static/font/fontello.1600365488745.eot
index 1a6931a0e..255f50372 100644
Binary files a/priv/static/static/font/fontello.1599568314856.eot and b/priv/static/static/font/fontello.1600365488745.eot differ
diff --git a/priv/static/static/font/fontello.1599568314856.svg b/priv/static/static/font/fontello.1600365488745.svg
similarity index 98%
rename from priv/static/static/font/fontello.1599568314856.svg
rename to priv/static/static/font/fontello.1600365488745.svg
index 71b5d70af..9eddf62ea 100644
--- a/priv/static/static/font/fontello.1599568314856.svg
+++ b/priv/static/static/font/fontello.1600365488745.svg
@@ -92,6 +92,8 @@
+
+
diff --git a/priv/static/static/font/fontello.1599568314856.ttf b/priv/static/static/font/fontello.1600365488745.ttf
similarity index 89%
rename from priv/static/static/font/fontello.1599568314856.ttf
rename to priv/static/static/font/fontello.1600365488745.ttf
index 795464475..6bda99d50 100644
Binary files a/priv/static/static/font/fontello.1599568314856.ttf and b/priv/static/static/font/fontello.1600365488745.ttf differ
diff --git a/priv/static/static/font/fontello.1600365488745.woff b/priv/static/static/font/fontello.1600365488745.woff
new file mode 100644
index 000000000..11c866ae0
Binary files /dev/null and b/priv/static/static/font/fontello.1600365488745.woff differ
diff --git a/priv/static/static/font/fontello.1600365488745.woff2 b/priv/static/static/font/fontello.1600365488745.woff2
new file mode 100644
index 000000000..06151d28c
Binary files /dev/null and b/priv/static/static/font/fontello.1600365488745.woff2 differ
diff --git a/priv/static/static/fontello.1599568314856.css b/priv/static/static/fontello.1600365488745.css
similarity index 89%
rename from priv/static/static/fontello.1599568314856.css
rename to priv/static/static/fontello.1600365488745.css
index e636286c0..781ff7620 100644
Binary files a/priv/static/static/fontello.1599568314856.css and b/priv/static/static/fontello.1600365488745.css differ
diff --git a/priv/static/static/fontello.json b/priv/static/static/fontello.json
index 706800cdb..b0136fd90 100644
--- a/priv/static/static/fontello.json
+++ b/priv/static/static/fontello.json
@@ -405,6 +405,12 @@
"css": "block",
"code": 59434,
"src": "fontawesome"
+ },
+ {
+ "uid": "3e674995cacc2b09692c096ea7eb6165",
+ "css": "megaphone",
+ "code": 59435,
+ "src": "fontawesome"
}
]
}
\ No newline at end of file
diff --git a/priv/static/static/js/2.c92f4803ff24726cea58.js.map b/priv/static/static/js/2.c92f4803ff24726cea58.js.map
deleted file mode 100644
index e3cc6a3fb..000000000
Binary files a/priv/static/static/js/2.c92f4803ff24726cea58.js.map and /dev/null differ
diff --git a/priv/static/static/js/2.c92f4803ff24726cea58.js b/priv/static/static/js/2.e852a6b4b3bba752b838.js
similarity index 66%
rename from priv/static/static/js/2.c92f4803ff24726cea58.js
rename to priv/static/static/js/2.e852a6b4b3bba752b838.js
index 55aa1f44e..42e446575 100644
Binary files a/priv/static/static/js/2.c92f4803ff24726cea58.js and b/priv/static/static/js/2.e852a6b4b3bba752b838.js differ
diff --git a/priv/static/static/js/2.e852a6b4b3bba752b838.js.map b/priv/static/static/js/2.e852a6b4b3bba752b838.js.map
new file mode 100644
index 000000000..d698f09e1
Binary files /dev/null and b/priv/static/static/js/2.e852a6b4b3bba752b838.js.map differ
diff --git a/priv/static/static/js/app.55d173dc5e39519aa518.js b/priv/static/static/js/app.55d173dc5e39519aa518.js
deleted file mode 100644
index d04ae3499..000000000
Binary files a/priv/static/static/js/app.55d173dc5e39519aa518.js and /dev/null differ
diff --git a/priv/static/static/js/app.55d173dc5e39519aa518.js.map b/priv/static/static/js/app.55d173dc5e39519aa518.js.map
deleted file mode 100644
index 600e97afa..000000000
Binary files a/priv/static/static/js/app.55d173dc5e39519aa518.js.map and /dev/null differ
diff --git a/priv/static/static/js/app.826c44232e0a76bbd9ba.js b/priv/static/static/js/app.826c44232e0a76bbd9ba.js
new file mode 100644
index 000000000..16762165e
Binary files /dev/null and b/priv/static/static/js/app.826c44232e0a76bbd9ba.js differ
diff --git a/priv/static/static/js/app.826c44232e0a76bbd9ba.js.map b/priv/static/static/js/app.826c44232e0a76bbd9ba.js.map
new file mode 100644
index 000000000..b188c3379
Binary files /dev/null and b/priv/static/static/js/app.826c44232e0a76bbd9ba.js.map differ
diff --git a/priv/static/sw-pleroma.js b/priv/static/sw-pleroma.js
index 54c6ed8f0..fa4969025 100644
Binary files a/priv/static/sw-pleroma.js and b/priv/static/sw-pleroma.js differ
diff --git a/test/integration/mastodon_websocket_test.exs b/test/integration/mastodon_websocket_test.exs
index ea17e9feb..76fbc8bda 100644
--- a/test/integration/mastodon_websocket_test.exs
+++ b/test/integration/mastodon_websocket_test.exs
@@ -99,30 +99,30 @@ test "accepts valid tokens", state do
test "accepts the 'user' stream", %{token: token} = _state do
assert {:ok, _} = start_socket("?stream=user&access_token=#{token.token}")
- assert capture_log(fn ->
- assert {:error, {401, _}} = start_socket("?stream=user")
- Process.sleep(30)
- end) =~ ":badarg"
+ capture_log(fn ->
+ assert {:error, {401, _}} = start_socket("?stream=user")
+ Process.sleep(30)
+ end)
end
test "accepts the 'user:notification' stream", %{token: token} = _state do
assert {:ok, _} = start_socket("?stream=user:notification&access_token=#{token.token}")
- assert capture_log(fn ->
- assert {:error, {401, _}} = start_socket("?stream=user:notification")
- Process.sleep(30)
- end) =~ ":badarg"
+ capture_log(fn ->
+ assert {:error, {401, _}} = start_socket("?stream=user:notification")
+ Process.sleep(30)
+ end)
end
test "accepts valid token on Sec-WebSocket-Protocol header", %{token: token} do
assert {:ok, _} = start_socket("?stream=user", [{"Sec-WebSocket-Protocol", token.token}])
- assert capture_log(fn ->
- assert {:error, {401, _}} =
- start_socket("?stream=user", [{"Sec-WebSocket-Protocol", "I am a friend"}])
+ capture_log(fn ->
+ assert {:error, {401, _}} =
+ start_socket("?stream=user", [{"Sec-WebSocket-Protocol", "I am a friend"}])
- Process.sleep(30)
- end) =~ ":badarg"
+ Process.sleep(30)
+ end)
end
end
end
diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex
index a0ebf65d9..d9be248dc 100644
--- a/test/support/http_request_mock.ex
+++ b/test/support/http_request_mock.ex
@@ -1436,4 +1436,21 @@ def post(url, query, body, headers) do
inspect(headers)
}"}
end
+
+ # Most of the rich media mocks are missing HEAD requests, so we just return 404.
+ @rich_media_mocks [
+ "https://example.com/ogp",
+ "https://example.com/ogp-missing-data",
+ "https://example.com/twitter-card"
+ ]
+ def head(url, _query, _body, _headers) when url in @rich_media_mocks do
+ {:ok, %Tesla.Env{status: 404, body: ""}}
+ end
+
+ def head(url, query, body, headers) do
+ {:error,
+ "Mock response not implemented for HEAD #{inspect(url)}, #{query}, #{inspect(body)}, #{
+ inspect(headers)
+ }"}
+ end
end
diff --git a/test/user_test.exs b/test/user_test.exs
index 3cf248659..301d8f05e 100644
--- a/test/user_test.exs
+++ b/test/user_test.exs
@@ -440,6 +440,45 @@ test "it sends a welcome chat message if it is set" do
assert activity.actor == welcome_user.ap_id
end
+ setup do:
+ clear_config(:mrf_simple,
+ media_removal: [],
+ media_nsfw: [],
+ federated_timeline_removal: [],
+ report_removal: [],
+ reject: [],
+ followers_only: [],
+ accept: [],
+ avatar_removal: [],
+ banner_removal: [],
+ reject_deletes: []
+ )
+
+ setup do:
+ clear_config(:mrf,
+ policies: [
+ Pleroma.Web.ActivityPub.MRF.SimplePolicy
+ ]
+ )
+
+ test "it sends a welcome chat message when Simple policy applied to local instance" do
+ Pleroma.Config.put([:mrf_simple, :media_nsfw], ["localhost"])
+
+ welcome_user = insert(:user)
+ Pleroma.Config.put([:welcome, :chat_message, :enabled], true)
+ Pleroma.Config.put([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
+ Pleroma.Config.put([:welcome, :chat_message, :message], "Hello, this is a chat message")
+
+ cng = User.register_changeset(%User{}, @full_user_data)
+ {:ok, registered_user} = User.register(cng)
+ ObanHelpers.perform_all()
+
+ activity = Repo.one(Pleroma.Activity)
+ assert registered_user.ap_id in activity.recipients
+ assert Object.normalize(activity).data["content"] =~ "chat message"
+ assert activity.actor == welcome_user.ap_id
+ end
+
test "it sends a welcome email message if it is set" do
welcome_user = insert(:user)
Pleroma.Config.put([:welcome, :email, :enabled], true)
diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs
index 03f968aaf..b579bb0bb 100644
--- a/test/web/activity_pub/activity_pub_test.exs
+++ b/test/web/activity_pub/activity_pub_test.exs
@@ -1773,6 +1773,14 @@ test "public timeline with default reply_visibility `self`", %{users: %{u1: user
|> Enum.map(& &1.id)
assert activities_ids == []
+
+ activities_ids =
+ %{}
+ |> Map.put(:reply_visibility, "self")
+ |> Map.put(:reply_filtering_user, nil)
+ |> ActivityPub.fetch_public_activities()
+
+ assert activities_ids == []
end
test "home timeline", %{users: %{u1: user}} do
diff --git a/test/web/activity_pub/pipeline_test.exs b/test/web/activity_pub/pipeline_test.exs
index f2a231eaf..210a06563 100644
--- a/test/web/activity_pub/pipeline_test.exs
+++ b/test/web/activity_pub/pipeline_test.exs
@@ -26,7 +26,7 @@ test "when given an `object_data` in meta, Federation will receive a the origina
{
Pleroma.Web.ActivityPub.MRF,
[],
- [filter: fn o -> {:ok, o} end]
+ [pipeline_filter: fn o, m -> {:ok, o, m} end]
},
{
Pleroma.Web.ActivityPub.ActivityPub,
@@ -51,7 +51,7 @@ test "when given an `object_data` in meta, Federation will receive a the origina
Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity, meta)
assert_called(Pleroma.Web.ActivityPub.ObjectValidator.validate(activity, meta))
- assert_called(Pleroma.Web.ActivityPub.MRF.filter(activity))
+ assert_called(Pleroma.Web.ActivityPub.MRF.pipeline_filter(activity, meta))
assert_called(Pleroma.Web.ActivityPub.ActivityPub.persist(activity, meta))
assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta))
refute called(Pleroma.Web.Federator.publish(activity))
@@ -68,7 +68,7 @@ test "it goes through validation, filtering, persisting, side effects and federa
{
Pleroma.Web.ActivityPub.MRF,
[],
- [filter: fn o -> {:ok, o} end]
+ [pipeline_filter: fn o, m -> {:ok, o, m} end]
},
{
Pleroma.Web.ActivityPub.ActivityPub,
@@ -93,7 +93,7 @@ test "it goes through validation, filtering, persisting, side effects and federa
Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity, meta)
assert_called(Pleroma.Web.ActivityPub.ObjectValidator.validate(activity, meta))
- assert_called(Pleroma.Web.ActivityPub.MRF.filter(activity))
+ assert_called(Pleroma.Web.ActivityPub.MRF.pipeline_filter(activity, meta))
assert_called(Pleroma.Web.ActivityPub.ActivityPub.persist(activity, meta))
assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta))
assert_called(Pleroma.Web.Federator.publish(activity))
@@ -109,7 +109,7 @@ test "it goes through validation, filtering, persisting, side effects without fe
{
Pleroma.Web.ActivityPub.MRF,
[],
- [filter: fn o -> {:ok, o} end]
+ [pipeline_filter: fn o, m -> {:ok, o, m} end]
},
{
Pleroma.Web.ActivityPub.ActivityPub,
@@ -131,7 +131,7 @@ test "it goes through validation, filtering, persisting, side effects without fe
Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity, meta)
assert_called(Pleroma.Web.ActivityPub.ObjectValidator.validate(activity, meta))
- assert_called(Pleroma.Web.ActivityPub.MRF.filter(activity))
+ assert_called(Pleroma.Web.ActivityPub.MRF.pipeline_filter(activity, meta))
assert_called(Pleroma.Web.ActivityPub.ActivityPub.persist(activity, meta))
assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta))
end
@@ -148,7 +148,7 @@ test "it goes through validation, filtering, persisting, side effects without fe
{
Pleroma.Web.ActivityPub.MRF,
[],
- [filter: fn o -> {:ok, o} end]
+ [pipeline_filter: fn o, m -> {:ok, o, m} end]
},
{
Pleroma.Web.ActivityPub.ActivityPub,
@@ -170,7 +170,7 @@ test "it goes through validation, filtering, persisting, side effects without fe
Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity, meta)
assert_called(Pleroma.Web.ActivityPub.ObjectValidator.validate(activity, meta))
- assert_called(Pleroma.Web.ActivityPub.MRF.filter(activity))
+ assert_called(Pleroma.Web.ActivityPub.MRF.pipeline_filter(activity, meta))
assert_called(Pleroma.Web.ActivityPub.ActivityPub.persist(activity, meta))
assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta))
end
diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs
index 4ba6232dc..28bb6db30 100644
--- a/test/web/common_api/common_api_test.exs
+++ b/test/web/common_api/common_api_test.exs
@@ -213,6 +213,17 @@ test "it reject messages over the local limit" do
assert message == :content_too_long
end
+
+ test "it reject messages via MRF" do
+ clear_config([:mrf_keyword, :reject], ["GNO"])
+ clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.KeywordPolicy])
+
+ author = insert(:user)
+ recipient = insert(:user)
+
+ assert {:reject, "[KeywordPolicy] Matches with rejected keyword"} ==
+ CommonAPI.post_chat_message(author, recipient, "GNO/Linux")
+ end
end
describe "unblocking" do
diff --git a/test/web/pleroma_api/controllers/chat_controller_test.exs b/test/web/pleroma_api/controllers/chat_controller_test.exs
index 7be5fe09c..44a78a738 100644
--- a/test/web/pleroma_api/controllers/chat_controller_test.exs
+++ b/test/web/pleroma_api/controllers/chat_controller_test.exs
@@ -100,7 +100,7 @@ test "it fails if there is no content", %{conn: conn, user: user} do
|> post("/api/v1/pleroma/chats/#{chat.id}/messages")
|> json_response_and_validate_schema(400)
- assert result
+ assert %{"error" => "no_content"} == result
end
test "it works with an attachment", %{conn: conn, user: user} do
@@ -126,6 +126,23 @@ test "it works with an attachment", %{conn: conn, user: user} do
assert result["attachment"]
end
+
+ test "gets MRF reason when rejected", %{conn: conn, user: user} do
+ clear_config([:mrf_keyword, :reject], ["GNO"])
+ clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.KeywordPolicy])
+
+ other_user = insert(:user)
+
+ {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id)
+
+ result =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/pleroma/chats/#{chat.id}/messages", %{"content" => "GNO/Linux"})
+ |> json_response_and_validate_schema(422)
+
+ assert %{"error" => "[KeywordPolicy] Matches with rejected keyword"} == result
+ end
end
describe "DELETE /api/v1/pleroma/chats/:id/messages/:message_id" do
diff --git a/test/web/rich_media/parser_test.exs b/test/web/rich_media/parser_test.exs
index 1e09cbf84..b8ef2cccf 100644
--- a/test/web/rich_media/parser_test.exs
+++ b/test/web/rich_media/parser_test.exs
@@ -56,6 +56,27 @@ defmodule Pleroma.Web.RichMedia.ParserTest do
%{method: :get, url: "http://example.com/error"} ->
{:error, :overload}
+
+ %{
+ method: :head,
+ url: "http://example.com/huge-page"
+ } ->
+ %Tesla.Env{
+ status: 200,
+ headers: [{"content-length", "2000001"}, {"content-type", "text/html"}]
+ }
+
+ %{
+ method: :head,
+ url: "http://example.com/pdf-file"
+ } ->
+ %Tesla.Env{
+ status: 200,
+ headers: [{"content-length", "1000000"}, {"content-type", "application/pdf"}]
+ }
+
+ %{method: :head} ->
+ %Tesla.Env{status: 404, body: "", headers: []}
end)
:ok
@@ -146,4 +167,12 @@ test "rejects invalid OGP data" do
test "returns error if getting page was not successful" do
assert {:error, :overload} = Parser.parse("http://example.com/error")
end
+
+ test "does a HEAD request to check if the body is too large" do
+ assert {:error, :body_too_large} = Parser.parse("http://example.com/huge-page")
+ end
+
+ test "does a HEAD request to check if the body is html" do
+ assert {:error, {:content_type, _}} = Parser.parse("http://example.com/pdf-file")
+ end
end