Merge branch 'develop' into feature/hide-follows-remote

This commit is contained in:
rinpatch 2019-07-31 14:12:29 +03:00
commit c88a5d3251
43 changed files with 951 additions and 387 deletions

View file

@ -6,10 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased] ## [Unreleased]
### Changed ### 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: 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: OpenGraph and TwitterCard providers enabled by default
- Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text - 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 - 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 `skipThreadContainment` in `metadata` for the `skip_thread_containment` option
- NodeInfo: Return `mailerEnabled` in `metadata`
- Mastodon API: Unsubscribe followers when they unfollow a user - Mastodon API: Unsubscribe followers when they unfollow a user
- AdminAPI: Add "godmode" while fetching user statuses (i.e. admin can see private statuses) - 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: 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. - 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: 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 ### Added
- MRF: Support for priming the mediaproxy cache (`Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy`) - 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: Add an internal service actor for fetching ActivityPub objects.
- ActivityPub: Optional signing of ActivityPub object fetches. - ActivityPub: Optional signing of ActivityPub object fetches.
- Admin API: Endpoint for fetching latest user's statuses - 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 ### Changed
- Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text - Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text

View file

@ -534,7 +534,8 @@ config :pleroma, :rate_limit,
relation_id_action: {60_000, 2}, relation_id_action: {60_000, 2},
statuses_actions: {10_000, 15}, statuses_actions: {10_000, 15},
status_id_action: {60_000, 3}, 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 # Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above. # of this file so it overrides the configuration defined above.

View file

@ -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_banner`: Set/clear user banner image
- PATCH `/api/v1/pleroma/accounts/update_background`: Set/clear user background 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` ## `/api/v1/pleroma/mascot`
### Gets user mascot image ### Gets user mascot image
* Method `GET` * Method `GET`

View file

@ -8,6 +8,7 @@ defmodule Mix.Tasks.Pleroma.Database do
alias Pleroma.Repo alias Pleroma.Repo
alias Pleroma.User alias Pleroma.User
require Logger require Logger
require Pleroma.Constants
import Mix.Pleroma import Mix.Pleroma
use Mix.Task use Mix.Task
@ -99,10 +100,15 @@ defmodule Mix.Tasks.Pleroma.Database do
NaiveDateTime.utc_now() NaiveDateTime.utc_now()
|> NaiveDateTime.add(-(deadline * 86_400)) |> NaiveDateTime.add(-(deadline * 86_400))
public = "https://www.w3.org/ns/activitystreams#Public"
from(o in Object, 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: o.inserted_at < ^time_deadline,
where: where:
fragment("split_part(?->>'actor', '/', 3) != ?", o.data, ^Pleroma.Web.Endpoint.host()) fragment("split_part(?->>'actor', '/', 3) != ?", o.data, ^Pleroma.Web.Endpoint.host())

View file

@ -9,6 +9,8 @@ defmodule Pleroma.Activity.Search do
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.ActivityPub.Visibility
require Pleroma.Constants
import Ecto.Query import Ecto.Query
def search(user, search_query, options \\ []) do def search(user, search_query, options \\ []) do
@ -39,7 +41,7 @@ defmodule Pleroma.Activity.Search do
defp restrict_public(q) do defp restrict_public(q) do
from([a, o] in q, from([a, o] in q,
where: fragment("?->>'type' = 'Create'", a.data), 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 end

9
lib/pleroma/constants.ex Normal file
View 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

View file

@ -11,6 +11,7 @@ defmodule Pleroma.HTTP.Connection do
connect_timeout: 10_000, connect_timeout: 10_000,
recv_timeout: 20_000, recv_timeout: 20_000,
follow_redirect: true, follow_redirect: true,
force_redirect: true,
pool: :federation pool: :federation
] ]
@adapter Application.get_env(:tesla, :adapter) @adapter Application.get_env(:tesla, :adapter)

View file

@ -15,7 +15,7 @@ defmodule Pleroma.Signature do
|> Map.put(:fragment, nil) |> Map.put(:fragment, nil)
uri = 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", "")) Map.put(uri, :path, String.replace(uri.path, "/publickey", ""))
else else
uri uri

View file

@ -477,7 +477,7 @@ defmodule Pleroma.User do
end end
def update_and_set_cache(changeset) do 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) set_cache(user)
else else
e -> e e -> e

View file

@ -23,6 +23,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
import Pleroma.Web.ActivityPub.Visibility import Pleroma.Web.ActivityPub.Visibility
require Logger require Logger
require Pleroma.Constants
# For Announce activities, we filter the recipients based on following status for any actors # 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. # that match actual users. See issue #164 for more information about why this is necessary.
@ -207,8 +208,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
def stream_out_participations(_, _), do: :noop def stream_out_participations(_, _), do: :noop
def stream_out(activity) do def stream_out(activity) do
public = "https://www.w3.org/ns/activitystreams#Public"
if activity.data["type"] in ["Create", "Announce", "Delete"] do if activity.data["type"] in ["Create", "Announce", "Delete"] do
object = Object.normalize(activity) object = Object.normalize(activity)
# Do not stream out poll replies # Do not stream out poll replies
@ -216,7 +215,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
Pleroma.Web.Streamer.stream("user", activity) Pleroma.Web.Streamer.stream("user", activity)
Pleroma.Web.Streamer.stream("list", 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) Pleroma.Web.Streamer.stream("public", activity)
if activity.local do if activity.local do
@ -238,12 +237,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end end
end end
else else
# TODO: Write test, replace with visibility test if get_visibility(activity) == "direct",
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) do: Pleroma.Web.Streamer.stream("direct", activity)
end end
end end
@ -514,7 +508,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end end
defp fetch_activities_for_context_query(context, opts) do defp fetch_activities_for_context_query(context, opts) do
public = ["https://www.w3.org/ns/activitystreams#Public"] public = [Pleroma.Constants.as_public()]
recipients = recipients =
if opts["user"], do: [opts["user"].ap_id | opts["user"].following] ++ public, else: public if opts["user"], do: [opts["user"].ap_id | opts["user"].following] ++ public, else: public
@ -555,7 +549,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end end
def fetch_public_activities(opts \\ %{}) do 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 q
|> restrict_unlisted() |> restrict_unlisted()
@ -646,10 +640,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp user_activities_recipients(%{"reading_user" => reading_user}) do defp user_activities_recipients(%{"reading_user" => reading_user}) do
if reading_user do if reading_user do
["https://www.w3.org/ns/activitystreams#Public"] ++ [Pleroma.Constants.as_public()] ++ [reading_user.ap_id | reading_user.following]
[reading_user.ap_id | reading_user.following]
else else
["https://www.w3.org/ns/activitystreams#Public"] [Pleroma.Constants.as_public()]
end end
end end
@ -834,7 +827,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
fragment( fragment(
"not (coalesce(?->'cc', '{}'::jsonb) \\?| ?)", "not (coalesce(?->'cc', '{}'::jsonb) \\?| ?)",
activity.data, activity.data,
^["https://www.w3.org/ns/activitystreams#Public"] ^[Pleroma.Constants.as_public()]
) )
) )
end end
@ -971,7 +964,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
where: where:
fragment("? && ?", activity.recipients, ^recipients) or fragment("? && ?", activity.recipients, ^recipients) or
(fragment("? && ?", activity.recipients, ^recipients_with_public) and (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 end

View file

@ -4,6 +4,9 @@
defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicy do defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicy do
alias Pleroma.User alias Pleroma.User
require Pleroma.Constants
@moduledoc "Block messages with too much mentions (configurable)" @moduledoc "Block messages with too much mentions (configurable)"
@behaviour Pleroma.Web.ActivityPub.MRF @behaviour Pleroma.Web.ActivityPub.MRF
@ -19,12 +22,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicy do
when follower_collection? and recipients > threshold -> when follower_collection? and recipients > threshold ->
message message
|> Map.put("to", [follower_collection]) |> 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 -> {:public, recipients} when recipients > threshold ->
message message
|> Map.put("to", []) |> Map.put("to", [])
|> Map.put("cc", ["https://www.w3.org/ns/activitystreams#Public"]) |> Map.put("cc", [Pleroma.Constants.as_public()])
_ -> _ ->
message message
@ -51,10 +54,10 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicy do
recipients = (message["to"] || []) ++ (message["cc"] || []) recipients = (message["to"] || []) ++ (message["cc"] || [])
follower_collection = User.get_cached_by_ap_id(message["actor"]).follower_address 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 =
recipients recipients
|> List.delete("https://www.w3.org/ns/activitystreams#Public") |> List.delete(Pleroma.Constants.as_public())
|> List.delete(follower_collection) |> List.delete(follower_collection)
{:public, length(recipients)} {:public, length(recipients)}

View file

@ -3,6 +3,8 @@
# SPDX-License-Identifier: AGPL-3.0-only # SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
require Pleroma.Constants
@moduledoc "Reject or Word-Replace messages with a keyword or regex" @moduledoc "Reject or Word-Replace messages with a keyword or regex"
@behaviour Pleroma.Web.ActivityPub.MRF @behaviour Pleroma.Web.ActivityPub.MRF
@ -31,12 +33,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
defp check_ftl_removal( defp check_ftl_removal(
%{"to" => to, "object" => %{"content" => content, "summary" => summary}} = message %{"to" => to, "object" => %{"content" => content, "summary" => summary}} = message
) do ) 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 -> Enum.any?(Pleroma.Config.get([:mrf_keyword, :federated_timeline_removal]), fn pattern ->
string_matches?(content, pattern) or string_matches?(summary, pattern) string_matches?(content, pattern) or string_matches?(summary, pattern)
end) do end) do
to = List.delete(to, "https://www.w3.org/ns/activitystreams#Public") to = List.delete(to, Pleroma.Constants.as_public())
cc = ["https://www.w3.org/ns/activitystreams#Public" | message["cc"] || []] cc = [Pleroma.Constants.as_public() | message["cc"] || []]
message = message =
message message

View file

@ -10,7 +10,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublic do
@behaviour Pleroma.Web.ActivityPub.MRF @behaviour Pleroma.Web.ActivityPub.MRF
@public "https://www.w3.org/ns/activitystreams#Public" require Pleroma.Constants
@impl true @impl true
def filter(%{"type" => "Create"} = object) do def filter(%{"type" => "Create"} = object) do
@ -19,8 +19,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublic do
# Determine visibility # Determine visibility
visibility = visibility =
cond do cond do
@public in object["to"] -> "public" Pleroma.Constants.as_public() in object["to"] -> "public"
@public in object["cc"] -> "unlisted" Pleroma.Constants.as_public() in object["cc"] -> "unlisted"
user.follower_address in object["to"] -> "followers" user.follower_address in object["to"] -> "followers"
true -> "direct" true -> "direct"
end end

View file

@ -8,6 +8,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
@moduledoc "Filter activities depending on their origin instance" @moduledoc "Filter activities depending on their origin instance"
@behaviour MRF @behaviour MRF
require Pleroma.Constants
defp check_accept(%{host: actor_host} = _actor_info, object) do defp check_accept(%{host: actor_host} = _actor_info, object) do
accepts = accepts =
Pleroma.Config.get([:mrf_simple, :accept]) Pleroma.Config.get([:mrf_simple, :accept])
@ -89,14 +91,10 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
object = object =
with true <- MRF.subdomain_match?(timeline_removal, actor_host), with true <- MRF.subdomain_match?(timeline_removal, actor_host),
user <- User.get_cached_by_ap_id(object["actor"]), user <- User.get_cached_by_ap_id(object["actor"]),
true <- "https://www.w3.org/ns/activitystreams#Public" in object["to"] do true <- Pleroma.Constants.as_public() in object["to"] do
to = to = List.delete(object["to"], Pleroma.Constants.as_public()) ++ [user.follower_address]
List.delete(object["to"], "https://www.w3.org/ns/activitystreams#Public") ++
[user.follower_address]
cc = cc = List.delete(object["cc"], user.follower_address) ++ [Pleroma.Constants.as_public()]
List.delete(object["cc"], user.follower_address) ++
["https://www.w3.org/ns/activitystreams#Public"]
object object
|> Map.put("to", to) |> Map.put("to", to)

View file

@ -19,7 +19,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do
- `mrf_tag:disable-any-subscription`: Reject any follow requests - `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(%User{tags: tags}) when is_list(tags), do: tags
defp get_tags(_), do: [] defp get_tags(_), do: []
@ -70,9 +70,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do
) do ) do
user = User.get_cached_by_ap_id(actor) user = User.get_cached_by_ap_id(actor)
if Enum.member?(to, @public) do if Enum.member?(to, Pleroma.Constants.as_public()) do
to = List.delete(to, @public) ++ [user.follower_address] to = List.delete(to, Pleroma.Constants.as_public()) ++ [user.follower_address]
cc = List.delete(cc, user.follower_address) ++ [@public] cc = List.delete(cc, user.follower_address) ++ [Pleroma.Constants.as_public()]
object = object =
object object
@ -103,9 +103,10 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do
) do ) do
user = User.get_cached_by_ap_id(actor) user = User.get_cached_by_ap_id(actor)
if Enum.member?(to, @public) or Enum.member?(cc, @public) do if Enum.member?(to, Pleroma.Constants.as_public()) or
to = List.delete(to, @public) ++ [user.follower_address] Enum.member?(cc, Pleroma.Constants.as_public()) do
cc = List.delete(cc, @public) to = List.delete(to, Pleroma.Constants.as_public()) ++ [user.follower_address]
cc = List.delete(cc, Pleroma.Constants.as_public())
object = object =
object object

View file

@ -11,6 +11,8 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
alias Pleroma.Web.ActivityPub.Relay alias Pleroma.Web.ActivityPub.Relay
alias Pleroma.Web.ActivityPub.Transmogrifier alias Pleroma.Web.ActivityPub.Transmogrifier
require Pleroma.Constants
import Pleroma.Web.ActivityPub.Visibility import Pleroma.Web.ActivityPub.Visibility
@behaviour Pleroma.Web.Federator.Publisher @behaviour Pleroma.Web.Federator.Publisher
@ -117,8 +119,6 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|> Enum.map(& &1.ap_id) |> Enum.map(& &1.ap_id)
end end
@as_public "https://www.w3.org/ns/activitystreams#Public"
defp maybe_use_sharedinbox(%User{info: %{source_data: data}}), defp maybe_use_sharedinbox(%User{info: %{source_data: data}}),
do: (is_map(data["endpoints"]) && Map.get(data["endpoints"], "sharedInbox")) || data["inbox"] do: (is_map(data["endpoints"]) && Map.get(data["endpoints"], "sharedInbox")) || data["inbox"]
@ -145,7 +145,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
type == "Delete" -> type == "Delete" ->
maybe_use_sharedinbox(user) 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) maybe_use_sharedinbox(user)
length(to) + length(cc) > 1 -> length(to) + length(cc) > 1 ->

View file

@ -19,6 +19,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
import Ecto.Query import Ecto.Query
require Logger require Logger
require Pleroma.Constants
@doc """ @doc """
Modifies an incoming AP object (mastodon format) to our internal format. Modifies an incoming AP object (mastodon format) to our internal format.
@ -102,8 +103,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
follower_collection = User.get_cached_by_ap_id(Containment.get_actor(object)).follower_address follower_collection = User.get_cached_by_ap_id(Containment.get_actor(object)).follower_address
explicit_mentions = explicit_mentions = explicit_mentions ++ [Pleroma.Constants.as_public(), follower_collection]
explicit_mentions ++ ["https://www.w3.org/ns/activitystreams#Public", follower_collection]
fix_explicit_addressing(object, explicit_mentions, follower_collection) fix_explicit_addressing(object, explicit_mentions, follower_collection)
end end
@ -115,11 +115,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
if followers_collection not in recipients do if followers_collection not in recipients do
cond do cond do
"https://www.w3.org/ns/activitystreams#Public" in cc -> Pleroma.Constants.as_public() in cc ->
to = to ++ [followers_collection] to = to ++ [followers_collection]
Map.put(object, "to", to) Map.put(object, "to", to)
"https://www.w3.org/ns/activitystreams#Public" in to -> Pleroma.Constants.as_public() in to ->
cc = cc ++ [followers_collection] cc = cc ++ [followers_collection]
Map.put(object, "cc", cc) Map.put(object, "cc", cc)
@ -480,8 +480,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
{:ok, %User{} = follower} <- User.get_or_fetch_by_ap_id(follower), {:ok, %User{} = follower} <- User.get_or_fetch_by_ap_id(follower),
{:ok, activity} <- ActivityPub.follow(follower, followed, id, false) do {:ok, activity} <- ActivityPub.follow(follower, followed, id, false) do
with deny_follow_blocked <- Pleroma.Config.get([:user, :deny_follow_blocked]), with deny_follow_blocked <- Pleroma.Config.get([:user, :deny_follow_blocked]),
{_, false} <- {_, false} <- {:user_blocked, User.blocks?(followed, follower) && deny_follow_blocked},
{:user_blocked, User.blocks?(followed, follower) && deny_follow_blocked},
{_, false} <- {:user_locked, User.locked?(followed)}, {_, false} <- {:user_locked, User.locked?(followed)},
{_, {:ok, follower}} <- {:follow, User.follow(follower, followed)}, {_, {:ok, follower}} <- {:follow, User.follow(follower, followed)},
{_, {:ok, _}} <- {_, {:ok, _}} <-
@ -656,20 +655,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
nil -> nil ->
case User.get_cached_by_ap_id(object_id) do case User.get_cached_by_ap_id(object_id) do
%User{ap_id: ^actor} = user -> %User{ap_id: ^actor} = user ->
{:ok, followers} = User.get_followers(user) User.delete(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)
nil -> nil ->
:error :error

View file

@ -18,6 +18,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
import Ecto.Query import Ecto.Query
require Logger require Logger
require Pleroma.Constants
@supported_object_types ["Article", "Note", "Video", "Page", "Question", "Answer"] @supported_object_types ["Article", "Note", "Video", "Page", "Question", "Answer"]
@supported_report_states ~w(open closed resolved) @supported_report_states ~w(open closed resolved)
@ -418,7 +419,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
"type" => "Follow", "type" => "Follow",
"actor" => follower_id, "actor" => follower_id,
"to" => [followed_id], "to" => [followed_id],
"cc" => ["https://www.w3.org/ns/activitystreams#Public"], "cc" => [Pleroma.Constants.as_public()],
"object" => followed_id, "object" => followed_id,
"state" => "pending" "state" => "pending"
} }
@ -510,7 +511,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
"actor" => ap_id, "actor" => ap_id,
"object" => id, "object" => id,
"to" => [user.follower_address, object.data["actor"]], "to" => [user.follower_address, object.data["actor"]],
"cc" => ["https://www.w3.org/ns/activitystreams#Public"], "cc" => [Pleroma.Constants.as_public()],
"context" => object.data["context"] "context" => object.data["context"]
} }
@ -530,7 +531,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
"actor" => ap_id, "actor" => ap_id,
"object" => activity.data, "object" => activity.data,
"to" => [user.follower_address, activity.data["actor"]], "to" => [user.follower_address, activity.data["actor"]],
"cc" => ["https://www.w3.org/ns/activitystreams#Public"], "cc" => [Pleroma.Constants.as_public()],
"context" => context "context" => context
} }
@ -547,7 +548,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
"actor" => ap_id, "actor" => ap_id,
"object" => activity.data, "object" => activity.data,
"to" => [user.follower_address, activity.data["actor"]], "to" => [user.follower_address, activity.data["actor"]],
"cc" => ["https://www.w3.org/ns/activitystreams#Public"], "cc" => [Pleroma.Constants.as_public()],
"context" => context "context" => context
} }
@ -556,7 +557,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
def add_announce_to_object( def add_announce_to_object(
%Activity{ %Activity{
data: %{"actor" => actor, "cc" => ["https://www.w3.org/ns/activitystreams#Public"]} data: %{"actor" => actor, "cc" => [Pleroma.Constants.as_public()]}
}, },
object object
) do ) do
@ -765,7 +766,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
) do ) do
cc = Map.get(data, "cc", []) cc = Map.get(data, "cc", [])
follower_address = User.get_cached_by_ap_id(data["actor"]).follower_address 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 case visibility do
"public" -> "public" ->

View file

@ -8,14 +8,14 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
alias Pleroma.Repo alias Pleroma.Repo
alias Pleroma.User alias Pleroma.User
@public "https://www.w3.org/ns/activitystreams#Public" require Pleroma.Constants
@spec is_public?(Object.t() | Activity.t() | map()) :: boolean() @spec is_public?(Object.t() | Activity.t() | map()) :: boolean()
def is_public?(%Object{data: %{"type" => "Tombstone"}}), do: false def is_public?(%Object{data: %{"type" => "Tombstone"}}), do: false
def is_public?(%Object{data: data}), do: is_public?(data) def is_public?(%Object{data: data}), do: is_public?(data)
def is_public?(%Activity{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?(%{"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 def is_private?(activity) do
with false <- is_public?(activity), with false <- is_public?(activity),
@ -73,10 +73,10 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
cc = object.data["cc"] || [] cc = object.data["cc"] || []
cond do cond do
@public in to -> Pleroma.Constants.as_public() in to ->
"public" "public"
@public in cc -> Pleroma.Constants.as_public() in cc ->
"unlisted" "unlisted"
# this should use the sql for the object's activity # this should use the sql for the object's activity

View file

@ -21,8 +21,7 @@ defmodule Pleroma.Web.Auth.Authenticator do
def create_from_registration(plug, registration), def create_from_registration(plug, registration),
do: implementation().create_from_registration(plug, registration) do: implementation().create_from_registration(plug, registration)
@callback get_registration(Plug.Conn.t()) :: @callback get_registration(Plug.Conn.t()) :: {:ok, Registration.t()} | {:error, any()}
{:ok, Registration.t()} | {:error, any()}
def get_registration(plug), do: implementation().get_registration(plug) def get_registration(plug), do: implementation().get_registration(plug)
@callback handle_error(Plug.Conn.t(), any()) :: any() @callback handle_error(Plug.Conn.t(), any()) :: any()

View file

@ -300,8 +300,7 @@ defmodule Pleroma.Web.CommonAPI do
} }
} = activity <- get_by_id_or_ap_id(id_or_ap_id), } = activity <- get_by_id_or_ap_id(id_or_ap_id),
true <- Visibility.is_public?(activity), true <- Visibility.is_public?(activity),
%{valid?: true} = info_changeset <- %{valid?: true} = info_changeset <- User.Info.add_pinnned_activity(user.info, activity),
User.Info.add_pinnned_activity(user.info, activity),
changeset <- changeset <-
Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_changeset), Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_changeset),
{:ok, _user} <- User.update_and_set_cache(changeset) do {:ok, _user} <- User.update_and_set_cache(changeset) do

View file

@ -19,6 +19,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
alias Pleroma.Web.MediaProxy alias Pleroma.Web.MediaProxy
require Logger require Logger
require Pleroma.Constants
# This is a hack for twidere. # This is a hack for twidere.
def get_by_id_or_ap_id(id) do def get_by_id_or_ap_id(id) do
@ -66,7 +67,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
@spec get_to_and_cc(User.t(), list(String.t()), Activity.t() | nil, String.t()) :: @spec get_to_and_cc(User.t(), list(String.t()), Activity.t() | nil, String.t()) ::
{list(String.t()), list(String.t())} {list(String.t()), list(String.t())}
def get_to_and_cc(user, mentioned_users, inReplyTo, "public") do 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] cc = [user.follower_address]
if inReplyTo do if inReplyTo do
@ -78,7 +79,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
def get_to_and_cc(user, mentioned_users, inReplyTo, "unlisted") do def get_to_and_cc(user, mentioned_users, inReplyTo, "unlisted") do
to = [user.follower_address | mentioned_users] to = [user.follower_address | mentioned_users]
cc = ["https://www.w3.org/ns/activitystreams#Public"] cc = [Pleroma.Constants.as_public()]
if inReplyTo do if inReplyTo do
{Enum.uniq([inReplyTo.data["actor"] | to]), cc} {Enum.uniq([inReplyTo.data["actor"] | to]), cc}

View 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

View file

@ -4,6 +4,9 @@
defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
use Pleroma.Web, :controller use Pleroma.Web, :controller
import Pleroma.Web.ControllerHelper, only: [json_response: 3]
alias Ecto.Changeset alias Ecto.Changeset
alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.Bookmark alias Pleroma.Bookmark
@ -46,6 +49,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
import Ecto.Query import Ecto.Query
require Logger require Logger
require Pleroma.Constants
@rate_limited_relations_actions ~w(follow unfollow)a @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, :app_account_creation when action == :account_register)
plug(RateLimiter, :search when action in [:search, :search2, :account_search]) plug(RateLimiter, :search when action in [:search, :search2, :account_search])
plug(RateLimiter, :password_reset when action == :password_reset) plug(RateLimiter, :password_reset when action == :password_reset)
plug(RateLimiter, :account_confirmation_resend when action == :account_confirmation_resend)
@local_mastodon_name "Mastodon-Local" @local_mastodon_name "Mastodon-Local"
@ -1220,10 +1225,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
recipients = recipients =
if for_user do if for_user do
["https://www.w3.org/ns/activitystreams#Public"] ++ [Pleroma.Constants.as_public()] ++ [for_user.ap_id | for_user.following]
[for_user.ap_id | for_user.following]
else else
["https://www.w3.org/ns/activitystreams#Public"] [Pleroma.Constants.as_public()]
end end
activities = activities =
@ -1839,6 +1843,16 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end end
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) def try_render(conn, target, params)
when is_binary(target) do when is_binary(target) do
case render(conn, target, params) do case render(conn, target, params) do

View file

@ -165,6 +165,7 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
}, },
accountActivationRequired: Config.get([:instance, :account_activation_required], false), accountActivationRequired: Config.get([:instance, :account_activation_required], false),
invitesEnabled: Config.get([:instance, :invites_enabled], false), invitesEnabled: Config.get([:instance, :invites_enabled], false),
mailerEnabled: Config.get([Pleroma.Emails.Mailer, :enabled], false),
features: features, features: features,
restrictedNicknames: Config.get([Pleroma.User, :restricted_nicknames]), restrictedNicknames: Config.get([Pleroma.User, :restricted_nicknames]),
skipThreadContainment: Config.get([:instance, :skip_thread_containment], false) skipThreadContainment: Config.get([:instance, :skip_thread_containment], false)

View file

@ -365,8 +365,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
def register(%Plug.Conn{} = conn, %{"authorization" => _, "op" => "connect"} = params) do def register(%Plug.Conn{} = conn, %{"authorization" => _, "op" => "connect"} = params) do
with registration_id when not is_nil(registration_id) <- get_session_registration_id(conn), with registration_id when not is_nil(registration_id) <- get_session_registration_id(conn),
%Registration{} = registration <- Repo.get(Registration, registration_id), %Registration{} = registration <- Repo.get(Registration, registration_id),
{_, {:ok, auth}} <- {_, {:ok, auth}} <- {:create_authorization, do_create_authorization(conn, params)},
{:create_authorization, do_create_authorization(conn, params)},
%User{} = user <- Repo.preload(auth, :user).user, %User{} = user <- Repo.preload(auth, :user).user,
{:ok, _updated_registration} <- Registration.bind_to_user(registration, user) do {:ok, _updated_registration} <- Registration.bind_to_user(registration, user) do
conn conn

View file

@ -44,8 +44,7 @@ defmodule Pleroma.Web.OAuth.Token do
|> Repo.find_resource() |> Repo.find_resource()
end end
@spec exchange_token(App.t(), Authorization.t()) :: @spec exchange_token(App.t(), Authorization.t()) :: {:ok, Token.t()} | {:error, Changeset.t()}
{:ok, Token.t()} | {:error, Changeset.t()}
def exchange_token(app, auth) do def exchange_token(app, auth) do
with {:ok, auth} <- Authorization.use_token(auth), with {:ok, auth} <- Authorization.use_token(auth),
true <- auth.app_id == app.id do true <- auth.app_id == app.id do

View file

@ -9,6 +9,7 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do
alias Pleroma.Web.OStatus.UserRepresenter alias Pleroma.Web.OStatus.UserRepresenter
require Logger require Logger
require Pleroma.Constants
defp get_href(id) do defp get_href(id) do
with %Object{data: %{"external_url" => external_url}} <- Object.get_cached_by_ap_id(id) do with %Object{data: %{"external_url" => external_url}} <- Object.get_cached_by_ap_id(id) do
@ -34,7 +35,7 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do
Enum.map(to, fn id -> Enum.map(to, fn id ->
cond do cond do
# Special handling for the AP/Ostatus public collections # Special handling for the AP/Ostatus public collections
"https://www.w3.org/ns/activitystreams#Public" == id -> Pleroma.Constants.as_public() == id ->
{:link, {:link,
[ [
rel: "mentioned", rel: "mentioned",

View file

@ -4,6 +4,7 @@
defmodule Pleroma.Web.OStatus.NoteHandler do defmodule Pleroma.Web.OStatus.NoteHandler do
require Logger require Logger
require Pleroma.Constants
alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.Object alias Pleroma.Object
@ -49,7 +50,7 @@ defmodule Pleroma.Web.OStatus.NoteHandler do
def get_collection_mentions(entry) do def get_collection_mentions(entry) do
transmogrify = fn transmogrify = fn
"http://activityschema.org/collection/public" -> "http://activityschema.org/collection/public" ->
"https://www.w3.org/ns/activitystreams#Public" Pleroma.Constants.as_public()
group -> group ->
group group
@ -126,7 +127,7 @@ defmodule Pleroma.Web.OStatus.NoteHandler do
to <- make_to_list(actor, mentions), to <- make_to_list(actor, mentions),
date <- XML.string_from_xpath("//published", entry), date <- XML.string_from_xpath("//published", entry),
unlisted <- XML.string_from_xpath("//mastodon:scope", entry) == "unlisted", 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 <- note <-
CommonAPI.Utils.make_note_data( CommonAPI.Utils.make_note_data(
actor.ap_id, actor.ap_id,

View file

@ -5,6 +5,7 @@
defmodule Pleroma.Web.OStatus.OStatusController do defmodule Pleroma.Web.OStatus.OStatusController do
use Pleroma.Web, :controller use Pleroma.Web, :controller
alias Fallback.RedirectController
alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.User alias Pleroma.User
@ -12,42 +13,44 @@ defmodule Pleroma.Web.OStatus.OStatusController do
alias Pleroma.Web.ActivityPub.ActivityPubController alias Pleroma.Web.ActivityPub.ActivityPubController
alias Pleroma.Web.ActivityPub.ObjectView alias Pleroma.Web.ActivityPub.ObjectView
alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.Endpoint
alias Pleroma.Web.Federator alias Pleroma.Web.Federator
alias Pleroma.Web.Metadata.PlayerView
alias Pleroma.Web.OStatus alias Pleroma.Web.OStatus
alias Pleroma.Web.OStatus.ActivityRepresenter alias Pleroma.Web.OStatus.ActivityRepresenter
alias Pleroma.Web.OStatus.FeedRepresenter alias Pleroma.Web.OStatus.FeedRepresenter
alias Pleroma.Web.Router
alias Pleroma.Web.XML alias Pleroma.Web.XML
plug(Pleroma.Web.FederatingPlug when action in [:salmon_incoming]) plug(Pleroma.Web.FederatingPlug when action in [:salmon_incoming])
plug(
Pleroma.Plugs.SetFormatPlug
when action in [:feed_redirect, :object, :activity, :notice]
)
action_fallback(:errors) 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 def feed_redirect(conn, %{"nickname" => nickname}) do
case get_format(conn) do with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname(nickname)} 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)) redirect(conn, external: OStatus.feed_path(user))
else
nil -> {:error, :not_found}
end
end end
end end
def feed(conn, %{"nickname" => nickname} = params) do 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 = query_params =
Map.take(params, ["max_id"]) Map.take(params, ["max_id"])
|> Map.merge(%{"whole_db" => true, "actor_id" => user.ap_id}) |> Map.merge(%{"whole_db" => true, "actor_id" => user.ap_id})
@ -65,8 +68,6 @@ defmodule Pleroma.Web.OStatus.OStatusController do
conn conn
|> put_resp_content_type("application/atom+xml") |> put_resp_content_type("application/atom+xml")
|> send_resp(200, response) |> send_resp(200, response)
else
nil -> {:error, :not_found}
end end
end end
@ -97,93 +98,82 @@ defmodule Pleroma.Web.OStatus.OStatusController do
|> send_resp(200, "") |> send_resp(200, "")
end end
def object(conn, %{"uuid" => uuid}) do def object(%{assigns: %{format: format}} = conn, %{"uuid" => _uuid})
if get_format(conn) in ["activity+json", "json"] do when format in ["json", "activity+json"] do
ActivityPubController.call(conn, :object) ActivityPubController.call(conn, :object)
else end
def object(%{assigns: %{format: format}} = conn, %{"uuid" => uuid}) do
with id <- o_status_url(conn, :object, uuid), with id <- o_status_url(conn, :object, uuid),
{_, %Activity{} = activity} <- {_, %Activity{} = activity} <-
{:activity, Activity.get_create_by_object_ap_id_with_object(id)}, {:activity, Activity.get_create_by_object_ap_id_with_object(id)},
{_, true} <- {:public?, Visibility.is_public?(activity)}, {_, true} <- {:public?, Visibility.is_public?(activity)},
%User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
case get_format(conn) do case format do
"html" -> redirect(conn, to: "/notice/#{activity.id}") "html" -> redirect(conn, to: "/notice/#{activity.id}")
_ -> represent_activity(conn, nil, activity, user) _ -> represent_activity(conn, nil, activity, user)
end end
else else
{:public?, false} -> reason when reason in [{:public?, false}, {:activity, nil}] ->
{:error, :not_found}
{:activity, nil} ->
{:error, :not_found} {:error, :not_found}
e -> e ->
e e
end end
end end
def activity(%{assigns: %{format: format}} = conn, %{"uuid" => _uuid})
when format in ["json", "activity+json"] do
ActivityPubController.call(conn, :activity)
end end
def activity(conn, %{"uuid" => uuid}) do def activity(%{assigns: %{format: format}} = 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), with id <- o_status_url(conn, :activity, uuid),
{_, %Activity{} = activity} <- {:activity, Activity.normalize(id)}, {_, %Activity{} = activity} <- {:activity, Activity.normalize(id)},
{_, true} <- {:public?, Visibility.is_public?(activity)}, {_, true} <- {:public?, Visibility.is_public?(activity)},
%User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
case format = get_format(conn) do case format do
"html" -> redirect(conn, to: "/notice/#{activity.id}") "html" -> redirect(conn, to: "/notice/#{activity.id}")
_ -> represent_activity(conn, format, activity, user) _ -> represent_activity(conn, format, activity, user)
end end
else else
{:public?, false} -> reason when reason in [{:public?, false}, {:activity, nil}] ->
{:error, :not_found}
{:activity, nil} ->
{:error, :not_found} {:error, :not_found}
e -> e ->
e e
end end
end 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)}, with {_, %Activity{} = activity} <- {:activity, Activity.get_by_id_with_object(id)},
{_, true} <- {:public?, Visibility.is_public?(activity)}, {_, true} <- {:public?, Visibility.is_public?(activity)},
%User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
case format = get_format(conn) do cond do
"html" -> format == "html" && activity.data["type"] == "Create" ->
if activity.data["type"] == "Create" do
%Object{} = object = Object.normalize(activity) %Object{} = object = Object.normalize(activity)
Fallback.RedirectController.redirector_with_meta(conn, %{ RedirectController.redirector_with_meta(
conn,
%{
activity_id: activity.id, activity_id: activity.id,
object: object, object: object,
url: url: Router.Helpers.o_status_url(Endpoint, :notice, activity.id),
Pleroma.Web.Router.Helpers.o_status_url(
Pleroma.Web.Endpoint,
:notice,
activity.id
),
user: user user: user
}) }
else )
Fallback.RedirectController.redirector(conn, nil)
end
_ -> format == "html" ->
RedirectController.redirector(conn, nil)
true ->
represent_activity(conn, format, activity, user) represent_activity(conn, format, activity, user)
end end
else else
{:public?, false} -> reason when reason in [{:public?, false}, {:activity, nil}] ->
conn conn
|> put_status(404) |> put_status(404)
|> Fallback.RedirectController.redirector(nil, 404) |> RedirectController.redirector(nil, 404)
{:activity, nil} ->
conn
|> Fallback.RedirectController.redirector(nil, 404)
e -> e ->
e e
@ -204,13 +194,13 @@ defmodule Pleroma.Web.OStatus.OStatusController do
"content-security-policy", "content-security-policy",
"default-src 'none';style-src 'self' 'unsafe-inline';img-src 'self' data: https:; media-src 'self' https:;" "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) |> render("player.html", url)
else else
_error -> _error ->
conn conn
|> put_status(404) |> put_status(404)
|> Fallback.RedirectController.redirector(nil, 404) |> RedirectController.redirector(nil, 404)
end end
end end
@ -248,6 +238,8 @@ defmodule Pleroma.Web.OStatus.OStatusController do
render_error(conn, :not_found, "Not found") render_error(conn, :not_found, "Not found")
end end
def errors(conn, {:fetch_user, nil}), do: errors(conn, {:error, :not_found})
def errors(conn, _) do def errors(conn, _) do
render_error(conn, :internal_server_error, "Something went wrong") render_error(conn, :internal_server_error, "Something went wrong")
end end

View file

@ -19,8 +19,7 @@ defmodule Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl do
defp is_aws_signed_url(image) when is_binary(image) do defp is_aws_signed_url(image) when is_binary(image) do
%URI{host: host, query: query} = URI.parse(image) %URI{host: host, query: query} = URI.parse(image)
if String.contains?(host, "amazonaws.com") and if String.contains?(host, "amazonaws.com") and String.contains?(query, "X-Amz-Expires") do
String.contains?(query, "X-Amz-Expires") do
image image
else else
nil nil

View file

@ -412,6 +412,12 @@ defmodule Pleroma.Web.Router do
get("/accounts/search", SearchController, :account_search) get("/accounts/search", SearchController, :account_search)
post(
"/pleroma/accounts/confirmation_resend",
MastodonAPIController,
:account_confirmation_resend
)
scope [] do scope [] do
pipe_through(:oauth_read_or_public) pipe_through(:oauth_read_or_public)
@ -692,7 +698,7 @@ defmodule Pleroma.Web.Router do
post("/auth/password", MastodonAPIController, :password_reset) post("/auth/password", MastodonAPIController, :password_reset)
scope [] do scope [] do
pipe_through(:oauth_read_or_public) pipe_through(:oauth_read)
get("/web/*path", MastodonAPIController, :index) get("/web/*path", MastodonAPIController, :index)
end end
end end
@ -729,68 +735,3 @@ defmodule Pleroma.Web.Router do
options("/*path", RedirectController, :empty) options("/*path", RedirectController, :empty)
end end
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

View file

@ -15,6 +15,8 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
import Ecto.Query import Ecto.Query
require Pleroma.Constants
def create_status(%User{} = user, %{"status" => _} = data) do def create_status(%User{} = user, %{"status" => _} = data) do
CommonAPI.post(user, data) CommonAPI.post(user, data)
end end
@ -286,7 +288,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
from( from(
[a, o] in Activity.with_preloaded_object(Activity), [a, o] in Activity.with_preloaded_object(Activity),
where: fragment("?->>'type' = 'Create'", a.data), 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: where:
fragment( fragment(
"to_tsvector('english', ?->>'content') @@ plainto_tsquery('english', ?)", "to_tsvector('english', ?->>'content') @@ plainto_tsquery('english', ?)",

View file

@ -19,6 +19,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
import Ecto.Query import Ecto.Query
require Logger require Logger
require Pleroma.Constants
defp query_context_ids([]), do: [] defp query_context_ids([]), do: []
@ -91,7 +92,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
String.ends_with?(ap_id, "/followers") -> String.ends_with?(ap_id, "/followers") ->
nil nil
ap_id == "https://www.w3.org/ns/activitystreams#Public" -> ap_id == Pleroma.Constants.as_public() ->
nil nil
user = User.get_cached_by_ap_id(ap_id) -> user = User.get_cached_by_ap_id(ap_id) ->

View file

@ -10,6 +10,8 @@ defmodule Pleroma.Web.TwitterAPI.NotificationView do
alias Pleroma.Web.TwitterAPI.ActivityView alias Pleroma.Web.TwitterAPI.ActivityView
alias Pleroma.Web.TwitterAPI.UserView alias Pleroma.Web.TwitterAPI.UserView
require Pleroma.Constants
defp get_user(ap_id, opts) do defp get_user(ap_id, opts) do
cond do cond do
user = opts[:users][ap_id] -> user = opts[:users][ap_id] ->
@ -18,7 +20,7 @@ defmodule Pleroma.Web.TwitterAPI.NotificationView do
String.ends_with?(ap_id, "/followers") -> String.ends_with?(ap_id, "/followers") ->
nil nil
ap_id == "https://www.w3.org/ns/activitystreams#Public" -> ap_id == Pleroma.Constants.as_public() ->
nil nil
true -> true ->

View file

@ -150,6 +150,7 @@ defmodule Pleroma.Mixfile do
{:benchee, "~> 1.0"}, {:benchee, "~> 1.0"},
{:esshd, "~> 0.1.0", runtime: Application.get_env(:esshd, :enabled, false)}, {:esshd, "~> 0.1.0", runtime: Application.get_env(:esshd, :enabled, false)},
{:ex_rated, "~> 1.3"}, {:ex_rated, "~> 1.3"},
{:ex_const, "~> 0.2"},
{:plug_static_index_html, "~> 1.0.0"}, {:plug_static_index_html, "~> 1.0.0"},
{:excoveralls, "~> 0.11.1", only: :test}, {:excoveralls, "~> 0.11.1", only: :test},
{:mox, "~> 0.5", only: :test} {:mox, "~> 0.5", only: :test}

View file

@ -27,6 +27,7 @@
"ex2ms": {:hex, :ex2ms, "1.5.0", "19e27f9212be9a96093fed8cdfbef0a2b56c21237196d26760f11dfcfae58e97", [:mix], [], "hexpm"}, "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": {: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_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_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_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"}, "ex_rated": {:hex, :ex_rated, "1.3.3", "30ecbdabe91f7eaa9d37fa4e81c85ba420f371babeb9d1910adbcd79ec798d27", [:mix], [{:ex2ms, "~> 1.5", [hex: :ex2ms, repo: "hexpm", optional: false]}], "hexpm"},

View file

@ -564,6 +564,64 @@ defmodule Pleroma.NotificationTest do
assert Enum.empty?(Notification.for_user(user)) assert Enum.empty?(Notification.for_user(user))
end 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 end
describe "for_user" do describe "for_user" do

View file

@ -1369,4 +1369,28 @@ defmodule Pleroma.UserTest do
assert User.is_internal_user?(user) assert User.is_internal_user?(user)
end end
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 end

View file

@ -30,6 +30,10 @@ defmodule Pleroma.Web.FallbackTest do
|> json_response(404) == %{"error" => "Not implemented"} |> json_response(404) == %{"error" => "Not implemented"}
end 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 test "GET /*path", %{conn: conn} do
assert conn assert conn
|> get("/foo") |> get("/foo")

View file

@ -3154,6 +3154,21 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert redirected_to(conn) == "/web/login" assert redirected_to(conn) == "/web/login"
end 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 test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
token = insert(:oauth_token) token = insert(:oauth_token)
@ -3923,4 +3938,45 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
assert conn.resp_body == "" assert conn.resp_body == ""
end end
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 end

View file

@ -101,6 +101,7 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
assert response(conn, 404) assert response(conn, 404)
end end
describe "GET object/2" do
test "gets an object", %{conn: conn} do test "gets an object", %{conn: conn} do
note_activity = insert(:note_activity) note_activity = insert(:note_activity)
object = Object.normalize(note_activity) object = Object.normalize(note_activity)
@ -122,6 +123,37 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
assert response(conn, 200) == expected assert response(conn, 200) == expected
end 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 test "404s on private objects", %{conn: conn} do
note_activity = insert(:direct_note_activity) note_activity = insert(:direct_note_activity)
object = Object.normalize(note_activity) object = Object.normalize(note_activity)
@ -137,7 +169,9 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
|> get("/objects/123") |> get("/objects/123")
|> response(404) |> response(404)
end end
end
describe "GET activity/2" do
test "gets an activity in xml format", %{conn: conn} do test "gets an activity in xml format", %{conn: conn} do
note_activity = insert(:note_activity) note_activity = insert(:note_activity)
[_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"])) [_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"]))
@ -148,6 +182,33 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
|> response(200) |> response(200)
end end
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"]))
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 test "404s on deleted objects", %{conn: conn} do
note_activity = insert(:note_activity) note_activity = insert(:note_activity)
object = Object.normalize(note_activity) object = Object.normalize(note_activity)
@ -181,6 +242,21 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
|> response(404) |> response(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}"
conn =
conn
|> put_req_header("accept", "application/activity+json")
|> get(url)
assert json_response(conn, 200)
end
end
describe "GET notice/2" do
test "gets a notice in xml format", %{conn: conn} do test "gets a notice in xml format", %{conn: conn} do
note_activity = insert(:note_activity) note_activity = insert(:note_activity)
@ -198,6 +274,19 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
|> json_response(200) |> json_response(200)
end end
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)
conn =
conn
|> get("/notice/#{note_activity.id}")
assert response(conn, 500) == ~S({"error":"Something went wrong"})
end
test "only gets a notice in AS2 format for Create messages", %{conn: conn} do test "only gets a notice in AS2 format for Create messages", %{conn: conn} do
note_activity = insert(:note_activity) note_activity = insert(:note_activity)
url = "/notice/#{note_activity.id}" url = "/notice/#{note_activity.id}"
@ -224,17 +313,31 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
assert response(conn, 404) assert response(conn, 404)
end end
test "gets an activity in AS2 format", %{conn: conn} do test "render html for redirect for html format", %{conn: conn} do
note_activity = insert(:note_activity) note_activity = insert(:note_activity)
[_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["id"]))
url = "/activities/#{uuid}"
conn = resp =
conn conn
|> put_req_header("accept", "application/activity+json") |> put_req_header("accept", "text/html")
|> get(url) |> get("/notice/#{note_activity.id}")
|> response(200)
assert json_response(conn, 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 end
test "404s a private notice", %{conn: conn} do test "404s a private notice", %{conn: conn} do
@ -257,4 +360,279 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
assert response(conn, 404) assert response(conn, 404)
end end
end
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"])
response =
conn
|> put_req_header("accept", "application/xml")
|> get("/users/#{user.nickname}")
|> response(302)
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
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)
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"
}
]
}
])
object
|> Ecto.Changeset.change(data: object_data)
|> Pleroma.Repo.update()
conn =
conn
|> get("/notice/#{note_activity.id}/embed_player")
assert Plug.Conn.get_resp_header(conn, "x-frame-options") == ["ALLOW"]
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 end

View file

@ -124,8 +124,7 @@ defmodule Pleroma.Web.Push.ImplTest do
{:ok, _, _, activity} = CommonAPI.follow(user, other_user) {:ok, _, _, activity} = CommonAPI.follow(user, other_user)
object = Object.normalize(activity) object = Object.normalize(activity)
assert Impl.format_body(%{activity: activity}, user, object) == assert Impl.format_body(%{activity: activity}, user, object) == "@Bob has followed you"
"@Bob has followed you"
end end
test "renders body for announce activity" do test "renders body for announce activity" do
@ -156,7 +155,6 @@ defmodule Pleroma.Web.Push.ImplTest do
{:ok, activity, _} = CommonAPI.favorite(activity.id, user) {:ok, activity, _} = CommonAPI.favorite(activity.id, user)
object = Object.normalize(activity) object = Object.normalize(activity)
assert Impl.format_body(%{activity: activity}, user, object) == assert Impl.format_body(%{activity: activity}, user, object) == "@Bob has favorited your post"
"@Bob has favorited your post"
end end
end end