Merge branch 'fixes_2034_reports_should_send_a_notification_to_admins' into 'develop'
authorlain <lain@soykaf.club>
Fri, 13 Nov 2020 13:35:47 +0000 (13:35 +0000)
committerlain <lain@soykaf.club>
Fri, 13 Nov 2020 13:35:47 +0000 (13:35 +0000)
fixes 2034 Make notifs view work for reports

Closes #2034

See merge request pleroma/pleroma!2912

55 files changed:
CHANGELOG.md
Dockerfile
config/description.exs
docs/administration/CLI_tasks/release_environments.md [deleted file]
docs/configuration/optimizing_beam.md [new file with mode: 0644]
docs/dev.md
docs/installation/debian_based_en.md
docs/installation/otp_en.md
installation/init.d/pleroma
installation/pleroma.service
lib/mix/tasks/pleroma/instance.ex
lib/mix/tasks/pleroma/release_env.ex [deleted file]
lib/pleroma/docs/json.ex
lib/pleroma/emails/admin_email.ex
lib/pleroma/object/fetcher.ex
lib/pleroma/web/activity_pub/mrf.ex
lib/pleroma/web/activity_pub/mrf/activity_expiration_policy.ex
lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex
lib/pleroma/web/activity_pub/mrf/keyword_policy.ex
lib/pleroma/web/activity_pub/mrf/mention_policy.ex
lib/pleroma/web/activity_pub/mrf/normalize_markup.ex
lib/pleroma/web/activity_pub/mrf/object_age_policy.ex
lib/pleroma/web/activity_pub/mrf/reject_non_public.ex
lib/pleroma/web/activity_pub/mrf/simple_policy.ex
lib/pleroma/web/activity_pub/mrf/subchain_policy.ex
lib/pleroma/web/activity_pub/mrf/user_allow_list_policy.ex
lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex
lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex
lib/pleroma/web/activity_pub/transmogrifier.ex
lib/pleroma/web/fallback/redirect_controller.ex
lib/pleroma/web/feed/feed_view.ex
lib/pleroma/web/mastodon_api/views/status_view.ex
lib/pleroma/web/templates/feed/feed/_activity.atom.eex
lib/pleroma/web/templates/feed/feed/_activity.rss.eex
priv/repo/migrations/20201113060459_remove_purge_expired_activity_worker_from_oban_config.exs [new file with mode: 0644]
priv/static/index.html
test/fixtures/modules/good_mrf.ex [new file with mode: 0644]
test/fixtures/spoofed-object.json [new file with mode: 0644]
test/mix/tasks/pleroma/instance_test.exs
test/mix/tasks/pleroma/release_env_test.exs [deleted file]
test/pleroma/emails/admin_email_test.exs
test/pleroma/object/fetcher_test.exs
test/pleroma/object_test.exs
test/pleroma/web/activity_pub/activity_pub_test.exs
test/pleroma/web/activity_pub/mrf_test.exs
test/pleroma/web/activity_pub/object_validators/attachment_validator_test.exs
test/pleroma/web/activity_pub/transmogrifier/announce_handling_test.exs
test/pleroma/web/activity_pub/transmogrifier/article_handling_test.exs
test/pleroma/web/activity_pub/transmogrifier/audio_handling_test.exs
test/pleroma/web/activity_pub/transmogrifier/event_handling_test.exs
test/pleroma/web/activity_pub/transmogrifier/video_handling_test.exs
test/pleroma/web/fallback_test.exs
test/pleroma/web/feed/user_controller_test.exs
test/pleroma/web/mastodon_api/views/status_view_test.exs
test/support/http_request_mock.ex

index c963972c85707470902531f4af8a795292f48473..2ecb434831d80ac00a1d439846b3fe7fe4d1931a 100644 (file)
@@ -18,6 +18,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - Account backup
 - Configuration: Add `:instance, autofollowing_nicknames` setting to provide a way to make accounts automatically follow new users that register on the local Pleroma instance.
 - Ability to view remote timelines, with ex. `/api/v1/timelines/public?instance=lain.com` and streams `public:remote` and `public:remote:media`
+- The site title is now injected as a `title` tag like preloads or metadata.
 
 ### Changed
 
@@ -33,6 +34,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - Minimum lifetime for ephmeral activities changed to 10 minutes and made configurable (`:min_lifetime` option).
 - Introduced optional dependencies on `ffmpeg`, `ImageMagick`, `exiftool` software packages. Please refer to `docs/installation/optional/media_graphics_packages.md`.
 - Polls now always return a `voters_count`, even if they are single-choice
+- Admin Emails: The ap id is used as the user link in emails now.
 
 <details>
   <summary>API Changes</summary>
index c210cf79c777629bdb32425540626adcc4faa8fb..4e7c01c5d458b1b907862d6e64b3426a002f9052 100644 (file)
@@ -4,7 +4,7 @@ COPY . .
 
 ENV MIX_ENV=prod
 
-RUN apk add git gcc g++ musl-dev make cmake &&\
+RUN apk add git gcc g++ musl-dev make cmake file-dev &&\
        echo "import Mix.Config" > config/prod.secret.exs &&\
        mix local.hex --force &&\
        mix local.rebar --force &&\
index 0b651696b4bb37fa0a76fef692606c3adefd07a5..0552b37e07670f008e389306d38d49b922be0739 100644 (file)
@@ -1,5 +1,4 @@
 use Mix.Config
-alias Pleroma.Docs.Generator
 
 websocket_config = [
   path: "/websocket",
@@ -1555,298 +1554,6 @@ config :pleroma, :config_description, [
       }
     ]
   },
-  %{
-    group: :pleroma,
-    key: :mrf,
-    tab: :mrf,
-    label: "MRF",
-    type: :group,
-    description: "General MRF settings",
-    children: [
-      %{
-        key: :policies,
-        type: [:module, {:list, :module}],
-        description:
-          "A list of MRF policies enabled. Module names are shortened (removed leading `Pleroma.Web.ActivityPub.MRF.` part), but on adding custom module you need to use full name.",
-        suggestions: {:list_behaviour_implementations, Pleroma.Web.ActivityPub.MRF}
-      },
-      %{
-        key: :transparency,
-        label: "MRF transparency",
-        type: :boolean,
-        description:
-          "Make the content of your Message Rewrite Facility settings public (via nodeinfo)"
-      },
-      %{
-        key: :transparency_exclusions,
-        label: "MRF transparency exclusions",
-        type: {:list, :string},
-        description:
-          "Exclude specific instance names from MRF transparency. The use of the exclusions feature will be disclosed in nodeinfo as a boolean value.",
-        suggestions: [
-          "exclusion.com"
-        ]
-      }
-    ]
-  },
-  %{
-    group: :pleroma,
-    key: :mrf_simple,
-    tab: :mrf,
-    related_policy: "Pleroma.Web.ActivityPub.MRF.SimplePolicy",
-    label: "MRF Simple",
-    type: :group,
-    description: "Simple ingress policies",
-    children: [
-      %{
-        key: :media_removal,
-        type: {:list, :string},
-        description: "List of instances to strip media attachments from",
-        suggestions: ["example.com", "*.example.com"]
-      },
-      %{
-        key: :media_nsfw,
-        label: "Media NSFW",
-        type: {:list, :string},
-        description: "List of instances to tag all media as NSFW (sensitive) from",
-        suggestions: ["example.com", "*.example.com"]
-      },
-      %{
-        key: :federated_timeline_removal,
-        type: {:list, :string},
-        description:
-          "List of instances to remove from the Federated (aka The Whole Known Network) Timeline",
-        suggestions: ["example.com", "*.example.com"]
-      },
-      %{
-        key: :reject,
-        type: {:list, :string},
-        description: "List of instances to reject activities from (except deletes)",
-        suggestions: ["example.com", "*.example.com"]
-      },
-      %{
-        key: :accept,
-        type: {:list, :string},
-        description: "List of instances to only accept activities from (except deletes)",
-        suggestions: ["example.com", "*.example.com"]
-      },
-      %{
-        key: :followers_only,
-        type: {:list, :string},
-        description: "Force posts from the given instances to be visible by followers only",
-        suggestions: ["example.com", "*.example.com"]
-      },
-      %{
-        key: :report_removal,
-        type: {:list, :string},
-        description: "List of instances to reject reports from",
-        suggestions: ["example.com", "*.example.com"]
-      },
-      %{
-        key: :avatar_removal,
-        type: {:list, :string},
-        description: "List of instances to strip avatars from",
-        suggestions: ["example.com", "*.example.com"]
-      },
-      %{
-        key: :banner_removal,
-        type: {:list, :string},
-        description: "List of instances to strip banners from",
-        suggestions: ["example.com", "*.example.com"]
-      },
-      %{
-        key: :reject_deletes,
-        type: {:list, :string},
-        description: "List of instances to reject deletions from",
-        suggestions: ["example.com", "*.example.com"]
-      }
-    ]
-  },
-  %{
-    group: :pleroma,
-    key: :mrf_activity_expiration,
-    tab: :mrf,
-    related_policy: "Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy",
-    label: "MRF Activity Expiration Policy",
-    type: :group,
-    description: "Adds automatic expiration to all local activities",
-    children: [
-      %{
-        key: :days,
-        type: :integer,
-        description: "Default global expiration time for all local activities (in days)",
-        suggestions: [90, 365]
-      }
-    ]
-  },
-  %{
-    group: :pleroma,
-    key: :mrf_subchain,
-    tab: :mrf,
-    related_policy: "Pleroma.Web.ActivityPub.MRF.SubchainPolicy",
-    label: "MRF Subchain",
-    type: :group,
-    description:
-      "This policy processes messages through an alternate pipeline when a given message matches certain criteria." <>
-        " All criteria are configured as a map of regular expressions to lists of policy modules.",
-    children: [
-      %{
-        key: :match_actor,
-        type: {:map, {:list, :string}},
-        description: "Matches a series of regular expressions against the actor field",
-        suggestions: [
-          %{
-            ~r/https:\/\/example.com/s => [Pleroma.Web.ActivityPub.MRF.DropPolicy]
-          }
-        ]
-      }
-    ]
-  },
-  %{
-    group: :pleroma,
-    key: :mrf_rejectnonpublic,
-    tab: :mrf,
-    related_policy: "Pleroma.Web.ActivityPub.MRF.RejectNonPublic",
-    description: "RejectNonPublic drops posts with non-public visibility settings.",
-    label: "MRF Reject Non Public",
-    type: :group,
-    children: [
-      %{
-        key: :allow_followersonly,
-        label: "Allow followers-only",
-        type: :boolean,
-        description: "Whether to allow followers-only posts"
-      },
-      %{
-        key: :allow_direct,
-        type: :boolean,
-        description: "Whether to allow direct messages"
-      }
-    ]
-  },
-  %{
-    group: :pleroma,
-    key: :mrf_hellthread,
-    tab: :mrf,
-    related_policy: "Pleroma.Web.ActivityPub.MRF.HellthreadPolicy",
-    label: "MRF Hellthread",
-    type: :group,
-    description: "Block messages with excessive user mentions",
-    children: [
-      %{
-        key: :delist_threshold,
-        type: :integer,
-        description:
-          "Number of mentioned users after which the message gets removed from timelines and" <>
-            "disables notifications. Set to 0 to disable.",
-        suggestions: [10]
-      },
-      %{
-        key: :reject_threshold,
-        type: :integer,
-        description:
-          "Number of mentioned users after which the messaged gets rejected. Set to 0 to disable.",
-        suggestions: [20]
-      }
-    ]
-  },
-  %{
-    group: :pleroma,
-    key: :mrf_keyword,
-    tab: :mrf,
-    related_policy: "Pleroma.Web.ActivityPub.MRF.KeywordPolicy",
-    label: "MRF Keyword",
-    type: :group,
-    description:
-      "Reject or Word-Replace messages matching a keyword or [Regex](https://hexdocs.pm/elixir/Regex.html).",
-    children: [
-      %{
-        key: :reject,
-        type: {:list, :string},
-        description: """
-          A list of patterns which result in message being rejected.
-
-          Each pattern can be a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`.
-        """,
-        suggestions: ["foo", ~r/foo/iu]
-      },
-      %{
-        key: :federated_timeline_removal,
-        type: {:list, :string},
-        description: """
-          A list of patterns which result in message being removed from federated timelines (a.k.a unlisted).
-
-          Each pattern can be a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`.
-        """,
-        suggestions: ["foo", ~r/foo/iu]
-      },
-      %{
-        key: :replace,
-        type: {:list, :tuple},
-        description: """
-          **Pattern**: a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`.
-
-          **Replacement**: a string. Leaving the field empty is permitted.
-        """
-      }
-    ]
-  },
-  %{
-    group: :pleroma,
-    key: :mrf_mention,
-    tab: :mrf,
-    related_policy: "Pleroma.Web.ActivityPub.MRF.MentionPolicy",
-    label: "MRF Mention",
-    type: :group,
-    description: "Block messages which mention a specific user",
-    children: [
-      %{
-        key: :actors,
-        type: {:list, :string},
-        description: "A list of actors for which any post mentioning them will be dropped",
-        suggestions: ["actor1", "actor2"]
-      }
-    ]
-  },
-  %{
-    group: :pleroma,
-    key: :mrf_vocabulary,
-    tab: :mrf,
-    related_policy: "Pleroma.Web.ActivityPub.MRF.VocabularyPolicy",
-    label: "MRF Vocabulary",
-    type: :group,
-    description: "Filter messages which belong to certain activity vocabularies",
-    children: [
-      %{
-        key: :accept,
-        type: {:list, :string},
-        description:
-          "A list of ActivityStreams terms to accept. If empty, all supported messages are accepted.",
-        suggestions: ["Create", "Follow", "Mention", "Announce", "Like"]
-      },
-      %{
-        key: :reject,
-        type: {:list, :string},
-        description:
-          "A list of ActivityStreams terms to reject. If empty, no messages are rejected.",
-        suggestions: ["Create", "Follow", "Mention", "Announce", "Like"]
-      }
-    ]
-  },
-  # %{
-  #   group: :pleroma,
-  #   key: :mrf_user_allowlist,
-  #   tab: :mrf,
-  #   related_policy: "Pleroma.Web.ActivityPub.MRF.UserAllowListPolicy",
-  #   type: :map,
-  #   description:
-  #     "The keys in this section are the domain names that the policy should apply to." <>
-  #       " Each key should be assigned a list of users that should be allowed through by their ActivityPub ID",
-  #     suggestions: [
-  #       %{"example.org" => ["https://example.org/users/admin"]}
-  #     ]
-  #   ]
-  # },
   %{
     group: :pleroma,
     key: :media_proxy,
@@ -3159,22 +2866,6 @@ config :pleroma, :config_description, [
       }
     ]
   },
-  %{
-    group: :pleroma,
-    key: :mrf_normalize_markup,
-    tab: :mrf,
-    related_policy: "Pleroma.Web.ActivityPub.MRF.NormalizeMarkup",
-    label: "MRF Normalize Markup",
-    description: "MRF NormalizeMarkup settings. Scrub configured hypertext markup.",
-    type: :group,
-    children: [
-      %{
-        key: :scrub_policy,
-        type: :module,
-        suggestions: [Pleroma.HTML.Scrubber.Default]
-      }
-    ]
-  },
   %{
     group: :pleroma,
     key: Pleroma.User,
@@ -3364,33 +3055,6 @@ config :pleroma, :config_description, [
       }
     ]
   },
-  %{
-    group: :pleroma,
-    key: :mrf_object_age,
-    tab: :mrf,
-    related_policy: "Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy",
-    label: "MRF Object Age",
-    type: :group,
-    description:
-      "Rejects or delists posts based on their timestamp deviance from your server's clock.",
-    children: [
-      %{
-        key: :threshold,
-        type: :integer,
-        description: "Required age (in seconds) of a post before actions are taken.",
-        suggestions: [172_800]
-      },
-      %{
-        key: :actions,
-        type: {:list, :atom},
-        description:
-          "A list of actions to apply to the post. `:delist` removes the post from public timelines; " <>
-            "`:strip_followers` removes followers from the ActivityPub recipient list ensuring they won't be delivered to home timelines; " <>
-            "`:reject` rejects the message entirely",
-        suggestions: [:delist, :strip_followers, :reject]
-      }
-    ]
-  },
   %{
     group: :pleroma,
     key: :modules,
diff --git a/docs/administration/CLI_tasks/release_environments.md b/docs/administration/CLI_tasks/release_environments.md
deleted file mode 100644 (file)
index 36ab438..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-# Generate release environment file
-
-```sh tab="OTP"
- ./bin/pleroma_ctl release_env gen
-```
-
-```sh tab="From Source"
-mix pleroma.release_env gen
-```
diff --git a/docs/configuration/optimizing_beam.md b/docs/configuration/optimizing_beam.md
new file mode 100644 (file)
index 0000000..e336bd3
--- /dev/null
@@ -0,0 +1,66 @@
+# Optimizing the BEAM
+
+Pleroma is built upon the Erlang/OTP VM known as BEAM. The BEAM VM is highly optimized for latency, but this has drawbacks in environments without dedicated hardware. One of the tricks used by the BEAM VM is [busy waiting](https://en.wikipedia.org/wiki/Busy_waiting). This allows the application to pretend to be busy working so the OS kernel does not pause the application process and switch to another process waiting for the CPU to execute its workload. It does this by spinning for a period of time which inflates the apparent CPU usage of the application so it is immediately ready to execute another task. This can be observed with utilities like **top(1)** which will show consistently high CPU usage for the process. Switching between procesess is a rather expensive operation and also clears CPU caches further affecting latency and performance. The goal of busy waiting is to avoid this penalty.
+
+This strategy is very successful in making a performant and responsive application, but is not desirable on Virtual Machines or hardware with few CPU cores. Pleroma instances are often deployed on the same server as the required PostgreSQL database which can lead to situations where the Pleroma application is holding the CPU in a busy-wait loop and as a result the database cannot process requests in a timely manner. The fewer CPUs available, the more this problem is exacerbated. The latency is further amplified by the OS being installed on a Virtual Machine as the Hypervisor uses CPU time-slicing to pause the entire OS and switch between other tasks.
+
+More adventurous admins can be creative with CPU affinity (e.g., *taskset* for Linux and *cpuset* on FreeBSD) to pin processes to specific CPUs and eliminate much of this contention. The most important advice is to run as few processes as possible on your server to achieve the best performance. Even idle background processes can occasionally create [software interrupts](https://en.wikipedia.org/wiki/Interrupt) and take attention away from the executing process creating latency spikes and invalidation of the CPU caches as they must be cleared when switching between processes for security.
+
+Please only change these settings if you are experiencing issues or really know what you are doing. In general, there's no need to change these settings.
+
+## VPS Provider Recommendations
+
+### Good
+
+* Hetzner Cloud
+
+### Bad
+
+* AWS (known to use burst scheduling)
+
+
+## Example configurations
+
+Tuning the BEAM requires you provide a config file normally called [vm.args](http://erlang.org/doc/man/erl.html#emulator-flags). If you are using systemd to manage the service you can modify the unit file as such:
+
+`ExecStart=/usr/bin/elixir --erl '-args_file /opt/pleroma/config/vm.args' -S /usr/bin/mix phx.server`
+
+Check your OS documentation to adopt a similar strategy on other platforms.
+
+### Virtual Machine and/or few CPU cores
+
+Disable the busy-waiting. This should generally only be done if you're on a platform that does burst scheduling, like AWS.
+
+**vm.args:**
+
+```
++sbwt none
++sbwtdcpu none
++sbwtdio none
+```
+
+### Dedicated Hardware
+
+Enable more busy waiting, increase the internal maximum limit of BEAM processes and ports. You can use this if you run on dedicated hardware, but it is not necessary.
+
+**vm.args:**
+
+```
++P 16777216
++Q 16777216
++K true
++A 128
++sbt db
++sbwt very_long
++swt very_low
++sub true
++Mulmbcs 32767
++Mumbcgs 1
++Musmbcs 2047
+```
+
+## Additional Reading
+
+* [WhatsApp: Scaling to Millions of Simultaneous Connections](https://www.erlang-factory.com/upload/presentations/558/efsf2012-whatsapp-scaling.pdf)
+* [Preemptive Scheduling and Spinlocks](https://www.uio.no/studier/emner/matnat/ifi/nedlagte-emner/INF3150/h03/annet/slides/preemptive.pdf)
+* [The Curious Case of BEAM CPU Usage](https://stressgrid.com/blog/beam_cpu_usage/)
index 22e0691f14e35e906bbb4a1a546874e4d0606b77..aa89a941fdfe3e011150a7115f47e372fbc12a2f 100644 (file)
@@ -21,3 +21,26 @@ This document contains notes and guidelines for Pleroma developers.
 ## Auth-related configuration, OAuth consumer mode etc.
 
 See `Authentication` section of [the configuration cheatsheet](configuration/cheatsheet.md#authentication).
+
+## MRF policies descriptions
+
+If MRF policy depends on config, it can be added into MRF tab to adminFE by adding `config_description/0` method, which returns map with special structure.
+
+Example:
+
+```elixir
+%{
+      key: :mrf_activity_expiration,
+      related_policy: "Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy",
+      label: "MRF Activity Expiration Policy",
+      description: "Adds automatic expiration to all local activities",
+      children: [
+        %{
+          key: :days,
+          type: :integer,
+          description: "Default global expiration time for all local activities (in days)",
+          suggestions: [90, 365]
+        }
+      ]
+    }
+```
index b9fc4e1126cdaac01e40e5d69742068e07b6c558..75ceb65959f9288e397a70645e732edd9f2ab0fa 100644 (file)
@@ -182,7 +182,6 @@ sudo cp /opt/pleroma/installation/pleroma.service /etc/systemd/system/pleroma.se
 ```
 
 * Edit the service file and make sure that all paths fit your installation
-* Check that `EnvironmentFile` contains the correct path to the env file. Or generate the env file: `sudo -Hu pleroma mix pleroma.release_env gen`
 * Enable and start `pleroma.service`:
 
 ```shell
index 98360bcf747c77e59693d005e2d75118c010cbd8..63eda63ca230a2cb6f4b2f2035d0ecf978debffb 100644 (file)
@@ -149,9 +149,6 @@ chown -R pleroma /etc/pleroma
 # Run the config generator
 su pleroma -s $SHELL -lc "./bin/pleroma_ctl instance gen --output /etc/pleroma/config.exs --output-psql /tmp/setup_db.psql"
 
-# Run the environment file generator.
-su pleroma -s $SHELL -lc "./bin/pleroma_ctl release_env gen"
-
 # Create the postgres database
 su postgres -s $SHELL -lc "psql -f /tmp/setup_db.psql"
 
index e908cda1b318ab4bea6d6371b898b8ecb12a6667..384536f7e99d50efdb17bfe1683990efb6b1ea04 100755 (executable)
@@ -8,7 +8,6 @@ pidfile="/var/run/pleroma.pid"
 directory=/opt/pleroma
 healthcheck_delay=60
 healthcheck_timer=30
-export $(cat /opt/pleroma/config/pleroma.env)
 
 : ${pleroma_port:-4000}
 
index 63e83ed6efe27842d4867a2927fcf5c6c0aebd16..8338228d8a61616d11fddd4ceffab111f01ec104 100644 (file)
@@ -17,8 +17,6 @@ Environment="MIX_ENV=prod"
 Environment="HOME=/var/lib/pleroma"
 ; Path to the folder containing the Pleroma installation.
 WorkingDirectory=/opt/pleroma
-; Path to the environment file. the file contains RELEASE_COOKIE and etc 
-EnvironmentFile=/opt/pleroma/config/pleroma.env
 ; Path to the Mix binary.
 ExecStart=/usr/bin/mix phx.server
 
index 1915aacd9b2973092eebadd8adb708bf3d432371..fc21ae06255b88677088beb4270d6871e6a5e30c 100644 (file)
@@ -36,9 +36,7 @@ defmodule Mix.Tasks.Pleroma.Instance do
           listen_port: :string,
           strip_uploads: :string,
           anonymize_uploads: :string,
-          dedupe_uploads: :string,
-          skip_release_env: :boolean,
-          release_env_file: :string
+          dedupe_uploads: :string
         ],
         aliases: [
           o: :output,
@@ -243,24 +241,6 @@ defmodule Mix.Tasks.Pleroma.Instance do
 
       write_robots_txt(static_dir, indexable, template_dir)
 
-      if Keyword.get(options, :skip_release_env, false) do
-        shell_info("""
-        Release environment file is skip. Please generate the release env file before start.
-        `MIX_ENV=#{Mix.env()} mix pleroma.release_env gen`
-        """)
-      else
-        shell_info("Generation the environment file:")
-
-        release_env_args =
-          with path when not is_nil(path) <- Keyword.get(options, :release_env_file) do
-            ["gen", "--path", path]
-          else
-            _ -> ["gen"]
-          end
-
-        Mix.Tasks.Pleroma.ReleaseEnv.run(release_env_args)
-      end
-
       shell_info(
         "\n All files successfully written! Refer to the installation instructions for your platform for next steps."
       )
diff --git a/lib/mix/tasks/pleroma/release_env.ex b/lib/mix/tasks/pleroma/release_env.ex
deleted file mode 100644 (file)
index 9da74ff..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright Â© 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Mix.Tasks.Pleroma.ReleaseEnv do
-  use Mix.Task
-  import Mix.Pleroma
-
-  @shortdoc "Generate Pleroma environment file."
-  @moduledoc File.read!("docs/administration/CLI_tasks/release_environments.md")
-
-  def run(["gen" | rest]) do
-    {options, [], []} =
-      OptionParser.parse(
-        rest,
-        strict: [
-          force: :boolean,
-          path: :string
-        ],
-        aliases: [
-          p: :path,
-          f: :force
-        ]
-      )
-
-    file_path =
-      get_option(
-        options,
-        :path,
-        "Environment file path",
-        "./config/pleroma.env"
-      )
-
-    env_path = Path.expand(file_path)
-
-    proceed? =
-      if File.exists?(env_path) do
-        get_option(
-          options,
-          :force,
-          "Environment file already exists. Do you want to overwrite the #{env_path} file? (y/n)",
-          "n"
-        ) === "y"
-      else
-        true
-      end
-
-    if proceed? do
-      case do_generate(env_path) do
-        {:error, reason} ->
-          shell_error(
-            File.Error.message(%{action: "write to file", reason: reason, path: env_path})
-          )
-
-        _ ->
-          shell_info("\nThe file generated: #{env_path}.\n")
-
-          shell_info("""
-          WARNING: before start pleroma app please make sure to make the file read-only and non-modifiable.
-            Example:
-              chmod 0444 #{file_path}
-              chattr +i #{file_path}
-          """)
-      end
-    else
-      shell_info("\nThe file is exist. #{env_path}.\n")
-    end
-  end
-
-  def do_generate(path) do
-    content = "RELEASE_COOKIE=#{Base.encode32(:crypto.strong_rand_bytes(32))}"
-
-    File.mkdir_p!(Path.dirname(path))
-    File.write(path, content)
-  end
-end
index 13618b509430a72f839069e142bd269ecb03f9c4..a583e2a5b7d31daa8734f2ff1896d7254a8de02c 100644 (file)
@@ -11,7 +11,11 @@ defmodule Pleroma.Docs.JSON do
 
   @spec compile :: :ok
   def compile do
-    :persistent_term.put(@term, Pleroma.Docs.Generator.convert_to_strings(@raw_descriptions))
+    descriptions =
+      Pleroma.Web.ActivityPub.MRF.config_descriptions()
+      |> Enum.reduce(@raw_descriptions, fn description, acc -> [description | acc] end)
+
+    :persistent_term.put(@term, Pleroma.Docs.Generator.convert_to_strings(descriptions))
   end
 
   @spec compiled_descriptions :: Map.t()
index 8979db2f8269518fa63ceaecfbe61c7dbda0b088..02274554fe285414a4b63ac631a177d397296f7c 100644 (file)
@@ -18,10 +18,6 @@ defmodule Pleroma.Emails.AdminEmail do
     Keyword.get(instance_config(), :notify_email, instance_config()[:email])
   end
 
-  defp user_url(user) do
-    Helpers.user_feed_url(Pleroma.Web.Endpoint, :feed_redirect, user.id)
-  end
-
   def test_email(mail_to \\ nil) do
     html_body = """
     <h3>Instance Test Email</h3>
@@ -69,8 +65,8 @@ defmodule Pleroma.Emails.AdminEmail do
       end
 
     html_body = """
-    <p>Reported by: <a href="#{user_url(reporter)}">#{reporter.nickname}</a></p>
-    <p>Reported Account: <a href="#{user_url(account)}">#{account.nickname}</a></p>
+    <p>Reported by: <a href="#{reporter.ap_id}">#{reporter.nickname}</a></p>
+    <p>Reported Account: <a href="#{account.ap_id}">#{account.nickname}</a></p>
     #{comment_html}
     #{statuses_html}
     <p>
@@ -86,7 +82,7 @@ defmodule Pleroma.Emails.AdminEmail do
 
   def new_unapproved_registration(to, account) do
     html_body = """
-    <p>New account for review: <a href="#{user_url(account)}">@#{account.nickname}</a></p>
+    <p>New account for review: <a href="#{account.ap_id}">@#{account.nickname}</a></p>
     <blockquote>#{HTML.strip_tags(account.registration_reason)}</blockquote>
     <a href="#{Pleroma.Web.base_url()}/pleroma/admin/#/users/#{account.id}/">Visit AdminFE</a>
     """
index 169298b344df29782b972676c03ff44d2f9dcf8e..ae4301738a0d240aa6b250d558d9400bed621522 100644 (file)
@@ -232,8 +232,24 @@ defmodule Pleroma.Object.Fetcher do
       |> sign_fetch(id, date)
 
     case HTTP.get(id, headers) do
-      {:ok, %{body: body, status: code}} when code in 200..299 ->
-        {:ok, body}
+      {:ok, %{body: body, status: code, headers: headers}} when code in 200..299 ->
+        case List.keyfind(headers, "content-type", 0) do
+          {_, content_type} ->
+            case Plug.Conn.Utils.media_type(content_type) do
+              {:ok, "application", "activity+json", _} ->
+                {:ok, body}
+
+              {:ok, "application", "ld+json",
+               %{"profile" => "https://www.w3.org/ns/activitystreams"}} ->
+                {:ok, body}
+
+              _ ->
+                {:error, {:content_type, content_type}}
+            end
+
+          _ ->
+            {:error, {:content_type, nil}}
+        end
 
       {:ok, %{status: code}} when code in [404, 410] ->
         {:error, "Object has been deleted"}
index 5e5361082755d11f3036d678d0f6881564b15433..6e73b2f22f7e685d1ba12d1b89f2240df6c421d4 100644 (file)
@@ -3,7 +3,62 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 
 defmodule Pleroma.Web.ActivityPub.MRF do
+  require Logger
+
+  @mrf_config_descriptions [
+    %{
+      group: :pleroma,
+      key: :mrf,
+      tab: :mrf,
+      label: "MRF",
+      type: :group,
+      description: "General MRF settings",
+      children: [
+        %{
+          key: :policies,
+          type: [:module, {:list, :module}],
+          description:
+            "A list of MRF policies enabled. Module names are shortened (removed leading `Pleroma.Web.ActivityPub.MRF.` part), but on adding custom module you need to use full name.",
+          suggestions: {:list_behaviour_implementations, Pleroma.Web.ActivityPub.MRF}
+        },
+        %{
+          key: :transparency,
+          label: "MRF transparency",
+          type: :boolean,
+          description:
+            "Make the content of your Message Rewrite Facility settings public (via nodeinfo)"
+        },
+        %{
+          key: :transparency_exclusions,
+          label: "MRF transparency exclusions",
+          type: {:list, :string},
+          description:
+            "Exclude specific instance names from MRF transparency. The use of the exclusions feature will be disclosed in nodeinfo as a boolean value.",
+          suggestions: [
+            "exclusion.com"
+          ]
+        }
+      ]
+    }
+  ]
+
+  @default_description %{
+    label: "",
+    description: ""
+  }
+
+  @required_description_keys [:key, :related_policy]
+
   @callback filter(Map.t()) :: {:ok | :reject, Map.t()}
+  @callback describe() :: {:ok | :error, Map.t()}
+  @callback config_description() :: %{
+              optional(:children) => [map()],
+              key: atom(),
+              related_policy: String.t(),
+              label: String.t(),
+              description: String.t()
+            }
+  @optional_callbacks config_description: 0
 
   def filter(policies, %{} = message) do
     policies
@@ -51,8 +106,6 @@ defmodule Pleroma.Web.ActivityPub.MRF do
     Enum.any?(domains, fn domain -> Regex.match?(domain, host) end)
   end
 
-  @callback describe() :: {:ok | :error, Map.t()}
-
   def describe(policies) do
     {:ok, policy_configs} =
       policies
@@ -82,4 +135,41 @@ defmodule Pleroma.Web.ActivityPub.MRF do
   end
 
   def describe, do: get_policies() |> describe()
+
+  def config_descriptions do
+    Pleroma.Web.ActivityPub.MRF
+    |> Pleroma.Docs.Generator.list_behaviour_implementations()
+    |> config_descriptions()
+  end
+
+  def config_descriptions(policies) do
+    Enum.reduce(policies, @mrf_config_descriptions, fn policy, acc ->
+      if function_exported?(policy, :config_description, 0) do
+        description =
+          @default_description
+          |> Map.merge(policy.config_description)
+          |> Map.put(:group, :pleroma)
+          |> Map.put(:tab, :mrf)
+          |> Map.put(:type, :group)
+
+        if Enum.all?(@required_description_keys, &Map.has_key?(description, &1)) do
+          [description | acc]
+        else
+          Logger.warn(
+            "#{policy} config description doesn't have one or all required keys #{
+              inspect(@required_description_keys)
+            }"
+          )
+
+          acc
+        end
+      else
+        Logger.debug(
+          "#{policy} is excluded from config descriptions, because does not implement `config_description/0` method."
+        )
+
+        acc
+      end
+    end)
+  end
 end
index bee47b4edd4b47e0931d1db953b6b2fd916f61ea..655a2ced06034927fd83d2f4bc7aafcbccffe90e 100644 (file)
@@ -40,4 +40,22 @@ defmodule Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy do
       _ -> Map.put(activity, "expires_at", expires_at)
     end
   end
+
+  @impl true
+  def config_description do
+    %{
+      key: :mrf_activity_expiration,
+      related_policy: "Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy",
+      label: "MRF Activity Expiration Policy",
+      description: "Adds automatic expiration to all local activities",
+      children: [
+        %{
+          key: :days,
+          type: :integer,
+          description: "Default global expiration time for all local activities (in days)",
+          suggestions: [90, 365]
+        }
+      ]
+    }
+  end
 end
index 9ba07b4e38b73c4a1bffdfba131511aee90855f9..3fd5c1e0a9c5cf6a3dd19fb6ad89baad58d94d92 100644 (file)
@@ -97,4 +97,31 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicy do
   @impl true
   def describe,
     do: {:ok, %{mrf_hellthread: Pleroma.Config.get(:mrf_hellthread) |> Enum.into(%{})}}
+
+  @impl true
+  def config_description do
+    %{
+      key: :mrf_hellthread,
+      related_policy: "Pleroma.Web.ActivityPub.MRF.HellthreadPolicy",
+      label: "MRF Hellthread",
+      description: "Block messages with excessive user mentions",
+      children: [
+        %{
+          key: :delist_threshold,
+          type: :integer,
+          description:
+            "Number of mentioned users after which the message gets removed from timelines and" <>
+              "disables notifications. Set to 0 to disable.",
+          suggestions: [10]
+        },
+        %{
+          key: :reject_threshold,
+          type: :integer,
+          description:
+            "Number of mentioned users after which the messaged gets rejected. Set to 0 to disable.",
+          suggestions: [20]
+        }
+      ]
+    }
+  end
 end
index db66cfa3ec92638e9f556c4cd90b401c313daeda..ded0fe7f277de1a4ddbddadb688b2d6f3bd75f69 100644 (file)
@@ -126,4 +126,46 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
 
     {:ok, %{mrf_keyword: mrf_keyword}}
   end
+
+  @impl true
+  def config_description do
+    %{
+      key: :mrf_keyword,
+      related_policy: "Pleroma.Web.ActivityPub.MRF.KeywordPolicy",
+      label: "MRF Keyword",
+      description:
+        "Reject or Word-Replace messages matching a keyword or [Regex](https://hexdocs.pm/elixir/Regex.html).",
+      children: [
+        %{
+          key: :reject,
+          type: {:list, :string},
+          description: """
+            A list of patterns which result in message being rejected.
+
+            Each pattern can be a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`.
+          """,
+          suggestions: ["foo", ~r/foo/iu]
+        },
+        %{
+          key: :federated_timeline_removal,
+          type: {:list, :string},
+          description: """
+            A list of patterns which result in message being removed from federated timelines (a.k.a unlisted).
+
+            Each pattern can be a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`.
+          """,
+          suggestions: ["foo", ~r/foo/iu]
+        },
+        %{
+          key: :replace,
+          type: {:list, :tuple},
+          description: """
+            **Pattern**: a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`.
+
+            **Replacement**: a string. Leaving the field empty is permitted.
+          """
+        }
+      ]
+    }
+  end
 end
index 7910ca131830d3b782a2f3d5040c13f2196caefd..9c096712a653abc71724e107e7e6c0eb9c4a68c8 100644 (file)
@@ -25,4 +25,22 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicy do
 
   @impl true
   def describe, do: {:ok, %{}}
+
+  @impl true
+  def config_description do
+    %{
+      key: :mrf_mention,
+      related_policy: "Pleroma.Web.ActivityPub.MRF.MentionPolicy",
+      label: "MRF Mention",
+      description: "Block messages which mention a specific user",
+      children: [
+        %{
+          key: :actors,
+          type: {:list, :string},
+          description: "A list of actors for which any post mentioning them will be dropped",
+          suggestions: ["actor1", "actor2"]
+        }
+      ]
+    }
+  end
 end
index 7abae37aea2486161dd49cc0203ede72b50338e1..e00575c2a3cefb1e7baf512a8224ad81b0c35ee1 100644 (file)
@@ -8,6 +8,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.NormalizeMarkup do
 
   @behaviour Pleroma.Web.ActivityPub.MRF
 
+  @impl true
   def filter(%{"type" => "Create", "object" => child_object} = object) do
     scrub_policy = Pleroma.Config.get([:mrf_normalize_markup, :scrub_policy])
 
@@ -22,5 +23,23 @@ defmodule Pleroma.Web.ActivityPub.MRF.NormalizeMarkup do
 
   def filter(object), do: {:ok, object}
 
+  @impl true
   def describe, do: {:ok, %{}}
+
+  @impl true
+  def config_description do
+    %{
+      key: :mrf_normalize_markup,
+      related_policy: "Pleroma.Web.ActivityPub.MRF.NormalizeMarkup",
+      label: "MRF Normalize Markup",
+      description: "MRF NormalizeMarkup settings. Scrub configured hypertext markup.",
+      children: [
+        %{
+          key: :scrub_policy,
+          type: :module,
+          suggestions: [Pleroma.HTML.Scrubber.Default]
+        }
+      ]
+    }
+  end
 end
index d45d2d7e36ef2ce1644d569cf4fae60f0fb2c740..eb0481f20a2e3fbf32912f3302e925adea6c7c30 100644 (file)
@@ -106,4 +106,32 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy do
 
     {:ok, %{mrf_object_age: mrf_object_age}}
   end
+
+  @impl true
+  def config_description do
+    %{
+      key: :mrf_object_age,
+      related_policy: "Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy",
+      label: "MRF Object Age",
+      description:
+        "Rejects or delists posts based on their timestamp deviance from your server's clock.",
+      children: [
+        %{
+          key: :threshold,
+          type: :integer,
+          description: "Required age (in seconds) of a post before actions are taken.",
+          suggestions: [172_800]
+        },
+        %{
+          key: :actions,
+          type: {:list, :atom},
+          description:
+            "A list of actions to apply to the post. `:delist` removes the post from public timelines; " <>
+              "`:strip_followers` removes followers from the ActivityPub recipient list ensuring they won't be delivered to home timelines; " <>
+              "`:reject` rejects the message entirely",
+          suggestions: [:delist, :strip_followers, :reject]
+        }
+      ]
+    }
+  end
 end
index 0b9ed2224dc82a334f6a2efc7d4082a311651bd9..cd7665e313d87989cdc7049d7e82150cc2f71105 100644 (file)
@@ -48,4 +48,27 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublic do
   @impl true
   def describe,
     do: {:ok, %{mrf_rejectnonpublic: Config.get(:mrf_rejectnonpublic) |> Enum.into(%{})}}
+
+  @impl true
+  def config_description do
+    %{
+      key: :mrf_rejectnonpublic,
+      related_policy: "Pleroma.Web.ActivityPub.MRF.RejectNonPublic",
+      description: "RejectNonPublic drops posts with non-public visibility settings.",
+      label: "MRF Reject Non Public",
+      children: [
+        %{
+          key: :allow_followersonly,
+          label: "Allow followers-only",
+          type: :boolean,
+          description: "Whether to allow followers-only posts"
+        },
+        %{
+          key: :allow_direct,
+          type: :boolean,
+          description: "Whether to allow direct messages"
+        }
+      ]
+    }
+  end
 end
index 16117772717091489ae3c7b5fa0b76e651bad7ab..6cd91826db178ba72f9cc0859fe7eac5c7397eca 100644 (file)
@@ -244,4 +244,78 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
 
     {:ok, %{mrf_simple: mrf_simple}}
   end
+
+  @impl true
+  def config_description do
+    %{
+      key: :mrf_simple,
+      related_policy: "Pleroma.Web.ActivityPub.MRF.SimplePolicy",
+      label: "MRF Simple",
+      description: "Simple ingress policies",
+      children: [
+        %{
+          key: :media_removal,
+          type: {:list, :string},
+          description: "List of instances to strip media attachments from",
+          suggestions: ["example.com", "*.example.com"]
+        },
+        %{
+          key: :media_nsfw,
+          label: "Media NSFW",
+          type: {:list, :string},
+          description: "List of instances to tag all media as NSFW (sensitive) from",
+          suggestions: ["example.com", "*.example.com"]
+        },
+        %{
+          key: :federated_timeline_removal,
+          type: {:list, :string},
+          description:
+            "List of instances to remove from the Federated (aka The Whole Known Network) Timeline",
+          suggestions: ["example.com", "*.example.com"]
+        },
+        %{
+          key: :reject,
+          type: {:list, :string},
+          description: "List of instances to reject activities from (except deletes)",
+          suggestions: ["example.com", "*.example.com"]
+        },
+        %{
+          key: :accept,
+          type: {:list, :string},
+          description: "List of instances to only accept activities from (except deletes)",
+          suggestions: ["example.com", "*.example.com"]
+        },
+        %{
+          key: :followers_only,
+          type: {:list, :string},
+          description: "Force posts from the given instances to be visible by followers only",
+          suggestions: ["example.com", "*.example.com"]
+        },
+        %{
+          key: :report_removal,
+          type: {:list, :string},
+          description: "List of instances to reject reports from",
+          suggestions: ["example.com", "*.example.com"]
+        },
+        %{
+          key: :avatar_removal,
+          type: {:list, :string},
+          description: "List of instances to strip avatars from",
+          suggestions: ["example.com", "*.example.com"]
+        },
+        %{
+          key: :banner_removal,
+          type: {:list, :string},
+          description: "List of instances to strip banners from",
+          suggestions: ["example.com", "*.example.com"]
+        },
+        %{
+          key: :reject_deletes,
+          type: {:list, :string},
+          description: "List of instances to reject deletions from",
+          suggestions: ["example.com", "*.example.com"]
+        }
+      ]
+    }
+  end
 end
index 048052da69fdd5097e2271e6b621fce7e0a38813..2ec45260ad76523df8660af4a935eab9b3d38946 100644 (file)
@@ -39,4 +39,28 @@ defmodule Pleroma.Web.ActivityPub.MRF.SubchainPolicy do
 
   @impl true
   def describe, do: {:ok, %{}}
+
+  @impl true
+  def config_description do
+    %{
+      key: :mrf_subchain,
+      related_policy: "Pleroma.Web.ActivityPub.MRF.SubchainPolicy",
+      label: "MRF Subchain",
+      description:
+        "This policy processes messages through an alternate pipeline when a given message matches certain criteria." <>
+          " All criteria are configured as a map of regular expressions to lists of policy modules.",
+      children: [
+        %{
+          key: :match_actor,
+          type: {:map, {:list, :string}},
+          description: "Matches a series of regular expressions against the actor field",
+          suggestions: [
+            %{
+              ~r/https:\/\/example.com/s => [Pleroma.Web.ActivityPub.MRF.DropPolicy]
+            }
+          ]
+        }
+      ]
+    }
+  end
 end
index 1a28f2ba21d118563324d36b9e602d6d87eb60a9..e9d0d0503c3e39e2987fd8b0712825944ed6744f 100644 (file)
@@ -41,4 +41,25 @@ defmodule Pleroma.Web.ActivityPub.MRF.UserAllowListPolicy do
 
     {:ok, %{mrf_user_allowlist: mrf_user_allowlist}}
   end
+
+  # TODO: change way of getting settings on `lib/pleroma/web/activity_pub/mrf/user_allow_list_policy.ex:18` to use `hosts` subkey
+  # @impl true
+  # def config_description do
+  #   %{
+  #     key: :mrf_user_allowlist,
+  #     related_policy: "Pleroma.Web.ActivityPub.MRF.UserAllowListPolicy",
+  #     description: "Accept-list of users from specified instances",
+  #     children: [
+  #       %{
+  #         key: :hosts,
+  #         type: :map,
+  #         description:
+  #           "The keys in this section are the domain names that the policy should apply to." <>
+  #             " Each key should be assigned a list of users that should be allowed " <>
+  #             "through by their ActivityPub ID",
+  #         suggestions: [%{"example.org" => ["https://example.org/users/admin"]}]
+  #       }
+  #     ]
+  #   }
+  # end
 end
index a6c5455702c27cdc733619e5ecc90a9f780962ca..f325cb680dca9e081aa19d036a73f321aef66a37 100644 (file)
@@ -7,6 +7,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicy do
 
   @behaviour Pleroma.Web.ActivityPub.MRF
 
+  @impl true
   def filter(%{"type" => "Undo", "object" => child_message} = message) do
     with {:ok, _} <- filter(child_message) do
       {:ok, message}
@@ -36,6 +37,33 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicy do
 
   def filter(message), do: {:ok, message}
 
+  @impl true
   def describe,
     do: {:ok, %{mrf_vocabulary: Pleroma.Config.get(:mrf_vocabulary) |> Enum.into(%{})}}
+
+  @impl true
+  def config_description do
+    %{
+      key: :mrf_vocabulary,
+      related_policy: "Pleroma.Web.ActivityPub.MRF.VocabularyPolicy",
+      label: "MRF Vocabulary",
+      description: "Filter messages which belong to certain activity vocabularies",
+      children: [
+        %{
+          key: :accept,
+          type: {:list, :string},
+          description:
+            "A list of ActivityStreams terms to accept. If empty, all supported messages are accepted.",
+          suggestions: ["Create", "Follow", "Mention", "Announce", "Like"]
+        },
+        %{
+          key: :reject,
+          type: {:list, :string},
+          description:
+            "A list of ActivityStreams terms to reject. If empty, no messages are rejected.",
+          suggestions: ["Create", "Follow", "Mention", "Announce", "Like"]
+        }
+      ]
+    }
+  end
 end
index df102a134d63b6e4461ef597d952c63a8cb979c8..f96fd54bf61aad8ca0380ecf8999828d91d16183 100644 (file)
@@ -15,6 +15,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator do
     field(:type, :string)
     field(:mediaType, :string, default: "application/octet-stream")
     field(:name, :string)
+    field(:blurhash, :string)
 
     embeds_many :url, UrlObjectValidator, primary_key: false do
       field(:type, :string)
@@ -41,7 +42,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator do
       |> fix_url()
 
     struct
-    |> cast(data, [:type, :mediaType, :name])
+    |> cast(data, [:type, :mediaType, :name, :blurhash])
     |> cast_embed(:url, with: &url_changeset/2)
     |> validate_inclusion(:type, ~w[Link Document Audio Image Video])
     |> validate_required([:type, :mediaType, :url])
index 39c8f7e396ac064afc69d185613aaa28f59b53e5..0bcd1db227ce62fcde9702d10e06fca21ca03485 100644 (file)
@@ -252,6 +252,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
           }
           |> Maps.put_if_present("mediaType", media_type)
           |> Maps.put_if_present("name", data["name"])
+          |> Maps.put_if_present("blurhash", data["blurhash"])
         else
           nil
         end
index 6f759d559648cc2cb9ebe34f40ce15102d6ebf9e..1ac1319f815d8441e6181b9c965a1e1a8fc16f87 100644 (file)
@@ -37,10 +37,11 @@ defmodule Pleroma.Web.Fallback.RedirectController do
 
     tags = build_tags(conn, params)
     preloads = preload_data(conn, params)
+    title = "<title>#{Pleroma.Config.get([:instance, :name])}</title>"
 
     response =
       index_content
-      |> String.replace("<!--server-generated-meta-->", tags <> preloads)
+      |> String.replace("<!--server-generated-meta-->", tags <> preloads <> title)
 
     conn
     |> put_resp_content_type("text/html")
@@ -54,10 +55,11 @@ defmodule Pleroma.Web.Fallback.RedirectController do
   def redirector_with_preload(conn, params) do
     {:ok, index_content} = File.read(index_file_path())
     preloads = preload_data(conn, params)
+    title = "<title>#{Pleroma.Config.get([:instance, :name])}</title>"
 
     response =
       index_content
-      |> String.replace("<!--server-generated-meta-->", preloads)
+      |> String.replace("<!--server-generated-meta-->", preloads <> title)
 
     conn
     |> put_resp_content_type("text/html")
index 1ae03e7e28d2d3651cb91a9134168e7f50beb2b9..56c024617c9cb948083ed8d8413659a0da0f6e7b 100644 (file)
@@ -83,7 +83,7 @@ defmodule Pleroma.Web.Feed.FeedView do
 
   def activity_content(_), do: ""
 
-  def activity_context(activity), do: activity.data["context"]
+  def activity_context(activity), do: escape(activity.data["context"])
 
   def attachment_href(attachment) do
     attachment["url"]
index 435bcde157552b063deb98a72829c3527e6ea60f..7cbbd3750468a2f0d9f75c1f204348d5e6755bf6 100644 (file)
@@ -435,7 +435,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
       text_url: href,
       type: type,
       description: attachment["name"],
-      pleroma: %{mime_type: media_type}
+      pleroma: %{mime_type: media_type},
+      blurhash: attachment["blurhash"]
     }
   end
 
index 78350f2aa194c8ca311a6db733155a55027871d4..3fd150c4e7570b6d54e449a87ffac7d1adc74d7a 100644 (file)
@@ -12,7 +12,7 @@
   <link href="<%= activity_context(@activity) %>" rel="ostatus:conversation"/>
 
   <%= if @data["summary"] do %>
-    <summary><%= @data["summary"] %></summary>
+    <summary><%= escape(@data["summary"]) %></summary>
   <% end %>
 
   <%= if @activity.local do %>
index a304a16afecec2827062775909c9c97d17a4de6e..42960de7d45f58926546a23145a8d1db60ad108f 100644 (file)
@@ -12,7 +12,7 @@
   <link rel="ostatus:conversation"><%= activity_context(@activity) %></link>
 
   <%= if @data["summary"] do %>
-    <description><%= @data["summary"] %></description>
+    <description><%= escape(@data["summary"]) %></description>
   <% end %>
 
   <%= if @activity.local do %>
diff --git a/priv/repo/migrations/20201113060459_remove_purge_expired_activity_worker_from_oban_config.exs b/priv/repo/migrations/20201113060459_remove_purge_expired_activity_worker_from_oban_config.exs
new file mode 100644 (file)
index 0000000..fe31f44
--- /dev/null
@@ -0,0 +1,19 @@
+defmodule Pleroma.Repo.Migrations.RemovePurgeExpiredActivityWorkerFromObanConfig do
+  use Ecto.Migration
+
+  def change do
+    with %Pleroma.ConfigDB{} = config <-
+           Pleroma.ConfigDB.get_by_params(%{group: :pleroma, key: Oban}),
+         crontab when is_list(crontab) <- config.value[:crontab],
+         index when is_integer(index) <-
+           Enum.find_index(crontab, fn {_, worker} ->
+             worker == Pleroma.Workers.Cron.PurgeExpiredActivitiesWorker
+           end) do
+      updated_value = Keyword.put(config.value, :crontab, List.delete_at(crontab, index))
+
+      config
+      |> Ecto.Changeset.change(value: updated_value)
+      |> Pleroma.Repo.update()
+    end
+  end
+end
index f5690a8d6fcaaf30bf6d640aecba6931bee21cd2..e848c5f8c1242d61a473fe198ed4916e324fa07e 100644 (file)
@@ -1 +1 @@
-<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1,user-scalable=no"><title>Pleroma</title><!--server-generated-meta--><link rel=icon type=image/png href=/favicon.png><link href=/static/css/app.77b1644622e3bae24b6b.css rel=stylesheet><link href=/static/fontello.1600365488745.css rel=stylesheet></head><body class=hidden><noscript>To use Pleroma, please enable JavaScript.</noscript><div id=app></div><script type=text/javascript src=/static/js/vendors~app.90c4af83c1ae68f4cd95.js></script><script type=text/javascript src=/static/js/app.826c44232e0a76bbd9ba.js></script></body></html>
\ No newline at end of file
+<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1,user-scalable=no"><!--server-generated-meta--><link rel=icon type=image/png href=/favicon.png><link href=/static/css/app.77b1644622e3bae24b6b.css rel=stylesheet><link href=/static/fontello.1600365488745.css rel=stylesheet></head><body class=hidden><noscript>To use Pleroma, please enable JavaScript.</noscript><div id=app></div><script type=text/javascript src=/static/js/vendors~app.90c4af83c1ae68f4cd95.js></script><script type=text/javascript src=/static/js/app.826c44232e0a76bbd9ba.js></script></body></html>
diff --git a/test/fixtures/modules/good_mrf.ex b/test/fixtures/modules/good_mrf.ex
new file mode 100644 (file)
index 0000000..39d0f14
--- /dev/null
@@ -0,0 +1,19 @@
+defmodule Fixtures.Modules.GoodMRF do
+  @behaviour Pleroma.Web.ActivityPub.MRF
+
+  @impl true
+  def filter(a), do: {:ok, a}
+
+  @impl true
+  def describe, do: %{}
+
+  @impl true
+  def config_description do
+    %{
+      key: :good_mrf,
+      related_policy: "Fixtures.Modules.GoodMRF",
+      label: "Good MRF",
+      description: "Some description"
+    }
+  end
+end
diff --git a/test/fixtures/spoofed-object.json b/test/fixtures/spoofed-object.json
new file mode 100644 (file)
index 0000000..91e3430
--- /dev/null
@@ -0,0 +1,26 @@
+{
+  "@context": [
+    "https://www.w3.org/ns/activitystreams",
+    "https://patch.cx/schemas/litepub-0.1.jsonld",
+    {
+      "@language": "und"
+    }
+  ],
+  "actor": "https://patch.cx/users/rin",
+  "attachment": [],
+  "attributedTo": "https://patch.cx/users/rin",
+  "cc": [
+    "https://patch.cx/users/rin/followers"
+  ],
+  "content": "Oracle Corporation (NYSE: ORCL) today announced that it has signed a definitive merger agreement to acquire Pleroma AG (FRA: PLA), for $26.50 per share (approximately $10.3 billion). The transaction has been approved by the boards of directors of both companies and should close by early January.",
+  "context": "https://patch.cx/contexts/spoof",
+  "id": "https://patch.cx/objects/spoof",
+  "published": "2020-10-23T18:02:06.038856Z",
+  "sensitive": false,
+  "summary": "Oracle buys Pleroma",
+  "tag": [],
+  "to": [
+    "https://www.w3.org/ns/activitystreams#Public"
+  ],
+  "type": "Note"
+}
index fe69a2def027b752dd0f44c9394c647658fac8bf..8a02710ee2b336e7aed49b167de6217c711c6500 100644 (file)
@@ -5,8 +5,6 @@
 defmodule Mix.Tasks.Pleroma.InstanceTest do
   use ExUnit.Case
 
-  @release_env_file "./test/pleroma.test.env"
-
   setup do
     File.mkdir_p!(tmp_path())
 
@@ -18,8 +16,6 @@ defmodule Mix.Tasks.Pleroma.InstanceTest do
         File.rm_rf(Path.join(static_dir, "robots.txt"))
       end
 
-      if File.exists?(@release_env_file), do: File.rm_rf(@release_env_file)
-
       Pleroma.Config.put([:instance, :static_dir], static_dir)
     end)
 
@@ -73,9 +69,7 @@ defmodule Mix.Tasks.Pleroma.InstanceTest do
         "--dedupe-uploads",
         "n",
         "--anonymize-uploads",
-        "n",
-        "--release-env-file",
-        @release_env_file
+        "n"
       ])
     end
 
@@ -97,9 +91,6 @@ defmodule Mix.Tasks.Pleroma.InstanceTest do
     assert generated_config =~ "filters: [Pleroma.Upload.Filter.ExifTool]"
     assert File.read!(tmp_path() <> "setup.psql") == generated_setup_psql()
     assert File.exists?(Path.expand("./test/instance/static/robots.txt"))
-    assert File.exists?(@release_env_file)
-
-    assert File.read!(@release_env_file) =~ ~r/^RELEASE_COOKIE=.*/
   end
 
   defp generated_setup_psql do
diff --git a/test/mix/tasks/pleroma/release_env_test.exs b/test/mix/tasks/pleroma/release_env_test.exs
deleted file mode 100644 (file)
index 519f1eb..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright Â© 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Mix.Tasks.Pleroma.ReleaseEnvTest do
-  use ExUnit.Case
-  import ExUnit.CaptureIO, only: [capture_io: 1]
-
-  @path "config/pleroma.test.env"
-
-  def do_clean do
-    if File.exists?(@path) do
-      File.rm_rf(@path)
-    end
-  end
-
-  setup do
-    do_clean()
-    on_exit(fn -> do_clean() end)
-    :ok
-  end
-
-  test "generate pleroma.env" do
-    assert capture_io(fn ->
-             Mix.Tasks.Pleroma.ReleaseEnv.run(["gen", "--path", @path, "--force"])
-           end) =~ "The file generated"
-
-    assert File.read!(@path) =~ "RELEASE_COOKIE="
-  end
-end
index 155057f3e1b2a399801202e688829347e48a140e..0da0699ccddf3a4c8144372f9d260a54c2989291 100644 (file)
@@ -19,8 +19,8 @@ defmodule Pleroma.Emails.AdminEmailTest do
       AdminEmail.report(to_user, reporter, account, [%{name: "Test", id: "12"}], "Test comment")
 
     status_url = Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, "12")
-    reporter_url = Helpers.user_feed_url(Pleroma.Web.Endpoint, :feed_redirect, reporter.id)
-    account_url = Helpers.user_feed_url(Pleroma.Web.Endpoint, :feed_redirect, account.id)
+    reporter_url = reporter.ap_id
+    account_url = account.ap_id
 
     assert res.to == [{to_user.name, to_user.email}]
     assert res.from == {config[:name], config[:notify_email]}
@@ -54,7 +54,7 @@ defmodule Pleroma.Emails.AdminEmailTest do
 
     res = AdminEmail.new_unapproved_registration(to_user, account)
 
-    account_url = Helpers.user_feed_url(Pleroma.Web.Endpoint, :feed_redirect, account.id)
+    account_url = account.ap_id
 
     assert res.to == [{to_user.name, to_user.email}]
     assert res.from == {config[:name], config[:notify_email]}
index 14d2c645fe4fbbbc83f62bc70b157eef0e9ff345..7df6af7fe57f7907a71e4df74437dbce027d3f07 100644 (file)
@@ -21,6 +21,17 @@ defmodule Pleroma.Object.FetcherTest do
       %{method: :get, url: "https://mastodon.example.org/users/userisgone404"} ->
         %Tesla.Env{status: 404}
 
+      %{
+        method: :get,
+        url:
+          "https://patch.cx/media/03ca3c8b4ac3ddd08bf0f84be7885f2f88de0f709112131a22d83650819e36c2.json"
+      } ->
+        %Tesla.Env{
+          status: 200,
+          headers: [{"content-type", "application/json"}],
+          body: File.read!("test/fixtures/spoofed-object.json")
+        }
+
       env ->
         apply(HttpRequestMock, :request, [env])
     end)
@@ -34,19 +45,22 @@ defmodule Pleroma.Object.FetcherTest do
         %{method: :get, url: "https://social.sakamoto.gq/notice/9wTkLEnuq47B25EehM"} ->
           %Tesla.Env{
             status: 200,
-            body: File.read!("test/fixtures/fetch_mocks/9wTkLEnuq47B25EehM.json")
+            body: File.read!("test/fixtures/fetch_mocks/9wTkLEnuq47B25EehM.json"),
+            headers: HttpRequestMock.activitypub_object_headers()
           }
 
         %{method: :get, url: "https://social.sakamoto.gq/users/eal"} ->
           %Tesla.Env{
             status: 200,
-            body: File.read!("test/fixtures/fetch_mocks/eal.json")
+            body: File.read!("test/fixtures/fetch_mocks/eal.json"),
+            headers: HttpRequestMock.activitypub_object_headers()
           }
 
         %{method: :get, url: "https://busshi.moe/users/tuxcrafting/statuses/104410921027210069"} ->
           %Tesla.Env{
             status: 200,
-            body: File.read!("test/fixtures/fetch_mocks/104410921027210069.json")
+            body: File.read!("test/fixtures/fetch_mocks/104410921027210069.json"),
+            headers: HttpRequestMock.activitypub_object_headers()
           }
 
         %{method: :get, url: "https://busshi.moe/users/tuxcrafting"} ->
@@ -132,6 +146,13 @@ defmodule Pleroma.Object.FetcherTest do
                  "http://mastodon.example.org/@admin/99541947525187367"
                )
     end
+
+    test "it does not fetch a spoofed object uploaded on an instance as an attachment" do
+      assert {:error, _} =
+               Fetcher.fetch_object_from_id(
+                 "https://patch.cx/media/03ca3c8b4ac3ddd08bf0f84be7885f2f88de0f709112131a22d83650819e36c2.json"
+               )
+    end
   end
 
   describe "implementation quirks" do
index 99caba3369ef289d979c46bb22fe77c7b7e88adb..5d4e6fb84691cb904aec72f4cafb10777718f92b 100644 (file)
@@ -281,7 +281,11 @@ defmodule Pleroma.ObjectTest do
     setup do
       mock(fn
         %{method: :get, url: "https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d"} ->
-          %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/poll_original.json")}
+          %Tesla.Env{
+            status: 200,
+            body: File.read!("test/fixtures/tesla_mock/poll_original.json"),
+            headers: HttpRequestMock.activitypub_object_headers()
+          }
 
         env ->
           apply(HttpRequestMock, :request, [env])
@@ -315,7 +319,8 @@ defmodule Pleroma.ObjectTest do
 
       mock_modified.(%Tesla.Env{
         status: 200,
-        body: File.read!("test/fixtures/tesla_mock/poll_modified.json")
+        body: File.read!("test/fixtures/tesla_mock/poll_modified.json"),
+        headers: HttpRequestMock.activitypub_object_headers()
       })
 
       updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: -1)
@@ -359,7 +364,8 @@ defmodule Pleroma.ObjectTest do
 
       mock_modified.(%Tesla.Env{
         status: 200,
-        body: File.read!("test/fixtures/tesla_mock/poll_modified.json")
+        body: File.read!("test/fixtures/tesla_mock/poll_modified.json"),
+        headers: HttpRequestMock.activitypub_object_headers()
       })
 
       updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: 100)
@@ -387,7 +393,8 @@ defmodule Pleroma.ObjectTest do
 
       mock_modified.(%Tesla.Env{
         status: 200,
-        body: File.read!("test/fixtures/tesla_mock/poll_modified.json")
+        body: File.read!("test/fixtures/tesla_mock/poll_modified.json"),
+        headers: HttpRequestMock.activitypub_object_headers()
       })
 
       updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: -1)
index 43bd14ee6f6de018089b9d8bd04ad37581340743..3eeb0f7358e9df94baf422a9bbc12ee09a2676fc 100644 (file)
@@ -1426,19 +1426,25 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
       mock(fn env ->
         case env.url do
           "http://localhost:4001/users/masto_hidden_counters/following" ->
-            json(%{
-              "@context" => "https://www.w3.org/ns/activitystreams",
-              "id" => "http://localhost:4001/users/masto_hidden_counters/followers"
-            })
+            json(
+              %{
+                "@context" => "https://www.w3.org/ns/activitystreams",
+                "id" => "http://localhost:4001/users/masto_hidden_counters/followers"
+              },
+              headers: HttpRequestMock.activitypub_object_headers()
+            )
 
           "http://localhost:4001/users/masto_hidden_counters/following?page=1" ->
             %Tesla.Env{status: 403, body: ""}
 
           "http://localhost:4001/users/masto_hidden_counters/followers" ->
-            json(%{
-              "@context" => "https://www.w3.org/ns/activitystreams",
-              "id" => "http://localhost:4001/users/masto_hidden_counters/following"
-            })
+            json(
+              %{
+                "@context" => "https://www.w3.org/ns/activitystreams",
+                "id" => "http://localhost:4001/users/masto_hidden_counters/following"
+              },
+              headers: HttpRequestMock.activitypub_object_headers()
+            )
 
           "http://localhost:4001/users/masto_hidden_counters/followers?page=1" ->
             %Tesla.Env{status: 403, body: ""}
@@ -2278,7 +2284,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
     Tesla.Mock.mock(fn
       %{method: :get, url: "https://princess.cat/users/mewmew"} ->
         file = File.read!("test/fixtures/mewmew_no_name.json")
-        %Tesla.Env{status: 200, body: file}
+        %Tesla.Env{status: 200, body: file, headers: HttpRequestMock.activitypub_object_headers()}
     end)
 
     {:ok, user} = ActivityPub.make_user_from_ap_id("https://princess.cat/users/mewmew")
index e8cdde2e1f82a91c7f7bb6b8ed053b838da44f86..44a9cf086b51f6e64a6b26cc825b1e8957911a51 100644 (file)
@@ -87,4 +87,20 @@ defmodule Pleroma.Web.ActivityPub.MRFTest do
       {:ok, ^expected} = MRF.describe()
     end
   end
+
+  test "config_descriptions/0" do
+    descriptions = MRF.config_descriptions()
+
+    good_mrf = Enum.find(descriptions, fn %{key: key} -> key == :good_mrf end)
+
+    assert good_mrf == %{
+             key: :good_mrf,
+             related_policy: "Fixtures.Modules.GoodMRF",
+             label: "Good MRF",
+             description: "Some description",
+             group: :pleroma,
+             tab: :mrf,
+             type: :group
+           }
+  end
 end
index 760388e802434261813b56319b864552686be23d..2e1975a7995504c0c822e9107c893a0f6d8cd1e3 100644 (file)
@@ -33,7 +33,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidatorTest do
           "http://mastodon.example.org/system/media_attachments/files/000/000/002/original/334ce029e7bfb920.jpg",
         "type" => "Document",
         "name" => nil,
-        "mediaType" => "image/jpeg"
+        "mediaType" => "image/jpeg",
+        "blurhash" => "UD9jJz~VSbR#xT$~%KtQX9R,WAs9RjWBs:of"
       }
 
       {:ok, attachment} =
@@ -50,6 +51,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidatorTest do
              ] = attachment.url
 
       assert attachment.mediaType == "image/jpeg"
+      assert attachment.blurhash == "UD9jJz~VSbR#xT$~%KtQX9R,WAs9RjWBs:of"
     end
 
     test "it handles our own uploads" do
index 54335acdbb011c9f126d63badb7c49f0fec126d5..99c296c74ba2bd4f7047d4af8da1760449c34e4c 100644 (file)
@@ -60,7 +60,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnnounceHandlingTest do
 
     Tesla.Mock.mock(fn
       %{method: :get} ->
-        %Tesla.Env{status: 200, body: File.read!("test/fixtures/mastodon-note-object.json")}
+        %Tesla.Env{
+          status: 200,
+          body: File.read!("test/fixtures/mastodon-note-object.json"),
+          headers: HttpRequestMock.activitypub_object_headers()
+        }
     end)
 
     _user = insert(:user, local: false, ap_id: data["actor"])
index 9b12a470ae2f8982d2610a2316a58c68e39eb577..b0ae804c50dccd41b42602bc1632a977e0d09f8b 100644 (file)
@@ -13,7 +13,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.ArticleHandlingTest do
 
   test "Pterotype (Wordpress Plugin) Article" do
     Tesla.Mock.mock(fn %{url: "https://wedistribute.org/wp-json/pterotype/v1/actor/-blog"} ->
-      %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/wedistribute-user.json")}
+      %Tesla.Env{
+        status: 200,
+        body: File.read!("test/fixtures/tesla_mock/wedistribute-user.json"),
+        headers: HttpRequestMock.activitypub_object_headers()
+      }
     end)
 
     data =
@@ -36,13 +40,15 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.ArticleHandlingTest do
       %{url: "https://baptiste.gelez.xyz/~/PlumeDevelopment/this-month-in-plume-june-2018/"} ->
         %Tesla.Env{
           status: 200,
-          body: File.read!("test/fixtures/tesla_mock/baptiste.gelex.xyz-article.json")
+          body: File.read!("test/fixtures/tesla_mock/baptiste.gelex.xyz-article.json"),
+          headers: HttpRequestMock.activitypub_object_headers()
         }
 
       %{url: "https://baptiste.gelez.xyz/@/BaptisteGelez"} ->
         %Tesla.Env{
           status: 200,
-          body: File.read!("test/fixtures/tesla_mock/baptiste.gelex.xyz-user.json")
+          body: File.read!("test/fixtures/tesla_mock/baptiste.gelex.xyz-user.json"),
+          headers: HttpRequestMock.activitypub_object_headers()
         }
     end)
 
@@ -61,7 +67,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.ArticleHandlingTest do
     Tesla.Mock.mock(fn %{url: "https://prismo.news/@mxb"} ->
       %Tesla.Env{
         status: 200,
-        body: File.read!("test/fixtures/tesla_mock/https___prismo.news__mxb.json")
+        body: File.read!("test/fixtures/tesla_mock/https___prismo.news__mxb.json"),
+        headers: HttpRequestMock.activitypub_object_headers()
       }
     end)
 
index 0636d00c5bd5b9cf646dee332df67388459cc286..6eeb1c863a1f20ac9d2993d1b807790e932a0095 100644 (file)
@@ -48,7 +48,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AudioHandlingTest do
       %{url: "https://channels.tests.funkwhale.audio/federation/actors/compositions"} ->
         %Tesla.Env{
           status: 200,
-          body: File.read!("test/fixtures/tesla_mock/funkwhale_channel.json")
+          body: File.read!("test/fixtures/tesla_mock/funkwhale_channel.json"),
+          headers: HttpRequestMock.activitypub_object_headers()
         }
     end)
 
@@ -69,6 +70,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AudioHandlingTest do
                "mediaType" => "audio/ogg",
                "type" => "Link",
                "name" => nil,
+               "blurhash" => nil,
                "url" => [
                  %{
                    "href" =>
index 7f1ef2cbd446ba3cdb958c7c1fbb5c04c12f829e..d7c55cfbec73a631b81afaf97ef6fa827bf35446 100644 (file)
@@ -13,13 +13,15 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.EventHandlingTest do
       %{url: "https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39"} ->
         %Tesla.Env{
           status: 200,
-          body: File.read!("test/fixtures/tesla_mock/mobilizon.org-event.json")
+          body: File.read!("test/fixtures/tesla_mock/mobilizon.org-event.json"),
+          headers: HttpRequestMock.activitypub_object_headers()
         }
 
       %{url: "https://mobilizon.org/@tcit"} ->
         %Tesla.Env{
           status: 200,
-          body: File.read!("test/fixtures/tesla_mock/mobilizon.org-user.json")
+          body: File.read!("test/fixtures/tesla_mock/mobilizon.org-user.json"),
+          headers: HttpRequestMock.activitypub_object_headers()
         }
     end)
 
index 69c953a2edfe4a41003e85633ac33e8788c999de..57411fafacd2f6491b7c64817b5c81909dd2dd5d 100644 (file)
@@ -54,6 +54,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.VideoHandlingTest do
                "type" => "Link",
                "mediaType" => "video/mp4",
                "name" => nil,
+               "blurhash" => nil,
                "url" => [
                  %{
                    "href" =>
@@ -76,6 +77,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.VideoHandlingTest do
                "type" => "Link",
                "mediaType" => "video/mp4",
                "name" => nil,
+               "blurhash" => nil,
                "url" => [
                  %{
                    "href" =>
index a658658603fcb0efce803a0bf52b92f5a5285d31..46c7bad1cf55037d5ceb777e138892944bfba1cd 100644 (file)
@@ -20,15 +20,26 @@ defmodule Pleroma.Web.FallbackTest do
     end
   end
 
+  test "GET /*path adds a title", %{conn: conn} do
+    clear_config([:instance, :name], "a cool title")
+
+    assert conn
+           |> get("/")
+           |> html_response(200) =~ "<title>a cool title</title>"
+  end
+
   describe "preloaded data and metadata attached to" do
     test "GET /:maybe_nickname_or_id", %{conn: conn} do
+      clear_config([:instance, :name], "a cool title")
+
       user = insert(:user)
       user_missing = get(conn, "/foo")
       user_present = get(conn, "/#{user.nickname}")
 
-      assert(html_response(user_missing, 200) =~ "<!--server-generated-meta-->")
+      assert html_response(user_missing, 200) =~ "<!--server-generated-meta-->"
       refute html_response(user_present, 200) =~ "<!--server-generated-meta-->"
       assert html_response(user_present, 200) =~ "initial-results"
+      assert html_response(user_present, 200) =~ "<title>a cool title</title>"
     end
 
     test "GET /*path", %{conn: conn} do
@@ -44,10 +55,13 @@ defmodule Pleroma.Web.FallbackTest do
 
   describe "preloaded data is attached to" do
     test "GET /main/public", %{conn: conn} do
+      clear_config([:instance, :name], "a cool title")
+
       public_page = get(conn, "/main/public")
 
       refute html_response(public_page, 200) =~ "<!--server-generated-meta-->"
       assert html_response(public_page, 200) =~ "initial-results"
+      assert html_response(public_page, 200) =~ "<title>a cool title</title>"
     end
 
     test "GET /main/all", %{conn: conn} do
index eabfe3a6383449a008b19796950f0f9eca193b4e..16f00271704fee1e19999a5179025c38ab5805e9 100644 (file)
@@ -12,16 +12,17 @@ defmodule Pleroma.Web.Feed.UserControllerTest do
   alias Pleroma.Object
   alias Pleroma.User
   alias Pleroma.Web.CommonAPI
+  alias Pleroma.Web.Feed.FeedView
 
   setup do: clear_config([:static_fe, :enabled], false)
 
   describe "feed" do
     setup do: clear_config([:feed])
 
-    test "gets an atom feed", %{conn: conn} do
+    setup do
       Config.put(
         [:feed, :post_title],
-        %{max_length: 10, omission: "..."}
+        %{max_length: 15, omission: "..."}
       )
 
       activity = insert(:note_activity)
@@ -29,7 +30,8 @@ defmodule Pleroma.Web.Feed.UserControllerTest do
       note =
         insert(:note,
           data: %{
-            "content" => "This is :moominmamma: note ",
+            "content" => "This & this is :moominmamma: note ",
+            "source" => "This & this is :moominmamma: note ",
             "attachment" => [
               %{
                 "url" => [
@@ -37,7 +39,9 @@ defmodule Pleroma.Web.Feed.UserControllerTest do
                 ]
               }
             ],
-            "inReplyTo" => activity.data["id"]
+            "inReplyTo" => activity.data["id"],
+            "context" => "2hu & as",
+            "summary" => "2hu & as"
           }
         )
 
@@ -48,7 +52,7 @@ defmodule Pleroma.Web.Feed.UserControllerTest do
         insert(:note,
           user: user,
           data: %{
-            "content" => "42 This is :moominmamma: note ",
+            "content" => "42 This is :moominmamma: note ",
             "inReplyTo" => activity.data["id"]
           }
         )
@@ -56,6 +60,10 @@ defmodule Pleroma.Web.Feed.UserControllerTest do
       note_activity2 = insert(:note_activity, note: note2)
       object = Object.normalize(note_activity)
 
+      [user: user, object: object, max_id: note_activity2.id]
+    end
+
+    test "gets an atom feed", %{conn: conn, user: user, object: object, max_id: max_id} do
       resp =
         conn
         |> put_req_header("accept", "application/atom+xml")
@@ -67,13 +75,15 @@ defmodule Pleroma.Web.Feed.UserControllerTest do
         |> SweetXml.parse()
         |> SweetXml.xpath(~x"//entry/title/text()"l)
 
-      assert activity_titles == ['42 This...', 'This is...']
-      assert resp =~ object.data["content"]
+      assert activity_titles == ['42 &amp; Thi...', 'This &amp; t...']
+      assert resp =~ FeedView.escape(object.data["content"])
+      assert resp =~ FeedView.escape(object.data["summary"])
+      assert resp =~ FeedView.escape(object.data["context"])
 
       resp =
         conn
         |> put_req_header("accept", "application/atom+xml")
-        |> get("/users/#{user.nickname}/feed", %{"max_id" => note_activity2.id})
+        |> get("/users/#{user.nickname}/feed", %{"max_id" => max_id})
         |> response(200)
 
       activity_titles =
@@ -81,47 +91,10 @@ defmodule Pleroma.Web.Feed.UserControllerTest do
         |> SweetXml.parse()
         |> SweetXml.xpath(~x"//entry/title/text()"l)
 
-      assert activity_titles == ['This is...']
+      assert activity_titles == ['This &amp; t...']
     end
 
-    test "gets a rss feed", %{conn: conn} do
-      Pleroma.Config.put(
-        [:feed, :post_title],
-        %{max_length: 10, omission: "..."}
-      )
-
-      activity = insert(:note_activity)
-
-      note =
-        insert(:note,
-          data: %{
-            "content" => "This is :moominmamma: note ",
-            "attachment" => [
-              %{
-                "url" => [
-                  %{"mediaType" => "image/png", "href" => "https://pleroma.gov/image.png"}
-                ]
-              }
-            ],
-            "inReplyTo" => activity.data["id"]
-          }
-        )
-
-      note_activity = insert(:note_activity, note: note)
-      user = User.get_cached_by_ap_id(note_activity.data["actor"])
-
-      note2 =
-        insert(:note,
-          user: user,
-          data: %{
-            "content" => "42 This is :moominmamma: note ",
-            "inReplyTo" => activity.data["id"]
-          }
-        )
-
-      note_activity2 = insert(:note_activity, note: note2)
-      object = Object.normalize(note_activity)
-
+    test "gets a rss feed", %{conn: conn, user: user, object: object, max_id: max_id} do
       resp =
         conn
         |> put_req_header("accept", "application/rss+xml")
@@ -133,13 +106,15 @@ defmodule Pleroma.Web.Feed.UserControllerTest do
         |> SweetXml.parse()
         |> SweetXml.xpath(~x"//item/title/text()"l)
 
-      assert activity_titles == ['42 This...', 'This is...']
-      assert resp =~ object.data["content"]
+      assert activity_titles == ['42 &amp; Thi...', 'This &amp; t...']
+      assert resp =~ FeedView.escape(object.data["content"])
+      assert resp =~ FeedView.escape(object.data["summary"])
+      assert resp =~ FeedView.escape(object.data["context"])
 
       resp =
         conn
         |> put_req_header("accept", "application/rss+xml")
-        |> get("/users/#{user.nickname}/feed.rss", %{"max_id" => note_activity2.id})
+        |> get("/users/#{user.nickname}/feed.rss", %{"max_id" => max_id})
         |> response(200)
 
       activity_titles =
@@ -147,7 +122,7 @@ defmodule Pleroma.Web.Feed.UserControllerTest do
         |> SweetXml.parse()
         |> SweetXml.xpath(~x"//item/title/text()"l)
 
-      assert activity_titles == ['This is...']
+      assert activity_titles == ['This &amp; t...']
     end
 
     test "returns 404 for a missing feed", %{conn: conn} do
index 70d829979bb0cde71f47aec6fee8c92be1158196..665199f972349f9f42c5f24ce027e05e63a5c7cd 100644 (file)
@@ -420,6 +420,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
           "href" => "someurl"
         }
       ],
+      "blurhash" => "UJJ8X[xYW,%Jtq%NNFbXB5j]IVM|9GV=WHRn",
       "uuid" => 6
     }
 
@@ -431,7 +432,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
       preview_url: "someurl",
       text_url: "someurl",
       description: nil,
-      pleroma: %{mime_type: "image/png"}
+      pleroma: %{mime_type: "image/png"},
+      blurhash: "UJJ8X[xYW,%Jtq%NNFbXB5j]IVM|9GV=WHRn"
     }
 
     api_spec = Pleroma.Web.ApiSpec.spec()
index cb022333f369a718a3eaf2f4f8c4768eaacbdfb0..93464ebffa9efceed0d6e49b6cf7077791a0bb1b 100644 (file)
@@ -5,6 +5,8 @@
 defmodule HttpRequestMock do
   require Logger
 
+  def activitypub_object_headers, do: [{"content-type", "application/activity+json"}]
+
   def request(
         %Tesla.Env{
           url: url,
@@ -34,7 +36,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/https___osada.macgirvin.com_channel_mike.json")
+       body: File.read!("test/fixtures/tesla_mock/https___osada.macgirvin.com_channel_mike.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -42,7 +45,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/moonman@shitposter.club.json")
+       body: File.read!("test/fixtures/tesla_mock/moonman@shitposter.club.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -50,7 +54,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/status.emelie.json")
+       body: File.read!("test/fixtures/tesla_mock/status.emelie.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -66,7 +71,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/emelie.json")
+       body: File.read!("test/fixtures/tesla_mock/emelie.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -78,7 +84,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/rinpatch.json")
+       body: File.read!("test/fixtures/tesla_mock/rinpatch.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -86,7 +93,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/poll_attachment.json")
+       body: File.read!("test/fixtures/tesla_mock/poll_attachment.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -99,7 +107,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/webfinger_emelie.json")
+       body: File.read!("test/fixtures/tesla_mock/webfinger_emelie.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -112,7 +121,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/mike@osada.macgirvin.com.json")
+       body: File.read!("test/fixtures/tesla_mock/mike@osada.macgirvin.com.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -190,7 +200,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/lucifermysticus.json")
+       body: File.read!("test/fixtures/tesla_mock/lucifermysticus.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -198,7 +209,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/https___prismo.news__mxb.json")
+       body: File.read!("test/fixtures/tesla_mock/https___prismo.news__mxb.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -211,7 +223,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/kaniini@hubzilla.example.org.json")
+       body: File.read!("test/fixtures/tesla_mock/kaniini@hubzilla.example.org.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -219,7 +232,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/rye.json")
+       body: File.read!("test/fixtures/tesla_mock/rye.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -227,7 +241,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/rye.json")
+       body: File.read!("test/fixtures/tesla_mock/rye.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -246,7 +261,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/puckipedia.com.json")
+       body: File.read!("test/fixtures/tesla_mock/puckipedia.com.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -254,7 +270,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/7even.json")
+       body: File.read!("test/fixtures/tesla_mock/7even.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -262,7 +279,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/peertube.moe-vid.json")
+       body: File.read!("test/fixtures/tesla_mock/peertube.moe-vid.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -270,7 +288,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/https___framatube.org_accounts_framasoft.json")
+       body: File.read!("test/fixtures/tesla_mock/https___framatube.org_accounts_framasoft.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -278,7 +297,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/framatube.org-video.json")
+       body: File.read!("test/fixtures/tesla_mock/framatube.org-video.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -286,7 +306,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/craigmaloney.json")
+       body: File.read!("test/fixtures/tesla_mock/craigmaloney.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -294,7 +315,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/peertube-social.json")
+       body: File.read!("test/fixtures/tesla_mock/peertube-social.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -304,7 +326,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/mobilizon.org-event.json")
+       body: File.read!("test/fixtures/tesla_mock/mobilizon.org-event.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -312,7 +335,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/mobilizon.org-user.json")
+       body: File.read!("test/fixtures/tesla_mock/mobilizon.org-user.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -320,7 +344,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/baptiste.gelex.xyz-user.json")
+       body: File.read!("test/fixtures/tesla_mock/baptiste.gelex.xyz-user.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -328,7 +353,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/baptiste.gelex.xyz-article.json")
+       body: File.read!("test/fixtures/tesla_mock/baptiste.gelex.xyz-article.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -336,7 +362,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/wedistribute-article.json")
+       body: File.read!("test/fixtures/tesla_mock/wedistribute-article.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -344,7 +371,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/wedistribute-user.json")
+       body: File.read!("test/fixtures/tesla_mock/wedistribute-user.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -352,7 +380,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/admin@mastdon.example.org.json")
+       body: File.read!("test/fixtures/tesla_mock/admin@mastdon.example.org.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -362,7 +391,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/relay@mastdon.example.org.json")
+       body: File.read!("test/fixtures/tesla_mock/relay@mastdon.example.org.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -482,7 +512,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/pekorino@pawoo.net_host_meta.json")
+       body: File.read!("test/fixtures/tesla_mock/pekorino@pawoo.net_host_meta.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -543,7 +574,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/mastodon-note-object.json")
+       body: File.read!("test/fixtures/mastodon-note-object.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -567,7 +599,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/mayumayu.json")
+       body: File.read!("test/fixtures/tesla_mock/mayumayu.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -580,7 +613,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/mayumayupost.json")
+       body: File.read!("test/fixtures/tesla_mock/mayumayupost.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -795,7 +829,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/winterdienst_webfinger.json")
+       body: File.read!("test/fixtures/tesla_mock/winterdienst_webfinger.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -867,12 +902,21 @@ defmodule HttpRequestMock do
   end
 
   def get("https://mastodon.social/users/lambadalambda", _, _, _) do
-    {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/lambadalambda.json")}}
+    {:ok,
+     %Tesla.Env{
+       status: 200,
+       body: File.read!("test/fixtures/lambadalambda.json"),
+       headers: activitypub_object_headers()
+     }}
   end
 
   def get("https://apfed.club/channel/indio", _, _, _) do
     {:ok,
-     %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/osada-user-indio.json")}}
+     %Tesla.Env{
+       status: 200,
+       body: File.read!("test/fixtures/tesla_mock/osada-user-indio.json"),
+       headers: activitypub_object_headers()
+     }}
   end
 
   def get("https://social.heldscal.la/user/23211", _, _, [{"accept", "application/activity+json"}]) do
@@ -895,7 +939,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/users_mock/masto_closed_followers.json")
+       body: File.read!("test/fixtures/users_mock/masto_closed_followers.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -903,7 +948,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/users_mock/masto_closed_followers_page.json")
+       body: File.read!("test/fixtures/users_mock/masto_closed_followers_page.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -911,7 +957,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/users_mock/masto_closed_following.json")
+       body: File.read!("test/fixtures/users_mock/masto_closed_following.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -919,7 +966,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/users_mock/masto_closed_following_page.json")
+       body: File.read!("test/fixtures/users_mock/masto_closed_following_page.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -927,7 +975,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/users_mock/friendica_followers.json")
+       body: File.read!("test/fixtures/users_mock/friendica_followers.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -935,7 +984,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/users_mock/friendica_following.json")
+       body: File.read!("test/fixtures/users_mock/friendica_following.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -943,7 +993,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/users_mock/pleroma_followers.json")
+       body: File.read!("test/fixtures/users_mock/pleroma_followers.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -951,7 +1002,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/users_mock/pleroma_following.json")
+       body: File.read!("test/fixtures/users_mock/pleroma_following.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -1049,7 +1101,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/https__info.pleroma.site_activity.json")
+       body: File.read!("test/fixtures/tesla_mock/https__info.pleroma.site_activity.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -1063,7 +1116,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/https__info.pleroma.site_activity2.json")
+       body: File.read!("test/fixtures/tesla_mock/https__info.pleroma.site_activity2.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -1077,7 +1131,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/https__info.pleroma.site_activity3.json")
+       body: File.read!("test/fixtures/tesla_mock/https__info.pleroma.site_activity3.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -1110,7 +1165,12 @@ defmodule HttpRequestMock do
   end
 
   def get("http://mastodon.example.org/@admin/99541947525187367", _, _, _) do
-    {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/mastodon-post-activity.json")}}
+    {:ok,
+     %Tesla.Env{
+       status: 200,
+       body: File.read!("test/fixtures/mastodon-post-activity.json"),
+       headers: activitypub_object_headers()
+     }}
   end
 
   def get("https://info.pleroma.site/activity4.json", _, _, _) do
@@ -1137,7 +1197,8 @@ defmodule HttpRequestMock do
     {:ok,
      %Tesla.Env{
        status: 200,
-       body: File.read!("test/fixtures/tesla_mock/misskey_poll_no_end_date.json")
+       body: File.read!("test/fixtures/tesla_mock/misskey_poll_no_end_date.json"),
+       headers: activitypub_object_headers()
      }}
   end
 
@@ -1146,11 +1207,21 @@ defmodule HttpRequestMock do
   end
 
   def get("https://skippers-bin.com/users/7v1w1r8ce6", _, _, _) do
-    {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/sjw.json")}}
+    {:ok,
+     %Tesla.Env{
+       status: 200,
+       body: File.read!("test/fixtures/tesla_mock/sjw.json"),
+       headers: activitypub_object_headers()
+     }}
   end
 
   def get("https://patch.cx/users/rin", _, _, _) do
-    {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/rin.json")}}
+    {:ok,
+     %Tesla.Env{
+       status: 200,
+       body: File.read!("test/fixtures/tesla_mock/rin.json"),
+       headers: activitypub_object_headers()
+     }}
   end
 
   def get(
@@ -1160,12 +1231,20 @@ defmodule HttpRequestMock do
         _
       ) do
     {:ok,
-     %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/funkwhale_audio.json")}}
+     %Tesla.Env{
+       status: 200,
+       body: File.read!("test/fixtures/tesla_mock/funkwhale_audio.json"),
+       headers: activitypub_object_headers()
+     }}
   end
 
   def get("https://channels.tests.funkwhale.audio/federation/actors/compositions", _, _, _) do
     {:ok,
-     %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/funkwhale_channel.json")}}
+     %Tesla.Env{
+       status: 200,
+       body: File.read!("test/fixtures/tesla_mock/funkwhale_channel.json"),
+       headers: activitypub_object_headers()
+     }}
   end
 
   def get("http://example.com/rel_me/error", _, _, _) do
@@ -1173,7 +1252,12 @@ defmodule HttpRequestMock do
   end
 
   def get("https://relay.mastodon.host/actor", _, _, _) do
-    {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/relay/relay.json")}}
+    {:ok,
+     %Tesla.Env{
+       status: 200,
+       body: File.read!("test/fixtures/relay/relay.json"),
+       headers: activitypub_object_headers()
+     }}
   end
 
   def get("http://localhost:4001/", _, "", [{"accept", "text/html"}]) do