forked from AkkomaGang/akkoma
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]
|
## [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
|
||||||
|
|
|
@ -534,7 +534,8 @@
|
||||||
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.
|
||||||
|
|
|
@ -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`
|
||||||
|
|
|
@ -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 @@ def run(["prune_objects" | args]) 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())
|
||||||
|
|
|
@ -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 @@ def maybe_restrict_author(query, _), do: query
|
||||||
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
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,
|
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)
|
||||||
|
|
|
@ -15,7 +15,7 @@ def key_id_to_actor_id(key_id) 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
|
||||||
|
|
|
@ -477,7 +477,7 @@ def set_cache(%User{} = 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
|
||||||
|
|
|
@ -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 @@ def stream_out_participations(%Object{data: %{"context" => context}}, user) 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 @@ def stream_out(activity) 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 @@ def stream_out(activity) 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 @@ def flag(
|
||||||
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 @@ def fetch_latest_activity_id_for_context(context, opts \\ %{}) 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 @@ defp user_activities_recipients(%{"godmode" => true}) 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 @@ defp restrict_unlisted(query) 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 @@ def fetch_activities_bounded_query(query, recipients, recipients_with_public) 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
|
||||||
|
|
||||||
|
|
|
@ -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 @@ defp delist_message(message, threshold) when threshold > 0 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 @@ defp get_recipient_count(message) 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)}
|
||||||
|
|
|
@ -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 @@ defp check_reject(%{"object" => %{"content" => content, "summary" => summary}} =
|
||||||
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
|
||||||
|
|
|
@ -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 @@ def filter(%{"type" => "Create"} = object) 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
|
||||||
|
|
|
@ -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 @@ defp check_ftl_removal(%{host: actor_host} = _actor_info, object) 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)
|
||||||
|
|
|
@ -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 @@ defp process_tag(
|
||||||
) 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 @@ defp process_tag(
|
||||||
) 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
|
||||||
|
|
|
@ -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 @@ defp get_cc_ap_ids(ap_id, recipients) 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 @@ def determine_inbox(
|
||||||
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 ->
|
||||||
|
|
|
@ -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 @@ def fix_explicit_addressing(object) 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 @@ def fix_implicit_addressing(%{"to" => to, "cc" => cc} = object, followers_collec
|
||||||
|
|
||||||
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 @@ def handle_incoming(
|
||||||
{: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 @@ def handle_incoming(
|
||||||
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
|
||||||
|
|
|
@ -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 @@ def make_follow_data(
|
||||||
"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 @@ def make_announce_data(
|
||||||
"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 @@ def make_unannounce_data(
|
||||||
"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 @@ def make_unlike_data(
|
||||||
"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 @@ def make_unlike_data(
|
||||||
|
|
||||||
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 @@ defp get_updated_targets(
|
||||||
) 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" ->
|
||||||
|
|
|
@ -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 @@ def get_visibility(object) 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
|
||||||
|
|
|
@ -21,8 +21,7 @@ def get_user(plug), do: implementation().get_user(plug)
|
||||||
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()
|
||||||
|
|
|
@ -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),
|
} = 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
|
||||||
|
|
|
@ -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 @@ def attachments_from_ids_descs(ids, descs_str) 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 @@ def get_to_and_cc(user, mentioned_users, inReplyTo, "public") 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}
|
||||||
|
|
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
|
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 @@ def user_favourites(%{assigns: %{user: for_user}} = conn, %{"id" => id} = params
|
||||||
|
|
||||||
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 @@ def password_reset(conn, params) 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
|
||||||
|
|
|
@ -165,6 +165,7 @@ def raw_nodeinfo 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)
|
||||||
|
|
|
@ -365,8 +365,7 @@ def registration_details(%Plug.Conn{} = conn, %{"authorization" => auth_attrs})
|
||||||
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
|
||||||
|
|
|
@ -44,8 +44,7 @@ def get_by_refresh_token(%App{id: app_id} = _app, 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
|
||||||
|
|
|
@ -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 @@ defp get_mentions(to) 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",
|
||||||
|
|
|
@ -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 @@ def get_people_mentions(entry) 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 @@ def handle_note(entry, doc \\ nil, options \\ []) 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,
|
||||||
|
|
|
@ -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 @@ def feed(conn, %{"nickname" => nickname} = params) 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 @@ def salmon_incoming(conn, _) 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 @@ def notice_player(conn, %{"id" => id}) 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 @@ def errors(conn, {:error, :not_found}) 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
|
||||||
|
|
|
@ -19,8 +19,7 @@ defp is_aws_signed_url(nil), do: nil
|
||||||
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
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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 @@ def search(_user, %{"q" => query} = params) 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', ?)",
|
||||||
|
|
|
@ -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 @@ defp get_user(ap_id, opts) 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) ->
|
||||||
|
|
|
@ -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 @@ defp get_user(ap_id, opts) 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 ->
|
||||||
|
|
1
mix.exs
1
mix.exs
|
@ -150,6 +150,7 @@ defp deps 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}
|
||||||
|
|
1
mix.lock
1
mix.lock
|
@ -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"},
|
||||||
|
|
|
@ -564,6 +564,64 @@ test "replying to a deleted post without tagging does not generate a notificatio
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -1369,4 +1369,28 @@ test "user with internal-prefixed nickname returns true" 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
|
||||||
|
|
|
@ -30,6 +30,10 @@ test "GET /api*path", %{conn: conn} 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")
|
||||||
|
|
|
@ -3154,6 +3154,21 @@ test "redirects not logged-in users to the login page", %{conn: conn, path: path
|
||||||
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 @@ test "it returns 400 when user is not local", %{conn: conn, user: user} 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
|
||||||
|
|
|
@ -101,6 +101,7 @@ test "returns 404 for a missing feed", %{conn: conn} 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 @@ test "gets an object", %{conn: conn} 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 @@ test "404s on nonexisting objects", %{conn: conn} 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 @@ test "gets an activity in xml format", %{conn: conn} 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 @@ test "404s on nonexistent activities", %{conn: conn} 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 @@ test "gets a notice in AS2 format", %{conn: conn} 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 @@ test "only gets a notice in AS2 format for Create messages", %{conn: conn} 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 @@ test "404s a nonexisting notice", %{conn: conn} 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
|
||||||
|
|
|
@ -124,8 +124,7 @@ test "renders body for follow activity" 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 @@ test "renders body for like activity" 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
|
||||||
|
|
Loading…
Reference in a new issue