forked from AkkomaGang/akkoma
Merge branch 'feature/mrf-describe' into 'develop'
MRF describe API See merge request pleroma/pleroma!1561
This commit is contained in:
commit
c3a54cc34d
21 changed files with 176 additions and 50 deletions
|
@ -35,4 +35,36 @@ def subdomains_regex(domains) when is_list(domains) do
|
||||||
def subdomain_match?(domains, host) do
|
def subdomain_match?(domains, host) do
|
||||||
Enum.any?(domains, fn domain -> Regex.match?(domain, host) end)
|
Enum.any?(domains, fn domain -> Regex.match?(domain, host) end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@callback describe() :: {:ok | :error, Map.t()}
|
||||||
|
|
||||||
|
def describe(policies) do
|
||||||
|
{:ok, policy_configs} =
|
||||||
|
policies
|
||||||
|
|> Enum.reduce({:ok, %{}}, fn
|
||||||
|
policy, {:ok, data} ->
|
||||||
|
{:ok, policy_data} = policy.describe()
|
||||||
|
{:ok, Map.merge(data, policy_data)}
|
||||||
|
|
||||||
|
_, error ->
|
||||||
|
error
|
||||||
|
end)
|
||||||
|
|
||||||
|
mrf_policies =
|
||||||
|
get_policies()
|
||||||
|
|> Enum.map(fn policy -> to_string(policy) |> String.split(".") |> List.last() end)
|
||||||
|
|
||||||
|
exclusions = Pleroma.Config.get([:instance, :mrf_transparency_exclusions])
|
||||||
|
|
||||||
|
base =
|
||||||
|
%{
|
||||||
|
mrf_policies: mrf_policies,
|
||||||
|
exclusions: length(exclusions) > 0
|
||||||
|
}
|
||||||
|
|> Map.merge(policy_configs)
|
||||||
|
|
||||||
|
{:ok, base}
|
||||||
|
end
|
||||||
|
|
||||||
|
def describe, do: get_policies() |> describe()
|
||||||
end
|
end
|
||||||
|
|
|
@ -62,4 +62,7 @@ def filter(%{"type" => "Follow", "actor" => actor_id} = message) do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(message), do: {:ok, message}
|
def filter(message), do: {:ok, message}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe, do: {:ok, %{}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy do
|
defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy do
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
|
||||||
|
@behaviour Pleroma.Web.ActivityPub.MRF
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
# has the user successfully posted before?
|
# has the user successfully posted before?
|
||||||
|
@ -22,6 +24,7 @@ defp contains_links?(%{"content" => content} = _object) do
|
||||||
|
|
||||||
defp contains_links?(_), do: false
|
defp contains_links?(_), do: false
|
||||||
|
|
||||||
|
@impl true
|
||||||
def filter(%{"type" => "Create", "actor" => actor, "object" => object} = message) do
|
def filter(%{"type" => "Create", "actor" => actor, "object" => object} = message) do
|
||||||
with {:ok, %User{} = u} <- User.get_or_fetch_by_ap_id(actor),
|
with {:ok, %User{} = u} <- User.get_or_fetch_by_ap_id(actor),
|
||||||
{:contains_links, true} <- {:contains_links, contains_links?(object)},
|
{:contains_links, true} <- {:contains_links, contains_links?(object)},
|
||||||
|
@ -45,4 +48,7 @@ def filter(%{"type" => "Create", "actor" => actor, "object" => object} = message
|
||||||
|
|
||||||
# in all other cases, pass through
|
# in all other cases, pass through
|
||||||
def filter(message), do: {:ok, message}
|
def filter(message), do: {:ok, message}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe, do: {:ok, %{}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,4 +12,7 @@ def filter(object) do
|
||||||
Logger.info("REJECTING #{inspect(object)}")
|
Logger.info("REJECTING #{inspect(object)}")
|
||||||
{:reject, object}
|
{:reject, object}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe, do: {:ok, %{}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -39,4 +39,6 @@ def filter(%{"type" => "Create", "object" => child_object} = object) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def filter(object), do: {:ok, object}
|
def filter(object), do: {:ok, object}
|
||||||
|
|
||||||
|
def describe, do: {:ok, %{}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -90,4 +90,7 @@ def filter(%{"type" => "Create"} = message) do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(message), do: {:ok, message}
|
def filter(message), do: {:ok, message}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe, do: {:ok, %{mrf_hellthread: Pleroma.Config.get([:mrf_hellthread])}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -96,4 +96,36 @@ def filter(%{"type" => "Create", "object" => %{"content" => _content}} = message
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(message), do: {:ok, message}
|
def filter(message), do: {:ok, message}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe do
|
||||||
|
# This horror is needed to convert regex sigils to strings
|
||||||
|
mrf_keyword =
|
||||||
|
Pleroma.Config.get(:mrf_keyword, [])
|
||||||
|
|> Enum.map(fn {key, value} ->
|
||||||
|
{key,
|
||||||
|
Enum.map(value, fn
|
||||||
|
{pattern, replacement} ->
|
||||||
|
%{
|
||||||
|
"pattern" =>
|
||||||
|
if not is_binary(pattern) do
|
||||||
|
inspect(pattern)
|
||||||
|
else
|
||||||
|
pattern
|
||||||
|
end,
|
||||||
|
"replacement" => replacement
|
||||||
|
}
|
||||||
|
|
||||||
|
pattern ->
|
||||||
|
if not is_binary(pattern) do
|
||||||
|
inspect(pattern)
|
||||||
|
else
|
||||||
|
pattern
|
||||||
|
end
|
||||||
|
end)}
|
||||||
|
end)
|
||||||
|
|> Enum.into(%{})
|
||||||
|
|
||||||
|
{:ok, %{mrf_keyword: mrf_keyword}}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -53,4 +53,7 @@ def filter(
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(message), do: {:ok, message}
|
def filter(message), do: {:ok, message}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe, do: {:ok, %{}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,4 +21,7 @@ def filter(%{"type" => "Create"} = message) do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(message), do: {:ok, message}
|
def filter(message), do: {:ok, message}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe, do: {:ok, %{}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -19,4 +19,7 @@ def filter(
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(object), do: {:ok, object}
|
def filter(object), do: {:ok, object}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe, do: {:ok, %{}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,4 +10,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.NoOpPolicy do
|
||||||
def filter(object) do
|
def filter(object) do
|
||||||
{:ok, object}
|
{:ok, object}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe, do: {:ok, %{}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,4 +21,6 @@ def filter(%{"type" => "Create", "object" => child_object} = object) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def filter(object), do: {:ok, object}
|
def filter(object), do: {:ok, object}
|
||||||
|
|
||||||
|
def describe, do: {:ok, %{}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -44,4 +44,7 @@ def filter(%{"type" => "Create"} = object) do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(object), do: {:ok, object}
|
def filter(object), do: {:ok, object}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe, do: {:ok, %{mrf_rejectnonpublic: Pleroma.Config.get([:mrf_rejectnonpublic])}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -177,4 +177,16 @@ def filter(%{"id" => actor, "type" => obj_type} = object)
|
||||||
end
|
end
|
||||||
|
|
||||||
def filter(object), do: {:ok, object}
|
def filter(object), do: {:ok, object}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe do
|
||||||
|
exclusions = Pleroma.Config.get([:instance, :mrf_transparency_exclusions])
|
||||||
|
|
||||||
|
mrf_simple =
|
||||||
|
Pleroma.Config.get(:mrf_simple)
|
||||||
|
|> Enum.map(fn {k, v} -> {k, Enum.reject(v, fn v -> v in exclusions end)} end)
|
||||||
|
|> Enum.into(%{})
|
||||||
|
|
||||||
|
{:ok, %{mrf_simple: mrf_simple}}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -37,4 +37,7 @@ def filter(%{"actor" => actor} = message) do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(message), do: {:ok, message}
|
def filter(message), do: {:ok, message}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe, do: {:ok, %{}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -165,4 +165,7 @@ def filter(%{"actor" => actor, "type" => "Create"} = message),
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def filter(message), do: {:ok, message}
|
def filter(message), do: {:ok, message}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe, do: {:ok, %{}}
|
||||||
end
|
end
|
||||||
|
|
|
@ -32,4 +32,13 @@ def filter(%{"actor" => actor} = object) do
|
||||||
end
|
end
|
||||||
|
|
||||||
def filter(object), do: {:ok, object}
|
def filter(object), do: {:ok, object}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe do
|
||||||
|
mrf_user_allowlist =
|
||||||
|
Config.get([:mrf_user_allowlist], [])
|
||||||
|
|> Enum.into(%{}, fn {k, v} -> {k, length(v)} end)
|
||||||
|
|
||||||
|
{:ok, %{mrf_user_allowlist: mrf_user_allowlist}}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -34,64 +34,18 @@ def schemas(conn, _params) do
|
||||||
def raw_nodeinfo do
|
def raw_nodeinfo do
|
||||||
stats = Stats.get_stats()
|
stats = Stats.get_stats()
|
||||||
|
|
||||||
exclusions = Config.get([:instance, :mrf_transparency_exclusions])
|
|
||||||
|
|
||||||
mrf_simple =
|
|
||||||
Config.get(:mrf_simple)
|
|
||||||
|> Enum.map(fn {k, v} -> {k, Enum.reject(v, fn v -> v in exclusions end)} end)
|
|
||||||
|> Enum.into(%{})
|
|
||||||
|
|
||||||
# This horror is needed to convert regex sigils to strings
|
|
||||||
mrf_keyword =
|
|
||||||
Config.get(:mrf_keyword, [])
|
|
||||||
|> Enum.map(fn {key, value} ->
|
|
||||||
{key,
|
|
||||||
Enum.map(value, fn
|
|
||||||
{pattern, replacement} ->
|
|
||||||
%{
|
|
||||||
"pattern" =>
|
|
||||||
if not is_binary(pattern) do
|
|
||||||
inspect(pattern)
|
|
||||||
else
|
|
||||||
pattern
|
|
||||||
end,
|
|
||||||
"replacement" => replacement
|
|
||||||
}
|
|
||||||
|
|
||||||
pattern ->
|
|
||||||
if not is_binary(pattern) do
|
|
||||||
inspect(pattern)
|
|
||||||
else
|
|
||||||
pattern
|
|
||||||
end
|
|
||||||
end)}
|
|
||||||
end)
|
|
||||||
|> Enum.into(%{})
|
|
||||||
|
|
||||||
mrf_policies =
|
|
||||||
MRF.get_policies()
|
|
||||||
|> Enum.map(fn policy -> to_string(policy) |> String.split(".") |> List.last() end)
|
|
||||||
|
|
||||||
quarantined = Config.get([:instance, :quarantined_instances], [])
|
quarantined = Config.get([:instance, :quarantined_instances], [])
|
||||||
|
|
||||||
staff_accounts =
|
staff_accounts =
|
||||||
User.all_superusers()
|
User.all_superusers()
|
||||||
|> Enum.map(fn u -> u.ap_id end)
|
|> Enum.map(fn u -> u.ap_id end)
|
||||||
|
|
||||||
mrf_user_allowlist =
|
|
||||||
Config.get([:mrf_user_allowlist], [])
|
|
||||||
|> Enum.into(%{}, fn {k, v} -> {k, length(v)} end)
|
|
||||||
|
|
||||||
federation_response =
|
federation_response =
|
||||||
if Config.get([:instance, :mrf_transparency]) do
|
if Config.get([:instance, :mrf_transparency]) do
|
||||||
%{
|
{:ok, data} = MRF.describe()
|
||||||
mrf_policies: mrf_policies,
|
|
||||||
mrf_simple: mrf_simple,
|
data
|
||||||
mrf_keyword: mrf_keyword,
|
|> Map.merge(%{quarantined_instances: quarantined})
|
||||||
mrf_user_allowlist: mrf_user_allowlist,
|
|
||||||
quarantined_instances: quarantined,
|
|
||||||
exclusions: length(exclusions) > 0
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
%{}
|
%{}
|
||||||
end
|
end
|
||||||
|
|
13
test/support/mrf_module_mock.ex
Normal file
13
test/support/mrf_module_mock.ex
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule MRFModuleMock do
|
||||||
|
@behaviour Pleroma.Web.ActivityPub.MRF
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def filter(message), do: {:ok, message}
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def describe, do: {:ok, %{mrf_module_mock: "some config data"}}
|
||||||
|
end
|
|
@ -57,4 +57,30 @@ test "matches are case-insensitive" do
|
||||||
refute MRF.subdomain_match?(regexes, "example.com")
|
refute MRF.subdomain_match?(regexes, "example.com")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "describe/0" do
|
||||||
|
test "it works as expected with noop policy" do
|
||||||
|
expected = %{
|
||||||
|
mrf_policies: ["NoOpPolicy"],
|
||||||
|
exclusions: false
|
||||||
|
}
|
||||||
|
|
||||||
|
{:ok, ^expected} = MRF.describe()
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it works as expected with mock policy" do
|
||||||
|
config = Pleroma.Config.get([:instance, :rewrite_policy])
|
||||||
|
Pleroma.Config.put([:instance, :rewrite_policy], [MRFModuleMock])
|
||||||
|
|
||||||
|
expected = %{
|
||||||
|
mrf_policies: ["MRFModuleMock"],
|
||||||
|
mrf_module_mock: "some config data",
|
||||||
|
exclusions: false
|
||||||
|
}
|
||||||
|
|
||||||
|
{:ok, ^expected} = MRF.describe()
|
||||||
|
|
||||||
|
Pleroma.Config.put([:instance, :rewrite_policy], config)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -85,6 +85,9 @@ test "it returns the safe_dm_mentions feature if enabled", %{conn: conn} do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it shows MRF transparency data if enabled", %{conn: conn} do
|
test "it shows MRF transparency data if enabled", %{conn: conn} do
|
||||||
|
config = Pleroma.Config.get([:instance, :rewrite_policy])
|
||||||
|
Pleroma.Config.put([:instance, :rewrite_policy], [Pleroma.Web.ActivityPub.MRF.SimplePolicy])
|
||||||
|
|
||||||
option = Pleroma.Config.get([:instance, :mrf_transparency])
|
option = Pleroma.Config.get([:instance, :mrf_transparency])
|
||||||
Pleroma.Config.put([:instance, :mrf_transparency], true)
|
Pleroma.Config.put([:instance, :mrf_transparency], true)
|
||||||
|
|
||||||
|
@ -98,11 +101,15 @@ test "it shows MRF transparency data if enabled", %{conn: conn} do
|
||||||
|
|
||||||
assert response["metadata"]["federation"]["mrf_simple"] == simple_config
|
assert response["metadata"]["federation"]["mrf_simple"] == simple_config
|
||||||
|
|
||||||
|
Pleroma.Config.put([:instance, :rewrite_policy], config)
|
||||||
Pleroma.Config.put([:instance, :mrf_transparency], option)
|
Pleroma.Config.put([:instance, :mrf_transparency], option)
|
||||||
Pleroma.Config.put(:mrf_simple, %{})
|
Pleroma.Config.put(:mrf_simple, %{})
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it performs exclusions from MRF transparency data if configured", %{conn: conn} do
|
test "it performs exclusions from MRF transparency data if configured", %{conn: conn} do
|
||||||
|
config = Pleroma.Config.get([:instance, :rewrite_policy])
|
||||||
|
Pleroma.Config.put([:instance, :rewrite_policy], [Pleroma.Web.ActivityPub.MRF.SimplePolicy])
|
||||||
|
|
||||||
option = Pleroma.Config.get([:instance, :mrf_transparency])
|
option = Pleroma.Config.get([:instance, :mrf_transparency])
|
||||||
Pleroma.Config.put([:instance, :mrf_transparency], true)
|
Pleroma.Config.put([:instance, :mrf_transparency], true)
|
||||||
|
|
||||||
|
@ -122,6 +129,7 @@ test "it performs exclusions from MRF transparency data if configured", %{conn:
|
||||||
assert response["metadata"]["federation"]["mrf_simple"] == expected_config
|
assert response["metadata"]["federation"]["mrf_simple"] == expected_config
|
||||||
assert response["metadata"]["federation"]["exclusions"] == true
|
assert response["metadata"]["federation"]["exclusions"] == true
|
||||||
|
|
||||||
|
Pleroma.Config.put([:instance, :rewrite_policy], config)
|
||||||
Pleroma.Config.put([:instance, :mrf_transparency], option)
|
Pleroma.Config.put([:instance, :mrf_transparency], option)
|
||||||
Pleroma.Config.put([:instance, :mrf_transparency_exclusions], exclusions)
|
Pleroma.Config.put([:instance, :mrf_transparency_exclusions], exclusions)
|
||||||
Pleroma.Config.put(:mrf_simple, %{})
|
Pleroma.Config.put(:mrf_simple, %{})
|
||||||
|
|
Loading…
Reference in a new issue