Merge remote-tracking branch 'origin/develop' into shigusegubu
This commit is contained in:
commit
dd35bf93c7
37 changed files with 514 additions and 43 deletions
11
CHANGELOG.md
11
CHANGELOG.md
|
|
@ -18,6 +18,17 @@ 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.4
|
||||||
|
|
||||||
|
## Security
|
||||||
|
- Fix XML External Entity (XXE) loading vulnerability allowing to fetch arbitary files from the server's filesystem
|
||||||
|
|
||||||
|
## 2.5.3
|
||||||
|
|
||||||
|
### Security
|
||||||
|
- Emoji pack loader sanitizes pack names
|
||||||
|
- Reduced permissions of config files and directories, distros requiring greater permissions like group-read need to pre-create the directories
|
||||||
|
|
||||||
## 2.5.2
|
## 2.5.2
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ USER pleroma
|
||||||
|
|
||||||
COPY --from=build --chown=pleroma:0 /release ${HOME}
|
COPY --from=build --chown=pleroma:0 /release ${HOME}
|
||||||
|
|
||||||
COPY ./config/docker.exs /etc/pleroma/config.exs
|
COPY --chown=pleroma --chmod=640 ./config/docker.exs /etc/pleroma/config.exs
|
||||||
COPY ./docker-entrypoint.sh ${HOME}
|
COPY ./docker-entrypoint.sh ${HOME}
|
||||||
|
|
||||||
EXPOSE 4000
|
EXPOSE 4000
|
||||||
|
|
|
||||||
1
changelog.d/3801.fix
Normal file
1
changelog.d/3801.fix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Filter context activities using Visibility.visible_for_user?
|
||||||
1
changelog.d/3879.fix
Normal file
1
changelog.d/3879.fix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
fix not being able to fetch flash file from remote instance
|
||||||
1
changelog.d/akkoma-xml-remote-entities.security
Normal file
1
changelog.d/akkoma-xml-remote-entities.security
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Fix XML External Entity (XXE) loading vulnerability allowing to fetch arbitary files from the server's filesystem
|
||||||
1
changelog.d/attachment-type-check.fix
Normal file
1
changelog.d/attachment-type-check.fix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Restrict attachments to only uploaded files only
|
||||||
1
changelog.d/check-attachment-attribution.security
Normal file
1
changelog.d/check-attachment-attribution.security
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
CommonAPI: Prevent users from accessing media of other users by creating a status with reused attachment ID
|
||||||
1
changelog.d/disable-xml-entity-resolution.security
Normal file
1
changelog.d/disable-xml-entity-resolution.security
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Disable XML entity resolution completely to fix a dos vulnerability
|
||||||
1
changelog.d/dockerfile-config-perms.fix
Normal file
1
changelog.d/dockerfile-config-perms.fix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
- Fix config ownership in dockerfile to pass restriction test
|
||||||
1
changelog.d/emoji-pack-sanitization.security
Normal file
1
changelog.d/emoji-pack-sanitization.security
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Emoji pack loader sanitizes pack names
|
||||||
0
changelog.d/gentoo_otp_intro.skip
Normal file
0
changelog.d/gentoo_otp_intro.skip
Normal file
0
changelog.d/lint.skip
Normal file
0
changelog.d/lint.skip
Normal file
1
changelog.d/otp_perms.security
Normal file
1
changelog.d/otp_perms.security
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
- Reduced permissions of config files and directories, distros requiring greater permissions like group-read need to pre-create the directories
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
{! backend/installation/otp_vs_from_source.include !}
|
{! backend/installation/otp_vs_from_source.include !}
|
||||||
|
|
||||||
A [manual installation guide for gentoo](./gentoo_en.md) is also available.
|
This guide covers installation via Gentoo provided packaging. A [manual installation guide for gentoo](./gentoo_en.md) is also available.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -266,12 +266,20 @@ defmodule Mix.Tasks.Pleroma.Instance do
|
||||||
config_dir = Path.dirname(config_path)
|
config_dir = Path.dirname(config_path)
|
||||||
psql_dir = Path.dirname(psql_path)
|
psql_dir = Path.dirname(psql_path)
|
||||||
|
|
||||||
|
# Note: Distros requiring group read (0o750) on those directories should
|
||||||
|
# pre-create the directories.
|
||||||
[config_dir, psql_dir, static_dir, uploads_dir]
|
[config_dir, psql_dir, static_dir, uploads_dir]
|
||||||
|> Enum.reject(&File.exists?/1)
|
|> Enum.reject(&File.exists?/1)
|
||||||
|> Enum.map(&File.mkdir_p!/1)
|
|> Enum.each(fn dir ->
|
||||||
|
File.mkdir_p!(dir)
|
||||||
|
File.chmod!(dir, 0o700)
|
||||||
|
end)
|
||||||
|
|
||||||
shell_info("Writing config to #{config_path}.")
|
shell_info("Writing config to #{config_path}.")
|
||||||
|
|
||||||
|
# Sadly no fchmod(2) equivalent in Elixir…
|
||||||
|
File.touch!(config_path)
|
||||||
|
File.chmod!(config_path, 0o640)
|
||||||
File.write(config_path, result_config)
|
File.write(config_path, result_config)
|
||||||
shell_info("Writing the postgres script to #{psql_path}.")
|
shell_info("Writing the postgres script to #{psql_path}.")
|
||||||
File.write(psql_path, result_psql)
|
File.write(psql_path, result_psql)
|
||||||
|
|
@ -290,8 +298,7 @@ defmodule Mix.Tasks.Pleroma.Instance do
|
||||||
else
|
else
|
||||||
shell_error(
|
shell_error(
|
||||||
"The task would have overwritten the following files:\n" <>
|
"The task would have overwritten the following files:\n" <>
|
||||||
(Enum.map(will_overwrite, &"- #{&1}\n") |> Enum.join("")) <>
|
Enum.map_join(will_overwrite, &"- #{&1}\n") <> "Rerun with `--force` to overwrite them."
|
||||||
"Rerun with `--force` to overwrite them."
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,20 @@ defmodule Pleroma.Config.ReleaseRuntimeProvider do
|
||||||
|
|
||||||
with_runtime_config =
|
with_runtime_config =
|
||||||
if File.exists?(config_path) do
|
if File.exists?(config_path) do
|
||||||
|
# <https://git.pleroma.social/pleroma/pleroma/-/issues/3135>
|
||||||
|
%File.Stat{mode: mode} = File.lstat!(config_path)
|
||||||
|
|
||||||
|
if Bitwise.band(mode, 0o007) > 0 do
|
||||||
|
raise "Configuration at #{config_path} has world-permissions, execute the following: chmod o= #{config_path}"
|
||||||
|
end
|
||||||
|
|
||||||
|
if Bitwise.band(mode, 0o020) > 0 do
|
||||||
|
raise "Configuration at #{config_path} has group-wise write permissions, execute the following: chmod g-w #{config_path}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Note: Elixir doesn't provides a getuid(2)
|
||||||
|
# so cannot forbid group-read only when config is owned by us
|
||||||
|
|
||||||
runtime_config = Config.Reader.read!(config_path)
|
runtime_config = Config.Reader.read!(config_path)
|
||||||
|
|
||||||
with_defaults
|
with_defaults
|
||||||
|
|
|
||||||
|
|
@ -81,4 +81,6 @@ defmodule Pleroma.Constants do
|
||||||
const(mime_regex,
|
const(mime_regex,
|
||||||
do: ~r/^[^[:cntrl:] ()<>@,;:\\"\/\[\]?=]+\/[^[:cntrl:] ()<>@,;:\\"\/\[\]?=]+(; .*)?$/
|
do: ~r/^[^[:cntrl:] ()<>@,;:\\"\/\[\]?=]+\/[^[:cntrl:] ()<>@,;:\\"\/\[\]?=]+(; .*)?$/
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const(upload_object_types, do: ["Document", "Image"])
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -285,6 +285,7 @@ defmodule Pleroma.Emoji.Pack do
|
||||||
|
|
||||||
@spec load_pack(String.t()) :: {:ok, t()} | {:error, :file.posix()}
|
@spec load_pack(String.t()) :: {:ok, t()} | {:error, :file.posix()}
|
||||||
def load_pack(name) do
|
def load_pack(name) do
|
||||||
|
name = Path.basename(name)
|
||||||
pack_file = Path.join([emoji_path(), name, "pack.json"])
|
pack_file = Path.join([emoji_path(), name, "pack.json"])
|
||||||
|
|
||||||
with {:ok, _} <- File.stat(pack_file),
|
with {:ok, _} <- File.stat(pack_file),
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,11 @@ defmodule Pleroma.ScheduledActivity do
|
||||||
%{changes: %{params: %{"media_ids" => media_ids} = params}} = changeset
|
%{changes: %{params: %{"media_ids" => media_ids} = params}} = changeset
|
||||||
)
|
)
|
||||||
when is_list(media_ids) do
|
when is_list(media_ids) do
|
||||||
media_attachments = Utils.attachments_from_ids(%{media_ids: media_ids})
|
media_attachments =
|
||||||
|
Utils.attachments_from_ids(
|
||||||
|
%{media_ids: media_ids},
|
||||||
|
User.get_cached_by_id(changeset.data.user_id)
|
||||||
|
)
|
||||||
|
|
||||||
params =
|
params =
|
||||||
params
|
params
|
||||||
|
|
|
||||||
|
|
@ -455,6 +455,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
||||||
|> maybe_preload_objects(opts)
|
|> maybe_preload_objects(opts)
|
||||||
|> maybe_preload_bookmarks(opts)
|
|> maybe_preload_bookmarks(opts)
|
||||||
|> maybe_set_thread_muted_field(opts)
|
|> maybe_set_thread_muted_field(opts)
|
||||||
|
|> restrict_unauthenticated(opts[:user])
|
||||||
|> restrict_blocked(opts)
|
|> restrict_blocked(opts)
|
||||||
|> restrict_blockers_visibility(opts)
|
|> restrict_blockers_visibility(opts)
|
||||||
|> restrict_recipients(recipients, opts[:user])
|
|> restrict_recipients(recipients, opts[:user])
|
||||||
|
|
@ -1215,6 +1216,27 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
||||||
|
|
||||||
defp restrict_filtered(query, _), do: query
|
defp restrict_filtered(query, _), do: query
|
||||||
|
|
||||||
|
defp restrict_unauthenticated(query, nil) do
|
||||||
|
local = Config.restrict_unauthenticated_access?(:activities, :local)
|
||||||
|
remote = Config.restrict_unauthenticated_access?(:activities, :remote)
|
||||||
|
|
||||||
|
cond do
|
||||||
|
local and remote ->
|
||||||
|
from(activity in query, where: false)
|
||||||
|
|
||||||
|
local ->
|
||||||
|
from(activity in query, where: activity.local == false)
|
||||||
|
|
||||||
|
remote ->
|
||||||
|
from(activity in query, where: activity.local == true)
|
||||||
|
|
||||||
|
true ->
|
||||||
|
query
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp restrict_unauthenticated(query, _), do: query
|
||||||
|
|
||||||
defp exclude_poll_votes(query, %{include_poll_votes: true}), do: query
|
defp exclude_poll_votes(query, %{include_poll_votes: true}), do: query
|
||||||
|
|
||||||
defp exclude_poll_votes(query, _) do
|
defp exclude_poll_votes(query, _) do
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ defmodule Pleroma.Web.CommonAPI do
|
||||||
|
|
||||||
def post_chat_message(%User{} = user, %User{} = recipient, content, opts \\ []) do
|
def post_chat_message(%User{} = user, %User{} = recipient, content, opts \\ []) do
|
||||||
with maybe_attachment <- opts[:media_id] && Object.get_by_id(opts[:media_id]),
|
with maybe_attachment <- opts[:media_id] && Object.get_by_id(opts[:media_id]),
|
||||||
|
:ok <- validate_chat_attachment_attribution(maybe_attachment, user),
|
||||||
:ok <- validate_chat_content_length(content, !!maybe_attachment),
|
:ok <- validate_chat_content_length(content, !!maybe_attachment),
|
||||||
{_, {:ok, chat_message_data, _meta}} <-
|
{_, {:ok, chat_message_data, _meta}} <-
|
||||||
{:build_object,
|
{:build_object,
|
||||||
|
|
@ -71,6 +72,17 @@ defmodule Pleroma.Web.CommonAPI do
|
||||||
text
|
text
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp validate_chat_attachment_attribution(nil, _), do: :ok
|
||||||
|
|
||||||
|
defp validate_chat_attachment_attribution(attachment, user) do
|
||||||
|
with :ok <- Object.authorize_access(attachment, user) do
|
||||||
|
:ok
|
||||||
|
else
|
||||||
|
e ->
|
||||||
|
e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
defp validate_chat_content_length(_, true), do: :ok
|
defp validate_chat_content_length(_, true), do: :ok
|
||||||
defp validate_chat_content_length(nil, false), do: {:error, :no_content}
|
defp validate_chat_content_length(nil, false), do: {:error, :no_content}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -111,7 +111,7 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp attachments(%{params: params} = draft) do
|
defp attachments(%{params: params} = draft) do
|
||||||
attachments = Utils.attachments_from_ids(params)
|
attachments = Utils.attachments_from_ids(params, draft.user)
|
||||||
draft = %__MODULE__{draft | attachments: attachments}
|
draft = %__MODULE__{draft | attachments: attachments}
|
||||||
|
|
||||||
case Utils.validate_attachments_count(attachments) do
|
case Utils.validate_attachments_count(attachments) do
|
||||||
|
|
|
||||||
|
|
@ -23,21 +23,21 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
||||||
require Logger
|
require Logger
|
||||||
require Pleroma.Constants
|
require Pleroma.Constants
|
||||||
|
|
||||||
def attachments_from_ids(%{media_ids: ids, descriptions: desc}) do
|
def attachments_from_ids(%{media_ids: ids, descriptions: desc}, user) do
|
||||||
attachments_from_ids_descs(ids, desc)
|
attachments_from_ids_descs(ids, desc, user)
|
||||||
end
|
end
|
||||||
|
|
||||||
def attachments_from_ids(%{media_ids: ids}) do
|
def attachments_from_ids(%{media_ids: ids}, user) do
|
||||||
attachments_from_ids_no_descs(ids)
|
attachments_from_ids_no_descs(ids, user)
|
||||||
end
|
end
|
||||||
|
|
||||||
def attachments_from_ids(_), do: []
|
def attachments_from_ids(_, _), do: []
|
||||||
|
|
||||||
def attachments_from_ids_no_descs([]), do: []
|
def attachments_from_ids_no_descs([], _), do: []
|
||||||
|
|
||||||
def attachments_from_ids_no_descs(ids) do
|
def attachments_from_ids_no_descs(ids, user) do
|
||||||
Enum.map(ids, fn media_id ->
|
Enum.map(ids, fn media_id ->
|
||||||
case get_attachment(media_id) do
|
case get_attachment(media_id, user) do
|
||||||
%Object{data: data} -> data
|
%Object{data: data} -> data
|
||||||
_ -> nil
|
_ -> nil
|
||||||
end
|
end
|
||||||
|
|
@ -45,21 +45,27 @@ defmodule Pleroma.Web.CommonAPI.Utils do
|
||||||
|> Enum.reject(&is_nil/1)
|
|> Enum.reject(&is_nil/1)
|
||||||
end
|
end
|
||||||
|
|
||||||
def attachments_from_ids_descs([], _), do: []
|
def attachments_from_ids_descs([], _, _), do: []
|
||||||
|
|
||||||
def attachments_from_ids_descs(ids, descs_str) do
|
def attachments_from_ids_descs(ids, descs_str, user) do
|
||||||
{_, descs} = Jason.decode(descs_str)
|
{_, descs} = Jason.decode(descs_str)
|
||||||
|
|
||||||
Enum.map(ids, fn media_id ->
|
Enum.map(ids, fn media_id ->
|
||||||
with %Object{data: data} <- get_attachment(media_id) do
|
with %Object{data: data} <- get_attachment(media_id, user) do
|
||||||
Map.put(data, "name", descs[media_id])
|
Map.put(data, "name", descs[media_id])
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|> Enum.reject(&is_nil/1)
|
|> Enum.reject(&is_nil/1)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp get_attachment(media_id) do
|
defp get_attachment(media_id, user) do
|
||||||
Repo.get(Object, media_id)
|
with %Object{data: data} = object <- Repo.get(Object, media_id),
|
||||||
|
%{"type" => type} when type in Pleroma.Constants.upload_object_types() <- data,
|
||||||
|
:ok <- Object.authorize_access(object, user) do
|
||||||
|
object
|
||||||
|
else
|
||||||
|
_ -> nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec get_to_and_cc(ActivityDraft.t()) :: {list(String.t()), list(String.t())}
|
@spec get_to_and_cc(ActivityDraft.t()) :: {list(String.t()), list(String.t())}
|
||||||
|
|
|
||||||
|
|
@ -93,18 +93,26 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlug do
|
||||||
|
|
||||||
img_src = "img-src 'self' data: blob:"
|
img_src = "img-src 'self' data: blob:"
|
||||||
media_src = "media-src 'self'"
|
media_src = "media-src 'self'"
|
||||||
|
connect_src = ["connect-src 'self' blob: ", static_url, ?\s, websocket_url]
|
||||||
|
|
||||||
# Strict multimedia CSP enforcement only when MediaProxy is enabled
|
# Strict multimedia CSP enforcement only when MediaProxy is enabled
|
||||||
{img_src, media_src} =
|
{img_src, media_src, connect_src} =
|
||||||
if Config.get([:media_proxy, :enabled]) &&
|
if Config.get([:media_proxy, :enabled]) &&
|
||||||
!Config.get([:media_proxy, :proxy_opts, :redirect_on_failure]) do
|
!Config.get([:media_proxy, :proxy_opts, :redirect_on_failure]) do
|
||||||
sources = build_csp_multimedia_source_list()
|
sources = build_csp_multimedia_source_list()
|
||||||
{[img_src, sources], [media_src, sources]}
|
|
||||||
else
|
|
||||||
{[img_src, " https:"], [media_src, " https:"]}
|
|
||||||
end
|
|
||||||
|
|
||||||
connect_src = ["connect-src 'self' blob: ", static_url, ?\s, websocket_url]
|
{
|
||||||
|
[img_src, sources],
|
||||||
|
[media_src, sources],
|
||||||
|
[connect_src, sources]
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[img_src, " https:"],
|
||||||
|
[media_src, " https:"],
|
||||||
|
[connect_src, " https:"]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
connect_src =
|
connect_src =
|
||||||
if Config.get(:env) == :dev do
|
if Config.get(:env) == :dev do
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,10 @@ defmodule Pleroma.Web.XML do
|
||||||
{doc, _rest} =
|
{doc, _rest} =
|
||||||
text
|
text
|
||||||
|> :binary.bin_to_list()
|
|> :binary.bin_to_list()
|
||||||
|> :xmerl_scan.string(quiet: true)
|
|> :xmerl_scan.string(
|
||||||
|
quiet: true,
|
||||||
|
allow_entities: false
|
||||||
|
)
|
||||||
|
|
||||||
{:ok, doc}
|
{:ok, doc}
|
||||||
rescue
|
rescue
|
||||||
|
|
|
||||||
2
mix.exs
2
mix.exs
|
|
@ -4,7 +4,7 @@ defmodule Pleroma.Mixfile do
|
||||||
def project do
|
def project do
|
||||||
[
|
[
|
||||||
app: :pleroma,
|
app: :pleroma,
|
||||||
version: version("2.5.52"),
|
version: version("2.5.54"),
|
||||||
elixir: "~> 1.11",
|
elixir: "~> 1.11",
|
||||||
elixirc_paths: elixirc_paths(Mix.env()),
|
elixirc_paths: elixirc_paths(Mix.env()),
|
||||||
compilers: [:phoenix] ++ Mix.compilers(),
|
compilers: [:phoenix] ++ Mix.compilers(),
|
||||||
|
|
|
||||||
15
test/fixtures/xml_billion_laughs.xml
vendored
Normal file
15
test/fixtures/xml_billion_laughs.xml
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE lolz [
|
||||||
|
<!ENTITY lol "lol">
|
||||||
|
<!ELEMENT lolz (#PCDATA)>
|
||||||
|
<!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
|
||||||
|
<!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
|
||||||
|
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
|
||||||
|
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
|
||||||
|
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
|
||||||
|
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
|
||||||
|
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
|
||||||
|
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
|
||||||
|
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
|
||||||
|
]>
|
||||||
|
<lolz>&lol9;</lolz>
|
||||||
3
test/fixtures/xml_external_entities.xml
vendored
Normal file
3
test/fixtures/xml_external_entities.xml
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
|
||||||
|
<stockCheck><productId>&xxe;</productId></stockCheck>
|
||||||
|
|
@ -17,6 +17,8 @@ defmodule Pleroma.Config.ReleaseRuntimeProviderTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "merged runtime config" do
|
test "merged runtime config" do
|
||||||
|
assert :ok == File.chmod!("test/fixtures/config/temp.secret.exs", 0o640)
|
||||||
|
|
||||||
merged =
|
merged =
|
||||||
ReleaseRuntimeProvider.load([], config_path: "test/fixtures/config/temp.secret.exs")
|
ReleaseRuntimeProvider.load([], config_path: "test/fixtures/config/temp.secret.exs")
|
||||||
|
|
||||||
|
|
@ -25,6 +27,8 @@ defmodule Pleroma.Config.ReleaseRuntimeProviderTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "merged exported config" do
|
test "merged exported config" do
|
||||||
|
assert :ok == File.chmod!("test/fixtures/config/temp.exported_from_db.secret.exs", 0o640)
|
||||||
|
|
||||||
ExUnit.CaptureIO.capture_io(fn ->
|
ExUnit.CaptureIO.capture_io(fn ->
|
||||||
merged =
|
merged =
|
||||||
ReleaseRuntimeProvider.load([],
|
ReleaseRuntimeProvider.load([],
|
||||||
|
|
@ -37,6 +41,9 @@ defmodule Pleroma.Config.ReleaseRuntimeProviderTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "runtime config is merged with exported config" do
|
test "runtime config is merged with exported config" do
|
||||||
|
assert :ok == File.chmod!("test/fixtures/config/temp.secret.exs", 0o640)
|
||||||
|
assert :ok == File.chmod!("test/fixtures/config/temp.exported_from_db.secret.exs", 0o640)
|
||||||
|
|
||||||
merged =
|
merged =
|
||||||
ReleaseRuntimeProvider.load([],
|
ReleaseRuntimeProvider.load([],
|
||||||
config_path: "test/fixtures/config/temp.secret.exs",
|
config_path: "test/fixtures/config/temp.secret.exs",
|
||||||
|
|
|
||||||
|
|
@ -90,4 +90,8 @@ defmodule Pleroma.Emoji.PackTest do
|
||||||
|
|
||||||
assert updated_pack.files_count == 1
|
assert updated_pack.files_count == 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "load_pack/1 ignores path traversal in a forged pack name", %{pack: pack} do
|
||||||
|
assert {:ok, ^pack} = Pack.load_pack("../../../../../dump_pack")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -586,41 +586,61 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "attachments_from_ids_descs/2" do
|
describe "attachments_from_ids_descs/3" do
|
||||||
test "returns [] when attachment ids is empty" do
|
test "returns [] when attachment ids is empty" do
|
||||||
assert Utils.attachments_from_ids_descs([], "{}") == []
|
assert Utils.attachments_from_ids_descs([], "{}", nil) == []
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns list attachments with desc" do
|
test "returns list attachments with desc" do
|
||||||
object = insert(:note)
|
user = insert(:user)
|
||||||
|
object = insert(:attachment, %{user: user})
|
||||||
desc = Jason.encode!(%{object.id => "test-desc"})
|
desc = Jason.encode!(%{object.id => "test-desc"})
|
||||||
|
|
||||||
assert Utils.attachments_from_ids_descs(["#{object.id}", "34"], desc) == [
|
assert Utils.attachments_from_ids_descs(["#{object.id}", "34"], desc, user) == [
|
||||||
Map.merge(object.data, %{"name" => "test-desc"})
|
Map.merge(object.data, %{"name" => "test-desc"})
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "attachments_from_ids/1" do
|
describe "attachments_from_ids/2" do
|
||||||
test "returns attachments with descs" do
|
test "returns attachments with descs" do
|
||||||
object = insert(:note)
|
user = insert(:user)
|
||||||
|
object = insert(:attachment, %{user: user})
|
||||||
desc = Jason.encode!(%{object.id => "test-desc"})
|
desc = Jason.encode!(%{object.id => "test-desc"})
|
||||||
|
|
||||||
assert Utils.attachments_from_ids(%{
|
assert Utils.attachments_from_ids(
|
||||||
|
%{
|
||||||
media_ids: ["#{object.id}"],
|
media_ids: ["#{object.id}"],
|
||||||
descriptions: desc
|
descriptions: desc
|
||||||
}) == [
|
},
|
||||||
|
user
|
||||||
|
) == [
|
||||||
Map.merge(object.data, %{"name" => "test-desc"})
|
Map.merge(object.data, %{"name" => "test-desc"})
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns attachments without descs" do
|
test "returns attachments without descs" do
|
||||||
object = insert(:note)
|
user = insert(:user)
|
||||||
assert Utils.attachments_from_ids(%{media_ids: ["#{object.id}"]}) == [object.data]
|
object = insert(:attachment, %{user: user})
|
||||||
|
assert Utils.attachments_from_ids(%{media_ids: ["#{object.id}"]}, user) == [object.data]
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns [] when not pass media_ids" do
|
test "returns [] when not pass media_ids" do
|
||||||
assert Utils.attachments_from_ids(%{}) == []
|
assert Utils.attachments_from_ids(%{}, nil) == []
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns [] when media_ids not belong to current user" do
|
||||||
|
user = insert(:user)
|
||||||
|
user2 = insert(:user)
|
||||||
|
|
||||||
|
object = insert(:attachment, %{user: user})
|
||||||
|
|
||||||
|
assert Utils.attachments_from_ids(%{media_ids: ["#{object.id}"]}, user2) == []
|
||||||
|
end
|
||||||
|
|
||||||
|
test "checks that the object is of upload type" do
|
||||||
|
object = insert(:note)
|
||||||
|
assert Utils.attachments_from_ids(%{media_ids: ["#{object.id}"]}, nil) == []
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -279,6 +279,24 @@ defmodule Pleroma.Web.CommonAPITest do
|
||||||
assert {:reject, "[KeywordPolicy] Matches with rejected keyword"} ==
|
assert {:reject, "[KeywordPolicy] Matches with rejected keyword"} ==
|
||||||
CommonAPI.post_chat_message(author, recipient, "GNO/Linux")
|
CommonAPI.post_chat_message(author, recipient, "GNO/Linux")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "it reject messages with attachments not belonging to user" do
|
||||||
|
author = insert(:user)
|
||||||
|
not_author = insert(:user)
|
||||||
|
recipient = author
|
||||||
|
|
||||||
|
attachment = insert(:attachment, %{user: not_author})
|
||||||
|
|
||||||
|
{:error, message} =
|
||||||
|
CommonAPI.post_chat_message(
|
||||||
|
author,
|
||||||
|
recipient,
|
||||||
|
"123",
|
||||||
|
media_id: attachment.id
|
||||||
|
)
|
||||||
|
|
||||||
|
assert message == :forbidden
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "unblocking" do
|
describe "unblocking" do
|
||||||
|
|
|
||||||
|
|
@ -771,6 +771,49 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|
||||||
{:ok, local: local, remote: remote}
|
{:ok, local: local, remote: remote}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp local_and_remote_context_activities do
|
||||||
|
local_user_1 = insert(:user)
|
||||||
|
local_user_2 = insert(:user)
|
||||||
|
remote_user = insert(:user, local: false)
|
||||||
|
|
||||||
|
{:ok, %{id: id1, data: %{"context" => context}}} =
|
||||||
|
CommonAPI.post(local_user_1, %{status: "post"})
|
||||||
|
|
||||||
|
{:ok, %{id: id2} = post} =
|
||||||
|
CommonAPI.post(local_user_2, %{status: "local reply", in_reply_to_status_id: id1})
|
||||||
|
|
||||||
|
params = %{
|
||||||
|
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||||
|
"actor" => remote_user.ap_id,
|
||||||
|
"type" => "Create",
|
||||||
|
"context" => context,
|
||||||
|
"id" => "#{remote_user.ap_id}/activities/1",
|
||||||
|
"inReplyTo" => post.data["id"],
|
||||||
|
"object" => %{
|
||||||
|
"type" => "Note",
|
||||||
|
"content" => "remote reply",
|
||||||
|
"context" => context,
|
||||||
|
"id" => "#{remote_user.ap_id}/objects/1",
|
||||||
|
"attributedTo" => remote_user.ap_id,
|
||||||
|
"to" => [
|
||||||
|
local_user_1.ap_id,
|
||||||
|
local_user_2.ap_id,
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"to" => [
|
||||||
|
local_user_1.ap_id,
|
||||||
|
local_user_2.ap_id,
|
||||||
|
"https://www.w3.org/ns/activitystreams#Public"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
{:ok, job} = Pleroma.Web.Federator.incoming_ap_doc(params)
|
||||||
|
{:ok, remote_activity} = ObanHelpers.perform(job)
|
||||||
|
|
||||||
|
%{locals: [id1, id2], remote: remote_activity.id, context: context}
|
||||||
|
end
|
||||||
|
|
||||||
describe "status with restrict unauthenticated activities for local and remote" do
|
describe "status with restrict unauthenticated activities for local and remote" do
|
||||||
setup do: local_and_remote_activities()
|
setup do: local_and_remote_activities()
|
||||||
|
|
||||||
|
|
@ -957,6 +1000,230 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "getting status contexts restricted unauthenticated for local and remote" do
|
||||||
|
setup do: local_and_remote_context_activities()
|
||||||
|
|
||||||
|
setup do: clear_config([:restrict_unauthenticated, :activities, :local], true)
|
||||||
|
|
||||||
|
setup do: clear_config([:restrict_unauthenticated, :activities, :remote], true)
|
||||||
|
|
||||||
|
test "if user is unauthenticated", %{conn: conn, locals: [post_id, _]} do
|
||||||
|
res_conn = get(conn, "/api/v1/statuses/#{post_id}/context")
|
||||||
|
|
||||||
|
assert json_response_and_validate_schema(res_conn, 200) == %{
|
||||||
|
"ancestors" => [],
|
||||||
|
"descendants" => []
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "if user is unauthenticated reply", %{conn: conn, locals: [_, reply_id]} do
|
||||||
|
res_conn = get(conn, "/api/v1/statuses/#{reply_id}/context")
|
||||||
|
|
||||||
|
assert json_response_and_validate_schema(res_conn, 200) == %{
|
||||||
|
"ancestors" => [],
|
||||||
|
"descendants" => []
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "if user is authenticated", %{locals: [post_id, reply_id], remote: remote_reply_id} do
|
||||||
|
%{conn: conn} = oauth_access(["read"])
|
||||||
|
res_conn = get(conn, "/api/v1/statuses/#{post_id}/context")
|
||||||
|
|
||||||
|
%{"ancestors" => [], "descendants" => descendants} =
|
||||||
|
json_response_and_validate_schema(res_conn, 200)
|
||||||
|
|
||||||
|
descendant_ids =
|
||||||
|
descendants
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
assert reply_id in descendant_ids
|
||||||
|
assert remote_reply_id in descendant_ids
|
||||||
|
end
|
||||||
|
|
||||||
|
test "if user is authenticated reply", %{locals: [post_id, reply_id], remote: remote_reply_id} do
|
||||||
|
%{conn: conn} = oauth_access(["read"])
|
||||||
|
res_conn = get(conn, "/api/v1/statuses/#{reply_id}/context")
|
||||||
|
|
||||||
|
%{"ancestors" => ancestors, "descendants" => descendants} =
|
||||||
|
json_response_and_validate_schema(res_conn, 200)
|
||||||
|
|
||||||
|
ancestor_ids =
|
||||||
|
ancestors
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
descendant_ids =
|
||||||
|
descendants
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
assert post_id in ancestor_ids
|
||||||
|
assert remote_reply_id in descendant_ids
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "getting status contexts restricted unauthenticated for local" do
|
||||||
|
setup do: local_and_remote_context_activities()
|
||||||
|
|
||||||
|
setup do: clear_config([:restrict_unauthenticated, :activities, :local], true)
|
||||||
|
|
||||||
|
setup do: clear_config([:restrict_unauthenticated, :activities, :remote], false)
|
||||||
|
|
||||||
|
test "if user is unauthenticated", %{
|
||||||
|
conn: conn,
|
||||||
|
locals: [post_id, reply_id],
|
||||||
|
remote: remote_reply_id
|
||||||
|
} do
|
||||||
|
res_conn = get(conn, "/api/v1/statuses/#{post_id}/context")
|
||||||
|
|
||||||
|
%{"ancestors" => [], "descendants" => descendants} =
|
||||||
|
json_response_and_validate_schema(res_conn, 200)
|
||||||
|
|
||||||
|
descendant_ids =
|
||||||
|
descendants
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
assert reply_id not in descendant_ids
|
||||||
|
assert remote_reply_id in descendant_ids
|
||||||
|
end
|
||||||
|
|
||||||
|
test "if user is unauthenticated reply", %{
|
||||||
|
conn: conn,
|
||||||
|
locals: [post_id, reply_id],
|
||||||
|
remote: remote_reply_id
|
||||||
|
} do
|
||||||
|
res_conn = get(conn, "/api/v1/statuses/#{reply_id}/context")
|
||||||
|
|
||||||
|
%{"ancestors" => ancestors, "descendants" => descendants} =
|
||||||
|
json_response_and_validate_schema(res_conn, 200)
|
||||||
|
|
||||||
|
ancestor_ids =
|
||||||
|
ancestors
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
descendant_ids =
|
||||||
|
descendants
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
assert post_id not in ancestor_ids
|
||||||
|
assert remote_reply_id in descendant_ids
|
||||||
|
end
|
||||||
|
|
||||||
|
test "if user is authenticated", %{locals: [post_id, reply_id], remote: remote_reply_id} do
|
||||||
|
%{conn: conn} = oauth_access(["read"])
|
||||||
|
res_conn = get(conn, "/api/v1/statuses/#{post_id}/context")
|
||||||
|
|
||||||
|
%{"ancestors" => [], "descendants" => descendants} =
|
||||||
|
json_response_and_validate_schema(res_conn, 200)
|
||||||
|
|
||||||
|
descendant_ids =
|
||||||
|
descendants
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
assert reply_id in descendant_ids
|
||||||
|
assert remote_reply_id in descendant_ids
|
||||||
|
end
|
||||||
|
|
||||||
|
test "if user is authenticated reply", %{locals: [post_id, reply_id], remote: remote_reply_id} do
|
||||||
|
%{conn: conn} = oauth_access(["read"])
|
||||||
|
res_conn = get(conn, "/api/v1/statuses/#{reply_id}/context")
|
||||||
|
|
||||||
|
%{"ancestors" => ancestors, "descendants" => descendants} =
|
||||||
|
json_response_and_validate_schema(res_conn, 200)
|
||||||
|
|
||||||
|
ancestor_ids =
|
||||||
|
ancestors
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
descendant_ids =
|
||||||
|
descendants
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
assert post_id in ancestor_ids
|
||||||
|
assert remote_reply_id in descendant_ids
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "getting status contexts restricted unauthenticated for remote" do
|
||||||
|
setup do: local_and_remote_context_activities()
|
||||||
|
|
||||||
|
setup do: clear_config([:restrict_unauthenticated, :activities, :local], false)
|
||||||
|
|
||||||
|
setup do: clear_config([:restrict_unauthenticated, :activities, :remote], true)
|
||||||
|
|
||||||
|
test "if user is unauthenticated", %{
|
||||||
|
conn: conn,
|
||||||
|
locals: [post_id, reply_id],
|
||||||
|
remote: remote_reply_id
|
||||||
|
} do
|
||||||
|
res_conn = get(conn, "/api/v1/statuses/#{post_id}/context")
|
||||||
|
|
||||||
|
%{"ancestors" => [], "descendants" => descendants} =
|
||||||
|
json_response_and_validate_schema(res_conn, 200)
|
||||||
|
|
||||||
|
descendant_ids =
|
||||||
|
descendants
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
assert reply_id in descendant_ids
|
||||||
|
assert remote_reply_id not in descendant_ids
|
||||||
|
end
|
||||||
|
|
||||||
|
test "if user is unauthenticated reply", %{
|
||||||
|
conn: conn,
|
||||||
|
locals: [post_id, reply_id],
|
||||||
|
remote: remote_reply_id
|
||||||
|
} do
|
||||||
|
res_conn = get(conn, "/api/v1/statuses/#{reply_id}/context")
|
||||||
|
|
||||||
|
%{"ancestors" => ancestors, "descendants" => descendants} =
|
||||||
|
json_response_and_validate_schema(res_conn, 200)
|
||||||
|
|
||||||
|
ancestor_ids =
|
||||||
|
ancestors
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
descendant_ids =
|
||||||
|
descendants
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
assert post_id in ancestor_ids
|
||||||
|
assert remote_reply_id not in descendant_ids
|
||||||
|
end
|
||||||
|
|
||||||
|
test "if user is authenticated", %{locals: [post_id, reply_id], remote: remote_reply_id} do
|
||||||
|
%{conn: conn} = oauth_access(["read"])
|
||||||
|
res_conn = get(conn, "/api/v1/statuses/#{post_id}/context")
|
||||||
|
|
||||||
|
%{"ancestors" => [], "descendants" => descendants} =
|
||||||
|
json_response_and_validate_schema(res_conn, 200)
|
||||||
|
|
||||||
|
reply_ids =
|
||||||
|
descendants
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
assert reply_id in reply_ids
|
||||||
|
assert remote_reply_id in reply_ids
|
||||||
|
end
|
||||||
|
|
||||||
|
test "if user is authenticated reply", %{locals: [post_id, reply_id], remote: remote_reply_id} do
|
||||||
|
%{conn: conn} = oauth_access(["read"])
|
||||||
|
res_conn = get(conn, "/api/v1/statuses/#{reply_id}/context")
|
||||||
|
|
||||||
|
%{"ancestors" => ancestors, "descendants" => descendants} =
|
||||||
|
json_response_and_validate_schema(res_conn, 200)
|
||||||
|
|
||||||
|
ancestor_ids =
|
||||||
|
ancestors
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
descendant_ids =
|
||||||
|
descendants
|
||||||
|
|> Enum.map(& &1["id"])
|
||||||
|
|
||||||
|
assert post_id in ancestor_ids
|
||||||
|
assert remote_reply_id in descendant_ids
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "deleting a status" do
|
describe "deleting a status" do
|
||||||
test "when you created it" do
|
test "when you created it" do
|
||||||
%{user: author, conn: conn} = oauth_access(["write:statuses"])
|
%{user: author, conn: conn} = oauth_access(["write:statuses"])
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityViewTest do
|
||||||
id: to_string(scheduled_activity.id),
|
id: to_string(scheduled_activity.id),
|
||||||
media_attachments:
|
media_attachments:
|
||||||
%{media_ids: [upload.id]}
|
%{media_ids: [upload.id]}
|
||||||
|> Utils.attachments_from_ids()
|
|> Utils.attachments_from_ids(user)
|
||||||
|> Enum.map(&StatusView.render("attachment.json", %{attachment: &1})),
|
|> Enum.map(&StatusView.render("attachment.json", %{attachment: &1})),
|
||||||
params: %{
|
params: %{
|
||||||
in_reply_to_id: to_string(activity.id),
|
in_reply_to_id: to_string(activity.id),
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ defmodule Pleroma.Web.PleromaAPI.ChatMessageReferenceViewTest do
|
||||||
filename: "an_image.jpg"
|
filename: "an_image.jpg"
|
||||||
}
|
}
|
||||||
|
|
||||||
{:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
|
{:ok, upload} = ActivityPub.upload(file, actor: recipient.ap_id)
|
||||||
|
|
||||||
{:ok, activity} =
|
{:ok, activity} =
|
||||||
CommonAPI.post_chat_message(user, recipient, "kippis :firefox:", idempotency_key: "123")
|
CommonAPI.post_chat_message(user, recipient, "kippis :firefox:", idempotency_key: "123")
|
||||||
|
|
|
||||||
|
|
@ -180,5 +180,28 @@ defmodule Pleroma.Web.WebFingerTest do
|
||||||
|
|
||||||
{:ok, _data} = WebFinger.finger("pekorino@pawoo.net")
|
{:ok, _data} = WebFinger.finger("pekorino@pawoo.net")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "refuses to process XML remote entities" do
|
||||||
|
Tesla.Mock.mock(fn
|
||||||
|
%{
|
||||||
|
url: "https://pawoo.net/.well-known/webfinger?resource=acct:pekorino@pawoo.net"
|
||||||
|
} ->
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body: File.read!("test/fixtures/xml_external_entities.xml"),
|
||||||
|
headers: [{"content-type", "application/xrd+xml"}]
|
||||||
|
}}
|
||||||
|
|
||||||
|
%{url: "https://pawoo.net/.well-known/host-meta"} ->
|
||||||
|
{:ok,
|
||||||
|
%Tesla.Env{
|
||||||
|
status: 200,
|
||||||
|
body: File.read!("test/fixtures/tesla_mock/pawoo.net_host_meta")
|
||||||
|
}}
|
||||||
|
end)
|
||||||
|
|
||||||
|
assert :error = WebFinger.finger("pekorino@pawoo.net")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
15
test/pleroma/web/xml_test.exs
Normal file
15
test/pleroma/web/xml_test.exs
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
defmodule Pleroma.Web.XMLTest do
|
||||||
|
use Pleroma.DataCase, async: true
|
||||||
|
|
||||||
|
alias Pleroma.Web.XML
|
||||||
|
|
||||||
|
test "refuses to parse any entities from XML" do
|
||||||
|
data = File.read!("test/fixtures/xml_billion_laughs.xml")
|
||||||
|
assert(:error == XML.parse_document(data))
|
||||||
|
end
|
||||||
|
|
||||||
|
test "refuses to load external entities from XML" do
|
||||||
|
data = File.read!("test/fixtures/xml_external_entities.xml")
|
||||||
|
assert(:error == XML.parse_document(data))
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Add table
Add a link
Reference in a new issue