diff --git a/lib/pleroma/ecto_type/activity_pub/object_validators/content_language_map.ex b/lib/pleroma/ecto_type/activity_pub/object_validators/content_language_map.ex new file mode 100644 index 000000000..2cc0fda00 --- /dev/null +++ b/lib/pleroma/ecto_type/activity_pub/object_validators/content_language_map.ex @@ -0,0 +1,49 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2023 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.ContentLanguageMap do + use Ecto.Type + + import Pleroma.EctoType.ActivityPub.ObjectValidators.LanguageCode, + only: [is_good_locale_code?: 1] + + def type, do: :map + + def cast(%{} = object) do + with {status, %{} = data} when status in [:modified, :ok] <- validate_map(object) do + {:ok, data} + else + {_, nil} -> {:ok, nil} + {:error, _} -> :error + end + end + + def cast(_), do: :error + + def dump(data), do: {:ok, data} + + def load(data), do: {:ok, data} + + defp validate_map(%{} = object) do + {status, data} = + object + |> Enum.reduce({:ok, %{}}, fn + {lang, value}, {status, acc} when is_binary(lang) and is_binary(value) -> + if is_good_locale_code?(lang) do + {status, Map.put(acc, lang, value)} + else + {:modified, acc} + end + + _, {_status, acc} -> + {:modified, acc} + end) + + if data == %{} do + {status, nil} + else + {status, data} + end + end +end diff --git a/test/pleroma/ecto_type/activity_pub/object_validators/content_language_map_test.exs b/test/pleroma/ecto_type/activity_pub/object_validators/content_language_map_test.exs new file mode 100644 index 000000000..a05871a6f --- /dev/null +++ b/test/pleroma/ecto_type/activity_pub/object_validators/content_language_map_test.exs @@ -0,0 +1,56 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2023 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.ContentLanguageMapTest do + use Pleroma.DataCase, async: true + + alias Pleroma.EctoType.ActivityPub.ObjectValidators.ContentLanguageMap + + test "it validates" do + data = %{ + "en-US" => "mew mew", + "en-GB" => "meow meow" + } + + assert {:ok, ^data} = ContentLanguageMap.cast(data) + end + + test "it validates empty strings" do + data = %{ + "en-US" => "mew mew", + "en-GB" => "" + } + + assert {:ok, ^data} = ContentLanguageMap.cast(data) + end + + test "it ignores non-strings within the map" do + data = %{ + "en-US" => "mew mew", + "en-GB" => 123 + } + + assert {:ok, validated_data} = ContentLanguageMap.cast(data) + + assert validated_data == %{"en-US" => "mew mew"} + end + + test "it ignores bad locale codes" do + data = %{ + "en-US" => "mew mew", + "en_GB" => "meow meow", + "en<<#@!$#!@%!GB" => "meow meow" + } + + assert {:ok, validated_data} = ContentLanguageMap.cast(data) + + assert validated_data == %{"en-US" => "mew mew"} + end + + test "it complains with non-map data" do + assert :error = ContentLanguageMap.cast("mew") + assert :error = ContentLanguageMap.cast(["mew"]) + assert :error = ContentLanguageMap.cast([%{"en-US" => "mew"}]) + end +end diff --git a/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs b/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs index a0c50b10d..c4e2aa838 100644 --- a/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs @@ -118,7 +118,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidatorTest end describe "Note language" do - test "it detects language from context" do + test "it detects language from JSON-LD context" do user = insert(:user) note_activity = %{