Merge branch 'develop' into feature/hide-follows-remote
This commit is contained in:
		
						commit
						c88a5d3251
					
				
					 43 changed files with 951 additions and 387 deletions
				
			
		| 
						 | 
				
			
			@ -6,10 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 | 
			
		|||
## [Unreleased]
 | 
			
		||||
### Changed
 | 
			
		||||
- **Breaking:** Configuration: A setting to explicitly disable the mailer was added, defaulting to true, if you are using a mailer add `config :pleroma, Pleroma.Emails.Mailer, enabled: true` to your config
 | 
			
		||||
- **Breaking:** Configuration: `/media/` is now removed when `base_url` is configured, append `/media/` to your `base_url` config to keep the old behaviour if desired
 | 
			
		||||
- Configuration: OpenGraph and TwitterCard providers enabled by default
 | 
			
		||||
- Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text
 | 
			
		||||
- Federation: Return 403 errors when trying to request pages from a user's follower/following collections if they have `hide_followers`/`hide_follows` set
 | 
			
		||||
- NodeInfo: Return `skipThreadContainment` in `metadata` for the `skip_thread_containment` option
 | 
			
		||||
- NodeInfo: Return `mailerEnabled` in `metadata`
 | 
			
		||||
- Mastodon API: Unsubscribe followers when they unfollow a user
 | 
			
		||||
- AdminAPI: Add "godmode" while fetching user statuses (i.e. admin can see private statuses)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -26,6 +28,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 | 
			
		|||
- Rich Media: Parser failing when no TTL can be found by image TTL setters
 | 
			
		||||
- Rich Media: The crawled URL is now spliced into the rich media data.
 | 
			
		||||
- ActivityPub S2S: sharedInbox usage has been mostly aligned with the rules in the AP specification.
 | 
			
		||||
- ActivityPub S2S: remote user deletions now work the same as local user deletions.
 | 
			
		||||
- Not being able to access the Mastodon FE login page on private instances
 | 
			
		||||
 | 
			
		||||
### Added
 | 
			
		||||
- MRF: Support for priming the mediaproxy cache (`Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy`)
 | 
			
		||||
| 
						 | 
				
			
			@ -57,6 +61,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 | 
			
		|||
- ActivityPub: Add an internal service actor for fetching ActivityPub objects.
 | 
			
		||||
- ActivityPub: Optional signing of ActivityPub object fetches.
 | 
			
		||||
- Admin API: Endpoint for fetching latest user's statuses
 | 
			
		||||
- Pleroma API: Add `/api/v1/pleroma/accounts/confirmation_resend?email=<email>` for resending account confirmation.
 | 
			
		||||
 | 
			
		||||
### Changed
 | 
			
		||||
- Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -534,7 +534,8 @@
 | 
			
		|||
  relation_id_action: {60_000, 2},
 | 
			
		||||
  statuses_actions: {10_000, 15},
 | 
			
		||||
  status_id_action: {60_000, 3},
 | 
			
		||||
  password_reset: {1_800_000, 5}
 | 
			
		||||
  password_reset: {1_800_000, 5},
 | 
			
		||||
  account_confirmation_resend: {8_640_000, 5}
 | 
			
		||||
 | 
			
		||||
# Import environment specific config. This must remain at the bottom
 | 
			
		||||
# of this file so it overrides the configuration defined above.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -245,6 +245,14 @@ See [Admin-API](Admin-API.md)
 | 
			
		|||
- PATCH `/api/v1/pleroma/accounts/update_banner`: Set/clear user banner image
 | 
			
		||||
- PATCH `/api/v1/pleroma/accounts/update_background`: Set/clear user background image
 | 
			
		||||
 | 
			
		||||
## `/api/v1/pleroma/accounts/confirmation_resend`
 | 
			
		||||
### Resend confirmation email
 | 
			
		||||
* Method `POST`
 | 
			
		||||
* Params:
 | 
			
		||||
    * `email`: email of that needs to be verified
 | 
			
		||||
* Authentication: not required
 | 
			
		||||
* Response: 204 No Content 
 | 
			
		||||
 | 
			
		||||
## `/api/v1/pleroma/mascot`
 | 
			
		||||
### Gets user mascot image
 | 
			
		||||
* Method `GET`
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,7 @@ defmodule Mix.Tasks.Pleroma.Database do
 | 
			
		|||
  alias Pleroma.Repo
 | 
			
		||||
  alias Pleroma.User
 | 
			
		||||
  require Logger
 | 
			
		||||
  require Pleroma.Constants
 | 
			
		||||
  import Mix.Pleroma
 | 
			
		||||
  use Mix.Task
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -99,10 +100,15 @@ def run(["prune_objects" | args]) do
 | 
			
		|||
      NaiveDateTime.utc_now()
 | 
			
		||||
      |> NaiveDateTime.add(-(deadline * 86_400))
 | 
			
		||||
 | 
			
		||||
    public = "https://www.w3.org/ns/activitystreams#Public"
 | 
			
		||||
 | 
			
		||||
    from(o in Object,
 | 
			
		||||
      where: fragment("?->'to' \\? ? OR ?->'cc' \\? ?", o.data, ^public, o.data, ^public),
 | 
			
		||||
      where:
 | 
			
		||||
        fragment(
 | 
			
		||||
          "?->'to' \\? ? OR ?->'cc' \\? ?",
 | 
			
		||||
          o.data,
 | 
			
		||||
          ^Pleroma.Constants.as_public(),
 | 
			
		||||
          o.data,
 | 
			
		||||
          ^Pleroma.Constants.as_public()
 | 
			
		||||
        ),
 | 
			
		||||
      where: o.inserted_at < ^time_deadline,
 | 
			
		||||
      where:
 | 
			
		||||
        fragment("split_part(?->>'actor', '/', 3) != ?", o.data, ^Pleroma.Web.Endpoint.host())
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,8 @@ defmodule Pleroma.Activity.Search do
 | 
			
		|||
  alias Pleroma.User
 | 
			
		||||
  alias Pleroma.Web.ActivityPub.Visibility
 | 
			
		||||
 | 
			
		||||
  require Pleroma.Constants
 | 
			
		||||
 | 
			
		||||
  import Ecto.Query
 | 
			
		||||
 | 
			
		||||
  def search(user, search_query, options \\ []) do
 | 
			
		||||
| 
						 | 
				
			
			@ -39,7 +41,7 @@ def maybe_restrict_author(query, _), do: query
 | 
			
		|||
  defp restrict_public(q) do
 | 
			
		||||
    from([a, o] in q,
 | 
			
		||||
      where: fragment("?->>'type' = 'Create'", a.data),
 | 
			
		||||
      where: "https://www.w3.org/ns/activitystreams#Public" in a.recipients
 | 
			
		||||
      where: ^Pleroma.Constants.as_public() in a.recipients
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										9
									
								
								lib/pleroma/constants.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								lib/pleroma/constants.ex
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
# Pleroma: A lightweight social networking server
 | 
			
		||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
 | 
			
		||||
# SPDX-License-Identifier: AGPL-3.0-only
 | 
			
		||||
 | 
			
		||||
defmodule Pleroma.Constants do
 | 
			
		||||
  use Const
 | 
			
		||||
 | 
			
		||||
  const(as_public, do: "https://www.w3.org/ns/activitystreams#Public")
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -11,6 +11,7 @@ defmodule Pleroma.HTTP.Connection do
 | 
			
		|||
    connect_timeout: 10_000,
 | 
			
		||||
    recv_timeout: 20_000,
 | 
			
		||||
    follow_redirect: true,
 | 
			
		||||
    force_redirect: true,
 | 
			
		||||
    pool: :federation
 | 
			
		||||
  ]
 | 
			
		||||
  @adapter Application.get_env(:tesla, :adapter)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,7 +15,7 @@ def key_id_to_actor_id(key_id) do
 | 
			
		|||
      |> Map.put(:fragment, nil)
 | 
			
		||||
 | 
			
		||||
    uri =
 | 
			
		||||
      if String.ends_with?(uri.path, "/publickey") do
 | 
			
		||||
      if not is_nil(uri.path) and String.ends_with?(uri.path, "/publickey") do
 | 
			
		||||
        Map.put(uri, :path, String.replace(uri.path, "/publickey", ""))
 | 
			
		||||
      else
 | 
			
		||||
        uri
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -477,7 +477,7 @@ def set_cache(%User{} = user) do
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def update_and_set_cache(changeset) do
 | 
			
		||||
    with {:ok, user} <- Repo.update(changeset) do
 | 
			
		||||
    with {:ok, user} <- Repo.update(changeset, stale_error_field: :id) do
 | 
			
		||||
      set_cache(user)
 | 
			
		||||
    else
 | 
			
		||||
      e -> e
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,6 +23,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
 | 
			
		|||
  import Pleroma.Web.ActivityPub.Visibility
 | 
			
		||||
 | 
			
		||||
  require Logger
 | 
			
		||||
  require Pleroma.Constants
 | 
			
		||||
 | 
			
		||||
  # For Announce activities, we filter the recipients based on following status for any actors
 | 
			
		||||
  # that match actual users.  See issue #164 for more information about why this is necessary.
 | 
			
		||||
| 
						 | 
				
			
			@ -207,8 +208,6 @@ def stream_out_participations(%Object{data: %{"context" => context}}, user) do
 | 
			
		|||
  def stream_out_participations(_, _), do: :noop
 | 
			
		||||
 | 
			
		||||
  def stream_out(activity) do
 | 
			
		||||
    public = "https://www.w3.org/ns/activitystreams#Public"
 | 
			
		||||
 | 
			
		||||
    if activity.data["type"] in ["Create", "Announce", "Delete"] do
 | 
			
		||||
      object = Object.normalize(activity)
 | 
			
		||||
      # Do not stream out poll replies
 | 
			
		||||
| 
						 | 
				
			
			@ -216,7 +215,7 @@ def stream_out(activity) do
 | 
			
		|||
        Pleroma.Web.Streamer.stream("user", activity)
 | 
			
		||||
        Pleroma.Web.Streamer.stream("list", activity)
 | 
			
		||||
 | 
			
		||||
        if Enum.member?(activity.data["to"], public) do
 | 
			
		||||
        if get_visibility(activity) == "public" do
 | 
			
		||||
          Pleroma.Web.Streamer.stream("public", activity)
 | 
			
		||||
 | 
			
		||||
          if activity.local do
 | 
			
		||||
| 
						 | 
				
			
			@ -238,13 +237,8 @@ def stream_out(activity) do
 | 
			
		|||
            end
 | 
			
		||||
          end
 | 
			
		||||
        else
 | 
			
		||||
          # TODO: Write test, replace with visibility test
 | 
			
		||||
          if !Enum.member?(activity.data["cc"] || [], public) &&
 | 
			
		||||
               !Enum.member?(
 | 
			
		||||
                 activity.data["to"],
 | 
			
		||||
                 User.get_cached_by_ap_id(activity.data["actor"]).follower_address
 | 
			
		||||
               ),
 | 
			
		||||
             do: Pleroma.Web.Streamer.stream("direct", activity)
 | 
			
		||||
          if get_visibility(activity) == "direct",
 | 
			
		||||
            do: Pleroma.Web.Streamer.stream("direct", activity)
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
| 
						 | 
				
			
			@ -514,7 +508,7 @@ def flag(
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  defp fetch_activities_for_context_query(context, opts) do
 | 
			
		||||
    public = ["https://www.w3.org/ns/activitystreams#Public"]
 | 
			
		||||
    public = [Pleroma.Constants.as_public()]
 | 
			
		||||
 | 
			
		||||
    recipients =
 | 
			
		||||
      if opts["user"], do: [opts["user"].ap_id | opts["user"].following] ++ public, else: public
 | 
			
		||||
| 
						 | 
				
			
			@ -555,7 +549,7 @@ def fetch_latest_activity_id_for_context(context, opts \\ %{}) do
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def fetch_public_activities(opts \\ %{}) do
 | 
			
		||||
    q = fetch_activities_query(["https://www.w3.org/ns/activitystreams#Public"], opts)
 | 
			
		||||
    q = fetch_activities_query([Pleroma.Constants.as_public()], opts)
 | 
			
		||||
 | 
			
		||||
    q
 | 
			
		||||
    |> restrict_unlisted()
 | 
			
		||||
| 
						 | 
				
			
			@ -646,10 +640,9 @@ defp user_activities_recipients(%{"godmode" => true}) do
 | 
			
		|||
 | 
			
		||||
  defp user_activities_recipients(%{"reading_user" => reading_user}) do
 | 
			
		||||
    if reading_user do
 | 
			
		||||
      ["https://www.w3.org/ns/activitystreams#Public"] ++
 | 
			
		||||
        [reading_user.ap_id | reading_user.following]
 | 
			
		||||
      [Pleroma.Constants.as_public()] ++ [reading_user.ap_id | reading_user.following]
 | 
			
		||||
    else
 | 
			
		||||
      ["https://www.w3.org/ns/activitystreams#Public"]
 | 
			
		||||
      [Pleroma.Constants.as_public()]
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -834,7 +827,7 @@ defp restrict_unlisted(query) do
 | 
			
		|||
        fragment(
 | 
			
		||||
          "not (coalesce(?->'cc', '{}'::jsonb) \\?| ?)",
 | 
			
		||||
          activity.data,
 | 
			
		||||
          ^["https://www.w3.org/ns/activitystreams#Public"]
 | 
			
		||||
          ^[Pleroma.Constants.as_public()]
 | 
			
		||||
        )
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			@ -971,7 +964,7 @@ def fetch_activities_bounded_query(query, recipients, recipients_with_public) do
 | 
			
		|||
      where:
 | 
			
		||||
        fragment("? && ?", activity.recipients, ^recipients) or
 | 
			
		||||
          (fragment("? && ?", activity.recipients, ^recipients_with_public) and
 | 
			
		||||
             "https://www.w3.org/ns/activitystreams#Public" in activity.recipients)
 | 
			
		||||
             ^Pleroma.Constants.as_public() in activity.recipients)
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,6 +4,9 @@
 | 
			
		|||
 | 
			
		||||
defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicy do
 | 
			
		||||
  alias Pleroma.User
 | 
			
		||||
 | 
			
		||||
  require Pleroma.Constants
 | 
			
		||||
 | 
			
		||||
  @moduledoc "Block messages with too much mentions (configurable)"
 | 
			
		||||
 | 
			
		||||
  @behaviour Pleroma.Web.ActivityPub.MRF
 | 
			
		||||
| 
						 | 
				
			
			@ -19,12 +22,12 @@ defp delist_message(message, threshold) when threshold > 0 do
 | 
			
		|||
        when follower_collection? and recipients > threshold ->
 | 
			
		||||
          message
 | 
			
		||||
          |> Map.put("to", [follower_collection])
 | 
			
		||||
          |> Map.put("cc", ["https://www.w3.org/ns/activitystreams#Public"])
 | 
			
		||||
          |> Map.put("cc", [Pleroma.Constants.as_public()])
 | 
			
		||||
 | 
			
		||||
        {:public, recipients} when recipients > threshold ->
 | 
			
		||||
          message
 | 
			
		||||
          |> Map.put("to", [])
 | 
			
		||||
          |> Map.put("cc", ["https://www.w3.org/ns/activitystreams#Public"])
 | 
			
		||||
          |> Map.put("cc", [Pleroma.Constants.as_public()])
 | 
			
		||||
 | 
			
		||||
        _ ->
 | 
			
		||||
          message
 | 
			
		||||
| 
						 | 
				
			
			@ -51,10 +54,10 @@ defp get_recipient_count(message) do
 | 
			
		|||
    recipients = (message["to"] || []) ++ (message["cc"] || [])
 | 
			
		||||
    follower_collection = User.get_cached_by_ap_id(message["actor"]).follower_address
 | 
			
		||||
 | 
			
		||||
    if Enum.member?(recipients, "https://www.w3.org/ns/activitystreams#Public") do
 | 
			
		||||
    if Enum.member?(recipients, Pleroma.Constants.as_public()) do
 | 
			
		||||
      recipients =
 | 
			
		||||
        recipients
 | 
			
		||||
        |> List.delete("https://www.w3.org/ns/activitystreams#Public")
 | 
			
		||||
        |> List.delete(Pleroma.Constants.as_public())
 | 
			
		||||
        |> List.delete(follower_collection)
 | 
			
		||||
 | 
			
		||||
      {:public, length(recipients)}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,8 @@
 | 
			
		|||
# SPDX-License-Identifier: AGPL-3.0-only
 | 
			
		||||
 | 
			
		||||
defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
 | 
			
		||||
  require Pleroma.Constants
 | 
			
		||||
 | 
			
		||||
  @moduledoc "Reject or Word-Replace messages with a keyword or regex"
 | 
			
		||||
 | 
			
		||||
  @behaviour Pleroma.Web.ActivityPub.MRF
 | 
			
		||||
| 
						 | 
				
			
			@ -31,12 +33,12 @@ defp check_reject(%{"object" => %{"content" => content, "summary" => summary}} =
 | 
			
		|||
  defp check_ftl_removal(
 | 
			
		||||
         %{"to" => to, "object" => %{"content" => content, "summary" => summary}} = message
 | 
			
		||||
       ) do
 | 
			
		||||
    if "https://www.w3.org/ns/activitystreams#Public" in to and
 | 
			
		||||
    if Pleroma.Constants.as_public() in to and
 | 
			
		||||
         Enum.any?(Pleroma.Config.get([:mrf_keyword, :federated_timeline_removal]), fn pattern ->
 | 
			
		||||
           string_matches?(content, pattern) or string_matches?(summary, pattern)
 | 
			
		||||
         end) do
 | 
			
		||||
      to = List.delete(to, "https://www.w3.org/ns/activitystreams#Public")
 | 
			
		||||
      cc = ["https://www.w3.org/ns/activitystreams#Public" | message["cc"] || []]
 | 
			
		||||
      to = List.delete(to, Pleroma.Constants.as_public())
 | 
			
		||||
      cc = [Pleroma.Constants.as_public() | message["cc"] || []]
 | 
			
		||||
 | 
			
		||||
      message =
 | 
			
		||||
        message
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,7 +10,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublic do
 | 
			
		|||
 | 
			
		||||
  @behaviour Pleroma.Web.ActivityPub.MRF
 | 
			
		||||
 | 
			
		||||
  @public "https://www.w3.org/ns/activitystreams#Public"
 | 
			
		||||
  require Pleroma.Constants
 | 
			
		||||
 | 
			
		||||
  @impl true
 | 
			
		||||
  def filter(%{"type" => "Create"} = object) do
 | 
			
		||||
| 
						 | 
				
			
			@ -19,8 +19,8 @@ def filter(%{"type" => "Create"} = object) do
 | 
			
		|||
    # Determine visibility
 | 
			
		||||
    visibility =
 | 
			
		||||
      cond do
 | 
			
		||||
        @public in object["to"] -> "public"
 | 
			
		||||
        @public in object["cc"] -> "unlisted"
 | 
			
		||||
        Pleroma.Constants.as_public() in object["to"] -> "public"
 | 
			
		||||
        Pleroma.Constants.as_public() in object["cc"] -> "unlisted"
 | 
			
		||||
        user.follower_address in object["to"] -> "followers"
 | 
			
		||||
        true -> "direct"
 | 
			
		||||
      end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
 | 
			
		|||
  @moduledoc "Filter activities depending on their origin instance"
 | 
			
		||||
  @behaviour MRF
 | 
			
		||||
 | 
			
		||||
  require Pleroma.Constants
 | 
			
		||||
 | 
			
		||||
  defp check_accept(%{host: actor_host} = _actor_info, object) do
 | 
			
		||||
    accepts =
 | 
			
		||||
      Pleroma.Config.get([:mrf_simple, :accept])
 | 
			
		||||
| 
						 | 
				
			
			@ -89,14 +91,10 @@ defp check_ftl_removal(%{host: actor_host} = _actor_info, object) do
 | 
			
		|||
    object =
 | 
			
		||||
      with true <- MRF.subdomain_match?(timeline_removal, actor_host),
 | 
			
		||||
           user <- User.get_cached_by_ap_id(object["actor"]),
 | 
			
		||||
           true <- "https://www.w3.org/ns/activitystreams#Public" in object["to"] do
 | 
			
		||||
        to =
 | 
			
		||||
          List.delete(object["to"], "https://www.w3.org/ns/activitystreams#Public") ++
 | 
			
		||||
            [user.follower_address]
 | 
			
		||||
           true <- Pleroma.Constants.as_public() in object["to"] do
 | 
			
		||||
        to = List.delete(object["to"], Pleroma.Constants.as_public()) ++ [user.follower_address]
 | 
			
		||||
 | 
			
		||||
        cc =
 | 
			
		||||
          List.delete(object["cc"], user.follower_address) ++
 | 
			
		||||
            ["https://www.w3.org/ns/activitystreams#Public"]
 | 
			
		||||
        cc = List.delete(object["cc"], user.follower_address) ++ [Pleroma.Constants.as_public()]
 | 
			
		||||
 | 
			
		||||
        object
 | 
			
		||||
        |> Map.put("to", to)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do
 | 
			
		|||
     - `mrf_tag:disable-any-subscription`: Reject any follow requests
 | 
			
		||||
  """
 | 
			
		||||
 | 
			
		||||
  @public "https://www.w3.org/ns/activitystreams#Public"
 | 
			
		||||
  require Pleroma.Constants
 | 
			
		||||
 | 
			
		||||
  defp get_tags(%User{tags: tags}) when is_list(tags), do: tags
 | 
			
		||||
  defp get_tags(_), do: []
 | 
			
		||||
| 
						 | 
				
			
			@ -70,9 +70,9 @@ defp process_tag(
 | 
			
		|||
       ) do
 | 
			
		||||
    user = User.get_cached_by_ap_id(actor)
 | 
			
		||||
 | 
			
		||||
    if Enum.member?(to, @public) do
 | 
			
		||||
      to = List.delete(to, @public) ++ [user.follower_address]
 | 
			
		||||
      cc = List.delete(cc, user.follower_address) ++ [@public]
 | 
			
		||||
    if Enum.member?(to, Pleroma.Constants.as_public()) do
 | 
			
		||||
      to = List.delete(to, Pleroma.Constants.as_public()) ++ [user.follower_address]
 | 
			
		||||
      cc = List.delete(cc, user.follower_address) ++ [Pleroma.Constants.as_public()]
 | 
			
		||||
 | 
			
		||||
      object =
 | 
			
		||||
        object
 | 
			
		||||
| 
						 | 
				
			
			@ -103,9 +103,10 @@ defp process_tag(
 | 
			
		|||
       ) do
 | 
			
		||||
    user = User.get_cached_by_ap_id(actor)
 | 
			
		||||
 | 
			
		||||
    if Enum.member?(to, @public) or Enum.member?(cc, @public) do
 | 
			
		||||
      to = List.delete(to, @public) ++ [user.follower_address]
 | 
			
		||||
      cc = List.delete(cc, @public)
 | 
			
		||||
    if Enum.member?(to, Pleroma.Constants.as_public()) or
 | 
			
		||||
         Enum.member?(cc, Pleroma.Constants.as_public()) do
 | 
			
		||||
      to = List.delete(to, Pleroma.Constants.as_public()) ++ [user.follower_address]
 | 
			
		||||
      cc = List.delete(cc, Pleroma.Constants.as_public())
 | 
			
		||||
 | 
			
		||||
      object =
 | 
			
		||||
        object
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,8 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
 | 
			
		|||
  alias Pleroma.Web.ActivityPub.Relay
 | 
			
		||||
  alias Pleroma.Web.ActivityPub.Transmogrifier
 | 
			
		||||
 | 
			
		||||
  require Pleroma.Constants
 | 
			
		||||
 | 
			
		||||
  import Pleroma.Web.ActivityPub.Visibility
 | 
			
		||||
 | 
			
		||||
  @behaviour Pleroma.Web.Federator.Publisher
 | 
			
		||||
| 
						 | 
				
			
			@ -117,8 +119,6 @@ defp get_cc_ap_ids(ap_id, recipients) do
 | 
			
		|||
    |> Enum.map(& &1.ap_id)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  @as_public "https://www.w3.org/ns/activitystreams#Public"
 | 
			
		||||
 | 
			
		||||
  defp maybe_use_sharedinbox(%User{info: %{source_data: data}}),
 | 
			
		||||
    do: (is_map(data["endpoints"]) && Map.get(data["endpoints"], "sharedInbox")) || data["inbox"]
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -145,7 +145,7 @@ def determine_inbox(
 | 
			
		|||
      type == "Delete" ->
 | 
			
		||||
        maybe_use_sharedinbox(user)
 | 
			
		||||
 | 
			
		||||
      @as_public in to || @as_public in cc ->
 | 
			
		||||
      Pleroma.Constants.as_public() in to || Pleroma.Constants.as_public() in cc ->
 | 
			
		||||
        maybe_use_sharedinbox(user)
 | 
			
		||||
 | 
			
		||||
      length(to) + length(cc) > 1 ->
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
 | 
			
		|||
  import Ecto.Query
 | 
			
		||||
 | 
			
		||||
  require Logger
 | 
			
		||||
  require Pleroma.Constants
 | 
			
		||||
 | 
			
		||||
  @doc """
 | 
			
		||||
  Modifies an incoming AP object (mastodon format) to our internal format.
 | 
			
		||||
| 
						 | 
				
			
			@ -102,8 +103,7 @@ def fix_explicit_addressing(object) do
 | 
			
		|||
 | 
			
		||||
    follower_collection = User.get_cached_by_ap_id(Containment.get_actor(object)).follower_address
 | 
			
		||||
 | 
			
		||||
    explicit_mentions =
 | 
			
		||||
      explicit_mentions ++ ["https://www.w3.org/ns/activitystreams#Public", follower_collection]
 | 
			
		||||
    explicit_mentions = explicit_mentions ++ [Pleroma.Constants.as_public(), follower_collection]
 | 
			
		||||
 | 
			
		||||
    fix_explicit_addressing(object, explicit_mentions, follower_collection)
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			@ -115,11 +115,11 @@ def fix_implicit_addressing(%{"to" => to, "cc" => cc} = object, followers_collec
 | 
			
		|||
 | 
			
		||||
    if followers_collection not in recipients do
 | 
			
		||||
      cond do
 | 
			
		||||
        "https://www.w3.org/ns/activitystreams#Public" in cc ->
 | 
			
		||||
        Pleroma.Constants.as_public() in cc ->
 | 
			
		||||
          to = to ++ [followers_collection]
 | 
			
		||||
          Map.put(object, "to", to)
 | 
			
		||||
 | 
			
		||||
        "https://www.w3.org/ns/activitystreams#Public" in to ->
 | 
			
		||||
        Pleroma.Constants.as_public() in to ->
 | 
			
		||||
          cc = cc ++ [followers_collection]
 | 
			
		||||
          Map.put(object, "cc", cc)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -480,8 +480,7 @@ def handle_incoming(
 | 
			
		|||
         {:ok, %User{} = follower} <- User.get_or_fetch_by_ap_id(follower),
 | 
			
		||||
         {:ok, activity} <- ActivityPub.follow(follower, followed, id, false) do
 | 
			
		||||
      with deny_follow_blocked <- Pleroma.Config.get([:user, :deny_follow_blocked]),
 | 
			
		||||
           {_, false} <-
 | 
			
		||||
             {:user_blocked, User.blocks?(followed, follower) && deny_follow_blocked},
 | 
			
		||||
           {_, false} <- {:user_blocked, User.blocks?(followed, follower) && deny_follow_blocked},
 | 
			
		||||
           {_, false} <- {:user_locked, User.locked?(followed)},
 | 
			
		||||
           {_, {:ok, follower}} <- {:follow, User.follow(follower, followed)},
 | 
			
		||||
           {_, {:ok, _}} <-
 | 
			
		||||
| 
						 | 
				
			
			@ -656,20 +655,7 @@ def handle_incoming(
 | 
			
		|||
      nil ->
 | 
			
		||||
        case User.get_cached_by_ap_id(object_id) do
 | 
			
		||||
          %User{ap_id: ^actor} = user ->
 | 
			
		||||
            {:ok, followers} = User.get_followers(user)
 | 
			
		||||
 | 
			
		||||
            Enum.each(followers, fn follower ->
 | 
			
		||||
              User.unfollow(follower, user)
 | 
			
		||||
            end)
 | 
			
		||||
 | 
			
		||||
            {:ok, friends} = User.get_friends(user)
 | 
			
		||||
 | 
			
		||||
            Enum.each(friends, fn followed ->
 | 
			
		||||
              User.unfollow(user, followed)
 | 
			
		||||
            end)
 | 
			
		||||
 | 
			
		||||
            User.invalidate_cache(user)
 | 
			
		||||
            Repo.delete(user)
 | 
			
		||||
            User.delete(user)
 | 
			
		||||
 | 
			
		||||
          nil ->
 | 
			
		||||
            :error
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,6 +18,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
 | 
			
		|||
  import Ecto.Query
 | 
			
		||||
 | 
			
		||||
  require Logger
 | 
			
		||||
  require Pleroma.Constants
 | 
			
		||||
 | 
			
		||||
  @supported_object_types ["Article", "Note", "Video", "Page", "Question", "Answer"]
 | 
			
		||||
  @supported_report_states ~w(open closed resolved)
 | 
			
		||||
| 
						 | 
				
			
			@ -418,7 +419,7 @@ def make_follow_data(
 | 
			
		|||
      "type" => "Follow",
 | 
			
		||||
      "actor" => follower_id,
 | 
			
		||||
      "to" => [followed_id],
 | 
			
		||||
      "cc" => ["https://www.w3.org/ns/activitystreams#Public"],
 | 
			
		||||
      "cc" => [Pleroma.Constants.as_public()],
 | 
			
		||||
      "object" => followed_id,
 | 
			
		||||
      "state" => "pending"
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -510,7 +511,7 @@ def make_announce_data(
 | 
			
		|||
      "actor" => ap_id,
 | 
			
		||||
      "object" => id,
 | 
			
		||||
      "to" => [user.follower_address, object.data["actor"]],
 | 
			
		||||
      "cc" => ["https://www.w3.org/ns/activitystreams#Public"],
 | 
			
		||||
      "cc" => [Pleroma.Constants.as_public()],
 | 
			
		||||
      "context" => object.data["context"]
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -530,7 +531,7 @@ def make_unannounce_data(
 | 
			
		|||
      "actor" => ap_id,
 | 
			
		||||
      "object" => activity.data,
 | 
			
		||||
      "to" => [user.follower_address, activity.data["actor"]],
 | 
			
		||||
      "cc" => ["https://www.w3.org/ns/activitystreams#Public"],
 | 
			
		||||
      "cc" => [Pleroma.Constants.as_public()],
 | 
			
		||||
      "context" => context
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -547,7 +548,7 @@ def make_unlike_data(
 | 
			
		|||
      "actor" => ap_id,
 | 
			
		||||
      "object" => activity.data,
 | 
			
		||||
      "to" => [user.follower_address, activity.data["actor"]],
 | 
			
		||||
      "cc" => ["https://www.w3.org/ns/activitystreams#Public"],
 | 
			
		||||
      "cc" => [Pleroma.Constants.as_public()],
 | 
			
		||||
      "context" => context
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -556,7 +557,7 @@ def make_unlike_data(
 | 
			
		|||
 | 
			
		||||
  def add_announce_to_object(
 | 
			
		||||
        %Activity{
 | 
			
		||||
          data: %{"actor" => actor, "cc" => ["https://www.w3.org/ns/activitystreams#Public"]}
 | 
			
		||||
          data: %{"actor" => actor, "cc" => [Pleroma.Constants.as_public()]}
 | 
			
		||||
        },
 | 
			
		||||
        object
 | 
			
		||||
      ) do
 | 
			
		||||
| 
						 | 
				
			
			@ -765,7 +766,7 @@ defp get_updated_targets(
 | 
			
		|||
       ) do
 | 
			
		||||
    cc = Map.get(data, "cc", [])
 | 
			
		||||
    follower_address = User.get_cached_by_ap_id(data["actor"]).follower_address
 | 
			
		||||
    public = "https://www.w3.org/ns/activitystreams#Public"
 | 
			
		||||
    public = Pleroma.Constants.as_public()
 | 
			
		||||
 | 
			
		||||
    case visibility do
 | 
			
		||||
      "public" ->
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,14 +8,14 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
 | 
			
		|||
  alias Pleroma.Repo
 | 
			
		||||
  alias Pleroma.User
 | 
			
		||||
 | 
			
		||||
  @public "https://www.w3.org/ns/activitystreams#Public"
 | 
			
		||||
  require Pleroma.Constants
 | 
			
		||||
 | 
			
		||||
  @spec is_public?(Object.t() | Activity.t() | map()) :: boolean()
 | 
			
		||||
  def is_public?(%Object{data: %{"type" => "Tombstone"}}), do: false
 | 
			
		||||
  def is_public?(%Object{data: data}), do: is_public?(data)
 | 
			
		||||
  def is_public?(%Activity{data: data}), do: is_public?(data)
 | 
			
		||||
  def is_public?(%{"directMessage" => true}), do: false
 | 
			
		||||
  def is_public?(data), do: @public in (data["to"] ++ (data["cc"] || []))
 | 
			
		||||
  def is_public?(data), do: Pleroma.Constants.as_public() in (data["to"] ++ (data["cc"] || []))
 | 
			
		||||
 | 
			
		||||
  def is_private?(activity) do
 | 
			
		||||
    with false <- is_public?(activity),
 | 
			
		||||
| 
						 | 
				
			
			@ -73,10 +73,10 @@ def get_visibility(object) do
 | 
			
		|||
    cc = object.data["cc"] || []
 | 
			
		||||
 | 
			
		||||
    cond do
 | 
			
		||||
      @public in to ->
 | 
			
		||||
      Pleroma.Constants.as_public() in to ->
 | 
			
		||||
        "public"
 | 
			
		||||
 | 
			
		||||
      @public in cc ->
 | 
			
		||||
      Pleroma.Constants.as_public() in cc ->
 | 
			
		||||
        "unlisted"
 | 
			
		||||
 | 
			
		||||
      # this should use the sql for the object's activity
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,8 +21,7 @@ def get_user(plug), do: implementation().get_user(plug)
 | 
			
		|||
  def create_from_registration(plug, registration),
 | 
			
		||||
    do: implementation().create_from_registration(plug, registration)
 | 
			
		||||
 | 
			
		||||
  @callback get_registration(Plug.Conn.t()) ::
 | 
			
		||||
              {:ok, Registration.t()} | {:error, any()}
 | 
			
		||||
  @callback get_registration(Plug.Conn.t()) :: {:ok, Registration.t()} | {:error, any()}
 | 
			
		||||
  def get_registration(plug), do: implementation().get_registration(plug)
 | 
			
		||||
 | 
			
		||||
  @callback handle_error(Plug.Conn.t(), any()) :: any()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -300,8 +300,7 @@ def pin(id_or_ap_id, %{ap_id: user_ap_id} = user) do
 | 
			
		|||
           }
 | 
			
		||||
         } = activity <- get_by_id_or_ap_id(id_or_ap_id),
 | 
			
		||||
         true <- Visibility.is_public?(activity),
 | 
			
		||||
         %{valid?: true} = info_changeset <-
 | 
			
		||||
           User.Info.add_pinnned_activity(user.info, activity),
 | 
			
		||||
         %{valid?: true} = info_changeset <- User.Info.add_pinnned_activity(user.info, activity),
 | 
			
		||||
         changeset <-
 | 
			
		||||
           Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_changeset),
 | 
			
		||||
         {:ok, _user} <- User.update_and_set_cache(changeset) do
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
 | 
			
		|||
  alias Pleroma.Web.MediaProxy
 | 
			
		||||
 | 
			
		||||
  require Logger
 | 
			
		||||
  require Pleroma.Constants
 | 
			
		||||
 | 
			
		||||
  # This is a hack for twidere.
 | 
			
		||||
  def get_by_id_or_ap_id(id) do
 | 
			
		||||
| 
						 | 
				
			
			@ -66,7 +67,7 @@ def attachments_from_ids_descs(ids, descs_str) do
 | 
			
		|||
  @spec get_to_and_cc(User.t(), list(String.t()), Activity.t() | nil, String.t()) ::
 | 
			
		||||
          {list(String.t()), list(String.t())}
 | 
			
		||||
  def get_to_and_cc(user, mentioned_users, inReplyTo, "public") do
 | 
			
		||||
    to = ["https://www.w3.org/ns/activitystreams#Public" | mentioned_users]
 | 
			
		||||
    to = [Pleroma.Constants.as_public() | mentioned_users]
 | 
			
		||||
    cc = [user.follower_address]
 | 
			
		||||
 | 
			
		||||
    if inReplyTo do
 | 
			
		||||
| 
						 | 
				
			
			@ -78,7 +79,7 @@ def get_to_and_cc(user, mentioned_users, inReplyTo, "public") do
 | 
			
		|||
 | 
			
		||||
  def get_to_and_cc(user, mentioned_users, inReplyTo, "unlisted") do
 | 
			
		||||
    to = [user.follower_address | mentioned_users]
 | 
			
		||||
    cc = ["https://www.w3.org/ns/activitystreams#Public"]
 | 
			
		||||
    cc = [Pleroma.Constants.as_public()]
 | 
			
		||||
 | 
			
		||||
    if inReplyTo do
 | 
			
		||||
      {Enum.uniq([inReplyTo.data["actor"] | to]), cc}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										77
									
								
								lib/pleroma/web/fallback_redirect_controller.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								lib/pleroma/web/fallback_redirect_controller.ex
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,77 @@
 | 
			
		|||
# Pleroma: A lightweight social networking server
 | 
			
		||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
 | 
			
		||||
# SPDX-License-Identifier: AGPL-3.0-only
 | 
			
		||||
 | 
			
		||||
defmodule Fallback.RedirectController do
 | 
			
		||||
  use Pleroma.Web, :controller
 | 
			
		||||
  require Logger
 | 
			
		||||
  alias Pleroma.User
 | 
			
		||||
  alias Pleroma.Web.Metadata
 | 
			
		||||
 | 
			
		||||
  def api_not_implemented(conn, _params) do
 | 
			
		||||
    conn
 | 
			
		||||
    |> put_status(404)
 | 
			
		||||
    |> json(%{error: "Not implemented"})
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def redirector(conn, _params, code \\ 200)
 | 
			
		||||
 | 
			
		||||
  # redirect to admin section
 | 
			
		||||
  # /pleroma/admin -> /pleroma/admin/
 | 
			
		||||
  #
 | 
			
		||||
  def redirector(conn, %{"path" => ["pleroma", "admin"]} = _, _code) do
 | 
			
		||||
    redirect(conn, to: "/pleroma/admin/")
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def redirector(conn, _params, code) do
 | 
			
		||||
    conn
 | 
			
		||||
    |> put_resp_content_type("text/html")
 | 
			
		||||
    |> send_file(code, index_file_path())
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def redirector_with_meta(conn, %{"maybe_nickname_or_id" => maybe_nickname_or_id} = params) do
 | 
			
		||||
    with %User{} = user <- User.get_cached_by_nickname_or_id(maybe_nickname_or_id) do
 | 
			
		||||
      redirector_with_meta(conn, %{user: user})
 | 
			
		||||
    else
 | 
			
		||||
      nil ->
 | 
			
		||||
        redirector(conn, params)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def redirector_with_meta(conn, params) do
 | 
			
		||||
    {:ok, index_content} = File.read(index_file_path())
 | 
			
		||||
 | 
			
		||||
    tags =
 | 
			
		||||
      try do
 | 
			
		||||
        Metadata.build_tags(params)
 | 
			
		||||
      rescue
 | 
			
		||||
        e ->
 | 
			
		||||
          Logger.error(
 | 
			
		||||
            "Metadata rendering for #{conn.request_path} failed.\n" <>
 | 
			
		||||
              Exception.format(:error, e, __STACKTRACE__)
 | 
			
		||||
          )
 | 
			
		||||
 | 
			
		||||
          ""
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
    response = String.replace(index_content, "<!--server-generated-meta-->", tags)
 | 
			
		||||
 | 
			
		||||
    conn
 | 
			
		||||
    |> put_resp_content_type("text/html")
 | 
			
		||||
    |> send_resp(200, response)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def index_file_path do
 | 
			
		||||
    Pleroma.Plugs.InstanceStatic.file_path("index.html")
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def registration_page(conn, params) do
 | 
			
		||||
    redirector(conn, params)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def empty(conn, _params) do
 | 
			
		||||
    conn
 | 
			
		||||
    |> put_status(204)
 | 
			
		||||
    |> text("")
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -4,6 +4,9 @@
 | 
			
		|||
 | 
			
		||||
defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
 | 
			
		||||
  use Pleroma.Web, :controller
 | 
			
		||||
 | 
			
		||||
  import Pleroma.Web.ControllerHelper, only: [json_response: 3]
 | 
			
		||||
 | 
			
		||||
  alias Ecto.Changeset
 | 
			
		||||
  alias Pleroma.Activity
 | 
			
		||||
  alias Pleroma.Bookmark
 | 
			
		||||
| 
						 | 
				
			
			@ -46,6 +49,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
 | 
			
		|||
  import Ecto.Query
 | 
			
		||||
 | 
			
		||||
  require Logger
 | 
			
		||||
  require Pleroma.Constants
 | 
			
		||||
 | 
			
		||||
  @rate_limited_relations_actions ~w(follow unfollow)a
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -74,6 +78,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
 | 
			
		|||
  plug(RateLimiter, :app_account_creation when action == :account_register)
 | 
			
		||||
  plug(RateLimiter, :search when action in [:search, :search2, :account_search])
 | 
			
		||||
  plug(RateLimiter, :password_reset when action == :password_reset)
 | 
			
		||||
  plug(RateLimiter, :account_confirmation_resend when action == :account_confirmation_resend)
 | 
			
		||||
 | 
			
		||||
  @local_mastodon_name "Mastodon-Local"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1220,10 +1225,9 @@ def user_favourites(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params
 | 
			
		|||
 | 
			
		||||
      recipients =
 | 
			
		||||
        if for_user do
 | 
			
		||||
          ["https://www.w3.org/ns/activitystreams#Public"] ++
 | 
			
		||||
            [for_user.ap_id | for_user.following]
 | 
			
		||||
          [Pleroma.Constants.as_public()] ++ [for_user.ap_id | for_user.following]
 | 
			
		||||
        else
 | 
			
		||||
          ["https://www.w3.org/ns/activitystreams#Public"]
 | 
			
		||||
          [Pleroma.Constants.as_public()]
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
      activities =
 | 
			
		||||
| 
						 | 
				
			
			@ -1839,6 +1843,16 @@ def password_reset(conn, params) do
 | 
			
		|||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def account_confirmation_resend(conn, params) do
 | 
			
		||||
    nickname_or_email = params["email"] || params["nickname"]
 | 
			
		||||
 | 
			
		||||
    with %User{} = user <- User.get_by_nickname_or_email(nickname_or_email),
 | 
			
		||||
         {:ok, _} <- User.try_send_confirmation_email(user) do
 | 
			
		||||
      conn
 | 
			
		||||
      |> json_response(:no_content, "")
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def try_render(conn, target, params)
 | 
			
		||||
      when is_binary(target) do
 | 
			
		||||
    case render(conn, target, params) do
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -165,6 +165,7 @@ def raw_nodeinfo do
 | 
			
		|||
        },
 | 
			
		||||
        accountActivationRequired: Config.get([:instance, :account_activation_required], false),
 | 
			
		||||
        invitesEnabled: Config.get([:instance, :invites_enabled], false),
 | 
			
		||||
        mailerEnabled: Config.get([Pleroma.Emails.Mailer, :enabled], false),
 | 
			
		||||
        features: features,
 | 
			
		||||
        restrictedNicknames: Config.get([Pleroma.User, :restricted_nicknames]),
 | 
			
		||||
        skipThreadContainment: Config.get([:instance, :skip_thread_containment], false)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -365,8 +365,7 @@ def registration_details(%Plug.Conn{} = conn, %{"authorization" => auth_attrs})
 | 
			
		|||
  def register(%Plug.Conn{} = conn, %{"authorization" => _, "op" => "connect"} = params) do
 | 
			
		||||
    with registration_id when not is_nil(registration_id) <- get_session_registration_id(conn),
 | 
			
		||||
         %Registration{} = registration <- Repo.get(Registration, registration_id),
 | 
			
		||||
         {_, {:ok, auth}} <-
 | 
			
		||||
           {:create_authorization, do_create_authorization(conn, params)},
 | 
			
		||||
         {_, {:ok, auth}} <- {:create_authorization, do_create_authorization(conn, params)},
 | 
			
		||||
         %User{} = user <- Repo.preload(auth, :user).user,
 | 
			
		||||
         {:ok, _updated_registration} <- Registration.bind_to_user(registration, user) do
 | 
			
		||||
      conn
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -44,8 +44,7 @@ def get_by_refresh_token(%App{id: app_id} = _app, token) do
 | 
			
		|||
    |> Repo.find_resource()
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  @spec exchange_token(App.t(), Authorization.t()) ::
 | 
			
		||||
          {:ok, Token.t()} | {:error, Changeset.t()}
 | 
			
		||||
  @spec exchange_token(App.t(), Authorization.t()) :: {:ok, Token.t()} | {:error, Changeset.t()}
 | 
			
		||||
  def exchange_token(app, auth) do
 | 
			
		||||
    with {:ok, auth} <- Authorization.use_token(auth),
 | 
			
		||||
         true <- auth.app_id == app.id do
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,7 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do
 | 
			
		|||
  alias Pleroma.Web.OStatus.UserRepresenter
 | 
			
		||||
 | 
			
		||||
  require Logger
 | 
			
		||||
  require Pleroma.Constants
 | 
			
		||||
 | 
			
		||||
  defp get_href(id) do
 | 
			
		||||
    with %Object{data: %{"external_url" => external_url}} <- Object.get_cached_by_ap_id(id) do
 | 
			
		||||
| 
						 | 
				
			
			@ -34,7 +35,7 @@ defp get_mentions(to) do
 | 
			
		|||
    Enum.map(to, fn id ->
 | 
			
		||||
      cond do
 | 
			
		||||
        # Special handling for the AP/Ostatus public collections
 | 
			
		||||
        "https://www.w3.org/ns/activitystreams#Public" == id ->
 | 
			
		||||
        Pleroma.Constants.as_public() == id ->
 | 
			
		||||
          {:link,
 | 
			
		||||
           [
 | 
			
		||||
             rel: "mentioned",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,6 +4,7 @@
 | 
			
		|||
 | 
			
		||||
defmodule Pleroma.Web.OStatus.NoteHandler do
 | 
			
		||||
  require Logger
 | 
			
		||||
  require Pleroma.Constants
 | 
			
		||||
 | 
			
		||||
  alias Pleroma.Activity
 | 
			
		||||
  alias Pleroma.Object
 | 
			
		||||
| 
						 | 
				
			
			@ -49,7 +50,7 @@ def get_people_mentions(entry) do
 | 
			
		|||
  def get_collection_mentions(entry) do
 | 
			
		||||
    transmogrify = fn
 | 
			
		||||
      "http://activityschema.org/collection/public" ->
 | 
			
		||||
        "https://www.w3.org/ns/activitystreams#Public"
 | 
			
		||||
        Pleroma.Constants.as_public()
 | 
			
		||||
 | 
			
		||||
      group ->
 | 
			
		||||
        group
 | 
			
		||||
| 
						 | 
				
			
			@ -126,7 +127,7 @@ def handle_note(entry, doc \\ nil, options \\ []) do
 | 
			
		|||
         to <- make_to_list(actor, mentions),
 | 
			
		||||
         date <- XML.string_from_xpath("//published", entry),
 | 
			
		||||
         unlisted <- XML.string_from_xpath("//mastodon:scope", entry) == "unlisted",
 | 
			
		||||
         cc <- if(unlisted, do: ["https://www.w3.org/ns/activitystreams#Public"], else: []),
 | 
			
		||||
         cc <- if(unlisted, do: [Pleroma.Constants.as_public()], else: []),
 | 
			
		||||
         note <-
 | 
			
		||||
           CommonAPI.Utils.make_note_data(
 | 
			
		||||
             actor.ap_id,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,7 @@
 | 
			
		|||
defmodule Pleroma.Web.OStatus.OStatusController do
 | 
			
		||||
  use Pleroma.Web, :controller
 | 
			
		||||
 | 
			
		||||
  alias Fallback.RedirectController
 | 
			
		||||
  alias Pleroma.Activity
 | 
			
		||||
  alias Pleroma.Object
 | 
			
		||||
  alias Pleroma.User
 | 
			
		||||
| 
						 | 
				
			
			@ -12,42 +13,44 @@ defmodule Pleroma.Web.OStatus.OStatusController do
 | 
			
		|||
  alias Pleroma.Web.ActivityPub.ActivityPubController
 | 
			
		||||
  alias Pleroma.Web.ActivityPub.ObjectView
 | 
			
		||||
  alias Pleroma.Web.ActivityPub.Visibility
 | 
			
		||||
  alias Pleroma.Web.Endpoint
 | 
			
		||||
  alias Pleroma.Web.Federator
 | 
			
		||||
  alias Pleroma.Web.Metadata.PlayerView
 | 
			
		||||
  alias Pleroma.Web.OStatus
 | 
			
		||||
  alias Pleroma.Web.OStatus.ActivityRepresenter
 | 
			
		||||
  alias Pleroma.Web.OStatus.FeedRepresenter
 | 
			
		||||
  alias Pleroma.Web.Router
 | 
			
		||||
  alias Pleroma.Web.XML
 | 
			
		||||
 | 
			
		||||
  plug(Pleroma.Web.FederatingPlug when action in [:salmon_incoming])
 | 
			
		||||
 | 
			
		||||
  plug(
 | 
			
		||||
    Pleroma.Plugs.SetFormatPlug
 | 
			
		||||
    when action in [:feed_redirect, :object, :activity, :notice]
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  action_fallback(:errors)
 | 
			
		||||
 | 
			
		||||
  def feed_redirect(%{assigns: %{format: "html"}} = conn, %{"nickname" => nickname}) do
 | 
			
		||||
    with {_, %User{} = user} <-
 | 
			
		||||
           {:fetch_user, User.get_cached_by_nickname_or_id(nickname)} do
 | 
			
		||||
      RedirectController.redirector_with_meta(conn, %{user: user})
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def feed_redirect(%{assigns: %{format: format}} = conn, _params)
 | 
			
		||||
      when format in ["json", "activity+json"] do
 | 
			
		||||
    ActivityPubController.call(conn, :user)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def feed_redirect(conn, %{"nickname" => nickname}) do
 | 
			
		||||
    case get_format(conn) do
 | 
			
		||||
      "html" ->
 | 
			
		||||
        with %User{} = user <- User.get_cached_by_nickname_or_id(nickname) do
 | 
			
		||||
          Fallback.RedirectController.redirector_with_meta(conn, %{user: user})
 | 
			
		||||
        else
 | 
			
		||||
          nil -> {:error, :not_found}
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
      "activity+json" ->
 | 
			
		||||
        ActivityPubController.call(conn, :user)
 | 
			
		||||
 | 
			
		||||
      "json" ->
 | 
			
		||||
        ActivityPubController.call(conn, :user)
 | 
			
		||||
 | 
			
		||||
      _ ->
 | 
			
		||||
        with %User{} = user <- User.get_cached_by_nickname(nickname) do
 | 
			
		||||
          redirect(conn, external: OStatus.feed_path(user))
 | 
			
		||||
        else
 | 
			
		||||
          nil -> {:error, :not_found}
 | 
			
		||||
        end
 | 
			
		||||
    with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname(nickname)} do
 | 
			
		||||
      redirect(conn, external: OStatus.feed_path(user))
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def feed(conn, %{"nickname" => nickname} = params) do
 | 
			
		||||
    with %User{} = user <- User.get_cached_by_nickname(nickname) do
 | 
			
		||||
    with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname(nickname)} do
 | 
			
		||||
      query_params =
 | 
			
		||||
        Map.take(params, ["max_id"])
 | 
			
		||||
        |> Map.merge(%{"whole_db" => true, "actor_id" => user.ap_id})
 | 
			
		||||
| 
						 | 
				
			
			@ -65,8 +68,6 @@ def feed(conn, %{"nickname" => nickname} = params) do
 | 
			
		|||
      conn
 | 
			
		||||
      |> put_resp_content_type("application/atom+xml")
 | 
			
		||||
      |> send_resp(200, response)
 | 
			
		||||
    else
 | 
			
		||||
      nil -> {:error, :not_found}
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -97,93 +98,82 @@ def salmon_incoming(conn, _) do
 | 
			
		|||
    |> send_resp(200, "")
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def object(conn, %{"uuid" => uuid}) do
 | 
			
		||||
    if get_format(conn) in ["activity+json", "json"] do
 | 
			
		||||
      ActivityPubController.call(conn, :object)
 | 
			
		||||
    else
 | 
			
		||||
      with id <- o_status_url(conn, :object, uuid),
 | 
			
		||||
           {_, %Activity{} = activity} <-
 | 
			
		||||
             {:activity, Activity.get_create_by_object_ap_id_with_object(id)},
 | 
			
		||||
           {_, true} <- {:public?, Visibility.is_public?(activity)},
 | 
			
		||||
           %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
 | 
			
		||||
        case get_format(conn) do
 | 
			
		||||
          "html" -> redirect(conn, to: "/notice/#{activity.id}")
 | 
			
		||||
          _ -> represent_activity(conn, nil, activity, user)
 | 
			
		||||
        end
 | 
			
		||||
      else
 | 
			
		||||
        {:public?, false} ->
 | 
			
		||||
          {:error, :not_found}
 | 
			
		||||
  def object(%{assigns: %{format: format}} = conn, %{"uuid" => _uuid})
 | 
			
		||||
      when format in ["json", "activity+json"] do
 | 
			
		||||
    ActivityPubController.call(conn, :object)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
        {:activity, nil} ->
 | 
			
		||||
          {:error, :not_found}
 | 
			
		||||
 | 
			
		||||
        e ->
 | 
			
		||||
          e
 | 
			
		||||
  def object(%{assigns: %{format: format}} = conn, %{"uuid" => uuid}) do
 | 
			
		||||
    with id <- o_status_url(conn, :object, uuid),
 | 
			
		||||
         {_, %Activity{} = activity} <-
 | 
			
		||||
           {:activity, Activity.get_create_by_object_ap_id_with_object(id)},
 | 
			
		||||
         {_, true} <- {:public?, Visibility.is_public?(activity)},
 | 
			
		||||
         %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
 | 
			
		||||
      case format do
 | 
			
		||||
        "html" -> redirect(conn, to: "/notice/#{activity.id}")
 | 
			
		||||
        _ -> represent_activity(conn, nil, activity, user)
 | 
			
		||||
      end
 | 
			
		||||
    else
 | 
			
		||||
      reason when reason in [{:public?, false}, {:activity, nil}] ->
 | 
			
		||||
        {:error, :not_found}
 | 
			
		||||
 | 
			
		||||
      e ->
 | 
			
		||||
        e
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def activity(conn, %{"uuid" => uuid}) do
 | 
			
		||||
    if get_format(conn) in ["activity+json", "json"] do
 | 
			
		||||
      ActivityPubController.call(conn, :activity)
 | 
			
		||||
    else
 | 
			
		||||
      with id <- o_status_url(conn, :activity, uuid),
 | 
			
		||||
           {_, %Activity{} = activity} <- {:activity, Activity.normalize(id)},
 | 
			
		||||
           {_, true} <- {:public?, Visibility.is_public?(activity)},
 | 
			
		||||
           %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
 | 
			
		||||
        case format = get_format(conn) do
 | 
			
		||||
          "html" -> redirect(conn, to: "/notice/#{activity.id}")
 | 
			
		||||
          _ -> represent_activity(conn, format, activity, user)
 | 
			
		||||
        end
 | 
			
		||||
      else
 | 
			
		||||
        {:public?, false} ->
 | 
			
		||||
          {:error, :not_found}
 | 
			
		||||
  def activity(%{assigns: %{format: format}} = conn, %{"uuid" => _uuid})
 | 
			
		||||
      when format in ["json", "activity+json"] do
 | 
			
		||||
    ActivityPubController.call(conn, :activity)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
        {:activity, nil} ->
 | 
			
		||||
          {:error, :not_found}
 | 
			
		||||
 | 
			
		||||
        e ->
 | 
			
		||||
          e
 | 
			
		||||
  def activity(%{assigns: %{format: format}} = conn, %{"uuid" => uuid}) do
 | 
			
		||||
    with id <- o_status_url(conn, :activity, uuid),
 | 
			
		||||
         {_, %Activity{} = activity} <- {:activity, Activity.normalize(id)},
 | 
			
		||||
         {_, true} <- {:public?, Visibility.is_public?(activity)},
 | 
			
		||||
         %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
 | 
			
		||||
      case format do
 | 
			
		||||
        "html" -> redirect(conn, to: "/notice/#{activity.id}")
 | 
			
		||||
        _ -> represent_activity(conn, format, activity, user)
 | 
			
		||||
      end
 | 
			
		||||
    else
 | 
			
		||||
      reason when reason in [{:public?, false}, {:activity, nil}] ->
 | 
			
		||||
        {:error, :not_found}
 | 
			
		||||
 | 
			
		||||
      e ->
 | 
			
		||||
        e
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def notice(conn, %{"id" => id}) do
 | 
			
		||||
  def notice(%{assigns: %{format: format}} = conn, %{"id" => id}) do
 | 
			
		||||
    with {_, %Activity{} = activity} <- {:activity, Activity.get_by_id_with_object(id)},
 | 
			
		||||
         {_, true} <- {:public?, Visibility.is_public?(activity)},
 | 
			
		||||
         %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
 | 
			
		||||
      case format = get_format(conn) do
 | 
			
		||||
        "html" ->
 | 
			
		||||
          if activity.data["type"] == "Create" do
 | 
			
		||||
            %Object{} = object = Object.normalize(activity)
 | 
			
		||||
      cond do
 | 
			
		||||
        format == "html" && activity.data["type"] == "Create" ->
 | 
			
		||||
          %Object{} = object = Object.normalize(activity)
 | 
			
		||||
 | 
			
		||||
            Fallback.RedirectController.redirector_with_meta(conn, %{
 | 
			
		||||
          RedirectController.redirector_with_meta(
 | 
			
		||||
            conn,
 | 
			
		||||
            %{
 | 
			
		||||
              activity_id: activity.id,
 | 
			
		||||
              object: object,
 | 
			
		||||
              url:
 | 
			
		||||
                Pleroma.Web.Router.Helpers.o_status_url(
 | 
			
		||||
                  Pleroma.Web.Endpoint,
 | 
			
		||||
                  :notice,
 | 
			
		||||
                  activity.id
 | 
			
		||||
                ),
 | 
			
		||||
              url: Router.Helpers.o_status_url(Endpoint, :notice, activity.id),
 | 
			
		||||
              user: user
 | 
			
		||||
            })
 | 
			
		||||
          else
 | 
			
		||||
            Fallback.RedirectController.redirector(conn, nil)
 | 
			
		||||
          end
 | 
			
		||||
            }
 | 
			
		||||
          )
 | 
			
		||||
 | 
			
		||||
        _ ->
 | 
			
		||||
        format == "html" ->
 | 
			
		||||
          RedirectController.redirector(conn, nil)
 | 
			
		||||
 | 
			
		||||
        true ->
 | 
			
		||||
          represent_activity(conn, format, activity, user)
 | 
			
		||||
      end
 | 
			
		||||
    else
 | 
			
		||||
      {:public?, false} ->
 | 
			
		||||
      reason when reason in [{:public?, false}, {:activity, nil}] ->
 | 
			
		||||
        conn
 | 
			
		||||
        |> put_status(404)
 | 
			
		||||
        |> Fallback.RedirectController.redirector(nil, 404)
 | 
			
		||||
 | 
			
		||||
      {:activity, nil} ->
 | 
			
		||||
        conn
 | 
			
		||||
        |> Fallback.RedirectController.redirector(nil, 404)
 | 
			
		||||
        |> RedirectController.redirector(nil, 404)
 | 
			
		||||
 | 
			
		||||
      e ->
 | 
			
		||||
        e
 | 
			
		||||
| 
						 | 
				
			
			@ -204,13 +194,13 @@ def notice_player(conn, %{"id" => id}) do
 | 
			
		|||
        "content-security-policy",
 | 
			
		||||
        "default-src 'none';style-src 'self' 'unsafe-inline';img-src 'self' data: https:; media-src 'self' https:;"
 | 
			
		||||
      )
 | 
			
		||||
      |> put_view(Pleroma.Web.Metadata.PlayerView)
 | 
			
		||||
      |> put_view(PlayerView)
 | 
			
		||||
      |> render("player.html", url)
 | 
			
		||||
    else
 | 
			
		||||
      _error ->
 | 
			
		||||
        conn
 | 
			
		||||
        |> put_status(404)
 | 
			
		||||
        |> Fallback.RedirectController.redirector(nil, 404)
 | 
			
		||||
        |> RedirectController.redirector(nil, 404)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -248,6 +238,8 @@ def errors(conn, {:error, :not_found}) do
 | 
			
		|||
    render_error(conn, :not_found, "Not found")
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def errors(conn, {:fetch_user, nil}), do: errors(conn, {:error, :not_found})
 | 
			
		||||
 | 
			
		||||
  def errors(conn, _) do
 | 
			
		||||
    render_error(conn, :internal_server_error, "Something went wrong")
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,8 +19,7 @@ defp is_aws_signed_url(nil), do: nil
 | 
			
		|||
  defp is_aws_signed_url(image) when is_binary(image) do
 | 
			
		||||
    %URI{host: host, query: query} = URI.parse(image)
 | 
			
		||||
 | 
			
		||||
    if String.contains?(host, "amazonaws.com") and
 | 
			
		||||
         String.contains?(query, "X-Amz-Expires") do
 | 
			
		||||
    if String.contains?(host, "amazonaws.com") and String.contains?(query, "X-Amz-Expires") do
 | 
			
		||||
      image
 | 
			
		||||
    else
 | 
			
		||||
      nil
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -412,6 +412,12 @@ defmodule Pleroma.Web.Router do
 | 
			
		|||
 | 
			
		||||
    get("/accounts/search", SearchController, :account_search)
 | 
			
		||||
 | 
			
		||||
    post(
 | 
			
		||||
      "/pleroma/accounts/confirmation_resend",
 | 
			
		||||
      MastodonAPIController,
 | 
			
		||||
      :account_confirmation_resend
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    scope [] do
 | 
			
		||||
      pipe_through(:oauth_read_or_public)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -692,7 +698,7 @@ defmodule Pleroma.Web.Router do
 | 
			
		|||
    post("/auth/password", MastodonAPIController, :password_reset)
 | 
			
		||||
 | 
			
		||||
    scope [] do
 | 
			
		||||
      pipe_through(:oauth_read_or_public)
 | 
			
		||||
      pipe_through(:oauth_read)
 | 
			
		||||
      get("/web/*path", MastodonAPIController, :index)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			@ -729,68 +735,3 @@ defmodule Pleroma.Web.Router do
 | 
			
		|||
    options("/*path", RedirectController, :empty)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
defmodule Fallback.RedirectController do
 | 
			
		||||
  use Pleroma.Web, :controller
 | 
			
		||||
  require Logger
 | 
			
		||||
  alias Pleroma.User
 | 
			
		||||
  alias Pleroma.Web.Metadata
 | 
			
		||||
 | 
			
		||||
  def api_not_implemented(conn, _params) do
 | 
			
		||||
    conn
 | 
			
		||||
    |> put_status(404)
 | 
			
		||||
    |> json(%{error: "Not implemented"})
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def redirector(conn, _params, code \\ 200) do
 | 
			
		||||
    conn
 | 
			
		||||
    |> put_resp_content_type("text/html")
 | 
			
		||||
    |> send_file(code, index_file_path())
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def redirector_with_meta(conn, %{"maybe_nickname_or_id" => maybe_nickname_or_id} = params) do
 | 
			
		||||
    with %User{} = user <- User.get_cached_by_nickname_or_id(maybe_nickname_or_id) do
 | 
			
		||||
      redirector_with_meta(conn, %{user: user})
 | 
			
		||||
    else
 | 
			
		||||
      nil ->
 | 
			
		||||
        redirector(conn, params)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def redirector_with_meta(conn, params) do
 | 
			
		||||
    {:ok, index_content} = File.read(index_file_path())
 | 
			
		||||
 | 
			
		||||
    tags =
 | 
			
		||||
      try do
 | 
			
		||||
        Metadata.build_tags(params)
 | 
			
		||||
      rescue
 | 
			
		||||
        e ->
 | 
			
		||||
          Logger.error(
 | 
			
		||||
            "Metadata rendering for #{conn.request_path} failed.\n" <>
 | 
			
		||||
              Exception.format(:error, e, __STACKTRACE__)
 | 
			
		||||
          )
 | 
			
		||||
 | 
			
		||||
          ""
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
    response = String.replace(index_content, "<!--server-generated-meta-->", tags)
 | 
			
		||||
 | 
			
		||||
    conn
 | 
			
		||||
    |> put_resp_content_type("text/html")
 | 
			
		||||
    |> send_resp(200, response)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def index_file_path do
 | 
			
		||||
    Pleroma.Plugs.InstanceStatic.file_path("index.html")
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def registration_page(conn, params) do
 | 
			
		||||
    redirector(conn, params)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def empty(conn, _params) do
 | 
			
		||||
    conn
 | 
			
		||||
    |> put_status(204)
 | 
			
		||||
    |> text("")
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,6 +15,8 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
 | 
			
		|||
 | 
			
		||||
  import Ecto.Query
 | 
			
		||||
 | 
			
		||||
  require Pleroma.Constants
 | 
			
		||||
 | 
			
		||||
  def create_status(%User{} = user, %{"status" => _} = data) do
 | 
			
		||||
    CommonAPI.post(user, data)
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			@ -286,7 +288,7 @@ def search(_user, %{"q" => query} = params) do
 | 
			
		|||
      from(
 | 
			
		||||
        [a, o] in Activity.with_preloaded_object(Activity),
 | 
			
		||||
        where: fragment("?->>'type' = 'Create'", a.data),
 | 
			
		||||
        where: "https://www.w3.org/ns/activitystreams#Public" in a.recipients,
 | 
			
		||||
        where: ^Pleroma.Constants.as_public() in a.recipients,
 | 
			
		||||
        where:
 | 
			
		||||
          fragment(
 | 
			
		||||
            "to_tsvector('english', ?->>'content') @@ plainto_tsquery('english', ?)",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
 | 
			
		|||
 | 
			
		||||
  import Ecto.Query
 | 
			
		||||
  require Logger
 | 
			
		||||
  require Pleroma.Constants
 | 
			
		||||
 | 
			
		||||
  defp query_context_ids([]), do: []
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -91,7 +92,7 @@ defp get_user(ap_id, opts) do
 | 
			
		|||
      String.ends_with?(ap_id, "/followers") ->
 | 
			
		||||
        nil
 | 
			
		||||
 | 
			
		||||
      ap_id == "https://www.w3.org/ns/activitystreams#Public" ->
 | 
			
		||||
      ap_id == Pleroma.Constants.as_public() ->
 | 
			
		||||
        nil
 | 
			
		||||
 | 
			
		||||
      user = User.get_cached_by_ap_id(ap_id) ->
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,8 @@ defmodule Pleroma.Web.TwitterAPI.NotificationView do
 | 
			
		|||
  alias Pleroma.Web.TwitterAPI.ActivityView
 | 
			
		||||
  alias Pleroma.Web.TwitterAPI.UserView
 | 
			
		||||
 | 
			
		||||
  require Pleroma.Constants
 | 
			
		||||
 | 
			
		||||
  defp get_user(ap_id, opts) do
 | 
			
		||||
    cond do
 | 
			
		||||
      user = opts[:users][ap_id] ->
 | 
			
		||||
| 
						 | 
				
			
			@ -18,7 +20,7 @@ defp get_user(ap_id, opts) do
 | 
			
		|||
      String.ends_with?(ap_id, "/followers") ->
 | 
			
		||||
        nil
 | 
			
		||||
 | 
			
		||||
      ap_id == "https://www.w3.org/ns/activitystreams#Public" ->
 | 
			
		||||
      ap_id == Pleroma.Constants.as_public() ->
 | 
			
		||||
        nil
 | 
			
		||||
 | 
			
		||||
      true ->
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1
									
								
								mix.exs
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								mix.exs
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -150,6 +150,7 @@ defp deps do
 | 
			
		|||
      {:benchee, "~> 1.0"},
 | 
			
		||||
      {:esshd, "~> 0.1.0", runtime: Application.get_env(:esshd, :enabled, false)},
 | 
			
		||||
      {:ex_rated, "~> 1.3"},
 | 
			
		||||
      {:ex_const, "~> 0.2"},
 | 
			
		||||
      {:plug_static_index_html, "~> 1.0.0"},
 | 
			
		||||
      {:excoveralls, "~> 0.11.1", only: :test},
 | 
			
		||||
      {:mox, "~> 0.5", only: :test}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1
									
								
								mix.lock
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								mix.lock
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -27,6 +27,7 @@
 | 
			
		|||
  "ex2ms": {:hex, :ex2ms, "1.5.0", "19e27f9212be9a96093fed8cdfbef0a2b56c21237196d26760f11dfcfae58e97", [:mix], [], "hexpm"},
 | 
			
		||||
  "ex_aws": {:hex, :ex_aws, "2.1.0", "b92651527d6c09c479f9013caa9c7331f19cba38a650590d82ebf2c6c16a1d8a", [:mix], [{:configparser_ex, "~> 2.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "1.6.3 or 1.6.5 or 1.7.1 or 1.8.6 or ~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8", [hex: :jsx, repo: "hexpm", optional: true]}, {:poison, ">= 1.2.0", [hex: :poison, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:xml_builder, "~> 0.1.0", [hex: :xml_builder, repo: "hexpm", optional: true]}], "hexpm"},
 | 
			
		||||
  "ex_aws_s3": {:hex, :ex_aws_s3, "2.0.1", "9e09366e77f25d3d88c5393824e613344631be8db0d1839faca49686e99b6704", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm"},
 | 
			
		||||
  "ex_const": {:hex, :ex_const, "0.2.4", "d06e540c9d834865b012a17407761455efa71d0ce91e5831e86881b9c9d82448", [:mix], [], "hexpm"},
 | 
			
		||||
  "ex_doc": {:hex, :ex_doc, "0.20.2", "1bd0dfb0304bade58beb77f20f21ee3558cc3c753743ae0ddbb0fd7ba2912331", [:mix], [{:earmark, "~> 1.3", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.10", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"},
 | 
			
		||||
  "ex_machina": {:hex, :ex_machina, "2.3.0", "92a5ad0a8b10ea6314b876a99c8c9e3f25f4dde71a2a835845b136b9adaf199a", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm"},
 | 
			
		||||
  "ex_rated": {:hex, :ex_rated, "1.3.3", "30ecbdabe91f7eaa9d37fa4e81c85ba420f371babeb9d1910adbcd79ec798d27", [:mix], [{:ex2ms, "~> 1.5", [hex: :ex2ms, repo: "hexpm", optional: false]}], "hexpm"},
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -564,6 +564,64 @@ test "replying to a deleted post without tagging does not generate a notificatio
 | 
			
		|||
 | 
			
		||||
      assert Enum.empty?(Notification.for_user(user))
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "notifications are deleted if a local user is deleted" do
 | 
			
		||||
      user = insert(:user)
 | 
			
		||||
      other_user = insert(:user)
 | 
			
		||||
 | 
			
		||||
      {:ok, _activity} =
 | 
			
		||||
        CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}", "visibility" => "direct"})
 | 
			
		||||
 | 
			
		||||
      refute Enum.empty?(Notification.for_user(other_user))
 | 
			
		||||
 | 
			
		||||
      User.delete(user)
 | 
			
		||||
 | 
			
		||||
      assert Enum.empty?(Notification.for_user(other_user))
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "notifications are deleted if a remote user is deleted" do
 | 
			
		||||
      remote_user = insert(:user)
 | 
			
		||||
      local_user = insert(:user)
 | 
			
		||||
 | 
			
		||||
      dm_message = %{
 | 
			
		||||
        "@context" => "https://www.w3.org/ns/activitystreams",
 | 
			
		||||
        "type" => "Create",
 | 
			
		||||
        "actor" => remote_user.ap_id,
 | 
			
		||||
        "id" => remote_user.ap_id <> "/activities/test",
 | 
			
		||||
        "to" => [local_user.ap_id],
 | 
			
		||||
        "cc" => [],
 | 
			
		||||
        "object" => %{
 | 
			
		||||
          "type" => "Note",
 | 
			
		||||
          "content" => "Hello!",
 | 
			
		||||
          "tag" => [
 | 
			
		||||
            %{
 | 
			
		||||
              "type" => "Mention",
 | 
			
		||||
              "href" => local_user.ap_id,
 | 
			
		||||
              "name" => "@#{local_user.nickname}"
 | 
			
		||||
            }
 | 
			
		||||
          ],
 | 
			
		||||
          "to" => [local_user.ap_id],
 | 
			
		||||
          "cc" => [],
 | 
			
		||||
          "attributedTo" => remote_user.ap_id
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      {:ok, _dm_activity} = Transmogrifier.handle_incoming(dm_message)
 | 
			
		||||
 | 
			
		||||
      refute Enum.empty?(Notification.for_user(local_user))
 | 
			
		||||
 | 
			
		||||
      delete_user_message = %{
 | 
			
		||||
        "@context" => "https://www.w3.org/ns/activitystreams",
 | 
			
		||||
        "id" => remote_user.ap_id <> "/activities/delete",
 | 
			
		||||
        "actor" => remote_user.ap_id,
 | 
			
		||||
        "type" => "Delete",
 | 
			
		||||
        "object" => remote_user.ap_id
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      {:ok, _delete_activity} = Transmogrifier.handle_incoming(delete_user_message)
 | 
			
		||||
 | 
			
		||||
      assert Enum.empty?(Notification.for_user(local_user))
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe "for_user" do
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1369,4 +1369,28 @@ test "user with internal-prefixed nickname returns true" do
 | 
			
		|||
      assert User.is_internal_user?(user)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe "update_and_set_cache/1" do
 | 
			
		||||
    test "returns error when user is stale instead Ecto.StaleEntryError" do
 | 
			
		||||
      user = insert(:user)
 | 
			
		||||
 | 
			
		||||
      changeset = Ecto.Changeset.change(user, bio: "test")
 | 
			
		||||
 | 
			
		||||
      Repo.delete(user)
 | 
			
		||||
 | 
			
		||||
      assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
 | 
			
		||||
               User.update_and_set_cache(changeset)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "performs update cache if user updated" do
 | 
			
		||||
      user = insert(:user)
 | 
			
		||||
      assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
 | 
			
		||||
 | 
			
		||||
      changeset = Ecto.Changeset.change(user, bio: "test-bio")
 | 
			
		||||
 | 
			
		||||
      assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
 | 
			
		||||
      assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
 | 
			
		||||
      assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,6 +30,10 @@ test "GET /api*path", %{conn: conn} do
 | 
			
		|||
           |> json_response(404) == %{"error" => "Not implemented"}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  test "GET /pleroma/admin -> /pleroma/admin/", %{conn: conn} do
 | 
			
		||||
    assert redirected_to(get(conn, "/pleroma/admin")) =~ "/pleroma/admin/"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  test "GET /*path", %{conn: conn} do
 | 
			
		||||
    assert conn
 | 
			
		||||
           |> get("/foo")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3154,6 +3154,21 @@ test "redirects not logged-in users to the login page", %{conn: conn, path: path
 | 
			
		|||
      assert redirected_to(conn) == "/web/login"
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "redirects not logged-in users to the login page on private instances", %{
 | 
			
		||||
      conn: conn,
 | 
			
		||||
      path: path
 | 
			
		||||
    } do
 | 
			
		||||
      is_public = Pleroma.Config.get([:instance, :public])
 | 
			
		||||
      Pleroma.Config.put([:instance, :public], false)
 | 
			
		||||
 | 
			
		||||
      conn = get(conn, path)
 | 
			
		||||
 | 
			
		||||
      assert conn.status == 302
 | 
			
		||||
      assert redirected_to(conn) == "/web/login"
 | 
			
		||||
 | 
			
		||||
      Pleroma.Config.put([:instance, :public], is_public)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
 | 
			
		||||
      token = insert(:oauth_token)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3923,4 +3938,45 @@ test "it returns 400 when user is not local", %{conn: conn, user: user} do
 | 
			
		|||
      assert conn.resp_body == ""
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe "POST /api/v1/pleroma/accounts/confirmation_resend" do
 | 
			
		||||
    setup do
 | 
			
		||||
      setting = Pleroma.Config.get([:instance, :account_activation_required])
 | 
			
		||||
 | 
			
		||||
      unless setting do
 | 
			
		||||
        Pleroma.Config.put([:instance, :account_activation_required], true)
 | 
			
		||||
        on_exit(fn -> Pleroma.Config.put([:instance, :account_activation_required], setting) end)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      user = insert(:user)
 | 
			
		||||
      info_change = User.Info.confirmation_changeset(user.info, need_confirmation: true)
 | 
			
		||||
 | 
			
		||||
      {:ok, user} =
 | 
			
		||||
        user
 | 
			
		||||
        |> Changeset.change()
 | 
			
		||||
        |> Changeset.put_embed(:info, info_change)
 | 
			
		||||
        |> Repo.update()
 | 
			
		||||
 | 
			
		||||
      assert user.info.confirmation_pending
 | 
			
		||||
 | 
			
		||||
      [user: user]
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "resend account confirmation email", %{conn: conn, user: user} do
 | 
			
		||||
      conn
 | 
			
		||||
      |> assign(:user, user)
 | 
			
		||||
      |> post("/api/v1/pleroma/accounts/confirmation_resend?email=#{user.email}")
 | 
			
		||||
      |> json_response(:no_content)
 | 
			
		||||
 | 
			
		||||
      email = Pleroma.Emails.UserEmail.account_confirmation_email(user)
 | 
			
		||||
      notify_email = Pleroma.Config.get([:instance, :notify_email])
 | 
			
		||||
      instance_name = Pleroma.Config.get([:instance, :name])
 | 
			
		||||
 | 
			
		||||
      assert_email_sent(
 | 
			
		||||
        from: {instance_name, notify_email},
 | 
			
		||||
        to: {user.name, user.email},
 | 
			
		||||
        html_body: email.html_body
 | 
			
		||||
      )
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -101,160 +101,538 @@ test "returns 404 for a missing feed", %{conn: conn} do
 | 
			
		|||
    assert response(conn, 404)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  test "gets an object", %{conn: conn} do
 | 
			
		||||
    note_activity = insert(:note_activity)
 | 
			
		||||
    object = Object.normalize(note_activity)
 | 
			
		||||
    user = User.get_cached_by_ap_id(note_activity.data["actor"])
 | 
			
		||||
    [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"]))
 | 
			
		||||
    url = "/objects/#{uuid}"
 | 
			
		||||
  describe "GET object/2" do
 | 
			
		||||
    test "gets an object", %{conn: conn} do
 | 
			
		||||
      note_activity = insert(:note_activity)
 | 
			
		||||
      object = Object.normalize(note_activity)
 | 
			
		||||
      user = User.get_cached_by_ap_id(note_activity.data["actor"])
 | 
			
		||||
      [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"]))
 | 
			
		||||
      url = "/objects/#{uuid}"
 | 
			
		||||
 | 
			
		||||
      conn =
 | 
			
		||||
        conn
 | 
			
		||||
        |> put_req_header("accept", "application/xml")
 | 
			
		||||
        |> get(url)
 | 
			
		||||
 | 
			
		||||
      expected =
 | 
			
		||||
        ActivityRepresenter.to_simple_form(note_activity, user, true)
 | 
			
		||||
        |> ActivityRepresenter.wrap_with_entry()
 | 
			
		||||
        |> :xmerl.export_simple(:xmerl_xml)
 | 
			
		||||
        |> to_string
 | 
			
		||||
 | 
			
		||||
      assert response(conn, 200) == expected
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "redirects to /notice/id for html format", %{conn: conn} do
 | 
			
		||||
      note_activity = insert(:note_activity)
 | 
			
		||||
      object = Object.normalize(note_activity)
 | 
			
		||||
      [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"]))
 | 
			
		||||
      url = "/objects/#{uuid}"
 | 
			
		||||
 | 
			
		||||
      conn =
 | 
			
		||||
        conn
 | 
			
		||||
        |> put_req_header("accept", "text/html")
 | 
			
		||||
        |> get(url)
 | 
			
		||||
 | 
			
		||||
      assert redirected_to(conn) == "/notice/#{note_activity.id}"
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "500s when user not found", %{conn: conn} do
 | 
			
		||||
      note_activity = insert(:note_activity)
 | 
			
		||||
      object = Object.normalize(note_activity)
 | 
			
		||||
      user = User.get_cached_by_ap_id(note_activity.data["actor"])
 | 
			
		||||
      User.invalidate_cache(user)
 | 
			
		||||
      Pleroma.Repo.delete(user)
 | 
			
		||||
      [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"]))
 | 
			
		||||
      url = "/objects/#{uuid}"
 | 
			
		||||
 | 
			
		||||
      conn =
 | 
			
		||||
        conn
 | 
			
		||||
        |> put_req_header("accept", "application/xml")
 | 
			
		||||
        |> get(url)
 | 
			
		||||
 | 
			
		||||
      assert response(conn, 500) == ~S({"error":"Something went wrong"})
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "404s on private objects", %{conn: conn} do
 | 
			
		||||
      note_activity = insert(:direct_note_activity)
 | 
			
		||||
      object = Object.normalize(note_activity)
 | 
			
		||||
      [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"]))
 | 
			
		||||
 | 
			
		||||
      conn
 | 
			
		||||
      |> get("/objects/#{uuid}")
 | 
			
		||||
      |> response(404)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "404s on nonexisting objects", %{conn: conn} do
 | 
			
		||||
      conn
 | 
			
		||||
      |> get("/objects/123")
 | 
			
		||||
      |> response(404)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe "GET activity/2" do
 | 
			
		||||
    test "gets an activity in xml format", %{conn: conn} do
 | 
			
		||||
      note_activity = insert(:note_activity)
 | 
			
		||||
      [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"]))
 | 
			
		||||
 | 
			
		||||
    conn =
 | 
			
		||||
      conn
 | 
			
		||||
      |> put_req_header("accept", "application/xml")
 | 
			
		||||
      |> get(url)
 | 
			
		||||
      |> get("/activities/#{uuid}")
 | 
			
		||||
      |> response(200)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    expected =
 | 
			
		||||
      ActivityRepresenter.to_simple_form(note_activity, user, true)
 | 
			
		||||
      |> ActivityRepresenter.wrap_with_entry()
 | 
			
		||||
      |> :xmerl.export_simple(:xmerl_xml)
 | 
			
		||||
      |> to_string
 | 
			
		||||
    test "redirects to /notice/id for html format", %{conn: conn} do
 | 
			
		||||
      note_activity = insert(:note_activity)
 | 
			
		||||
      [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"]))
 | 
			
		||||
 | 
			
		||||
    assert response(conn, 200) == expected
 | 
			
		||||
      conn =
 | 
			
		||||
        conn
 | 
			
		||||
        |> put_req_header("accept", "text/html")
 | 
			
		||||
        |> get("/activities/#{uuid}")
 | 
			
		||||
 | 
			
		||||
      assert redirected_to(conn) == "/notice/#{note_activity.id}"
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "505s when user not found", %{conn: conn} do
 | 
			
		||||
      note_activity = insert(:note_activity)
 | 
			
		||||
      [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"]))
 | 
			
		||||
      user = User.get_cached_by_ap_id(note_activity.data["actor"])
 | 
			
		||||
      User.invalidate_cache(user)
 | 
			
		||||
      Pleroma.Repo.delete(user)
 | 
			
		||||
 | 
			
		||||
      conn =
 | 
			
		||||
        conn
 | 
			
		||||
        |> put_req_header("accept", "text/html")
 | 
			
		||||
        |> get("/activities/#{uuid}")
 | 
			
		||||
 | 
			
		||||
      assert response(conn, 500) == ~S({"error":"Something went wrong"})
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "404s on deleted objects", %{conn: conn} do
 | 
			
		||||
      note_activity = insert(:note_activity)
 | 
			
		||||
      object = Object.normalize(note_activity)
 | 
			
		||||
      [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"]))
 | 
			
		||||
 | 
			
		||||
      conn
 | 
			
		||||
      |> put_req_header("accept", "application/xml")
 | 
			
		||||
      |> get("/objects/#{uuid}")
 | 
			
		||||
      |> response(200)
 | 
			
		||||
 | 
			
		||||
      Object.delete(object)
 | 
			
		||||
 | 
			
		||||
      conn
 | 
			
		||||
      |> put_req_header("accept", "application/xml")
 | 
			
		||||
      |> get("/objects/#{uuid}")
 | 
			
		||||
      |> response(404)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "404s on private activities", %{conn: conn} do
 | 
			
		||||
      note_activity = insert(:direct_note_activity)
 | 
			
		||||
      [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"]))
 | 
			
		||||
 | 
			
		||||
      conn
 | 
			
		||||
      |> get("/activities/#{uuid}")
 | 
			
		||||
      |> response(404)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "404s on nonexistent activities", %{conn: conn} do
 | 
			
		||||
      conn
 | 
			
		||||
      |> get("/activities/123")
 | 
			
		||||
      |> response(404)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "gets an activity in AS2 format", %{conn: conn} do
 | 
			
		||||
      note_activity = insert(:note_activity)
 | 
			
		||||
      [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"]))
 | 
			
		||||
      url = "/activities/#{uuid}"
 | 
			
		||||
 | 
			
		||||
      conn =
 | 
			
		||||
        conn
 | 
			
		||||
        |> put_req_header("accept", "application/activity+json")
 | 
			
		||||
        |> get(url)
 | 
			
		||||
 | 
			
		||||
      assert json_response(conn, 200)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  test "404s on private objects", %{conn: conn} do
 | 
			
		||||
    note_activity = insert(:direct_note_activity)
 | 
			
		||||
    object = Object.normalize(note_activity)
 | 
			
		||||
    [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"]))
 | 
			
		||||
  describe "GET notice/2" do
 | 
			
		||||
    test "gets a notice in xml format", %{conn: conn} do
 | 
			
		||||
      note_activity = insert(:note_activity)
 | 
			
		||||
 | 
			
		||||
    conn
 | 
			
		||||
    |> get("/objects/#{uuid}")
 | 
			
		||||
    |> response(404)
 | 
			
		||||
  end
 | 
			
		||||
      conn
 | 
			
		||||
      |> get("/notice/#{note_activity.id}")
 | 
			
		||||
      |> response(200)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
  test "404s on nonexisting objects", %{conn: conn} do
 | 
			
		||||
    conn
 | 
			
		||||
    |> get("/objects/123")
 | 
			
		||||
    |> response(404)
 | 
			
		||||
  end
 | 
			
		||||
    test "gets a notice in AS2 format", %{conn: conn} do
 | 
			
		||||
      note_activity = insert(:note_activity)
 | 
			
		||||
 | 
			
		||||
  test "gets an activity in xml format", %{conn: conn} do
 | 
			
		||||
    note_activity = insert(:note_activity)
 | 
			
		||||
    [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"]))
 | 
			
		||||
 | 
			
		||||
    conn
 | 
			
		||||
    |> put_req_header("accept", "application/xml")
 | 
			
		||||
    |> get("/activities/#{uuid}")
 | 
			
		||||
    |> response(200)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  test "404s on deleted objects", %{conn: conn} do
 | 
			
		||||
    note_activity = insert(:note_activity)
 | 
			
		||||
    object = Object.normalize(note_activity)
 | 
			
		||||
    [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"]))
 | 
			
		||||
 | 
			
		||||
    conn
 | 
			
		||||
    |> put_req_header("accept", "application/xml")
 | 
			
		||||
    |> get("/objects/#{uuid}")
 | 
			
		||||
    |> response(200)
 | 
			
		||||
 | 
			
		||||
    Object.delete(object)
 | 
			
		||||
 | 
			
		||||
    conn
 | 
			
		||||
    |> put_req_header("accept", "application/xml")
 | 
			
		||||
    |> get("/objects/#{uuid}")
 | 
			
		||||
    |> response(404)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  test "404s on private activities", %{conn: conn} do
 | 
			
		||||
    note_activity = insert(:direct_note_activity)
 | 
			
		||||
    [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"]))
 | 
			
		||||
 | 
			
		||||
    conn
 | 
			
		||||
    |> get("/activities/#{uuid}")
 | 
			
		||||
    |> response(404)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  test "404s on nonexistent activities", %{conn: conn} do
 | 
			
		||||
    conn
 | 
			
		||||
    |> get("/activities/123")
 | 
			
		||||
    |> response(404)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  test "gets a notice in xml format", %{conn: conn} do
 | 
			
		||||
    note_activity = insert(:note_activity)
 | 
			
		||||
 | 
			
		||||
    conn
 | 
			
		||||
    |> get("/notice/#{note_activity.id}")
 | 
			
		||||
    |> response(200)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  test "gets a notice in AS2 format", %{conn: conn} do
 | 
			
		||||
    note_activity = insert(:note_activity)
 | 
			
		||||
 | 
			
		||||
    conn
 | 
			
		||||
    |> put_req_header("accept", "application/activity+json")
 | 
			
		||||
    |> get("/notice/#{note_activity.id}")
 | 
			
		||||
    |> json_response(200)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  test "only gets a notice in AS2 format for Create messages", %{conn: conn} do
 | 
			
		||||
    note_activity = insert(:note_activity)
 | 
			
		||||
    url = "/notice/#{note_activity.id}"
 | 
			
		||||
 | 
			
		||||
    conn =
 | 
			
		||||
      conn
 | 
			
		||||
      |> put_req_header("accept", "application/activity+json")
 | 
			
		||||
      |> get(url)
 | 
			
		||||
      |> get("/notice/#{note_activity.id}")
 | 
			
		||||
      |> json_response(200)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    assert json_response(conn, 200)
 | 
			
		||||
    test "500s when actor not found", %{conn: conn} do
 | 
			
		||||
      note_activity = insert(:note_activity)
 | 
			
		||||
      user = User.get_cached_by_ap_id(note_activity.data["actor"])
 | 
			
		||||
      User.invalidate_cache(user)
 | 
			
		||||
      Pleroma.Repo.delete(user)
 | 
			
		||||
 | 
			
		||||
    user = insert(:user)
 | 
			
		||||
      conn =
 | 
			
		||||
        conn
 | 
			
		||||
        |> get("/notice/#{note_activity.id}")
 | 
			
		||||
 | 
			
		||||
    {:ok, like_activity, _} = CommonAPI.favorite(note_activity.id, user)
 | 
			
		||||
    url = "/notice/#{like_activity.id}"
 | 
			
		||||
      assert response(conn, 500) == ~S({"error":"Something went wrong"})
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    assert like_activity.data["type"] == "Like"
 | 
			
		||||
    test "only gets a notice in AS2 format for Create messages", %{conn: conn} do
 | 
			
		||||
      note_activity = insert(:note_activity)
 | 
			
		||||
      url = "/notice/#{note_activity.id}"
 | 
			
		||||
 | 
			
		||||
    conn =
 | 
			
		||||
      build_conn()
 | 
			
		||||
      |> put_req_header("accept", "application/activity+json")
 | 
			
		||||
      |> get(url)
 | 
			
		||||
      conn =
 | 
			
		||||
        conn
 | 
			
		||||
        |> put_req_header("accept", "application/activity+json")
 | 
			
		||||
        |> get(url)
 | 
			
		||||
 | 
			
		||||
    assert response(conn, 404)
 | 
			
		||||
      assert json_response(conn, 200)
 | 
			
		||||
 | 
			
		||||
      user = insert(:user)
 | 
			
		||||
 | 
			
		||||
      {:ok, like_activity, _} = CommonAPI.favorite(note_activity.id, user)
 | 
			
		||||
      url = "/notice/#{like_activity.id}"
 | 
			
		||||
 | 
			
		||||
      assert like_activity.data["type"] == "Like"
 | 
			
		||||
 | 
			
		||||
      conn =
 | 
			
		||||
        build_conn()
 | 
			
		||||
        |> put_req_header("accept", "application/activity+json")
 | 
			
		||||
        |> get(url)
 | 
			
		||||
 | 
			
		||||
      assert response(conn, 404)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "render html for redirect for html format", %{conn: conn} do
 | 
			
		||||
      note_activity = insert(:note_activity)
 | 
			
		||||
 | 
			
		||||
      resp =
 | 
			
		||||
        conn
 | 
			
		||||
        |> put_req_header("accept", "text/html")
 | 
			
		||||
        |> get("/notice/#{note_activity.id}")
 | 
			
		||||
        |> response(200)
 | 
			
		||||
 | 
			
		||||
      assert resp =~
 | 
			
		||||
               "<meta content=\"#{Pleroma.Web.base_url()}/notice/#{note_activity.id}\" property=\"og:url\">"
 | 
			
		||||
 | 
			
		||||
      user = insert(:user)
 | 
			
		||||
 | 
			
		||||
      {:ok, like_activity, _} = CommonAPI.favorite(note_activity.id, user)
 | 
			
		||||
 | 
			
		||||
      assert like_activity.data["type"] == "Like"
 | 
			
		||||
 | 
			
		||||
      resp =
 | 
			
		||||
        conn
 | 
			
		||||
        |> put_req_header("accept", "text/html")
 | 
			
		||||
        |> get("/notice/#{like_activity.id}")
 | 
			
		||||
        |> response(200)
 | 
			
		||||
 | 
			
		||||
      assert resp =~ "<!--server-generated-meta-->"
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "404s a private notice", %{conn: conn} do
 | 
			
		||||
      note_activity = insert(:direct_note_activity)
 | 
			
		||||
      url = "/notice/#{note_activity.id}"
 | 
			
		||||
 | 
			
		||||
      conn =
 | 
			
		||||
        conn
 | 
			
		||||
        |> get(url)
 | 
			
		||||
 | 
			
		||||
      assert response(conn, 404)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "404s a nonexisting notice", %{conn: conn} do
 | 
			
		||||
      url = "/notice/123"
 | 
			
		||||
 | 
			
		||||
      conn =
 | 
			
		||||
        conn
 | 
			
		||||
        |> get(url)
 | 
			
		||||
 | 
			
		||||
      assert response(conn, 404)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  test "gets an activity in AS2 format", %{conn: conn} do
 | 
			
		||||
    note_activity = insert(:note_activity)
 | 
			
		||||
    [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"]))
 | 
			
		||||
    url = "/activities/#{uuid}"
 | 
			
		||||
  describe "feed_redirect" do
 | 
			
		||||
    test "undefined format. it redirects to feed", %{conn: conn} do
 | 
			
		||||
      note_activity = insert(:note_activity)
 | 
			
		||||
      user = User.get_cached_by_ap_id(note_activity.data["actor"])
 | 
			
		||||
 | 
			
		||||
    conn =
 | 
			
		||||
      conn
 | 
			
		||||
      |> put_req_header("accept", "application/activity+json")
 | 
			
		||||
      |> get(url)
 | 
			
		||||
      response =
 | 
			
		||||
        conn
 | 
			
		||||
        |> put_req_header("accept", "application/xml")
 | 
			
		||||
        |> get("/users/#{user.nickname}")
 | 
			
		||||
        |> response(302)
 | 
			
		||||
 | 
			
		||||
    assert json_response(conn, 200)
 | 
			
		||||
      assert response ==
 | 
			
		||||
               "<html><body>You are being <a href=\"#{Pleroma.Web.base_url()}/users/#{
 | 
			
		||||
                 user.nickname
 | 
			
		||||
               }/feed.atom\">redirected</a>.</body></html>"
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "undefined format. it returns error when user not found", %{conn: conn} do
 | 
			
		||||
      response =
 | 
			
		||||
        conn
 | 
			
		||||
        |> put_req_header("accept", "application/xml")
 | 
			
		||||
        |> get("/users/jimm")
 | 
			
		||||
        |> response(404)
 | 
			
		||||
 | 
			
		||||
      assert response == ~S({"error":"Not found"})
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "activity+json format. it redirects on actual feed of user", %{conn: conn} do
 | 
			
		||||
      note_activity = insert(:note_activity)
 | 
			
		||||
      user = User.get_cached_by_ap_id(note_activity.data["actor"])
 | 
			
		||||
 | 
			
		||||
      response =
 | 
			
		||||
        conn
 | 
			
		||||
        |> put_req_header("accept", "application/activity+json")
 | 
			
		||||
        |> get("/users/#{user.nickname}")
 | 
			
		||||
        |> json_response(200)
 | 
			
		||||
 | 
			
		||||
      assert response["endpoints"] == %{
 | 
			
		||||
               "oauthAuthorizationEndpoint" => "#{Pleroma.Web.base_url()}/oauth/authorize",
 | 
			
		||||
               "oauthRegistrationEndpoint" => "#{Pleroma.Web.base_url()}/api/v1/apps",
 | 
			
		||||
               "oauthTokenEndpoint" => "#{Pleroma.Web.base_url()}/oauth/token",
 | 
			
		||||
               "sharedInbox" => "#{Pleroma.Web.base_url()}/inbox"
 | 
			
		||||
             }
 | 
			
		||||
 | 
			
		||||
      assert response["@context"] == [
 | 
			
		||||
               "https://www.w3.org/ns/activitystreams",
 | 
			
		||||
               "http://localhost:4001/schemas/litepub-0.1.jsonld",
 | 
			
		||||
               %{"@language" => "und"}
 | 
			
		||||
             ]
 | 
			
		||||
 | 
			
		||||
      assert Map.take(response, [
 | 
			
		||||
               "followers",
 | 
			
		||||
               "following",
 | 
			
		||||
               "id",
 | 
			
		||||
               "inbox",
 | 
			
		||||
               "manuallyApprovesFollowers",
 | 
			
		||||
               "name",
 | 
			
		||||
               "outbox",
 | 
			
		||||
               "preferredUsername",
 | 
			
		||||
               "summary",
 | 
			
		||||
               "tag",
 | 
			
		||||
               "type",
 | 
			
		||||
               "url"
 | 
			
		||||
             ]) == %{
 | 
			
		||||
               "followers" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/followers",
 | 
			
		||||
               "following" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/following",
 | 
			
		||||
               "id" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}",
 | 
			
		||||
               "inbox" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/inbox",
 | 
			
		||||
               "manuallyApprovesFollowers" => false,
 | 
			
		||||
               "name" => user.name,
 | 
			
		||||
               "outbox" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/outbox",
 | 
			
		||||
               "preferredUsername" => user.nickname,
 | 
			
		||||
               "summary" => user.bio,
 | 
			
		||||
               "tag" => [],
 | 
			
		||||
               "type" => "Person",
 | 
			
		||||
               "url" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}"
 | 
			
		||||
             }
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "activity+json format. it returns error whe use not found", %{conn: conn} do
 | 
			
		||||
      response =
 | 
			
		||||
        conn
 | 
			
		||||
        |> put_req_header("accept", "application/activity+json")
 | 
			
		||||
        |> get("/users/jimm")
 | 
			
		||||
        |> json_response(404)
 | 
			
		||||
 | 
			
		||||
      assert response == "Not found"
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "json format. it redirects on actual feed of user", %{conn: conn} do
 | 
			
		||||
      note_activity = insert(:note_activity)
 | 
			
		||||
      user = User.get_cached_by_ap_id(note_activity.data["actor"])
 | 
			
		||||
 | 
			
		||||
      response =
 | 
			
		||||
        conn
 | 
			
		||||
        |> put_req_header("accept", "application/json")
 | 
			
		||||
        |> get("/users/#{user.nickname}")
 | 
			
		||||
        |> json_response(200)
 | 
			
		||||
 | 
			
		||||
      assert response["endpoints"] == %{
 | 
			
		||||
               "oauthAuthorizationEndpoint" => "#{Pleroma.Web.base_url()}/oauth/authorize",
 | 
			
		||||
               "oauthRegistrationEndpoint" => "#{Pleroma.Web.base_url()}/api/v1/apps",
 | 
			
		||||
               "oauthTokenEndpoint" => "#{Pleroma.Web.base_url()}/oauth/token",
 | 
			
		||||
               "sharedInbox" => "#{Pleroma.Web.base_url()}/inbox"
 | 
			
		||||
             }
 | 
			
		||||
 | 
			
		||||
      assert response["@context"] == [
 | 
			
		||||
               "https://www.w3.org/ns/activitystreams",
 | 
			
		||||
               "http://localhost:4001/schemas/litepub-0.1.jsonld",
 | 
			
		||||
               %{"@language" => "und"}
 | 
			
		||||
             ]
 | 
			
		||||
 | 
			
		||||
      assert Map.take(response, [
 | 
			
		||||
               "followers",
 | 
			
		||||
               "following",
 | 
			
		||||
               "id",
 | 
			
		||||
               "inbox",
 | 
			
		||||
               "manuallyApprovesFollowers",
 | 
			
		||||
               "name",
 | 
			
		||||
               "outbox",
 | 
			
		||||
               "preferredUsername",
 | 
			
		||||
               "summary",
 | 
			
		||||
               "tag",
 | 
			
		||||
               "type",
 | 
			
		||||
               "url"
 | 
			
		||||
             ]) == %{
 | 
			
		||||
               "followers" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/followers",
 | 
			
		||||
               "following" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/following",
 | 
			
		||||
               "id" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}",
 | 
			
		||||
               "inbox" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/inbox",
 | 
			
		||||
               "manuallyApprovesFollowers" => false,
 | 
			
		||||
               "name" => user.name,
 | 
			
		||||
               "outbox" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}/outbox",
 | 
			
		||||
               "preferredUsername" => user.nickname,
 | 
			
		||||
               "summary" => user.bio,
 | 
			
		||||
               "tag" => [],
 | 
			
		||||
               "type" => "Person",
 | 
			
		||||
               "url" => "#{Pleroma.Web.base_url()}/users/#{user.nickname}"
 | 
			
		||||
             }
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "json format. it returns error whe use not found", %{conn: conn} do
 | 
			
		||||
      response =
 | 
			
		||||
        conn
 | 
			
		||||
        |> put_req_header("accept", "application/json")
 | 
			
		||||
        |> get("/users/jimm")
 | 
			
		||||
        |> json_response(404)
 | 
			
		||||
 | 
			
		||||
      assert response == "Not found"
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "html format. it redirects on actual feed of user", %{conn: conn} do
 | 
			
		||||
      note_activity = insert(:note_activity)
 | 
			
		||||
      user = User.get_cached_by_ap_id(note_activity.data["actor"])
 | 
			
		||||
 | 
			
		||||
      response =
 | 
			
		||||
        conn
 | 
			
		||||
        |> get("/users/#{user.nickname}")
 | 
			
		||||
        |> response(200)
 | 
			
		||||
 | 
			
		||||
      assert response ==
 | 
			
		||||
               Fallback.RedirectController.redirector_with_meta(
 | 
			
		||||
                 conn,
 | 
			
		||||
                 %{user: user}
 | 
			
		||||
               ).resp_body
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "html format. it returns error when user not found", %{conn: conn} do
 | 
			
		||||
      response =
 | 
			
		||||
        conn
 | 
			
		||||
        |> get("/users/jimm")
 | 
			
		||||
        |> json_response(404)
 | 
			
		||||
 | 
			
		||||
      assert response == %{"error" => "Not found"}
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  test "404s a private notice", %{conn: conn} do
 | 
			
		||||
    note_activity = insert(:direct_note_activity)
 | 
			
		||||
    url = "/notice/#{note_activity.id}"
 | 
			
		||||
  describe "GET /notice/:id/embed_player" do
 | 
			
		||||
    test "render embed player", %{conn: conn} do
 | 
			
		||||
      note_activity = insert(:note_activity)
 | 
			
		||||
      object = Pleroma.Object.normalize(note_activity)
 | 
			
		||||
 | 
			
		||||
    conn =
 | 
			
		||||
      conn
 | 
			
		||||
      |> get(url)
 | 
			
		||||
      object_data =
 | 
			
		||||
        Map.put(object.data, "attachment", [
 | 
			
		||||
          %{
 | 
			
		||||
            "url" => [
 | 
			
		||||
              %{
 | 
			
		||||
                "href" =>
 | 
			
		||||
                  "https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4",
 | 
			
		||||
                "mediaType" => "video/mp4",
 | 
			
		||||
                "type" => "Link"
 | 
			
		||||
              }
 | 
			
		||||
            ]
 | 
			
		||||
          }
 | 
			
		||||
        ])
 | 
			
		||||
 | 
			
		||||
    assert response(conn, 404)
 | 
			
		||||
  end
 | 
			
		||||
      object
 | 
			
		||||
      |> Ecto.Changeset.change(data: object_data)
 | 
			
		||||
      |> Pleroma.Repo.update()
 | 
			
		||||
 | 
			
		||||
  test "404s a nonexisting notice", %{conn: conn} do
 | 
			
		||||
    url = "/notice/123"
 | 
			
		||||
      conn =
 | 
			
		||||
        conn
 | 
			
		||||
        |> get("/notice/#{note_activity.id}/embed_player")
 | 
			
		||||
 | 
			
		||||
    conn =
 | 
			
		||||
      conn
 | 
			
		||||
      |> get(url)
 | 
			
		||||
      assert Plug.Conn.get_resp_header(conn, "x-frame-options") == ["ALLOW"]
 | 
			
		||||
 | 
			
		||||
    assert response(conn, 404)
 | 
			
		||||
      assert Plug.Conn.get_resp_header(
 | 
			
		||||
               conn,
 | 
			
		||||
               "content-security-policy"
 | 
			
		||||
             ) == [
 | 
			
		||||
               "default-src 'none';style-src 'self' 'unsafe-inline';img-src 'self' data: https:; media-src 'self' https:;"
 | 
			
		||||
             ]
 | 
			
		||||
 | 
			
		||||
      assert response(conn, 200) =~
 | 
			
		||||
               "<video controls loop><source src=\"https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4\" type=\"video/mp4\">Your browser does not support video/mp4 playback.</video>"
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "404s when activity isn't create", %{conn: conn} do
 | 
			
		||||
      note_activity = insert(:note_activity, data_attrs: %{"type" => "Like"})
 | 
			
		||||
 | 
			
		||||
      assert conn
 | 
			
		||||
             |> get("/notice/#{note_activity.id}/embed_player")
 | 
			
		||||
             |> response(404)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "404s when activity is direct message", %{conn: conn} do
 | 
			
		||||
      note_activity = insert(:note_activity, data_attrs: %{"directMessage" => true})
 | 
			
		||||
 | 
			
		||||
      assert conn
 | 
			
		||||
             |> get("/notice/#{note_activity.id}/embed_player")
 | 
			
		||||
             |> response(404)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "404s when attachment is empty", %{conn: conn} do
 | 
			
		||||
      note_activity = insert(:note_activity)
 | 
			
		||||
      object = Pleroma.Object.normalize(note_activity)
 | 
			
		||||
      object_data = Map.put(object.data, "attachment", [])
 | 
			
		||||
 | 
			
		||||
      object
 | 
			
		||||
      |> Ecto.Changeset.change(data: object_data)
 | 
			
		||||
      |> Pleroma.Repo.update()
 | 
			
		||||
 | 
			
		||||
      assert conn
 | 
			
		||||
             |> get("/notice/#{note_activity.id}/embed_player")
 | 
			
		||||
             |> response(404)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    test "404s when attachment isn't audio or video", %{conn: conn} do
 | 
			
		||||
      note_activity = insert(:note_activity)
 | 
			
		||||
      object = Pleroma.Object.normalize(note_activity)
 | 
			
		||||
 | 
			
		||||
      object_data =
 | 
			
		||||
        Map.put(object.data, "attachment", [
 | 
			
		||||
          %{
 | 
			
		||||
            "url" => [
 | 
			
		||||
              %{
 | 
			
		||||
                "href" => "https://peertube.moe/static/webseed/480.jpg",
 | 
			
		||||
                "mediaType" => "image/jpg",
 | 
			
		||||
                "type" => "Link"
 | 
			
		||||
              }
 | 
			
		||||
            ]
 | 
			
		||||
          }
 | 
			
		||||
        ])
 | 
			
		||||
 | 
			
		||||
      object
 | 
			
		||||
      |> Ecto.Changeset.change(data: object_data)
 | 
			
		||||
      |> Pleroma.Repo.update()
 | 
			
		||||
 | 
			
		||||
      assert conn
 | 
			
		||||
             |> get("/notice/#{note_activity.id}/embed_player")
 | 
			
		||||
             |> response(404)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -124,8 +124,7 @@ test "renders body for follow activity" do
 | 
			
		|||
    {:ok, _, _, activity} = CommonAPI.follow(user, other_user)
 | 
			
		||||
    object = Object.normalize(activity)
 | 
			
		||||
 | 
			
		||||
    assert Impl.format_body(%{activity: activity}, user, object) ==
 | 
			
		||||
             "@Bob has followed you"
 | 
			
		||||
    assert Impl.format_body(%{activity: activity}, user, object) == "@Bob has followed you"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  test "renders body for announce activity" do
 | 
			
		||||
| 
						 | 
				
			
			@ -156,7 +155,6 @@ test "renders body for like activity" do
 | 
			
		|||
    {:ok, activity, _} = CommonAPI.favorite(activity.id, user)
 | 
			
		||||
    object = Object.normalize(activity)
 | 
			
		||||
 | 
			
		||||
    assert Impl.format_body(%{activity: activity}, user, object) ==
 | 
			
		||||
             "@Bob has favorited your post"
 | 
			
		||||
    assert Impl.format_body(%{activity: activity}, user, object) == "@Bob has favorited your post"
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue