From b86b3a9e298b400ee2e2805b987cc14a24a44ea7 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Tue, 25 Apr 2023 13:30:20 +0100 Subject: [PATCH 01/15] Support public key URIs that incomprehensibly have GET args Fixes #528 --- CHANGELOG.md | 5 +++++ lib/pleroma/signature.ex | 1 + test/pleroma/signature_test.exs | 5 +++++ 3 files changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ef9d4e97..bb5b8fa04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ 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/). +## Unreleased + +## Fixed +- Support for `streams` public key URIs + ## 2023.04 ## Added diff --git a/lib/pleroma/signature.ex b/lib/pleroma/signature.ex index 1c59be9c7..b229e6296 100644 --- a/lib/pleroma/signature.ex +++ b/lib/pleroma/signature.ex @@ -17,6 +17,7 @@ def key_id_to_actor_id(key_id) do key_id |> URI.parse() |> Map.put(:fragment, nil) + |> Map.put(:query, nil) |> remove_suffix(@known_suffixes) maybe_ap_id = URI.to_string(uri) diff --git a/test/pleroma/signature_test.exs b/test/pleroma/signature_test.exs index 59674bbc0..21e6ed161 100644 --- a/test/pleroma/signature_test.exs +++ b/test/pleroma/signature_test.exs @@ -114,6 +114,11 @@ test "it deduces the actor id for gotoSocial" do {:ok, "https://example.com/users/1234"} end + test "it deduces the actor ID for streams" do + assert Signature.key_id_to_actor_id("https://example.com/users/1234?operation=getkey") == + {:ok, "https://example.com/users/1234"} + end + test "it calls webfinger for 'acct:' accounts" do with_mock(Pleroma.Web.WebFinger, finger: fn _ -> {:ok, %{"ap_id" => "https://gensokyo.2hu/users/raymoo"}} end From d8bed0ff635d99bcd75207e5ee78fac6d3f186a4 Mon Sep 17 00:00:00 2001 From: provable_ascent Date: Thu, 27 Apr 2023 05:22:12 +0000 Subject: [PATCH 02/15] Make UserNote comment default to the empty string. This make the behavior consistent between when UserNote doesn't exist and when comment is null. The current behavior may return null in APIs, which misleads some clients doing feature detection into thinking the server does not support comments. For example, see https://codeberg.org/husky/husky/issues/92 --- lib/pleroma/user_note.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/user_note.ex b/lib/pleroma/user_note.ex index 5e82d359f..ff4981cb7 100644 --- a/lib/pleroma/user_note.ex +++ b/lib/pleroma/user_note.ex @@ -31,7 +31,7 @@ def show(%User{} = source, %User{} = target) do UserNote |> where(source_id: ^source.id, target_id: ^target.id) |> Repo.one() do - note.comment + note.comment || "" else _ -> "" end From 145c73076d203b080fe69fc9f5fc05b42d711397 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Mon, 8 May 2023 16:29:25 +0100 Subject: [PATCH 03/15] Update dependencies --- mix.exs | 1 - mix.lock | 26 +++++++++++++------------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/mix.exs b/mix.exs index ebcca9660..2f318fea0 100644 --- a/mix.exs +++ b/mix.exs @@ -190,7 +190,6 @@ defp deps do {:mfm_parser, git: "https://akkoma.dev/AkkomaGang/mfm-parser.git", ref: "912fba81152d4d572e457fd5427f9875b2bc3dbe"}, - {:poison, ">= 0.0.0"}, ## dev & test {:ex_doc, "~> 0.22", only: :dev, runtime: false}, diff --git a/mix.lock b/mix.lock index bee2c1585..2cb91bfd7 100644 --- a/mix.lock +++ b/mix.lock @@ -15,21 +15,21 @@ "concurrent_limiter": {:hex, :concurrent_limiter, "0.1.1", "43ae1dc23edda1ab03dd66febc739c4ff710d047bb4d735754909f9a474ae01c", [:mix], [{:telemetry, "~> 0.3", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "53968ff238c0fbb4d7ed76ddb1af0be6f3b2f77909f6796e249e737c505a16eb"}, "connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"}, "cors_plug": {:hex, :cors_plug, "2.0.3", "316f806d10316e6d10f09473f19052d20ba0a0ce2a1d910ddf57d663dac402ae", [:mix], [{:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "ee4ae1418e6ce117fc42c2ba3e6cbdca4e95ecd2fe59a05ec6884ca16d469aea"}, - "cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"}, + "cowboy": {:hex, :cowboy, "2.10.0", "ff9ffeff91dae4ae270dd975642997afe2a1179d94b1887863e43f681a203e26", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "3afdccb7183cc6f143cb14d3cf51fa00e53db9ec80cdcd525482f5e99bc41d6b"}, "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.3.1", "ebd1a1d7aff97f27c66654e78ece187abdc646992714164380d8a041eda16754", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3a6efd3366130eab84ca372cbd4a7d3c3a97bdfcfb4911233b035d117063f0af"}, - "cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"}, + "cowlib": {:hex, :cowlib, "2.12.1", "a9fa9a625f1d2025fe6b462cb865881329b5caff8f1854d1cbc9f9533f00e1e1", [:make, :rebar3], [], "hexpm", "163b73f6367a7341b33c794c4e88e7dbfe6498ac42dcd69ef44c5bc5507c8db0"}, "credo": {:git, "https://github.com/rrrene/credo.git", "1c1b99ea41a457761383d81aaf6a606913996fe7", [ref: "1c1b99ea41a457761383d81aaf6a606913996fe7"]}, "custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"}, - "db_connection": {:hex, :db_connection, "2.4.3", "3b9aac9f27347ec65b271847e6baeb4443d8474289bd18c1d6f4de655b70c94d", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c127c15b0fa6cfb32eed07465e05da6c815b032508d4ed7c116122871df73c12"}, - "decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"}, + "db_connection": {:hex, :db_connection, "2.5.0", "bb6d4f30d35ded97b29fe80d8bd6f928a1912ca1ff110831edcd238a1973652c", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c92d5ba26cd69ead1ff7582dbb860adeedfff39774105a4f1c92cbb654b55aa2"}, + "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, - "dialyxir": {:hex, :dialyxir, "1.2.0", "58344b3e87c2e7095304c81a9ae65cb68b613e28340690dfe1a5597fd08dec37", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "61072136427a851674cab81762be4dbeae7679f85b1272b6d25c3a839aff8463"}, - "earmark": {:hex, :earmark, "1.4.37", "56ce845c543393aa3f9b294c818c3d783452a4a67e4ab18c4303a954a8b59363", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "d86d5e12868db86d5321b00e62a4bbcb4150346e4acc9a90a041fb188a5cb106"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.31", "a93921cdc6b9b869f519213d5bc79d9e218ba768d7270d46fdcf1c01bacff9e2", [:mix], [], "hexpm", "317d367ee0335ef037a87e46c91a2269fef6306413f731e8ec11fc45a7efd059"}, + "dialyxir": {:hex, :dialyxir, "1.3.0", "fd1672f0922b7648ff9ce7b1b26fcf0ef56dda964a459892ad15f6b4410b5284", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "00b2a4bcd6aa8db9dcb0b38c1225b7277dca9bc370b6438715667071a304696f"}, + "earmark": {:hex, :earmark, "1.4.38", "ba8fda946c259c6e8f6759d3647d448e9216e2c0afed8c6ae7f8ce1f7072a497", [:mix], [{:earmark_parser, "~> 1.4.32", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "f938e30de4167e7d8f3bf588b01dc041138278dda1e5a13fb9ec89b43dd5ec7f"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.32", "fa739a0ecfa34493de19426681b23f6814573faee95dfd4b4aafe15a7b5b32c6", [:mix], [], "hexpm", "b8b0dd77d60373e77a3d7e8afa598f325e49e8663a51bcc2b88ef41838cca755"}, "eblurhash": {:hex, :eblurhash, "1.2.2", "7da4255aaea984b31bb71155f673257353b0e0554d0d30dcf859547e74602582", [:rebar3], [], "hexpm", "8c20ca00904de023a835a9dcb7b7762fed32264c85a80c3cafa85288e405044c"}, "ecto": {:hex, :ecto, "3.9.5", "9f0aa7ae44a1577b651c98791c6988cd1b69b21bc724e3fd67090b97f7604263", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d4f3115d8cbacdc0bfa4b742865459fb1371d0715515842a1fb17fe31920b74c"}, "ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"}, - "ecto_psql_extras": {:hex, :ecto_psql_extras, "0.7.10", "e14d400930f401ca9f541b3349212634e44027d7f919bbb71224d7ac0d0e8acd", [:mix], [{:ecto_sql, "~> 3.4", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.15.7 or ~> 0.16.0", [hex: :postgrex, repo: "hexpm", optional: false]}, {:table_rex, "~> 3.1.1", [hex: :table_rex, repo: "hexpm", optional: false]}], "hexpm", "505e8cd81e4f17c090be0f99e92b1b3f0fd915f98e76965130b8ccfb891e7088"}, + "ecto_psql_extras": {:hex, :ecto_psql_extras, "0.7.11", "6e20144c1446dcccfcdb4c142c9d8b7992a90a569b1d5958cbea5458550b25f0", [:mix], [{:ecto_sql, "~> 3.4", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.15.7 or ~> 0.16.0 or ~> 0.17.0", [hex: :postgrex, repo: "hexpm", optional: false]}, {:table_rex, "~> 3.1.1", [hex: :table_rex, repo: "hexpm", optional: false]}], "hexpm", "def61f1f92d4f40d51c80bbae2157212d6c0a459eb604be446e47369cbd40b23"}, "ecto_sql": {:hex, :ecto_sql, "3.9.2", "34227501abe92dba10d9c3495ab6770e75e79b836d114c41108a4bf2ce200ad5", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.9.2", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "1eb5eeb4358fdbcd42eac11c1fbd87e3affd7904e639d77903c1358b2abd3f70"}, "elasticsearch": {:git, "https://akkoma.dev/AkkomaGang/elasticsearch-elixir.git", "6cd946f75f6ab9042521a009d1d32d29a90113ca", [ref: "main"]}, "elixir_make": {:hex, :elixir_make, "0.6.3", "bc07d53221216838d79e03a8019d0839786703129599e9619f4ab74c8c096eac", [:mix], [], "hexpm", "f5cbd651c5678bcaabdbb7857658ee106b12509cd976c2c2fca99688e1daf716"}, @@ -38,7 +38,7 @@ "ex_aws": {:hex, :ex_aws, "2.1.9", "dc4865ecc20a05190a34a0ac5213e3e5e2b0a75a0c2835e923ae7bfeac5e3c31", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "3e6c776703c9076001fbe1f7c049535f042cb2afa0d2cbd3b47cbc4e92ac0d10"}, "ex_aws_s3": {:hex, :ex_aws_s3, "2.4.0", "ce8decb6b523381812798396bc0e3aaa62282e1b40520125d1f4eff4abdff0f4", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "85dda6e27754d94582869d39cba3241d9ea60b6aa4167f9c88e309dc687e56bb"}, "ex_const": {:hex, :ex_const, "0.2.4", "d06e540c9d834865b012a17407761455efa71d0ce91e5831e86881b9c9d82448", [:mix], [], "hexpm", "96fd346610cc992b8f896ed26a98be82ac4efb065a0578f334a32d60a3ba9767"}, - "ex_doc": {:hex, :ex_doc, "0.29.3", "f07444bcafb302db86e4f02d8bbcd82f2e881a0dcf4f3e4740e4b8128b9353f7", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "3dc6787d7b08801ec3b51e9bd26be5e8826fbf1a17e92d1ebc252e1a1c75bfe1"}, + "ex_doc": {:hex, :ex_doc, "0.29.4", "6257ecbb20c7396b1fe5accd55b7b0d23f44b6aa18017b415cb4c2b91d997729", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "2c6699a737ae46cb61e4ed012af931b57b699643b24dabe2400a8168414bc4f5"}, "ex_machina": {:hex, :ex_machina, "2.7.0", "b792cc3127fd0680fecdb6299235b4727a4944a09ff0fa904cc639272cd92dc7", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "419aa7a39bde11894c87a615c4ecaa52d8f107bbdd81d810465186f783245bf8"}, "ex_syslogger": {:hex, :ex_syslogger, "1.5.2", "72b6aa2d47a236e999171f2e1ec18698740f40af0bd02c8c650bf5f1fd1bac79", [:mix], [{:poison, ">= 1.5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:syslog, "~> 1.1.0", [hex: :syslog, repo: "hexpm", optional: false]}], "hexpm", "ab9fab4136dbc62651ec6f16fa4842f10cf02ab4433fa3d0976c01be99398399"}, "excoveralls": {:hex, :excoveralls, "0.15.1", "83c8cf7973dd9d1d853dce37a2fb98aaf29b564bf7d01866e409abf59dac2c0e", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "f8416bd90c0082d56a2178cf46c837595a06575f70a5624f164a1ffe37de07e7"}, @@ -65,7 +65,7 @@ "mail": {:hex, :mail, "0.2.3", "2c6bb5f8a5f74845fa50ecd0fb45ea16b164026f285f45104f1c4c078cd616d4", [:mix], [], "hexpm", "932b398fa9c69fdf290d7ff63175826e0f1e24414d5b0763bb00a2acfc6c6bf5"}, "majic": {:hex, :majic, "1.0.0", "37e50648db5f5c2ff0c9fb46454d034d11596c03683807b9fb3850676ffdaab3", [:make, :mix], [{:elixir_make, "~> 0.6.1", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "7905858f76650d49695f14ea55cd9aaaee0c6654fa391671d4cf305c275a0a9e"}, "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, - "makeup_elixir": {:hex, :makeup_elixir, "0.16.0", "f8c570a0d33f8039513fbccaf7108c5d750f47d8defd44088371191b76492b0b", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "28b2cbdc13960a46ae9a8858c4bebdec3c9a6d7b4b9e7f4ed1502f8159f338e7"}, + "makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"}, "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, "meck": {:hex, :meck, "0.9.2", "85ccbab053f1db86c7ca240e9fc718170ee5bda03810a6292b5306bf31bae5f5", [:rebar3], [], "hexpm", "81344f561357dc40a8344afa53767c32669153355b626ea9fcbc8da6b3045826"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, @@ -77,10 +77,10 @@ "mogrify": {:hex, :mogrify, "0.9.2", "b360984adea7dd6a55f18028e6327973c58de7f548fdb86c9859848aa904d5b0", [:mix], [], "hexpm", "c18d10fd70ca20e2585301616c89f6e4f7159d92efc9cc8ee579e00c886f699d"}, "mox": {:hex, :mox, "1.0.2", "dc2057289ac478b35760ba74165b4b3f402f68803dd5aecd3bfd19c183815d64", [:mix], [], "hexpm", "f9864921b3aaf763c8741b5b8e6f908f44566f1e427b2630e89e9a73b981fef2"}, "nimble_options": {:hex, :nimble_options, "0.5.2", "42703307b924880f8c08d97719da7472673391905f528259915782bb346e0a1b", [:mix], [], "hexpm", "4da7f904b915fd71db549bcdc25f8d56f378ef7ae07dc1d372cbe72ba950dce0"}, - "nimble_parsec": {:hex, :nimble_parsec, "1.2.3", "244836e6e3f1200c7f30cb56733fd808744eca61fd182f731eac4af635cc6d0b", [:mix], [], "hexpm", "c8d789e39b9131acf7b99291e93dae60ab48ef14a7ee9d58c6964f59efb570b0"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.3.1", "2c54013ecf170e249e9291ed0a62e5832f70a476c61da16f6aac6dca0189f2af", [:mix], [], "hexpm", "2682e3c0b2eb58d90c6375fc0cc30bc7be06f365bf72608804fb9cffa5e1b167"}, "nimble_pool": {:hex, :nimble_pool, "0.2.6", "91f2f4c357da4c4a0a548286c84a3a28004f68f05609b4534526871a22053cde", [:mix], [], "hexpm", "1c715055095d3f2705c4e236c18b618420a35490da94149ff8b580a2144f653f"}, "oban": {:hex, :oban, "2.12.1", "f604d7e6a8be9fda4a9b0f6cebbd633deba569f85dbff70c4d25d99a6f023177", [:mix], [{:ecto_sql, "~> 3.6", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9b1844c2b74e0d788b73e5144b0c9d5674cb775eae29d88a36f3c3b48d42d058"}, - "open_api_spex": {:hex, :open_api_spex, "3.16.1", "8137c338129d63060b4b04947c6c57429f86267045c479c703a38a6d3f98dee1", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.0 or ~> 4.0 or ~> 5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:ymlr, "~> 2.0 or ~> 3.0", [hex: :ymlr, repo: "hexpm", optional: true]}], "hexpm", "ef6fd778ac121af866b48b75ad4ad256b6ff33949113ea4aa1629af8bfdfdbfb"}, + "open_api_spex": {:hex, :open_api_spex, "3.16.3", "11bc9798890073e516a97392d5846a235925e48ecbb468cb5b1cc207d5785a3e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.0 or ~> 4.0 or ~> 5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:ymlr, "~> 2.0 or ~> 3.0", [hex: :ymlr, repo: "hexpm", optional: true]}], "hexpm", "1bcbe6efab88f5d001c2fc377e0bd6058180aa31b68d32962d4926e934b8ecad"}, "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"}, "phoenix": {:hex, :phoenix, "1.6.16", "e5bdd18c7a06da5852a25c7befb72246de4ddc289182285f8685a40b7b5f5451", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e15989ff34f670a96b95ef6d1d25bad0d9c50df5df40b671d8f4a669e050ac39"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"}, @@ -107,7 +107,7 @@ "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"}, "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"}, "sweet_xml": {:hex, :sweet_xml, "0.7.3", "debb256781c75ff6a8c5cbf7981146312b66f044a2898f453709a53e5031b45b", [:mix], [], "hexpm", "e110c867a1b3fe74bfc7dd9893aa851f0eed5518d0d7cad76d7baafd30e4f5ba"}, - "swoosh": {:hex, :swoosh, "1.9.1", "0a5d7bf9954eb41d7e55525bc0940379982b090abbaef67cd8e1fd2ed7f8ca1a", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "76dffff3ffcab80f249d5937a592eaef7cc49ac6f4cdd27e622868326ed6371e"}, + "swoosh": {:hex, :swoosh, "1.10.2", "77acdc1261de404b893e24224d47459d1b42deb02577c7b31514e0a720f949d6", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "1736faf374ed49c6091845cdfd5b3a68c88c5f2bfd989447d12bffafc0dda03a"}, "syslog": {:hex, :syslog, "1.1.0", "6419a232bea84f07b56dc575225007ffe34d9fdc91abe6f1b2f254fd71d8efc2", [:rebar3], [], "hexpm", "4c6a41373c7e20587be33ef841d3de6f3beba08519809329ecc4d27b15b659e1"}, "table_rex": {:hex, :table_rex, "3.1.1", "0c67164d1714b5e806d5067c1e96ff098ba7ae79413cc075973e17c38a587caa", [:mix], [], "hexpm", "678a23aba4d670419c23c17790f9dcd635a4a89022040df7d5d772cb21012490"}, "telemetry": {:hex, :telemetry, "0.4.3", "a06428a514bdbc63293cd9a6263aad00ddeb66f608163bdec7c8995784080818", [:rebar3], [], "hexpm", "eb72b8365ffda5bed68a620d1da88525e326cb82a75ee61354fc24b844768041"}, From f1e66b39c75071f990a49d803ab4b8fd9ac13fb3 Mon Sep 17 00:00:00 2001 From: midnight Date: Mon, 8 May 2023 18:52:19 -0400 Subject: [PATCH 04/15] Return empty string in the event of no detected language --- .../akkoma/translators/libre_translate.ex | 6 +++--- .../pleroma/translators/libre_translate_test.exs | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/akkoma/translators/libre_translate.ex b/lib/pleroma/akkoma/translators/libre_translate.ex index 3a8d9d827..5b08a6384 100644 --- a/lib/pleroma/akkoma/translators/libre_translate.ex +++ b/lib/pleroma/akkoma/translators/libre_translate.ex @@ -39,9 +39,9 @@ def translate(string, from_language, to_language) do detected = if Map.has_key?(body, "detectedLanguage") do get_in(body, ["detectedLanguage", "language"]) - else - from_language - end + else + from_language || "" + end {:ok, detected, translated} else diff --git a/test/pleroma/translators/libre_translate_test.exs b/test/pleroma/translators/libre_translate_test.exs index 3c81c3d76..a93f408f5 100644 --- a/test/pleroma/translators/libre_translate_test.exs +++ b/test/pleroma/translators/libre_translate_test.exs @@ -133,5 +133,21 @@ test "should gracefully handle an unsupported language" do assert {:error, "libre_translate: request failed (code 400)"} = LibreTranslate.translate("ギュギュ握りつぶしちゃうぞ", nil, "zoop") end + + test "should work when no detected language is received" do + Tesla.Mock.mock(fn + %{method: :post, url: "http://libre.translate/translate"} -> + %Tesla.Env{ + status: 200, + body: + Jason.encode!(%{ + translatedText: "I will crush you" + }) + } + end) + + assert {:ok, "", "I will crush you"} = + LibreTranslate.translate("ギュギュ握りつぶしちゃうぞ", nil, "en") + end end end From 9c4203632da7b6e0bd7edbe6e93dc97e748819cc Mon Sep 17 00:00:00 2001 From: provable_ascent Date: Fri, 12 May 2023 02:18:24 +0000 Subject: [PATCH 05/15] Add user_note_test.exs. --- test/pleroma/user_note_test.exs | 39 +++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 test/pleroma/user_note_test.exs diff --git a/test/pleroma/user_note_test.exs b/test/pleroma/user_note_test.exs new file mode 100644 index 000000000..7d818196e --- /dev/null +++ b/test/pleroma/user_note_test.exs @@ -0,0 +1,39 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2021 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.UserNoteTest do + alias Pleroma.UserNote + + use Pleroma.DataCase, async: false + import Pleroma.Factory + + describe "show/2" do + setup do + {:ok, users: insert_list(2, :user)} + end + + test "if record does not exist, returns empty string", %{users: [user1, user2]} do + comment = UserNote.show(user1, user2) + + assert comment == "" + end + + test "if record exists with comment == nil, returns empty string", %{users: [user1, user2]} do + UserNote.create(user1, user2, nil) + + comment = UserNote.show(user1, user2) + + assert comment == "" + end + + test "if record exists with non-nil comment, returns comment", %{users: [user1, user2]} do + expected_comment = "hello" + UserNote.create(user1, user2, expected_comment) + + comment = UserNote.show(user1, user2) + + assert comment == expected_comment + end + end +end From ddf4d8026dd3b99df042de82a91c124e36b428ce Mon Sep 17 00:00:00 2001 From: Denys Nykula Date: Thu, 18 May 2023 22:53:40 +0300 Subject: [PATCH 06/15] fix remote interaction form style --- priv/static/static-fe/forms.css | 41 ++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/priv/static/static-fe/forms.css b/priv/static/static-fe/forms.css index 196713ea0..9d6085d1d 100644 --- a/priv/static/static-fe/forms.css +++ b/priv/static/static-fe/forms.css @@ -14,13 +14,13 @@ input { padding: 10px; margin-top: 5px; margin-bottom: 10px; - background-color: var(--background-color); - color: var(--primary-text-color); + background-color: transparent; + color: inherit; border: 0; transition-property: border-bottom; transition-duration: 0.35s; - border-bottom: 2px solid #2a384a; - font-size: 14px; + border-bottom: 2px solid var(--faint); + font: inherit; width: inherit; box-sizing: border-box; } @@ -91,26 +91,22 @@ [type="checkbox"]:checked+label:before { a.button, button { width: 100%; - background-color: #1c2a3a; - color: var(--primary-text-color); + background-color: var(--btn); + color: var(--btnText); border-radius: 4px; border: none; padding: 10px 16px; margin-top: 20px; margin-bottom: 20px; text-transform: uppercase; - font-size: 16px; - box-shadow: 0px 0px 2px 0px black, - 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset, - 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset; + box-shadow: var(--btnShadow); + font: inherit; } a.button:hover, button:hover { cursor: pointer; - box-shadow: 0px 0px 0px 1px var(--brand-color), - 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset, - 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset; + box-shadow: var(--btnHoverShadow); } .actions { @@ -155,4 +151,21 @@ .account-header__display-name { .account-header__nickname { font-size: 14px; color: var(--muted-text-color); -} \ No newline at end of file +} + +.oauth { + /* Remote interaction /main/ostatus has such hierarchy, and its header and + * content do not pad themselves: + * (.panel.oauth (h2) + * (form (input) + * (button))) */ + padding: 1px 1em; +} + +.oauth .container__content { + /* Frontend selection /oauth/authorize needs an inverse because its heading + * and content have their own background and padding: + * (.panel.oauth (form (.container__content (.panel-heading) + * (.panel-content)))) */ + margin: -1px -1em; +} From c7fb78cc32a91255f4bdc6af0db6b9c88b9e95b3 Mon Sep 17 00:00:00 2001 From: ilja Date: Sun, 21 May 2023 11:47:38 +0200 Subject: [PATCH 07/15] Move deadline and old_insert_date to setup Several tests for prune_objetcs need a date older than the deadline for pruning, so I moved that to the setup --- test/mix/tasks/pleroma/database_test.exs | 73 ++++++++---------------- 1 file changed, 23 insertions(+), 50 deletions(-) diff --git a/test/mix/tasks/pleroma/database_test.exs b/test/mix/tasks/pleroma/database_test.exs index 9edb2c115..21c365412 100644 --- a/test/mix/tasks/pleroma/database_test.exs +++ b/test/mix/tasks/pleroma/database_test.exs @@ -45,21 +45,25 @@ test "it replaces objects with references" do end describe "prune_objects" do - test "it prunes old objects from the database" do + setup do deadline = Pleroma.Config.get([:instance, :remote_post_retention_days]) + 1 - date = + old_insert_date = Timex.now() |> Timex.shift(days: -deadline) |> Timex.to_naive_datetime() |> NaiveDateTime.truncate(:second) + %{old_insert_date: old_insert_date} + end + + test "it prunes old objects from the database", %{old_insert_date: old_insert_date} do insert(:note) %{id: note_remote_public_id} = :note |> insert() - |> Ecto.Changeset.change(%{updated_at: date}) + |> Ecto.Changeset.change(%{updated_at: old_insert_date}) |> Repo.update!() note_remote_non_public = @@ -69,7 +73,7 @@ test "it prunes old objects from the database" do note_remote_non_public |> Ecto.Changeset.change(%{ - updated_at: date, + updated_at: old_insert_date, data: note_remote_non_public_data |> update_in(["to"], fn _ -> [] end) }) |> Repo.update!() @@ -83,21 +87,14 @@ test "it prunes old objects from the database" do refute Object.get_by_id(note_remote_non_public_id) end - test "with the --keep-non-public option it still keeps non-public posts even if they are not local" do - deadline = Pleroma.Config.get([:instance, :remote_post_retention_days]) + 1 - - date = - Timex.now() - |> Timex.shift(days: -deadline) - |> Timex.to_naive_datetime() - |> NaiveDateTime.truncate(:second) - + test "with the --keep-non-public option it still keeps non-public posts even if they are not local", + %{old_insert_date: old_insert_date} do insert(:note) %{id: note_remote_id} = :note |> insert() - |> Ecto.Changeset.change(%{updated_at: date}) + |> Ecto.Changeset.change(%{updated_at: old_insert_date}) |> Repo.update!() note_remote_non_public = @@ -107,7 +104,7 @@ test "with the --keep-non-public option it still keeps non-public posts even if note_remote_non_public |> Ecto.Changeset.change(%{ - updated_at: date, + updated_at: old_insert_date, data: note_remote_non_public_data |> update_in(["to"], fn _ -> [] end) }) |> Repo.update!() @@ -120,16 +117,10 @@ test "with the --keep-non-public option it still keeps non-public posts even if refute Object.get_by_id(note_remote_id) end - test "with the --keep-threads and --keep-non-public option it keeps old threads with non-public replies even if the interaction is not local" do + test "with the --keep-threads and --keep-non-public option it keeps old threads with non-public replies even if the interaction is not local", + %{old_insert_date: old_insert_date} do # For non-public we only check Create Activities because only these are relevant for threads # Flags are always non-public, Announces from relays can be non-public... - deadline = Pleroma.Config.get([:instance, :remote_post_retention_days]) + 1 - - old_insert_date = - Timex.now() - |> Timex.shift(days: -deadline) - |> Timex.to_naive_datetime() - |> NaiveDateTime.truncate(:second) remote_user1 = insert(:user, local: false) remote_user2 = insert(:user, local: false) @@ -212,15 +203,9 @@ test "with the --keep-threads option it still keeps non-old threads even with no assert length(Repo.all(Object)) == 2 end - test "with the --keep-threads option it deletes old threads with no local interaction" do - deadline = Pleroma.Config.get([:instance, :remote_post_retention_days]) + 1 - - old_insert_date = - Timex.now() - |> Timex.shift(days: -deadline) - |> Timex.to_naive_datetime() - |> NaiveDateTime.truncate(:second) - + test "with the --keep-threads option it deletes old threads with no local interaction", %{ + old_insert_date: old_insert_date + } do remote_user = insert(:user, local: false) remote_user2 = insert(:user, local: false) @@ -261,15 +246,9 @@ test "with the --keep-threads option it deletes old threads with no local intera assert length(Repo.all(Object)) == 0 end - test "with the --keep-threads option it keeps old threads with local interaction" do - deadline = Pleroma.Config.get([:instance, :remote_post_retention_days]) + 1 - - old_insert_date = - Timex.now() - |> Timex.shift(days: -deadline) - |> Timex.to_naive_datetime() - |> NaiveDateTime.truncate(:second) - + test "with the --keep-threads option it keeps old threads with local interaction", %{ + old_insert_date: old_insert_date + } do remote_user = insert(:user, local: false) local_user = insert(:user, local: true) @@ -326,15 +305,9 @@ test "with the --keep-threads option it keeps old threads with local interaction assert length(Repo.all(Object)) == 4 end - test "with the --keep-threads option it keeps old threads with bookmarked posts" do - deadline = Pleroma.Config.get([:instance, :remote_post_retention_days]) + 1 - - old_insert_date = - Timex.now() - |> Timex.shift(days: -deadline) - |> Timex.to_naive_datetime() - |> NaiveDateTime.truncate(:second) - + test "with the --keep-threads option it keeps old threads with bookmarked posts", %{ + old_insert_date: old_insert_date + } do remote_user = insert(:user, local: false) local_user = insert(:user, local: true) From f49e9e6d4cb7cfdd0c2fbb2ea74c82a7ec7d13e4 Mon Sep 17 00:00:00 2001 From: ilja Date: Sun, 21 May 2023 13:02:28 +0200 Subject: [PATCH 08/15] Clean up bookmarks after prune_objects When doing prune_objects, it's possible that bookmarked objects are deleted. This gave problems when fetching the bookmark TL. Here we clean up the bookmarks during pruning in the case were it's possible that bookmarked objects are deleted. --- lib/mix/tasks/pleroma/database.ex | 15 +++++++++++++++ test/mix/tasks/pleroma/database_test.exs | 24 ++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/lib/mix/tasks/pleroma/database.ex b/lib/mix/tasks/pleroma/database.ex index 726a22d41..55d1c8ddc 100644 --- a/lib/mix/tasks/pleroma/database.ex +++ b/lib/mix/tasks/pleroma/database.ex @@ -171,6 +171,21 @@ def run(["prune_objects" | args]) do end |> Repo.delete_all(timeout: :infinity) + if !Keyword.get(options, :keep_threads) do + # Without the --keep-threads option, it's possible that bookmarked + # objects have been deleted. We remove the corresponding bookmarks. + """ + delete from public.bookmarks + where id in ( + select b.id from public.bookmarks b + left join public.activities a on b.activity_id = a.id + left join public.objects o on a."data" ->> 'object' = o.data ->> 'id' + where o.id is null + ) + """ + |> Repo.query([], timeout: :infinity) + end + if Keyword.get(options, :prune_orphaned_activities) do # Prune activities who link to a single object """ diff --git a/test/mix/tasks/pleroma/database_test.exs b/test/mix/tasks/pleroma/database_test.exs index 21c365412..40c5fd402 100644 --- a/test/mix/tasks/pleroma/database_test.exs +++ b/test/mix/tasks/pleroma/database_test.exs @@ -7,6 +7,7 @@ defmodule Mix.Tasks.Pleroma.DatabaseTest do use Oban.Testing, repo: Pleroma.Repo alias Pleroma.Activity + alias Pleroma.Bookmark alias Pleroma.Object alias Pleroma.Repo alias Pleroma.User @@ -87,6 +88,29 @@ test "it prunes old objects from the database", %{old_insert_date: old_insert_da refute Object.get_by_id(note_remote_non_public_id) end + test "it cleans up bookmarks", %{old_insert_date: old_insert_date} do + user = insert(:user) + {:ok, old_object_activity} = CommonAPI.post(user, %{status: "yadayada"}) + + Repo.one(Object) + |> Ecto.Changeset.change(%{updated_at: old_insert_date}) + |> Repo.update!() + + {:ok, new_object_activity} = CommonAPI.post(user, %{status: "yadayada"}) + + {:ok, _} = Bookmark.create(user.id, old_object_activity.id) + {:ok, _} = Bookmark.create(user.id, new_object_activity.id) + + assert length(Repo.all(Object)) == 2 + assert length(Repo.all(Bookmark)) == 2 + + Mix.Tasks.Pleroma.Database.run(["prune_objects"]) + + assert length(Repo.all(Object)) == 1 + assert length(Repo.all(Bookmark)) == 1 + refute Bookmark.get(user.id, old_object_activity.id) + end + test "with the --keep-non-public option it still keeps non-public posts even if they are not local", %{old_insert_date: old_insert_date} do insert(:note) From d310f99d6aa777aa03215c29f469140221716f9f Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Mon, 22 May 2023 23:53:44 +0100 Subject: [PATCH 09/15] Add MRFs for direct message manipulation --- .../akkoma/translators/libre_translate.ex | 4 +- lib/pleroma/user.ex | 15 ++++++ lib/pleroma/web/activity_pub/mrf.ex | 3 +- .../mrf/direct_message_disabled_policy.ex | 46 +++++++++++++++++ ...eject_newly_created_account_note_policy.ex | 49 +++++++++++++++++++ .../api_spec/operations/account_operation.ex | 11 +++++ ...2213837_add_unfollowed_dm_restrictions.exs | 10 ++++ .../translators/libre_translate_test.exs | 3 +- test/pleroma/user_test.exs | 32 ++++++++++++ .../direct_message_disabled_policy_test.exs | 42 ++++++++++++++++ 10 files changed, 210 insertions(+), 5 deletions(-) create mode 100644 lib/pleroma/web/activity_pub/mrf/direct_message_disabled_policy.ex create mode 100644 lib/pleroma/web/activity_pub/mrf/reject_newly_created_account_note_policy.ex create mode 100644 priv/repo/migrations/20230522213837_add_unfollowed_dm_restrictions.exs create mode 100644 test/pleroma/web/activity_pub/mrf/direct_message_disabled_policy_test.exs diff --git a/lib/pleroma/akkoma/translators/libre_translate.ex b/lib/pleroma/akkoma/translators/libre_translate.ex index 5b08a6384..80956ab66 100644 --- a/lib/pleroma/akkoma/translators/libre_translate.ex +++ b/lib/pleroma/akkoma/translators/libre_translate.ex @@ -39,9 +39,9 @@ def translate(string, from_language, to_language) do detected = if Map.has_key?(body, "detectedLanguage") do get_in(body, ["detectedLanguage", "language"]) - else + else from_language || "" - end + end {:ok, detected, translated} else diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index ead37ccca..7f4dccf27 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -158,6 +158,8 @@ defmodule Pleroma.User do field(:last_status_at, :naive_datetime) field(:language, :string) field(:status_ttl_days, :integer, default: nil) + field(:accepts_direct_messages_from_followed, :boolean) + field(:accepts_direct_messages_from_not_followed, :boolean) embeds_one( :notification_settings, @@ -2722,4 +2724,17 @@ def unfollow_hashtag(%User{} = user, %Hashtag{} = hashtag) do def following_hashtag?(%User{} = user, %Hashtag{} = hashtag) do not is_nil(HashtagFollow.get(user, hashtag)) end + + def accepts_direct_messages?(%User{} = receiver, %User{} = sender) do + cond do + User.following?(receiver, sender) && receiver.accepts_direct_messages_from_followed == true -> + true + + receiver.accepts_direct_messages_from_not_followed == true -> + true + + true -> + false + end + end end diff --git a/lib/pleroma/web/activity_pub/mrf.ex b/lib/pleroma/web/activity_pub/mrf.ex index 6ecd62c99..88a58421e 100644 --- a/lib/pleroma/web/activity_pub/mrf.ex +++ b/lib/pleroma/web/activity_pub/mrf.ex @@ -147,7 +147,8 @@ def get_policies do |> Enum.concat([ Pleroma.Web.ActivityPub.MRF.HashtagPolicy, Pleroma.Web.ActivityPub.MRF.InlineQuotePolicy, - Pleroma.Web.ActivityPub.MRF.NormalizeMarkup + Pleroma.Web.ActivityPub.MRF.NormalizeMarkup, + Pleroma.Web.ActivityPub.MRF.DirectMessageDisabledPolicy ]) |> Enum.uniq() end diff --git a/lib/pleroma/web/activity_pub/mrf/direct_message_disabled_policy.ex b/lib/pleroma/web/activity_pub/mrf/direct_message_disabled_policy.ex new file mode 100644 index 000000000..27a59c4f1 --- /dev/null +++ b/lib/pleroma/web/activity_pub/mrf/direct_message_disabled_policy.ex @@ -0,0 +1,46 @@ +defmodule Pleroma.Web.ActivityPub.MRF.DirectMessageDisabledPolicy do + @behaviour Pleroma.Web.ActivityPub.MRF.Policy + + alias Pleroma.User + alias Pleroma.Web.ActivityPub.Visibility + + @moduledoc """ + Removes entries from the "To" field from direct messages if the user has requested to not + allow direct messages + """ + + @impl true + def filter( + %{ + "type" => "Note", + "actor" => actor + } = activity + ) do + with true <- Visibility.is_direct?(%{data: activity}), + recipients <- Map.get(activity, "to"), + sender <- User.get_cached_by_ap_id(actor) do + new_to = + Enum.filter(recipients, fn recv -> + should_filter?(sender, recv) + end) + + {:ok, Map.put(activity, :to, new_to)} + else + _ -> {:ok, activity} + end + end + + @impl true + def filter(object), do: {:ok, object} + + @impl true + def describe, do: {:ok, %{}} + + defp should_filter?(sender, receiver_ap_id) do + with %User{local: true} = receiver <- User.get_cached_by_ap_id(receiver_ap_id) do + User.accepts_direct_messages?(receiver, sender) + else + _ -> false + end + end +end diff --git a/lib/pleroma/web/activity_pub/mrf/reject_newly_created_account_note_policy.ex b/lib/pleroma/web/activity_pub/mrf/reject_newly_created_account_note_policy.ex new file mode 100644 index 000000000..4a2ab759a --- /dev/null +++ b/lib/pleroma/web/activity_pub/mrf/reject_newly_created_account_note_policy.ex @@ -0,0 +1,49 @@ +defmodule Pleroma.Web.ActivityPub.MRF.RejectNewlyCreatedAccountNotesPolicy do + @behaviour Pleroma.Web.ActivityPub.MRF.Policy + + alias Pleroma.User + + @moduledoc """ + Rejects notes from accounts that were created below a certain threshold of time ago + """ + @impl true + def filter( + %{ + "type" => type, + "actor" => actor + } = activity + ) when type in ["Note", "Create"] do + min_age = Pleroma.Config.get([:mrf_reject_newly_created_account_notes, :age]) + + with %User{} = user <- Pleroma.User.get_cached_by_ap_id(actor), + true <- Timex.diff(Timex.now(), user.inserted_at, :seconds) < min_age do + {:reject, "Account created too recently"} + else + _ -> {:ok, activity} + end + end + + @impl true + def filter(object), do: {:ok, object} + + @impl true + def describe, do: {:ok, %{}} + + @impl true + def config_description do + %{ + key: :mrf_reject_newly_created_account_notes, + related_policy: "Pleroma.Web.ActivityPub.MRF.RejectNewlyCreatedAccountNotesPolicy", + label: "MRF Reject New Accounts", + description: "Reject notes from accounts created too recently", + children: [ + %{ + key: :age, + type: :integer, + description: "Time below which to reject (in seconds)", + suggestions: [86_400] + } + ] + } + end +end diff --git a/lib/pleroma/web/api_spec/operations/account_operation.ex b/lib/pleroma/web/api_spec/operations/account_operation.ex index 894ad5db0..7971b5363 100644 --- a/lib/pleroma/web/api_spec/operations/account_operation.ex +++ b/lib/pleroma/web/api_spec/operations/account_operation.ex @@ -708,6 +708,17 @@ defp update_credentials_request do nullable: true, description: "Number of days after which statuses will be deleted. Set to -1 to disable." + }, + accepts_direct_messages_from_followed: %Schema{ + type: :boolean, + nullable: true, + description: + "Whether to accept DMs from people you follow (will be overridden by accepts_direct_messages_from_not_followed if true)" + }, + accepts_direct_messages_from_not_followed: %Schema{ + type: :boolean, + nullable: true, + description: "Whether to accept DMs from everyone" } }, example: %{ diff --git a/priv/repo/migrations/20230522213837_add_unfollowed_dm_restrictions.exs b/priv/repo/migrations/20230522213837_add_unfollowed_dm_restrictions.exs new file mode 100644 index 000000000..a373b11ee --- /dev/null +++ b/priv/repo/migrations/20230522213837_add_unfollowed_dm_restrictions.exs @@ -0,0 +1,10 @@ +defmodule Pleroma.Repo.Migrations.AddUnfollowedDmRestrictions do + use Ecto.Migration + + def change do + alter table(:users) do + add(:accepts_direct_messages_from_followed, :boolean, default: true) + add(:accepts_direct_messages_from_not_followed, :boolean, default: true) + end + end +end diff --git a/test/pleroma/translators/libre_translate_test.exs b/test/pleroma/translators/libre_translate_test.exs index a93f408f5..2ba75ec0e 100644 --- a/test/pleroma/translators/libre_translate_test.exs +++ b/test/pleroma/translators/libre_translate_test.exs @@ -146,8 +146,7 @@ test "should work when no detected language is received" do } end) - assert {:ok, "", "I will crush you"} = - LibreTranslate.translate("ギュギュ握りつぶしちゃうぞ", nil, "en") + assert {:ok, "", "I will crush you"} = LibreTranslate.translate("ギュギュ握りつぶしちゃうぞ", nil, "en") end end end diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs index 12ccc6bf4..094799968 100644 --- a/test/pleroma/user_test.exs +++ b/test/pleroma/user_test.exs @@ -2756,4 +2756,36 @@ test "should not error when trying to unfollow a hashtag twice" do assert user.followed_hashtags |> Enum.count() == 0 end end + + describe "accepts_direct_messages?/2" do + test "should return true if the recipient follows the sender and has turned on 'accept from follows'" do + recipient = + insert(:user, %{ + accepts_direct_messages_from_followed: true, + accepts_direct_messages_from_not_followed: false + }) + + sender = insert(:user) + + refute User.accepts_direct_messages?(recipient, sender) + + CommonAPI.follow(recipient, sender) + + assert User.accepts_direct_messages?(recipient, sender) + end + + test "should return true if the recipient has 'accept from everyone' on" do + recipient = insert(:user, %{accepts_direct_messages_from_not_followed: true}) + sender = insert(:user) + + assert User.accepts_direct_messages?(recipient, sender) + end + + test "should return false if the receipient has 'accept from everyone' off" do + recipient = insert(:user, %{accepts_direct_messages_from_not_followed: false}) + sender = insert(:user) + + refute User.accepts_direct_messages?(recipient, sender) + end + end end diff --git a/test/pleroma/web/activity_pub/mrf/direct_message_disabled_policy_test.exs b/test/pleroma/web/activity_pub/mrf/direct_message_disabled_policy_test.exs new file mode 100644 index 000000000..50ed36a0b --- /dev/null +++ b/test/pleroma/web/activity_pub/mrf/direct_message_disabled_policy_test.exs @@ -0,0 +1,42 @@ +defmodule Pleroma.Web.ActivityPub.MRF.DirectMessageDisabledPolicyTest do + use Pleroma.DataCase + import Pleroma.Factory + + alias Pleroma.Web.ActivityPub.MRF.DirectMessageDisabledPolicy + alias Pleroma.User + + describe "strips recipients" do + test "when the user denies the direct message" do + sender = insert(:user) + recipient = insert(:user, %{accepts_direct_messages_from_not_followed: false}) + + refute User.accepts_direct_messages?(recipient, sender) + + message = %{ + "actor" => sender.ap_id, + "to" => [recipient.ap_id], + "cc" => [], + "type" => "Note" + } + + assert {:ok, %{to: []}} = DirectMessageDisabledPolicy.filter(message) + end + + test "when the user does not deny the direct message" do + sender = insert(:user) + recipient = insert(:user, %{accepts_direct_messages_from_not_followed: true}) + + assert User.accepts_direct_messages?(recipient, sender) + + message = %{ + "actor" => sender.ap_id, + "to" => [recipient.ap_id], + "cc" => [], + "type" => "Note" + } + + assert {:ok, message} = DirectMessageDisabledPolicy.filter(message) + assert message.to == [recipient.ap_id] + end + end +end From ab34680554adb8864e910eb59d6c9150263bc88c Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Tue, 23 May 2023 10:29:08 +0100 Subject: [PATCH 10/15] switch to using an enum system for DM acceptance --- lib/pleroma/user.ex | 30 +++++++------ ...eject_newly_created_account_note_policy.ex | 3 +- .../api_spec/operations/account_operation.ex | 19 ++++---- .../controllers/account_controller.ex | 3 +- .../web/mastodon_api/views/account_view.ex | 1 + ...2213837_add_unfollowed_dm_restrictions.exs | 3 +- test/pleroma/user_test.exs | 13 +++--- .../mastodon_api/update_credentials_test.exs | 44 +++++++++++++++++++ 8 files changed, 82 insertions(+), 34 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 7f4dccf27..371dea85b 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -158,8 +158,10 @@ defmodule Pleroma.User do field(:last_status_at, :naive_datetime) field(:language, :string) field(:status_ttl_days, :integer, default: nil) - field(:accepts_direct_messages_from_followed, :boolean) - field(:accepts_direct_messages_from_not_followed, :boolean) + + field(:accepts_direct_messages_from, Ecto.Enum, + values: [:everybody, :people_i_follow, :nobody] + ) embeds_one( :notification_settings, @@ -538,7 +540,8 @@ def update_changeset(struct, params \\ %{}) do :is_discoverable, :actor_type, :disclose_client, - :status_ttl_days + :status_ttl_days, + :accepts_direct_messages_from ] ) |> unique_constraint(:nickname) @@ -2725,16 +2728,15 @@ def following_hashtag?(%User{} = user, %Hashtag{} = hashtag) do not is_nil(HashtagFollow.get(user, hashtag)) end - def accepts_direct_messages?(%User{} = receiver, %User{} = sender) do - cond do - User.following?(receiver, sender) && receiver.accepts_direct_messages_from_followed == true -> - true - - receiver.accepts_direct_messages_from_not_followed == true -> - true - - true -> - false - end + def accepts_direct_messages?( + %User{accepts_direct_messages_from: :people_i_follow} = receiver, + %User{} = sender + ) do + User.following?(receiver, sender) end + + def accepts_direct_messages?(%User{accepts_direct_messages_from: :everybody}, _), do: true + + def accepts_direct_messages?(%User{accepts_direct_messages_from: :nobody}, _), + do: false end diff --git a/lib/pleroma/web/activity_pub/mrf/reject_newly_created_account_note_policy.ex b/lib/pleroma/web/activity_pub/mrf/reject_newly_created_account_note_policy.ex index 4a2ab759a..5481f38de 100644 --- a/lib/pleroma/web/activity_pub/mrf/reject_newly_created_account_note_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/reject_newly_created_account_note_policy.ex @@ -12,7 +12,8 @@ def filter( "type" => type, "actor" => actor } = activity - ) when type in ["Note", "Create"] do + ) + when type in ["Note", "Create"] do min_age = Pleroma.Config.get([:mrf_reject_newly_created_account_notes, :age]) with %User{} = user <- Pleroma.User.get_cached_by_ap_id(actor), diff --git a/lib/pleroma/web/api_spec/operations/account_operation.ex b/lib/pleroma/web/api_spec/operations/account_operation.ex index 7971b5363..8a46ec32a 100644 --- a/lib/pleroma/web/api_spec/operations/account_operation.ex +++ b/lib/pleroma/web/api_spec/operations/account_operation.ex @@ -709,16 +709,16 @@ defp update_credentials_request do description: "Number of days after which statuses will be deleted. Set to -1 to disable." }, - accepts_direct_messages_from_followed: %Schema{ - type: :boolean, + accepts_direct_messages_from: %Schema{ + type: :string, + enum: [ + "everybody", + "nobody", + "people_i_follow" + ], nullable: true, description: - "Whether to accept DMs from people you follow (will be overridden by accepts_direct_messages_from_not_followed if true)" - }, - accepts_direct_messages_from_not_followed: %Schema{ - type: :boolean, - nullable: true, - description: "Whether to accept DMs from everyone" + "Who to accept DMs from" } }, example: %{ @@ -740,7 +740,8 @@ defp update_credentials_request do also_known_as: ["https://foo.bar/users/foo"], discoverable: false, actor_type: "Person", - status_ttl_days: 30 + status_ttl_days: 30, + accepts_direct_messages_from: "everybody" } } end diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index 678ec3a80..16b3e36a8 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -191,7 +191,7 @@ def update_credentials(%{assigns: %{user: user}, body_params: params} = conn, _p :show_role, :skip_thread_containment, :allow_following_move, - :also_known_as + :also_known_as, ] |> Enum.reduce(%{}, fn key, acc -> Maps.put_if_present(acc, key, params[key], &{:ok, Params.truthy_param?(&1)}) @@ -221,6 +221,7 @@ def update_credentials(%{assigns: %{user: user}, body_params: params} = conn, _p |> Maps.put_if_present(:is_discoverable, params[:discoverable]) |> Maps.put_if_present(:language, Pleroma.Web.Gettext.normalize_locale(params[:language])) |> Maps.put_if_present(:status_ttl_days, params[:status_ttl_days], status_ttl_days_value) + |> Maps.put_if_present(:accepts_direct_messages_from, params[:accepts_direct_messages_from]) # What happens here: # diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 190d6ebf2..e0fa3b033 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -354,6 +354,7 @@ defp maybe_put_settings( |> Kernel.put_in([:source, :privacy], user.default_scope) |> Kernel.put_in([:source, :pleroma, :show_role], user.show_role) |> Kernel.put_in([:source, :pleroma, :no_rich_text], user.no_rich_text) + |> Kernel.put_in([:accepts_direct_messages_from], user.accepts_direct_messages_from) end defp maybe_put_settings(data, _, _, _), do: data diff --git a/priv/repo/migrations/20230522213837_add_unfollowed_dm_restrictions.exs b/priv/repo/migrations/20230522213837_add_unfollowed_dm_restrictions.exs index a373b11ee..8947be738 100644 --- a/priv/repo/migrations/20230522213837_add_unfollowed_dm_restrictions.exs +++ b/priv/repo/migrations/20230522213837_add_unfollowed_dm_restrictions.exs @@ -3,8 +3,7 @@ defmodule Pleroma.Repo.Migrations.AddUnfollowedDmRestrictions do def change do alter table(:users) do - add(:accepts_direct_messages_from_followed, :boolean, default: true) - add(:accepts_direct_messages_from_not_followed, :boolean, default: true) + add(:accepts_direct_messages_from, :string, default: "everybody") end end end diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs index 094799968..f35a98f08 100644 --- a/test/pleroma/user_test.exs +++ b/test/pleroma/user_test.exs @@ -2758,11 +2758,10 @@ test "should not error when trying to unfollow a hashtag twice" do end describe "accepts_direct_messages?/2" do - test "should return true if the recipient follows the sender and has turned on 'accept from follows'" do + test "should return true if the recipient follows the sender and has set accept to :people_i_follow" do recipient = insert(:user, %{ - accepts_direct_messages_from_followed: true, - accepts_direct_messages_from_not_followed: false + accepts_direct_messages_from: :people_i_follow }) sender = insert(:user) @@ -2774,15 +2773,15 @@ test "should return true if the recipient follows the sender and has turned on ' assert User.accepts_direct_messages?(recipient, sender) end - test "should return true if the recipient has 'accept from everyone' on" do - recipient = insert(:user, %{accepts_direct_messages_from_not_followed: true}) + test "should return true if the recipient has set accept to :everyone" do + recipient = insert(:user, %{accepts_direct_messages_from: :everybody}) sender = insert(:user) assert User.accepts_direct_messages?(recipient, sender) end - test "should return false if the receipient has 'accept from everyone' off" do - recipient = insert(:user, %{accepts_direct_messages_from_not_followed: false}) + test "should return false if the receipient set accept to :nobody" do + recipient = insert(:user, %{accepts_direct_messages_from: :nobody}) sender = insert(:user) refute User.accepts_direct_messages?(recipient, sender) diff --git a/test/pleroma/web/mastodon_api/update_credentials_test.exs b/test/pleroma/web/mastodon_api/update_credentials_test.exs index 4aec31eac..925ea25aa 100644 --- a/test/pleroma/web/mastodon_api/update_credentials_test.exs +++ b/test/pleroma/web/mastodon_api/update_credentials_test.exs @@ -727,4 +727,48 @@ test "actor_type field has a higher priority than bot", %{conn: conn} do assert account["source"]["pleroma"]["actor_type"] == "Person" end end + + describe "Updating direct message settings" do + setup do: oauth_access(["write:accounts"]) + setup :request_content_type + + test "changing to :everybody", %{conn: conn} do + account = + conn + |> patch("/api/v1/accounts/update_credentials", %{accepts_direct_messages_from: "everybody"}) + |> json_response_and_validate_schema(200) + + assert account["accepts_direct_messages_from"] + assert account["accepts_direct_messages_from"] == "everybody" + assert Pleroma.User.get_by_ap_id(account["url"]).accepts_direct_messages_from == :everybody + end + + test "changing to :nobody", %{conn: conn} do + account = + conn + |> patch("/api/v1/accounts/update_credentials", %{accepts_direct_messages_from: "nobody"}) + |> json_response_and_validate_schema(200) + + assert account["accepts_direct_messages_from"] + assert account["accepts_direct_messages_from"] == "nobody" + assert Pleroma.User.get_by_ap_id(account["url"]).accepts_direct_messages_from == :nobody + end + + test "changing to :people_i_follow", %{conn: conn} do + account = + conn + |> patch("/api/v1/accounts/update_credentials", %{accepts_direct_messages_from: "people_i_follow"}) + |> json_response_and_validate_schema(200) + + assert account["accepts_direct_messages_from"] + assert account["accepts_direct_messages_from"] == "people_i_follow" + assert Pleroma.User.get_by_ap_id(account["url"]).accepts_direct_messages_from == :people_i_follow + end + + test "changing to an unsupported value", %{conn: conn} do + conn + |> patch("/api/v1/accounts/update_credentials", %{accepts_direct_messages_from: "unsupported"}) + |> json_response(400) + end + end end From 037f881187f1d7ec29efbf75f76dbc8b135b65cd Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Tue, 23 May 2023 13:16:20 +0100 Subject: [PATCH 11/15] Fix create processing in direct message disabled --- CHANGELOG.md | 9 ++++ config/config.exs | 2 + lib/pleroma/user.ex | 3 +- .../mrf/direct_message_disabled_policy.ex | 16 +++++-- ...eject_newly_created_account_note_policy.ex | 4 +- .../api_spec/operations/account_operation.ex | 3 +- .../controllers/account_controller.ex | 2 +- .../direct_message_disabled_policy_test.exs | 12 ++--- ...newly_created_account_note_policy_test.exs | 45 +++++++++++++++++++ test/pleroma/web/activity_pub/mrf_test.exs | 16 ++++++- .../transmogrifier/note_handling_test.exs | 8 ++-- .../mastodon_api/update_credentials_test.exs | 16 +++++-- 12 files changed, 111 insertions(+), 25 deletions(-) create mode 100644 test/pleroma/web/activity_pub/mrf/reject_newly_created_account_note_policy_test.exs diff --git a/CHANGELOG.md b/CHANGELOG.md index bb5b8fa04..207c99d67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Unreleased +## Added +- Custom options for users to accept/reject private messages + - options: everybody, nobody, people\_i\_follow +- MRF to reject notes from accounts newer than a given age + - this will have the side-effect of rejecting legitimate messages if your + post gets boosted outside of your local bubble and people your instance + does not know about reply to it. + ## Fixed - Support for `streams` public key URIs +- Bookmarks are cleaned up on DB prune now ## 2023.04 diff --git a/config/config.exs b/config/config.exs index 95c576385..ca397a8fd 100644 --- a/config/config.exs +++ b/config/config.exs @@ -418,6 +418,8 @@ config :pleroma, :mrf_follow_bot, follower_nickname: nil +config :pleroma, :mrf_reject_newly_created_account_notes, age: 86_400 + config :pleroma, :rich_media, enabled: true, ignore_hosts: [], diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 371dea85b..273bdf337 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -160,7 +160,8 @@ defmodule Pleroma.User do field(:status_ttl_days, :integer, default: nil) field(:accepts_direct_messages_from, Ecto.Enum, - values: [:everybody, :people_i_follow, :nobody] + values: [:everybody, :people_i_follow, :nobody], + default: :everybody ) embeds_one( diff --git a/lib/pleroma/web/activity_pub/mrf/direct_message_disabled_policy.ex b/lib/pleroma/web/activity_pub/mrf/direct_message_disabled_policy.ex index 27a59c4f1..ec6fa70e2 100644 --- a/lib/pleroma/web/activity_pub/mrf/direct_message_disabled_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/direct_message_disabled_policy.ex @@ -12,7 +12,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.DirectMessageDisabledPolicy do @impl true def filter( %{ - "type" => "Note", + "type" => "Create", "actor" => actor } = activity ) do @@ -24,9 +24,13 @@ def filter( should_filter?(sender, recv) end) - {:ok, Map.put(activity, :to, new_to)} + {:ok, + activity + |> Map.put("to", new_to) + |> maybe_replace_object_to(new_to)} else - _ -> {:ok, activity} + _ -> + {:ok, activity} end end @@ -43,4 +47,10 @@ defp should_filter?(sender, receiver_ap_id) do _ -> false end end + + defp maybe_replace_object_to(%{"object" => %{"to" => _}} = activity, to) do + Kernel.put_in(activity, ["object", "to"], to) + end + + defp maybe_replace_object_to(other, _), do: other end diff --git a/lib/pleroma/web/activity_pub/mrf/reject_newly_created_account_note_policy.ex b/lib/pleroma/web/activity_pub/mrf/reject_newly_created_account_note_policy.ex index 5481f38de..01a846831 100644 --- a/lib/pleroma/web/activity_pub/mrf/reject_newly_created_account_note_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/reject_newly_created_account_note_policy.ex @@ -16,9 +16,9 @@ def filter( when type in ["Note", "Create"] do min_age = Pleroma.Config.get([:mrf_reject_newly_created_account_notes, :age]) - with %User{} = user <- Pleroma.User.get_cached_by_ap_id(actor), + with %User{local: false} = user <- Pleroma.User.get_cached_by_ap_id(actor), true <- Timex.diff(Timex.now(), user.inserted_at, :seconds) < min_age do - {:reject, "Account created too recently"} + {:reject, "[RejectNewlyCreatedAccountNotesPolicy] Account created too recently"} else _ -> {:ok, activity} end diff --git a/lib/pleroma/web/api_spec/operations/account_operation.ex b/lib/pleroma/web/api_spec/operations/account_operation.ex index 8a46ec32a..8a6851d52 100644 --- a/lib/pleroma/web/api_spec/operations/account_operation.ex +++ b/lib/pleroma/web/api_spec/operations/account_operation.ex @@ -717,8 +717,7 @@ defp update_credentials_request do "people_i_follow" ], nullable: true, - description: - "Who to accept DMs from" + description: "Who to accept DMs from" } }, example: %{ diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index 16b3e36a8..057af762a 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -191,7 +191,7 @@ def update_credentials(%{assigns: %{user: user}, body_params: params} = conn, _p :show_role, :skip_thread_containment, :allow_following_move, - :also_known_as, + :also_known_as ] |> Enum.reduce(%{}, fn key, acc -> Maps.put_if_present(acc, key, params[key], &{:ok, Params.truthy_param?(&1)}) diff --git a/test/pleroma/web/activity_pub/mrf/direct_message_disabled_policy_test.exs b/test/pleroma/web/activity_pub/mrf/direct_message_disabled_policy_test.exs index 50ed36a0b..072fe0576 100644 --- a/test/pleroma/web/activity_pub/mrf/direct_message_disabled_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/direct_message_disabled_policy_test.exs @@ -8,7 +8,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.DirectMessageDisabledPolicyTest do describe "strips recipients" do test "when the user denies the direct message" do sender = insert(:user) - recipient = insert(:user, %{accepts_direct_messages_from_not_followed: false}) + recipient = insert(:user, %{accepts_direct_messages_from: :nobody}) refute User.accepts_direct_messages?(recipient, sender) @@ -16,15 +16,15 @@ test "when the user denies the direct message" do "actor" => sender.ap_id, "to" => [recipient.ap_id], "cc" => [], - "type" => "Note" + "type" => "Create" } - assert {:ok, %{to: []}} = DirectMessageDisabledPolicy.filter(message) + assert {:ok, %{"to" => []}} = DirectMessageDisabledPolicy.filter(message) end test "when the user does not deny the direct message" do sender = insert(:user) - recipient = insert(:user, %{accepts_direct_messages_from_not_followed: true}) + recipient = insert(:user, %{accepts_direct_messages_from: :everybody}) assert User.accepts_direct_messages?(recipient, sender) @@ -32,11 +32,11 @@ test "when the user does not deny the direct message" do "actor" => sender.ap_id, "to" => [recipient.ap_id], "cc" => [], - "type" => "Note" + "type" => "Create" } assert {:ok, message} = DirectMessageDisabledPolicy.filter(message) - assert message.to == [recipient.ap_id] + assert message["to"] == [recipient.ap_id] end end end diff --git a/test/pleroma/web/activity_pub/mrf/reject_newly_created_account_note_policy_test.exs b/test/pleroma/web/activity_pub/mrf/reject_newly_created_account_note_policy_test.exs new file mode 100644 index 000000000..2fc65e6d6 --- /dev/null +++ b/test/pleroma/web/activity_pub/mrf/reject_newly_created_account_note_policy_test.exs @@ -0,0 +1,45 @@ +defmodule Pleroma.Web.ActivityPub.MRF.RejectNewlyCreatedAccountNotesPolicyTest do + use Pleroma.DataCase + import Pleroma.Factory + + alias Pleroma.Web.ActivityPub.MRF.RejectNewlyCreatedAccountNotesPolicy + + describe "reject notes from new accounts" do + test "rejects notes from accounts created more recently than `age`" do + clear_config([:mrf_reject_newly_created_account_notes, :age], 86_400) + sender = insert(:user, %{inserted_at: Timex.now(), local: false}) + + message = %{ + "actor" => sender.ap_id, + "type" => "Create" + } + + assert {:reject, _} = RejectNewlyCreatedAccountNotesPolicy.filter(message) + end + + test "does not reject notes from accounts created longer ago" do + clear_config([:mrf_reject_newly_created_account_notes, :age], 86_400) + a_day_ago = Timex.shift(Timex.now(), days: -1) + sender = insert(:user, %{inserted_at: a_day_ago, local: false}) + + message = %{ + "actor" => sender.ap_id, + "type" => "Create" + } + + assert {:ok, _} = RejectNewlyCreatedAccountNotesPolicy.filter(message) + end + + test "does not affect local users" do + clear_config([:mrf_reject_newly_created_account_notes, :age], 86_400) + sender = insert(:user, %{inserted_at: Timex.now(), local: true}) + + message = %{ + "actor" => sender.ap_id, + "type" => "Create" + } + + assert {:ok, _} = RejectNewlyCreatedAccountNotesPolicy.filter(message) + end + end +end diff --git a/test/pleroma/web/activity_pub/mrf_test.exs b/test/pleroma/web/activity_pub/mrf_test.exs index 7359398fe..51af672cd 100644 --- a/test/pleroma/web/activity_pub/mrf_test.exs +++ b/test/pleroma/web/activity_pub/mrf_test.exs @@ -102,7 +102,13 @@ test "it works as expected with noop policy" do clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.NoOpPolicy]) expected = %{ - mrf_policies: ["NoOpPolicy", "HashtagPolicy", "InlineQuotePolicy", "NormalizeMarkup"], + mrf_policies: [ + "NoOpPolicy", + "HashtagPolicy", + "InlineQuotePolicy", + "NormalizeMarkup", + "DirectMessageDisabledPolicy" + ], mrf_hashtag: %{ federated_timeline_removal: [], reject: [], @@ -118,7 +124,13 @@ test "it works as expected with mock policy" do clear_config([:mrf, :policies], [MRFModuleMock]) expected = %{ - mrf_policies: ["MRFModuleMock", "HashtagPolicy", "InlineQuotePolicy", "NormalizeMarkup"], + mrf_policies: [ + "MRFModuleMock", + "HashtagPolicy", + "InlineQuotePolicy", + "NormalizeMarkup", + "DirectMessageDisabledPolicy" + ], mrf_module_mock: "some config data", mrf_hashtag: %{ federated_timeline_removal: [], diff --git a/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs index 002042802..9faee7aa3 100644 --- a/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs @@ -316,7 +316,7 @@ test "it strips internal reactions" do test "it correctly processes messages with non-array to field" do data = File.read!("test/fixtures/mastodon-post-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("to", "https://www.w3.org/ns/activitystreams#Public") |> put_in(["object", "to"], "https://www.w3.org/ns/activitystreams#Public") @@ -333,7 +333,7 @@ test "it correctly processes messages with non-array to field" do test "it correctly processes messages with non-array cc field" do data = File.read!("test/fixtures/mastodon-post-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("cc", "http://mastodon.example.org/users/admin/followers") |> put_in(["object", "cc"], "http://mastodon.example.org/users/admin/followers") @@ -346,7 +346,7 @@ test "it correctly processes messages with non-array cc field" do test "it correctly processes messages with weirdness in address fields" do data = File.read!("test/fixtures/mastodon-post-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Map.put("cc", ["http://mastodon.example.org/users/admin/followers", ["¿"]]) |> put_in(["object", "cc"], ["http://mastodon.example.org/users/admin/followers", ["¿"]]) @@ -412,7 +412,7 @@ test "does NOT schedule background fetching of `replies` beyond max thread depth activity = File.read!("test/fixtures/mastodon-post-activity.json") - |> Poison.decode!() + |> Jason.decode!() |> Kernel.put_in(["object", "replies"], replies) %{activity: activity} diff --git a/test/pleroma/web/mastodon_api/update_credentials_test.exs b/test/pleroma/web/mastodon_api/update_credentials_test.exs index 925ea25aa..70566f5d0 100644 --- a/test/pleroma/web/mastodon_api/update_credentials_test.exs +++ b/test/pleroma/web/mastodon_api/update_credentials_test.exs @@ -735,7 +735,9 @@ test "actor_type field has a higher priority than bot", %{conn: conn} do test "changing to :everybody", %{conn: conn} do account = conn - |> patch("/api/v1/accounts/update_credentials", %{accepts_direct_messages_from: "everybody"}) + |> patch("/api/v1/accounts/update_credentials", %{ + accepts_direct_messages_from: "everybody" + }) |> json_response_and_validate_schema(200) assert account["accepts_direct_messages_from"] @@ -757,17 +759,23 @@ test "changing to :nobody", %{conn: conn} do test "changing to :people_i_follow", %{conn: conn} do account = conn - |> patch("/api/v1/accounts/update_credentials", %{accepts_direct_messages_from: "people_i_follow"}) + |> patch("/api/v1/accounts/update_credentials", %{ + accepts_direct_messages_from: "people_i_follow" + }) |> json_response_and_validate_schema(200) assert account["accepts_direct_messages_from"] assert account["accepts_direct_messages_from"] == "people_i_follow" - assert Pleroma.User.get_by_ap_id(account["url"]).accepts_direct_messages_from == :people_i_follow + + assert Pleroma.User.get_by_ap_id(account["url"]).accepts_direct_messages_from == + :people_i_follow end test "changing to an unsupported value", %{conn: conn} do conn - |> patch("/api/v1/accounts/update_credentials", %{accepts_direct_messages_from: "unsupported"}) + |> patch("/api/v1/accounts/update_credentials", %{ + accepts_direct_messages_from: "unsupported" + }) |> json_response(400) end end From 8c208f751d619f6015378dff34933e036f05ee9f Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Tue, 23 May 2023 13:46:25 +0100 Subject: [PATCH 12/15] Fix filtering out incorrect addresses --- .../mrf/direct_message_disabled_policy.ex | 23 +++++++++++++------ .../direct_message_disabled_policy_test.exs | 16 ++++++++++--- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/lib/pleroma/web/activity_pub/mrf/direct_message_disabled_policy.ex b/lib/pleroma/web/activity_pub/mrf/direct_message_disabled_policy.ex index ec6fa70e2..7a834f6ae 100644 --- a/lib/pleroma/web/activity_pub/mrf/direct_message_disabled_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/direct_message_disabled_policy.ex @@ -2,7 +2,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.DirectMessageDisabledPolicy do @behaviour Pleroma.Web.ActivityPub.MRF.Policy alias Pleroma.User - alias Pleroma.Web.ActivityPub.Visibility + require Pleroma.Constants @moduledoc """ Removes entries from the "To" field from direct messages if the user has requested to not @@ -13,15 +13,19 @@ defmodule Pleroma.Web.ActivityPub.MRF.DirectMessageDisabledPolicy do def filter( %{ "type" => "Create", - "actor" => actor + "actor" => actor, + "object" => %{ + "type" => "Note" + } } = activity ) do - with true <- Visibility.is_direct?(%{data: activity}), - recipients <- Map.get(activity, "to"), + with recipients <- Map.get(activity, "to", []), + cc <- Map.get(activity, "cc", []), + true <- is_direct?(recipients, cc), sender <- User.get_cached_by_ap_id(actor) do new_to = Enum.filter(recipients, fn recv -> - should_filter?(sender, recv) + should_include?(sender, recv) end) {:ok, @@ -40,11 +44,11 @@ def filter(object), do: {:ok, object} @impl true def describe, do: {:ok, %{}} - defp should_filter?(sender, receiver_ap_id) do + defp should_include?(sender, receiver_ap_id) do with %User{local: true} = receiver <- User.get_cached_by_ap_id(receiver_ap_id) do User.accepts_direct_messages?(receiver, sender) else - _ -> false + _ -> true end end @@ -53,4 +57,9 @@ defp maybe_replace_object_to(%{"object" => %{"to" => _}} = activity, to) do end defp maybe_replace_object_to(other, _), do: other + + defp is_direct?(to, cc) do + !(Enum.member?(to, Pleroma.Constants.as_public()) || + Enum.member?(cc, Pleroma.Constants.as_public())) + end end diff --git a/test/pleroma/web/activity_pub/mrf/direct_message_disabled_policy_test.exs b/test/pleroma/web/activity_pub/mrf/direct_message_disabled_policy_test.exs index 072fe0576..02ae24a4d 100644 --- a/test/pleroma/web/activity_pub/mrf/direct_message_disabled_policy_test.exs +++ b/test/pleroma/web/activity_pub/mrf/direct_message_disabled_policy_test.exs @@ -16,10 +16,15 @@ test "when the user denies the direct message" do "actor" => sender.ap_id, "to" => [recipient.ap_id], "cc" => [], - "type" => "Create" + "type" => "Create", + "object" => %{ + "type" => "Note", + "to" => [recipient.ap_id] + } } - assert {:ok, %{"to" => []}} = DirectMessageDisabledPolicy.filter(message) + assert {:ok, %{"to" => [], "object" => %{"to" => []}}} = + DirectMessageDisabledPolicy.filter(message) end test "when the user does not deny the direct message" do @@ -32,11 +37,16 @@ test "when the user does not deny the direct message" do "actor" => sender.ap_id, "to" => [recipient.ap_id], "cc" => [], - "type" => "Create" + "type" => "Create", + "object" => %{ + "type" => "Note", + "to" => [recipient.ap_id] + } } assert {:ok, message} = DirectMessageDisabledPolicy.filter(message) assert message["to"] == [recipient.ap_id] + assert message["object"]["to"] == [recipient.ap_id] end end end From 2fc26609f6a413adec812c16f31c7bbc2ec21dbd Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Tue, 23 May 2023 13:53:54 +0100 Subject: [PATCH 13/15] ensure we depend on poison --- mix.exs | 1 + 1 file changed, 1 insertion(+) diff --git a/mix.exs b/mix.exs index 2f318fea0..f81a1a8a9 100644 --- a/mix.exs +++ b/mix.exs @@ -190,6 +190,7 @@ defp deps do {:mfm_parser, git: "https://akkoma.dev/AkkomaGang/mfm-parser.git", ref: "912fba81152d4d572e457fd5427f9875b2bc3dbe"}, + {:poison, "~> 5.0"}, ## dev & test {:ex_doc, "~> 0.22", only: :dev, runtime: false}, From 9e9cf58fdfb99e0d2e6112d824cc56daef9f8cd8 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Tue, 23 May 2023 13:54:22 +0100 Subject: [PATCH 14/15] or not --- mix.exs | 1 - 1 file changed, 1 deletion(-) diff --git a/mix.exs b/mix.exs index f81a1a8a9..2f318fea0 100644 --- a/mix.exs +++ b/mix.exs @@ -190,7 +190,6 @@ defp deps do {:mfm_parser, git: "https://akkoma.dev/AkkomaGang/mfm-parser.git", ref: "912fba81152d4d572e457fd5427f9875b2bc3dbe"}, - {:poison, "~> 5.0"}, ## dev & test {:ex_doc, "~> 0.22", only: :dev, runtime: false}, From 82ca7a64705daf780e03d329b73fed4fed16af06 Mon Sep 17 00:00:00 2001 From: FloatingGhost Date: Tue, 23 May 2023 14:10:01 +0100 Subject: [PATCH 15/15] bump version --- CHANGELOG.md | 2 +- mix.exs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 207c99d67..f6dd45e17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ 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/). -## Unreleased +## 2023.05 ## Added - Custom options for users to accept/reject private messages diff --git a/mix.exs b/mix.exs index 2f318fea0..11fc15639 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule Pleroma.Mixfile do def project do [ app: :pleroma, - version: version("3.8.0"), + version: version("3.9.0"), elixir: "~> 1.14", elixirc_paths: elixirc_paths(Mix.env()), compilers: [:phoenix] ++ Mix.compilers(),