aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/mix/tasks/pleroma/config.ex2
-rw-r--r--lib/mix/tasks/pleroma/database.ex12
-rw-r--r--lib/pleroma/activity/search.ex4
-rw-r--r--lib/pleroma/constants.ex9
-rw-r--r--lib/pleroma/flake_id.ex10
-rw-r--r--lib/pleroma/http/connection.ex1
-rw-r--r--lib/pleroma/object/fetcher.ex7
-rw-r--r--lib/pleroma/plugs/set_format_plug.ex24
-rw-r--r--lib/pleroma/signature.ex2
-rw-r--r--lib/pleroma/upload.ex9
-rw-r--r--lib/pleroma/user.ex116
-rw-r--r--lib/pleroma/user/info.ex24
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub.ex103
-rw-r--r--lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex11
-rw-r--r--lib/pleroma/web/activity_pub/mrf/keyword_policy.ex8
-rw-r--r--lib/pleroma/web/activity_pub/mrf/reject_non_public.ex6
-rw-r--r--lib/pleroma/web/activity_pub/mrf/simple_policy.ex14
-rw-r--r--lib/pleroma/web/activity_pub/mrf/tag_policy.ex15
-rw-r--r--lib/pleroma/web/activity_pub/publisher.ex6
-rw-r--r--lib/pleroma/web/activity_pub/transmogrifier.ex59
-rw-r--r--lib/pleroma/web/activity_pub/utils.ex13
-rw-r--r--lib/pleroma/web/activity_pub/visibility.ex8
-rw-r--r--lib/pleroma/web/admin_api/admin_api_controller.ex10
-rw-r--r--lib/pleroma/web/auth/authenticator.ex3
-rw-r--r--lib/pleroma/web/common_api/common_api.ex3
-rw-r--r--lib/pleroma/web/common_api/utils.ex12
-rw-r--r--lib/pleroma/web/fallback_redirect_controller.ex77
-rw-r--r--lib/pleroma/web/mastodon_api/mastodon_api_controller.ex20
-rw-r--r--lib/pleroma/web/mastodon_api/views/account_view.ex6
-rw-r--r--lib/pleroma/web/mastodon_api/views/status_view.ex2
-rw-r--r--lib/pleroma/web/nodeinfo/nodeinfo_controller.ex1
-rw-r--r--lib/pleroma/web/oauth/oauth_controller.ex3
-rw-r--r--lib/pleroma/web/oauth/token.ex3
-rw-r--r--lib/pleroma/web/ostatus/activity_representer.ex3
-rw-r--r--lib/pleroma/web/ostatus/handlers/follow_handler.ex6
-rw-r--r--lib/pleroma/web/ostatus/handlers/note_handler.ex7
-rw-r--r--lib/pleroma/web/ostatus/handlers/unfollow_handler.ex2
-rw-r--r--lib/pleroma/web/ostatus/ostatus.ex17
-rw-r--r--lib/pleroma/web/ostatus/ostatus_controller.ex168
-rw-r--r--lib/pleroma/web/rich_media/parsers/ttl/aws_signed_url.ex3
-rw-r--r--lib/pleroma/web/router.ex75
-rw-r--r--lib/pleroma/web/twitter_api/controllers/util_controller.ex198
-rw-r--r--lib/pleroma/web/twitter_api/twitter_api.ex4
-rw-r--r--lib/pleroma/web/twitter_api/views/activity_view.ex3
-rw-r--r--lib/pleroma/web/twitter_api/views/notification_view.ex4
-rw-r--r--lib/pleroma/web/web_finger/web_finger.ex17
-rw-r--r--lib/pleroma/web/web_finger/web_finger_controller.ex43
47 files changed, 688 insertions, 465 deletions
diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex
index a7d0fac5d..462940e7e 100644
--- a/lib/mix/tasks/pleroma/config.ex
+++ b/lib/mix/tasks/pleroma/config.ex
@@ -15,7 +15,7 @@ defmodule Mix.Tasks.Pleroma.Config do
mix pleroma.config migrate_to_db
- ## Transfers config from DB to file.
+ ## Transfers config from DB to file `config/env.exported_from_db.secret.exs`
mix pleroma.config migrate_from_db ENV
"""
diff --git a/lib/mix/tasks/pleroma/database.ex b/lib/mix/tasks/pleroma/database.ex
index e91fb31d1..8547a329a 100644
--- a/lib/mix/tasks/pleroma/database.ex
+++ b/lib/mix/tasks/pleroma/database.ex
@@ -8,6 +8,7 @@ defmodule Mix.Tasks.Pleroma.Database do
alias Pleroma.Repo
alias Pleroma.User
require Logger
+ require Pleroma.Constants
import Mix.Pleroma
use Mix.Task
@@ -99,10 +100,15 @@ defmodule Mix.Tasks.Pleroma.Database do
NaiveDateTime.utc_now()
|> NaiveDateTime.add(-(deadline * 86_400))
- public = "https://www.w3.org/ns/activitystreams#Public"
-
from(o in Object,
- where: fragment("?->'to' \\? ? OR ?->'cc' \\? ?", o.data, ^public, o.data, ^public),
+ where:
+ fragment(
+ "?->'to' \\? ? OR ?->'cc' \\? ?",
+ o.data,
+ ^Pleroma.Constants.as_public(),
+ o.data,
+ ^Pleroma.Constants.as_public()
+ ),
where: o.inserted_at < ^time_deadline,
where:
fragment("split_part(?->>'actor', '/', 3) != ?", o.data, ^Pleroma.Web.Endpoint.host())
diff --git a/lib/pleroma/activity/search.ex b/lib/pleroma/activity/search.ex
index 0cc3770a7..f847ac238 100644
--- a/lib/pleroma/activity/search.ex
+++ b/lib/pleroma/activity/search.ex
@@ -9,6 +9,8 @@ defmodule Pleroma.Activity.Search do
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Visibility
+ require Pleroma.Constants
+
import Ecto.Query
def search(user, search_query, options \\ []) do
@@ -39,7 +41,7 @@ defmodule Pleroma.Activity.Search do
defp restrict_public(q) do
from([a, o] in q,
where: fragment("?->>'type' = 'Create'", a.data),
- where: "https://www.w3.org/ns/activitystreams#Public" in a.recipients
+ where: ^Pleroma.Constants.as_public() in a.recipients
)
end
diff --git a/lib/pleroma/constants.ex b/lib/pleroma/constants.ex
new file mode 100644
index 000000000..ef1418543
--- /dev/null
+++ b/lib/pleroma/constants.ex
@@ -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
diff --git a/lib/pleroma/flake_id.ex b/lib/pleroma/flake_id.ex
index 58ab3650d..ca0610abc 100644
--- a/lib/pleroma/flake_id.ex
+++ b/lib/pleroma/flake_id.ex
@@ -66,6 +66,16 @@ defmodule Pleroma.FlakeId do
@spec get :: binary
def get, do: to_string(:gen_server.call(:flake, :get))
+ # checks that ID is is valid FlakeID
+ #
+ @spec is_flake_id?(String.t()) :: boolean
+ def is_flake_id?(id), do: is_flake_id?(String.to_charlist(id), true)
+ defp is_flake_id?([c | cs], true) when c >= ?0 and c <= ?9, do: is_flake_id?(cs, true)
+ defp is_flake_id?([c | cs], true) when c >= ?A and c <= ?Z, do: is_flake_id?(cs, true)
+ defp is_flake_id?([c | cs], true) when c >= ?a and c <= ?z, do: is_flake_id?(cs, true)
+ defp is_flake_id?([], true), do: true
+ defp is_flake_id?(_, _), do: false
+
# -- Ecto.Type API
@impl Ecto.Type
def type, do: :uuid
diff --git a/lib/pleroma/http/connection.ex b/lib/pleroma/http/connection.ex
index a1460d303..7e2c6f5e8 100644
--- a/lib/pleroma/http/connection.ex
+++ b/lib/pleroma/http/connection.ex
@@ -11,6 +11,7 @@ defmodule Pleroma.HTTP.Connection do
connect_timeout: 10_000,
recv_timeout: 20_000,
follow_redirect: true,
+ force_redirect: true,
pool: :federation
]
@adapter Application.get_env(:tesla, :adapter)
diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex
index 305ce8357..8d79ddb1f 100644
--- a/lib/pleroma/object/fetcher.ex
+++ b/lib/pleroma/object/fetcher.ex
@@ -114,7 +114,7 @@ defmodule Pleroma.Object.Fetcher do
end
end
- def fetch_and_contain_remote_object_from_id(id) do
+ def fetch_and_contain_remote_object_from_id(id) when is_binary(id) do
Logger.info("Fetching object #{id} via AP")
date =
@@ -141,4 +141,9 @@ defmodule Pleroma.Object.Fetcher do
{:error, e}
end
end
+
+ def fetch_and_contain_remote_object_from_id(%{"id" => id}),
+ do: fetch_and_contain_remote_object_from_id(id)
+
+ def fetch_and_contain_remote_object_from_id(_id), do: {:error, "id must be a string"}
end
diff --git a/lib/pleroma/plugs/set_format_plug.ex b/lib/pleroma/plugs/set_format_plug.ex
new file mode 100644
index 000000000..5ca741c64
--- /dev/null
+++ b/lib/pleroma/plugs/set_format_plug.ex
@@ -0,0 +1,24 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Plugs.SetFormatPlug do
+ import Plug.Conn, only: [assign: 3, fetch_query_params: 1]
+
+ def init(_), do: nil
+
+ def call(conn, _) do
+ case get_format(conn) do
+ nil -> conn
+ format -> assign(conn, :format, format)
+ end
+ end
+
+ defp get_format(conn) do
+ conn.private[:phoenix_format] ||
+ case fetch_query_params(conn) do
+ %{query_params: %{"_format" => format}} -> format
+ _ -> nil
+ end
+ end
+end
diff --git a/lib/pleroma/signature.ex b/lib/pleroma/signature.ex
index 0bf49fd7c..15bf3c317 100644
--- a/lib/pleroma/signature.ex
+++ b/lib/pleroma/signature.ex
@@ -15,7 +15,7 @@ defmodule Pleroma.Signature do
|> Map.put(:fragment, nil)
uri =
- if String.ends_with?(uri.path, "/publickey") do
+ if not is_nil(uri.path) and String.ends_with?(uri.path, "/publickey") do
Map.put(uri, :path, String.replace(uri.path, "/publickey", ""))
else
uri
diff --git a/lib/pleroma/upload.ex b/lib/pleroma/upload.ex
index c47d65241..9f0adde5b 100644
--- a/lib/pleroma/upload.ex
+++ b/lib/pleroma/upload.ex
@@ -228,7 +228,14 @@ defmodule Pleroma.Upload do
""
end
- [base_url, "media", path]
+ prefix =
+ if is_nil(Pleroma.Config.get([__MODULE__, :base_url])) do
+ "media"
+ else
+ ""
+ end
+
+ [base_url, prefix, path]
|> Path.join()
end
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index e8a3f9663..7d18f099e 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -115,7 +115,9 @@ defmodule Pleroma.User do
def user_info(%User{} = user, args \\ %{}) do
following_count =
- if args[:following_count], do: args[:following_count], else: following_count(user)
+ if args[:following_count],
+ do: args[:following_count],
+ else: user.info.following_count || following_count(user)
follower_count =
if args[:follower_count], do: args[:follower_count], else: user.info.follower_count
@@ -227,6 +229,7 @@ defmodule Pleroma.User do
|> put_password_hash
end
+ @spec reset_password(User.t(), map) :: {:ok, User.t()} | {:error, Ecto.Changeset.t()}
def reset_password(%User{id: user_id} = user, data) do
multi =
Multi.new()
@@ -331,6 +334,7 @@ defmodule Pleroma.User do
def needs_update?(_), do: true
+ @spec maybe_direct_follow(User.t(), User.t()) :: {:ok, User.t()} | {:error, String.t()}
def maybe_direct_follow(%User{} = follower, %User{local: true, info: %{locked: true}}) do
{:ok, follower}
end
@@ -405,6 +409,8 @@ defmodule Pleroma.User do
{1, [follower]} = Repo.update_all(q, [])
+ follower = maybe_update_following_count(follower)
+
{:ok, _} = update_follower_count(followed)
set_cache(follower)
@@ -424,6 +430,8 @@ defmodule Pleroma.User do
{1, [follower]} = Repo.update_all(q, [])
+ follower = maybe_update_following_count(follower)
+
{:ok, followed} = update_follower_count(followed)
set_cache(follower)
@@ -472,7 +480,7 @@ defmodule Pleroma.User do
end
def update_and_set_cache(changeset) do
- with {:ok, user} <- Repo.update(changeset) do
+ with {:ok, user} <- Repo.update(changeset, stale_error_field: :id) do
set_cache(user)
else
e -> e
@@ -708,32 +716,73 @@ defmodule Pleroma.User do
|> update_and_set_cache()
end
+ def maybe_fetch_follow_information(user) do
+ with {:ok, user} <- fetch_follow_information(user) do
+ user
+ else
+ e ->
+ Logger.error("Follower/Following counter update for #{user.ap_id} failed.\n#{inspect(e)}")
+
+ user
+ end
+ end
+
+ def fetch_follow_information(user) do
+ with {:ok, info} <- ActivityPub.fetch_follow_information_for_user(user) do
+ info_cng = User.Info.follow_information_update(user.info, info)
+
+ changeset =
+ user
+ |> change()
+ |> put_embed(:info, info_cng)
+
+ update_and_set_cache(changeset)
+ else
+ {:error, _} = e -> e
+ e -> {:error, e}
+ end
+ end
+
def update_follower_count(%User{} = user) do
- follower_count_query =
- User.Query.build(%{followers: user, deactivated: false})
- |> select([u], %{count: count(u.id)})
+ if user.local or !Pleroma.Config.get([:instance, :external_user_synchronization]) do
+ follower_count_query =
+ User.Query.build(%{followers: user, deactivated: false})
+ |> select([u], %{count: count(u.id)})
+
+ User
+ |> where(id: ^user.id)
+ |> join(:inner, [u], s in subquery(follower_count_query))
+ |> update([u, s],
+ set: [
+ info:
+ fragment(
+ "jsonb_set(?, '{follower_count}', ?::varchar::jsonb, true)",
+ u.info,
+ s.count
+ )
+ ]
+ )
+ |> select([u], u)
+ |> Repo.update_all([])
+ |> case do
+ {1, [user]} -> set_cache(user)
+ _ -> {:error, user}
+ end
+ else
+ {:ok, maybe_fetch_follow_information(user)}
+ end
+ end
- User
- |> where(id: ^user.id)
- |> join(:inner, [u], s in subquery(follower_count_query))
- |> update([u, s],
- set: [
- info:
- fragment(
- "jsonb_set(?, '{follower_count}', ?::varchar::jsonb, true)",
- u.info,
- s.count
- )
- ]
- )
- |> select([u], u)
- |> Repo.update_all([])
- |> case do
- {1, [user]} -> set_cache(user)
- _ -> {:error, user}
+ def maybe_update_following_count(%User{local: false} = user) do
+ if Pleroma.Config.get([:instance, :external_user_synchronization]) do
+ {:ok, maybe_fetch_follow_information(user)}
+ else
+ user
end
end
+ def maybe_update_following_count(user), do: user
+
def remove_duplicated_following(%User{following: following} = user) do
uniq_following = Enum.uniq(following)
@@ -883,18 +932,25 @@ defmodule Pleroma.User do
def muted_notifications?(user, %{ap_id: ap_id}),
do: Enum.member?(user.info.muted_notifications, ap_id)
- def blocks?(%User{info: info} = _user, %{ap_id: ap_id}) do
- blocks = info.blocks
+ def blocks?(%User{} = user, %User{} = target) do
+ blocks_ap_id?(user, target) || blocks_domain?(user, target)
+ end
- domain_blocks = Pleroma.Web.ActivityPub.MRF.subdomains_regex(info.domain_blocks)
+ def blocks?(nil, _), do: false
- %{host: host} = URI.parse(ap_id)
+ def blocks_ap_id?(%User{} = user, %User{} = target) do
+ Enum.member?(user.info.blocks, target.ap_id)
+ end
- Enum.member?(blocks, ap_id) ||
- Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, host)
+ def blocks_ap_id?(_, _), do: false
+
+ def blocks_domain?(%User{} = user, %User{} = target) do
+ domain_blocks = Pleroma.Web.ActivityPub.MRF.subdomains_regex(user.info.domain_blocks)
+ %{host: host} = URI.parse(target.ap_id)
+ Pleroma.Web.ActivityPub.MRF.subdomain_match?(domain_blocks, host)
end
- def blocks?(nil, _), do: false
+ def blocks_domain?(_, _), do: false
def subscribed_to?(user, %{ap_id: ap_id}) do
with %User{} = target <- get_cached_by_ap_id(ap_id) do
diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex
index 60b7a82ab..22eb9a182 100644
--- a/lib/pleroma/user/info.ex
+++ b/lib/pleroma/user/info.ex
@@ -16,6 +16,8 @@ defmodule Pleroma.User.Info do
field(:source_data, :map, default: %{})
field(:note_count, :integer, default: 0)
field(:follower_count, :integer, default: 0)
+ # Should be filled in only for remote users
+ field(:following_count, :integer, default: nil)
field(:locked, :boolean, default: false)
field(:confirmation_pending, :boolean, default: false)
field(:confirmation_token, :string, default: nil)
@@ -248,7 +250,11 @@ defmodule Pleroma.User.Info do
:uri,
:hub,
:topic,
- :salmon
+ :salmon,
+ :hide_followers,
+ :hide_follows,
+ :follower_count,
+ :following_count
])
end
@@ -259,7 +265,11 @@ defmodule Pleroma.User.Info do
:source_data,
:banner,
:locked,
- :magic_key
+ :magic_key,
+ :follower_count,
+ :following_count,
+ :hide_follows,
+ :hide_followers
])
end
@@ -373,4 +383,14 @@ defmodule Pleroma.User.Info do
cast(info, params, [:muted_reblogs])
end
+
+ def follow_information_update(info, params) do
+ info
+ |> cast(params, [
+ :hide_followers,
+ :hide_follows,
+ :follower_count,
+ :following_count
+ ])
+ end
end
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index a42c50875..07a65127b 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -23,6 +23,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
import Pleroma.Web.ActivityPub.Visibility
require Logger
+ require Pleroma.Constants
# For Announce activities, we filter the recipients based on following status for any actors
# that match actual users. See issue #164 for more information about why this is necessary.
@@ -207,8 +208,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
def stream_out_participations(_, _), do: :noop
def stream_out(activity) do
- public = "https://www.w3.org/ns/activitystreams#Public"
-
if activity.data["type"] in ["Create", "Announce", "Delete"] do
object = Object.normalize(activity)
# Do not stream out poll replies
@@ -216,7 +215,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
Pleroma.Web.Streamer.stream("user", activity)
Pleroma.Web.Streamer.stream("list", activity)
- if Enum.member?(activity.data["to"], public) do
+ if get_visibility(activity) == "public" do
Pleroma.Web.Streamer.stream("public", activity)
if activity.local do
@@ -238,13 +237,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
end
else
- # TODO: Write test, replace with visibility test
- if !Enum.member?(activity.data["cc"] || [], public) &&
- !Enum.member?(
- activity.data["to"],
- User.get_cached_by_ap_id(activity.data["actor"]).follower_address
- ),
- do: Pleroma.Web.Streamer.stream("direct", activity)
+ if get_visibility(activity) == "direct",
+ do: Pleroma.Web.Streamer.stream("direct", activity)
end
end
end
@@ -514,7 +508,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
defp fetch_activities_for_context_query(context, opts) do
- public = ["https://www.w3.org/ns/activitystreams#Public"]
+ public = [Pleroma.Constants.as_public()]
recipients =
if opts["user"], do: [opts["user"].ap_id | opts["user"].following] ++ public, else: public
@@ -555,7 +549,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
def fetch_public_activities(opts \\ %{}) do
- q = fetch_activities_query(["https://www.w3.org/ns/activitystreams#Public"], opts)
+ q = fetch_activities_query([Pleroma.Constants.as_public()], opts)
q
|> restrict_unlisted()
@@ -646,10 +640,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp user_activities_recipients(%{"reading_user" => reading_user}) do
if reading_user do
- ["https://www.w3.org/ns/activitystreams#Public"] ++
- [reading_user.ap_id | reading_user.following]
+ [Pleroma.Constants.as_public()] ++ [reading_user.ap_id | reading_user.following]
else
- ["https://www.w3.org/ns/activitystreams#Public"]
+ [Pleroma.Constants.as_public()]
end
end
@@ -834,7 +827,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
fragment(
"not (coalesce(?->'cc', '{}'::jsonb) \\?| ?)",
activity.data,
- ^["https://www.w3.org/ns/activitystreams#Public"]
+ ^[Pleroma.Constants.as_public()]
)
)
end
@@ -971,7 +964,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
where:
fragment("? && ?", activity.recipients, ^recipients) or
(fragment("? && ?", activity.recipients, ^recipients_with_public) and
- "https://www.w3.org/ns/activitystreams#Public" in activity.recipients)
+ ^Pleroma.Constants.as_public() in activity.recipients)
)
end
@@ -1016,10 +1009,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
user_data = %{
ap_id: data["id"],
info: %{
- "ap_enabled" => true,
- "source_data" => data,
- "banner" => banner,
- "locked" => locked
+ ap_enabled: true,
+ source_data: data,
+ banner: banner,
+ locked: locked
},
avatar: avatar,
name: data["name"],
@@ -1043,6 +1036,71 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
{:ok, user_data}
end
+ def fetch_follow_information_for_user(user) do
+ with {:ok, following_data} <-
+ Fetcher.fetch_and_contain_remote_object_from_id(user.following_address),
+ following_count when is_integer(following_count) <- following_data["totalItems"],
+ {:ok, hide_follows} <- collection_private(following_data),
+ {:ok, followers_data} <-
+ Fetcher.fetch_and_contain_remote_object_from_id(user.follower_address),
+ followers_count when is_integer(followers_count) <- followers_data["totalItems"],
+ {:ok, hide_followers} <- collection_private(followers_data) do
+ {:ok,
+ %{
+ hide_follows: hide_follows,
+ follower_count: followers_count,
+ following_count: following_count,
+ hide_followers: hide_followers
+ }}
+ else
+ {:error, _} = e ->
+ e
+
+ e ->
+ {:error, e}
+ end
+ end
+
+ defp maybe_update_follow_information(data) do
+ with {:enabled, true} <-
+ {:enabled, Pleroma.Config.get([:instance, :external_user_synchronization])},
+ {:ok, info} <- fetch_follow_information_for_user(data) do
+ info = Map.merge(data.info, info)
+ Map.put(data, :info, info)
+ else
+ {:enabled, false} ->
+ data
+
+ e ->
+ Logger.error(
+ "Follower/Following counter update for #{data.ap_id} failed.\n" <> inspect(e)
+ )
+
+ data
+ end
+ end
+
+ defp collection_private(data) do
+ if is_map(data["first"]) and
+ data["first"]["type"] in ["CollectionPage", "OrderedCollectionPage"] do
+ {:ok, false}
+ else
+ with {:ok, %{"type" => type}} when type in ["CollectionPage", "OrderedCollectionPage"] <-
+ Fetcher.fetch_and_contain_remote_object_from_id(data["first"]) do
+ {:ok, false}
+ else
+ {:error, {:ok, %{status: code}}} when code in [401, 403] ->
+ {:ok, true}
+
+ {:error, _} = e ->
+ e
+
+ e ->
+ {:error, e}
+ end
+ end
+ end
+
def user_data_from_user_object(data) do
with {:ok, data} <- MRF.filter(data),
{:ok, data} <- object_to_user_data(data) do
@@ -1054,7 +1112,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
def fetch_and_prepare_user_from_ap_id(ap_id) do
with {:ok, data} <- Fetcher.fetch_and_contain_remote_object_from_id(ap_id),
- {:ok, data} <- user_data_from_user_object(data) do
+ {:ok, data} <- user_data_from_user_object(data),
+ data <- maybe_update_follow_information(data) do
{:ok, data}
else
e -> Logger.error("Could not decode user at fetch #{ap_id}, #{inspect(e)}")
diff --git a/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex b/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex
index a699f6a7e..377987cf2 100644
--- a/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex
@@ -4,6 +4,9 @@
defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicy do
alias Pleroma.User
+
+ require Pleroma.Constants
+
@moduledoc "Block messages with too much mentions (configurable)"
@behaviour Pleroma.Web.ActivityPub.MRF
@@ -19,12 +22,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicy do
when follower_collection? and recipients > threshold ->
message
|> Map.put("to", [follower_collection])
- |> Map.put("cc", ["https://www.w3.org/ns/activitystreams#Public"])
+ |> Map.put("cc", [Pleroma.Constants.as_public()])
{:public, recipients} when recipients > threshold ->
message
|> Map.put("to", [])
- |> Map.put("cc", ["https://www.w3.org/ns/activitystreams#Public"])
+ |> Map.put("cc", [Pleroma.Constants.as_public()])
_ ->
message
@@ -51,10 +54,10 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicy do
recipients = (message["to"] || []) ++ (message["cc"] || [])
follower_collection = User.get_cached_by_ap_id(message["actor"]).follower_address
- if Enum.member?(recipients, "https://www.w3.org/ns/activitystreams#Public") do
+ if Enum.member?(recipients, Pleroma.Constants.as_public()) do
recipients =
recipients
- |> List.delete("https://www.w3.org/ns/activitystreams#Public")
+ |> List.delete(Pleroma.Constants.as_public())
|> List.delete(follower_collection)
{:public, length(recipients)}
diff --git a/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex b/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex
index d5c341433..4eec8b916 100644
--- a/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex
@@ -3,6 +3,8 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
+ require Pleroma.Constants
+
@moduledoc "Reject or Word-Replace messages with a keyword or regex"
@behaviour Pleroma.Web.ActivityPub.MRF
@@ -31,12 +33,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
defp check_ftl_removal(
%{"to" => to, "object" => %{"content" => content, "summary" => summary}} = message
) do
- if "https://www.w3.org/ns/activitystreams#Public" in to and
+ if Pleroma.Constants.as_public() in to and
Enum.any?(Pleroma.Config.get([:mrf_keyword, :federated_timeline_removal]), fn pattern ->
string_matches?(content, pattern) or string_matches?(summary, pattern)
end) do
- to = List.delete(to, "https://www.w3.org/ns/activitystreams#Public")
- cc = ["https://www.w3.org/ns/activitystreams#Public" | message["cc"] || []]
+ to = List.delete(to, Pleroma.Constants.as_public())
+ cc = [Pleroma.Constants.as_public() | message["cc"] || []]
message =
message
diff --git a/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex b/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex
index da13fd7c7..457b6ee10 100644
--- a/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex
+++ b/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex
@@ -10,7 +10,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublic do
@behaviour Pleroma.Web.ActivityPub.MRF
- @public "https://www.w3.org/ns/activitystreams#Public"
+ require Pleroma.Constants
@impl true
def filter(%{"type" => "Create"} = object) do
@@ -19,8 +19,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublic do
# Determine visibility
visibility =
cond do
- @public in object["to"] -> "public"
- @public in object["cc"] -> "unlisted"
+ Pleroma.Constants.as_public() in object["to"] -> "public"
+ Pleroma.Constants.as_public() in object["cc"] -> "unlisted"
user.follower_address in object["to"] -> "followers"
true -> "direct"
end
diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex
index 2cf63d3db..f266457e3 100644
--- a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex
@@ -8,6 +8,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
@moduledoc "Filter activities depending on their origin instance"
@behaviour MRF
+ require Pleroma.Constants
+
defp check_accept(%{host: actor_host} = _actor_info, object) do
accepts =
Pleroma.Config.get([:mrf_simple, :accept])
@@ -89,14 +91,10 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
object =
with true <- MRF.subdomain_match?(timeline_removal, actor_host),
user <- User.get_cached_by_ap_id(object["actor"]),
- true <- "https://www.w3.org/ns/activitystreams#Public" in object["to"] do
- to =
- List.delete(object["to"], "https://www.w3.org/ns/activitystreams#Public") ++
- [user.follower_address]
-
- cc =
- List.delete(object["cc"], user.follower_address) ++
- ["https://www.w3.org/ns/activitystreams#Public"]
+ true <- Pleroma.Constants.as_public() in object["to"] do
+ to = List.delete(object["to"], Pleroma.Constants.as_public()) ++ [user.follower_address]
+
+ cc = List.delete(object["cc"], user.follower_address) ++ [Pleroma.Constants.as_public()]
object
|> Map.put("to", to)
diff --git a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex
index b42c4ed76..70edf4f7f 100644
--- a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex
@@ -19,7 +19,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do
- `mrf_tag:disable-any-subscription`: Reject any follow requests
"""
- @public "https://www.w3.org/ns/activitystreams#Public"
+ require Pleroma.Constants
defp get_tags(%User{tags: tags}) when is_list(tags), do: tags
defp get_tags(_), do: []
@@ -70,9 +70,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do
) do
user = User.get_cached_by_ap_id(actor)
- if Enum.member?(to, @public) do
- to = List.delete(to, @public) ++ [user.follower_address]
- cc = List.delete(cc, user.follower_address) ++ [@public]
+ if Enum.member?(to, Pleroma.Constants.as_public()) do
+ to = List.delete(to, Pleroma.Constants.as_public()) ++ [user.follower_address]
+ cc = List.delete(cc, user.follower_address) ++ [Pleroma.Constants.as_public()]
object =
object
@@ -103,9 +103,10 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do
) do
user = User.get_cached_by_ap_id(actor)
- if Enum.member?(to, @public) or Enum.member?(cc, @public) do
- to = List.delete(to, @public) ++ [user.follower_address]
- cc = List.delete(cc, @public)
+ if Enum.member?(to, Pleroma.Constants.as_public()) or
+ Enum.member?(cc, Pleroma.Constants.as_public()) do
+ to = List.delete(to, Pleroma.Constants.as_public()) ++ [user.follower_address]
+ cc = List.delete(cc, Pleroma.Constants.as_public())
object =
object
diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex
index 016d78216..46edab0bd 100644
--- a/lib/pleroma/web/activity_pub/publisher.ex
+++ b/lib/pleroma/web/activity_pub/publisher.ex
@@ -11,6 +11,8 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
alias Pleroma.Web.ActivityPub.Relay
alias Pleroma.Web.ActivityPub.Transmogrifier
+ require Pleroma.Constants
+
import Pleroma.Web.ActivityPub.Visibility
@behaviour Pleroma.Web.Federator.Publisher
@@ -117,8 +119,6 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|> Enum.map(& &1.ap_id)
end
- @as_public "https://www.w3.org/ns/activitystreams#Public"
-
defp maybe_use_sharedinbox(%User{info: %{source_data: data}}),
do: (is_map(data["endpoints"]) && Map.get(data["endpoints"], "sharedInbox")) || data["inbox"]
@@ -145,7 +145,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
type == "Delete" ->
maybe_use_sharedinbox(user)
- @as_public in to || @as_public in cc ->
+ Pleroma.Constants.as_public() in to || Pleroma.Constants.as_public() in cc ->
maybe_use_sharedinbox(user)
length(to) + length(cc) > 1 ->
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index 602ae48e1..5403b71d8 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -19,6 +19,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
import Ecto.Query
require Logger
+ require Pleroma.Constants
@doc """
Modifies an incoming AP object (mastodon format) to our internal format.
@@ -102,8 +103,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
follower_collection = User.get_cached_by_ap_id(Containment.get_actor(object)).follower_address
- explicit_mentions =
- explicit_mentions ++ ["https://www.w3.org/ns/activitystreams#Public", follower_collection]
+ explicit_mentions = explicit_mentions ++ [Pleroma.Constants.as_public(), follower_collection]
fix_explicit_addressing(object, explicit_mentions, follower_collection)
end
@@ -115,11 +115,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
if followers_collection not in recipients do
cond do
- "https://www.w3.org/ns/activitystreams#Public" in cc ->
+ Pleroma.Constants.as_public() in cc ->
to = to ++ [followers_collection]
Map.put(object, "to", to)
- "https://www.w3.org/ns/activitystreams#Public" in to ->
+ Pleroma.Constants.as_public() in to ->
cc = cc ++ [followers_collection]
Map.put(object, "cc", cc)
@@ -480,8 +480,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
{:ok, %User{} = follower} <- User.get_or_fetch_by_ap_id(follower),
{:ok, activity} <- ActivityPub.follow(follower, followed, id, false) do
with deny_follow_blocked <- Pleroma.Config.get([:user, :deny_follow_blocked]),
- {_, false} <-
- {:user_blocked, User.blocks?(followed, follower) && deny_follow_blocked},
+ {_, false} <- {:user_blocked, User.blocks?(followed, follower) && deny_follow_blocked},
{_, false} <- {:user_locked, User.locked?(followed)},
{_, {:ok, follower}} <- {:follow, User.follow(follower, followed)},
{_, {:ok, _}} <-
@@ -609,13 +608,13 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
with %User{ap_id: ^actor_id} = actor <- User.get_cached_by_ap_id(object["id"]) do
{:ok, new_user_data} = ActivityPub.user_data_from_user_object(object)
- banner = new_user_data[:info]["banner"]
- locked = new_user_data[:info]["locked"] || false
+ banner = new_user_data[:info][:banner]
+ locked = new_user_data[:info][:locked] || false
update_data =
new_user_data
|> Map.take([:name, :bio, :avatar])
- |> Map.put(:info, %{"banner" => banner, "locked" => locked})
+ |> Map.put(:info, %{banner: banner, locked: locked})
actor
|> User.upgrade_changeset(update_data)
@@ -656,20 +655,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
nil ->
case User.get_cached_by_ap_id(object_id) do
%User{ap_id: ^actor} = user ->
- {:ok, followers} = User.get_followers(user)
-
- Enum.each(followers, fn follower ->
- User.unfollow(follower, user)
- end)
-
- {:ok, friends} = User.get_friends(user)
-
- Enum.each(friends, fn followed ->
- User.unfollow(user, followed)
- end)
-
- User.invalidate_cache(user)
- Repo.delete(user)
+ User.delete(user)
nil ->
:error
@@ -1090,10 +1076,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
PleromaJobQueue.enqueue(:transmogrifier, __MODULE__, [:user_upgrade, user])
end
- if Pleroma.Config.get([:instance, :external_user_synchronization]) do
- update_following_followers_counters(user)
- end
-
{:ok, user}
else
%User{} = user -> {:ok, user}
@@ -1126,27 +1108,4 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
data
|> maybe_fix_user_url
end
-
- def update_following_followers_counters(user) do
- info = %{}
-
- following = fetch_counter(user.following_address)
- info = if following, do: Map.put(info, :following_count, following), else: info
-
- followers = fetch_counter(user.follower_address)
- info = if followers, do: Map.put(info, :follower_count, followers), else: info
-
- User.set_info_cache(user, info)
- end
-
- defp fetch_counter(url) do
- with {:ok, %{body: body, status: code}} when code in 200..299 <-
- Pleroma.HTTP.get(
- url,
- [{:Accept, "application/activity+json"}]
- ),
- {:ok, data} <- Jason.decode(body) do
- data["totalItems"]
- end
- end
end
diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex
index c146f59d4..39074888b 100644
--- a/lib/pleroma/web/activity_pub/utils.ex
+++ b/lib/pleroma/web/activity_pub/utils.ex
@@ -18,6 +18,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
import Ecto.Query
require Logger
+ require Pleroma.Constants
@supported_object_types ["Article", "Note", "Video", "Page", "Question", "Answer"]
@supported_report_states ~w(open closed resolved)
@@ -418,7 +419,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
"type" => "Follow",
"actor" => follower_id,
"to" => [followed_id],
- "cc" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "cc" => [Pleroma.Constants.as_public()],
"object" => followed_id,
"state" => "pending"
}
@@ -510,7 +511,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
"actor" => ap_id,
"object" => id,
"to" => [user.follower_address, object.data["actor"]],
- "cc" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "cc" => [Pleroma.Constants.as_public()],
"context" => object.data["context"]
}
@@ -530,7 +531,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
"actor" => ap_id,
"object" => activity.data,
"to" => [user.follower_address, activity.data["actor"]],
- "cc" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "cc" => [Pleroma.Constants.as_public()],
"context" => context
}
@@ -547,7 +548,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
"actor" => ap_id,
"object" => activity.data,
"to" => [user.follower_address, activity.data["actor"]],
- "cc" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "cc" => [Pleroma.Constants.as_public()],
"context" => context
}
@@ -556,7 +557,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
def add_announce_to_object(
%Activity{
- data: %{"actor" => actor, "cc" => ["https://www.w3.org/ns/activitystreams#Public"]}
+ data: %{"actor" => actor, "cc" => [Pleroma.Constants.as_public()]}
},
object
) do
@@ -765,7 +766,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
) do
cc = Map.get(data, "cc", [])
follower_address = User.get_cached_by_ap_id(data["actor"]).follower_address
- public = "https://www.w3.org/ns/activitystreams#Public"
+ public = Pleroma.Constants.as_public()
case visibility do
"public" ->
diff --git a/lib/pleroma/web/activity_pub/visibility.ex b/lib/pleroma/web/activity_pub/visibility.ex
index 097fceb08..dfb166b65 100644
--- a/lib/pleroma/web/activity_pub/visibility.ex
+++ b/lib/pleroma/web/activity_pub/visibility.ex
@@ -8,14 +8,14 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
alias Pleroma.Repo
alias Pleroma.User
- @public "https://www.w3.org/ns/activitystreams#Public"
+ require Pleroma.Constants
@spec is_public?(Object.t() | Activity.t() | map()) :: boolean()
def is_public?(%Object{data: %{"type" => "Tombstone"}}), do: false
def is_public?(%Object{data: data}), do: is_public?(data)
def is_public?(%Activity{data: data}), do: is_public?(data)
def is_public?(%{"directMessage" => true}), do: false
- def is_public?(data), do: @public in (data["to"] ++ (data["cc"] || []))
+ def is_public?(data), do: Pleroma.Constants.as_public() in (data["to"] ++ (data["cc"] || []))
def is_private?(activity) do
with false <- is_public?(activity),
@@ -73,10 +73,10 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
cc = object.data["cc"] || []
cond do
- @public in to ->
+ Pleroma.Constants.as_public() in to ->
"public"
- @public in cc ->
+ Pleroma.Constants.as_public() in cc ->
"unlisted"
# this should use the sql for the object's activity
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
index 1ae5acd91..fcda57b3e 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -379,6 +379,16 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
end
end
+ def migrate_to_db(conn, _params) do
+ Mix.Tasks.Pleroma.Config.run(["migrate_to_db"])
+ json(conn, %{})
+ end
+
+ def migrate_from_db(conn, _params) do
+ Mix.Tasks.Pleroma.Config.run(["migrate_from_db", Pleroma.Config.get(:env), "true"])
+ json(conn, %{})
+ end
+
def config_show(conn, _params) do
configs = Pleroma.Repo.all(Config)
diff --git a/lib/pleroma/web/auth/authenticator.ex b/lib/pleroma/web/auth/authenticator.ex
index d4e0ffa80..dd49987f7 100644
--- a/lib/pleroma/web/auth/authenticator.ex
+++ b/lib/pleroma/web/auth/authenticator.ex
@@ -21,8 +21,7 @@ defmodule Pleroma.Web.Auth.Authenticator do
def create_from_registration(plug, registration),
do: implementation().create_from_registration(plug, registration)
- @callback get_registration(Plug.Conn.t()) ::
- {:ok, Registration.t()} | {:error, any()}
+ @callback get_registration(Plug.Conn.t()) :: {:ok, Registration.t()} | {:error, any()}
def get_registration(plug), do: implementation().get_registration(plug)
@callback handle_error(Plug.Conn.t(), any()) :: any()
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index 44af6a773..2db58324b 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -300,8 +300,7 @@ defmodule Pleroma.Web.CommonAPI do
}
} = activity <- get_by_id_or_ap_id(id_or_ap_id),
true <- Visibility.is_public?(activity),
- %{valid?: true} = info_changeset <-
- User.Info.add_pinnned_activity(user.info, activity),
+ %{valid?: true} = info_changeset <- User.Info.add_pinnned_activity(user.info, activity),
changeset <-
Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_changeset),
{:ok, _user} <- User.update_and_set_cache(changeset) do
diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex
index 94462c3dd..c8a743e8e 100644
--- a/lib/pleroma/web/common_api/utils.ex
+++ b/lib/pleroma/web/common_api/utils.ex
@@ -19,11 +19,17 @@ defmodule Pleroma.Web.CommonAPI.Utils do
alias Pleroma.Web.MediaProxy
require Logger
+ require Pleroma.Constants
# This is a hack for twidere.
def get_by_id_or_ap_id(id) do
activity =
- Activity.get_by_id_with_object(id) || Activity.get_create_by_object_ap_id_with_object(id)
+ with true <- Pleroma.FlakeId.is_flake_id?(id),
+ %Activity{} = activity <- Activity.get_by_id_with_object(id) do
+ activity
+ else
+ _ -> Activity.get_create_by_object_ap_id_with_object(id)
+ end
activity &&
if activity.data["type"] == "Create" do
@@ -66,7 +72,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
@spec get_to_and_cc(User.t(), list(String.t()), Activity.t() | nil, String.t()) ::
{list(String.t()), list(String.t())}
def get_to_and_cc(user, mentioned_users, inReplyTo, "public") do
- to = ["https://www.w3.org/ns/activitystreams#Public" | mentioned_users]
+ to = [Pleroma.Constants.as_public() | mentioned_users]
cc = [user.follower_address]
if inReplyTo do
@@ -78,7 +84,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
def get_to_and_cc(user, mentioned_users, inReplyTo, "unlisted") do
to = [user.follower_address | mentioned_users]
- cc = ["https://www.w3.org/ns/activitystreams#Public"]
+ cc = [Pleroma.Constants.as_public()]
if inReplyTo do
{Enum.uniq([inReplyTo.data["actor"] | to]), cc}
diff --git a/lib/pleroma/web/fallback_redirect_controller.ex b/lib/pleroma/web/fallback_redirect_controller.ex
new file mode 100644
index 000000000..5fbf3695f
--- /dev/null
+++ b/lib/pleroma/web/fallback_redirect_controller.ex
@@ -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
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index d660f3f05..174e93468 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -4,6 +4,9 @@
defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
use Pleroma.Web, :controller
+
+ import Pleroma.Web.ControllerHelper, only: [json_response: 3]
+
alias Ecto.Changeset
alias Pleroma.Activity
alias Pleroma.Bookmark
@@ -46,6 +49,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
import Ecto.Query
require Logger
+ require Pleroma.Constants
@rate_limited_relations_actions ~w(follow unfollow)a
@@ -74,6 +78,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
plug(RateLimiter, :app_account_creation when action == :account_register)
plug(RateLimiter, :search when action in [:search, :search2, :account_search])
plug(RateLimiter, :password_reset when action == :password_reset)
+ plug(RateLimiter, :account_confirmation_resend when action == :account_confirmation_resend)
@local_mastodon_name "Mastodon-Local"
@@ -1220,10 +1225,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
recipients =
if for_user do
- ["https://www.w3.org/ns/activitystreams#Public"] ++
- [for_user.ap_id | for_user.following]
+ [Pleroma.Constants.as_public()] ++ [for_user.ap_id | for_user.following]
else
- ["https://www.w3.org/ns/activitystreams#Public"]
+ [Pleroma.Constants.as_public()]
end
activities =
@@ -1839,6 +1843,16 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
end
+ def account_confirmation_resend(conn, params) do
+ nickname_or_email = params["email"] || params["nickname"]
+
+ with %User{} = user <- User.get_by_nickname_or_email(nickname_or_email),
+ {:ok, _} <- User.try_send_confirmation_email(user) do
+ conn
+ |> json_response(:no_content, "")
+ end
+ end
+
def try_render(conn, target, params)
when is_binary(target) do
case render(conn, target, params) do
diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex
index befb35c26..b2b06eeb9 100644
--- a/lib/pleroma/web/mastodon_api/views/account_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/account_view.ex
@@ -50,13 +50,13 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
id: to_string(target.id),
following: User.following?(user, target),
followed_by: User.following?(target, user),
- blocking: User.blocks?(user, target),
- blocked_by: User.blocks?(target, user),
+ blocking: User.blocks_ap_id?(user, target),
+ blocked_by: User.blocks_ap_id?(target, user),
muting: User.mutes?(user, target),
muting_notifications: User.muted_notifications?(user, target),
subscribing: User.subscribed_to?(user, target),
requested: requested,
- domain_blocking: false,
+ domain_blocking: User.blocks_domain?(user, target),
showing_reblogs: User.showing_reblogs?(user, target),
endorsed: false
}
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index de9425959..80df9b2ac 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -222,7 +222,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
if user.local do
Pleroma.Web.Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, activity)
else
- object.data["external_url"] || object.data["id"]
+ object.data["url"] || object.data["external_url"] || object.data["id"]
end
%{
diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
index a1d7fcc7d..54f89e65c 100644
--- a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
+++ b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
@@ -165,6 +165,7 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
},
accountActivationRequired: Config.get([:instance, :account_activation_required], false),
invitesEnabled: Config.get([:instance, :invites_enabled], false),
+ mailerEnabled: Config.get([Pleroma.Emails.Mailer, :enabled], false),
features: features,
restrictedNicknames: Config.get([Pleroma.User, :restricted_nicknames]),
skipThreadContainment: Config.get([:instance, :skip_thread_containment], false)
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index ef53b7ae3..81eae2c8b 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -365,8 +365,7 @@ defmodule Pleroma.Web.OAuth.OAuthController 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),
%Registration{} = registration <- Repo.get(Registration, registration_id),
- {_, {:ok, auth}} <-
- {:create_authorization, do_create_authorization(conn, params)},
+ {_, {:ok, auth}} <- {:create_authorization, do_create_authorization(conn, params)},
%User{} = user <- Repo.preload(auth, :user).user,
{:ok, _updated_registration} <- Registration.bind_to_user(registration, user) do
conn
diff --git a/lib/pleroma/web/oauth/token.ex b/lib/pleroma/web/oauth/token.ex
index 90c304487..40f131b57 100644
--- a/lib/pleroma/web/oauth/token.ex
+++ b/lib/pleroma/web/oauth/token.ex
@@ -44,8 +44,7 @@ defmodule Pleroma.Web.OAuth.Token do
|> Repo.find_resource()
end
- @spec exchange_token(App.t(), Authorization.t()) ::
- {:ok, Token.t()} | {:error, Changeset.t()}
+ @spec exchange_token(App.t(), Authorization.t()) :: {:ok, Token.t()} | {:error, Changeset.t()}
def exchange_token(app, auth) do
with {:ok, auth} <- Authorization.use_token(auth),
true <- auth.app_id == app.id do
diff --git a/lib/pleroma/web/ostatus/activity_representer.ex b/lib/pleroma/web/ostatus/activity_representer.ex
index 95037125d..760345301 100644
--- a/lib/pleroma/web/ostatus/activity_representer.ex
+++ b/lib/pleroma/web/ostatus/activity_representer.ex
@@ -9,6 +9,7 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do
alias Pleroma.Web.OStatus.UserRepresenter
require Logger
+ require Pleroma.Constants
defp get_href(id) do
with %Object{data: %{"external_url" => external_url}} <- Object.get_cached_by_ap_id(id) do
@@ -34,7 +35,7 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do
Enum.map(to, fn id ->
cond do
# Special handling for the AP/Ostatus public collections
- "https://www.w3.org/ns/activitystreams#Public" == id ->
+ Pleroma.Constants.as_public() == id ->
{:link,
[
rel: "mentioned",
diff --git a/lib/pleroma/web/ostatus/handlers/follow_handler.ex b/lib/pleroma/web/ostatus/handlers/follow_handler.ex
index 263d3b2dc..24513972e 100644
--- a/lib/pleroma/web/ostatus/handlers/follow_handler.ex
+++ b/lib/pleroma/web/ostatus/handlers/follow_handler.ex
@@ -9,14 +9,18 @@ defmodule Pleroma.Web.OStatus.FollowHandler do
alias Pleroma.Web.XML
def handle(entry, doc) do
- with {:ok, actor} <- OStatus.find_make_or_update_user(doc),
+ with {:ok, actor} <- OStatus.find_make_or_update_actor(doc),
id when not is_nil(id) <- XML.string_from_xpath("/entry/id", entry),
followed_uri when not is_nil(followed_uri) <-
XML.string_from_xpath("/entry/activity:object/id", entry),
{:ok, followed} <- OStatus.find_or_make_user(followed_uri),
+ {:locked, false} <- {:locked, followed.info.locked},
{:ok, activity} <- ActivityPub.follow(actor, followed, id, false) do
User.follow(actor, followed)
{:ok, activity}
+ else
+ {:locked, true} ->
+ {:error, "It's not possible to follow locked accounts over OStatus"}
end
end
end
diff --git a/lib/pleroma/web/ostatus/handlers/note_handler.ex b/lib/pleroma/web/ostatus/handlers/note_handler.ex
index 8e0adad91..7fae14f7b 100644
--- a/lib/pleroma/web/ostatus/handlers/note_handler.ex
+++ b/lib/pleroma/web/ostatus/handlers/note_handler.ex
@@ -4,6 +4,7 @@
defmodule Pleroma.Web.OStatus.NoteHandler do
require Logger
+ require Pleroma.Constants
alias Pleroma.Activity
alias Pleroma.Object
@@ -49,7 +50,7 @@ defmodule Pleroma.Web.OStatus.NoteHandler do
def get_collection_mentions(entry) do
transmogrify = fn
"http://activityschema.org/collection/public" ->
- "https://www.w3.org/ns/activitystreams#Public"
+ Pleroma.Constants.as_public()
group ->
group
@@ -110,7 +111,7 @@ defmodule Pleroma.Web.OStatus.NoteHandler do
with id <- XML.string_from_xpath("//id", entry),
activity when is_nil(activity) <- Activity.get_create_by_object_ap_id_with_object(id),
[author] <- :xmerl_xpath.string('//author[1]', doc),
- {:ok, actor} <- OStatus.find_make_or_update_user(author),
+ {:ok, actor} <- OStatus.find_make_or_update_actor(author),
content_html <- OStatus.get_content(entry),
cw <- OStatus.get_cw(entry),
in_reply_to <- XML.string_from_xpath("//thr:in-reply-to[1]/@ref", entry),
@@ -126,7 +127,7 @@ defmodule Pleroma.Web.OStatus.NoteHandler do
to <- make_to_list(actor, mentions),
date <- XML.string_from_xpath("//published", entry),
unlisted <- XML.string_from_xpath("//mastodon:scope", entry) == "unlisted",
- cc <- if(unlisted, do: ["https://www.w3.org/ns/activitystreams#Public"], else: []),
+ cc <- if(unlisted, do: [Pleroma.Constants.as_public()], else: []),
note <-
CommonAPI.Utils.make_note_data(
actor.ap_id,
diff --git a/lib/pleroma/web/ostatus/handlers/unfollow_handler.ex b/lib/pleroma/web/ostatus/handlers/unfollow_handler.ex
index 6596ada3b..2062432e3 100644
--- a/lib/pleroma/web/ostatus/handlers/unfollow_handler.ex
+++ b/lib/pleroma/web/ostatus/handlers/unfollow_handler.ex
@@ -9,7 +9,7 @@ defmodule Pleroma.Web.OStatus.UnfollowHandler do
alias Pleroma.Web.XML
def handle(entry, doc) do
- with {:ok, actor} <- OStatus.find_make_or_update_user(doc),
+ with {:ok, actor} <- OStatus.find_make_or_update_actor(doc),
id when not is_nil(id) <- XML.string_from_xpath("/entry/id", entry),
followed_uri when not is_nil(followed_uri) <-
XML.string_from_xpath("/entry/activity:object/id", entry),
diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex
index 502410c83..331cbc0b7 100644
--- a/lib/pleroma/web/ostatus/ostatus.ex
+++ b/lib/pleroma/web/ostatus/ostatus.ex
@@ -56,7 +56,7 @@ defmodule Pleroma.Web.OStatus do
def handle_incoming(xml_string, options \\ []) do
with doc when doc != :error <- parse_document(xml_string) do
- with {:ok, actor_user} <- find_make_or_update_user(doc),
+ with {:ok, actor_user} <- find_make_or_update_actor(doc),
do: Pleroma.Instances.set_reachable(actor_user.ap_id)
entries = :xmerl_xpath.string('//entry', doc)
@@ -120,7 +120,7 @@ defmodule Pleroma.Web.OStatus do
end
def make_share(entry, doc, retweeted_activity) do
- with {:ok, actor} <- find_make_or_update_user(doc),
+ with {:ok, actor} <- find_make_or_update_actor(doc),
%Object{} = object <- Object.normalize(retweeted_activity),
id when not is_nil(id) <- string_from_xpath("/entry/id", entry),
{:ok, activity, _object} = ActivityPub.announce(actor, object, id, false) do
@@ -138,7 +138,7 @@ defmodule Pleroma.Web.OStatus do
end
def make_favorite(entry, doc, favorited_activity) do
- with {:ok, actor} <- find_make_or_update_user(doc),
+ with {:ok, actor} <- find_make_or_update_actor(doc),
%Object{} = object <- Object.normalize(favorited_activity),
id when not is_nil(id) <- string_from_xpath("/entry/id", entry),
{:ok, activity, _object} = ActivityPub.like(actor, object, id, false) do
@@ -264,11 +264,18 @@ defmodule Pleroma.Web.OStatus do
end
end
- def find_make_or_update_user(doc) do
+ def find_make_or_update_actor(doc) do
uri = string_from_xpath("//author/uri[1]", doc)
- with {:ok, user} <- find_or_make_user(uri) do
+ with {:ok, %User{} = user} <- find_or_make_user(uri),
+ {:ap_enabled, false} <- {:ap_enabled, User.ap_enabled?(user)} do
maybe_update(doc, user)
+ else
+ {:ap_enabled, true} ->
+ {:error, :invalid_protocol}
+
+ _ ->
+ {:error, :unknown_user}
end
end
diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex
index 372d52899..c70063b84 100644
--- a/lib/pleroma/web/ostatus/ostatus_controller.ex
+++ b/lib/pleroma/web/ostatus/ostatus_controller.ex
@@ -5,6 +5,7 @@
defmodule Pleroma.Web.OStatus.OStatusController do
use Pleroma.Web, :controller
+ alias Fallback.RedirectController
alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.User
@@ -12,42 +13,44 @@ defmodule Pleroma.Web.OStatus.OStatusController do
alias Pleroma.Web.ActivityPub.ActivityPubController
alias Pleroma.Web.ActivityPub.ObjectView
alias Pleroma.Web.ActivityPub.Visibility
+ alias Pleroma.Web.Endpoint
alias Pleroma.Web.Federator
+ alias Pleroma.Web.Metadata.PlayerView
alias Pleroma.Web.OStatus
alias Pleroma.Web.OStatus.ActivityRepresenter
alias Pleroma.Web.OStatus.FeedRepresenter
+ alias Pleroma.Web.Router
alias Pleroma.Web.XML
plug(Pleroma.Web.FederatingPlug when action in [:salmon_incoming])
- action_fallback(:errors)
+ plug(
+ Pleroma.Plugs.SetFormatPlug
+ when action in [:feed_redirect, :object, :activity, :notice]
+ )
- def feed_redirect(conn, %{"nickname" => nickname}) do
- case get_format(conn) do
- "html" ->
- with %User{} = user <- User.get_cached_by_nickname_or_id(nickname) do
- Fallback.RedirectController.redirector_with_meta(conn, %{user: user})
- else
- nil -> {:error, :not_found}
- end
+ action_fallback(:errors)
- "activity+json" ->
- ActivityPubController.call(conn, :user)
+ 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
- "json" ->
- ActivityPubController.call(conn, :user)
+ def feed_redirect(%{assigns: %{format: format}} = conn, _params)
+ when format in ["json", "activity+json"] do
+ ActivityPubController.call(conn, :user)
+ end
- _ ->
- with %User{} = user <- User.get_cached_by_nickname(nickname) do
- redirect(conn, external: OStatus.feed_path(user))
- else
- nil -> {:error, :not_found}
- end
+ def feed_redirect(conn, %{"nickname" => nickname}) do
+ with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname(nickname)} do
+ redirect(conn, external: OStatus.feed_path(user))
end
end
def feed(conn, %{"nickname" => nickname} = params) do
- with %User{} = user <- User.get_cached_by_nickname(nickname) do
+ with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname(nickname)} do
query_params =
Map.take(params, ["max_id"])
|> Map.merge(%{"whole_db" => true, "actor_id" => user.ap_id})
@@ -65,8 +68,6 @@ defmodule Pleroma.Web.OStatus.OStatusController do
conn
|> put_resp_content_type("application/atom+xml")
|> send_resp(200, response)
- else
- nil -> {:error, :not_found}
end
end
@@ -97,93 +98,82 @@ defmodule Pleroma.Web.OStatus.OStatusController do
|> send_resp(200, "")
end
- def object(conn, %{"uuid" => uuid}) do
- if get_format(conn) in ["activity+json", "json"] do
- ActivityPubController.call(conn, :object)
- else
- with id <- o_status_url(conn, :object, uuid),
- {_, %Activity{} = activity} <-
- {:activity, Activity.get_create_by_object_ap_id_with_object(id)},
- {_, true} <- {:public?, Visibility.is_public?(activity)},
- %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
- case get_format(conn) do
- "html" -> redirect(conn, to: "/notice/#{activity.id}")
- _ -> represent_activity(conn, nil, activity, user)
- end
- else
- {:public?, false} ->
- {:error, :not_found}
-
- {:activity, nil} ->
- {:error, :not_found}
+ def object(%{assigns: %{format: format}} = conn, %{"uuid" => _uuid})
+ when format in ["json", "activity+json"] do
+ ActivityPubController.call(conn, :object)
+ end
- e ->
- e
+ def object(%{assigns: %{format: format}} = conn, %{"uuid" => uuid}) do
+ with id <- o_status_url(conn, :object, uuid),
+ {_, %Activity{} = activity} <-
+ {:activity, Activity.get_create_by_object_ap_id_with_object(id)},
+ {_, true} <- {:public?, Visibility.is_public?(activity)},
+ %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
+ case format do
+ "html" -> redirect(conn, to: "/notice/#{activity.id}")
+ _ -> represent_activity(conn, nil, activity, user)
end
+ else
+ reason when reason in [{:public?, false}, {:activity, nil}] ->
+ {:error, :not_found}
+
+ e ->
+ e
end
end
- def activity(conn, %{"uuid" => uuid}) do
- if get_format(conn) in ["activity+json", "json"] do
- ActivityPubController.call(conn, :activity)
- else
- with id <- o_status_url(conn, :activity, uuid),
- {_, %Activity{} = activity} <- {:activity, Activity.normalize(id)},
- {_, true} <- {:public?, Visibility.is_public?(activity)},
- %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
- case format = get_format(conn) do
- "html" -> redirect(conn, to: "/notice/#{activity.id}")
- _ -> represent_activity(conn, format, activity, user)
- end
- else
- {:public?, false} ->
- {:error, :not_found}
-
- {:activity, nil} ->
- {:error, :not_found}
+ def activity(%{assigns: %{format: format}} = conn, %{"uuid" => _uuid})
+ when format in ["json", "activity+json"] do
+ ActivityPubController.call(conn, :activity)
+ end
- e ->
- e
+ def activity(%{assigns: %{format: format}} = conn, %{"uuid" => uuid}) do
+ with id <- o_status_url(conn, :activity, uuid),
+ {_, %Activity{} = activity} <- {:activity, Activity.normalize(id)},
+ {_, true} <- {:public?, Visibility.is_public?(activity)},
+ %User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
+ case format do
+ "html" -> redirect(conn, to: "/notice/#{activity.id}")
+ _ -> represent_activity(conn, format, activity, user)
end
+ else
+ reason when reason in [{:public?, false}, {:activity, nil}] ->
+ {:error, :not_found}
+
+ e ->
+ e
end
end
- def notice(conn, %{"id" => id}) do
+ def notice(%{assigns: %{format: format}} = conn, %{"id" => id}) do
with {_, %Activity{} = activity} <- {:activity, Activity.get_by_id_with_object(id)},
{_, true} <- {:public?, Visibility.is_public?(activity)},
%User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
- case format = get_format(conn) do
- "html" ->
- if activity.data["type"] == "Create" do
- %Object{} = object = Object.normalize(activity)
+ cond do
+ format == "html" && activity.data["type"] == "Create" ->
+ %Object{} = object = Object.normalize(activity)
- Fallback.RedirectController.redirector_with_meta(conn, %{
+ RedirectController.redirector_with_meta(
+ conn,
+ %{
activity_id: activity.id,
object: object,
- url:
- Pleroma.Web.Router.Helpers.o_status_url(
- Pleroma.Web.Endpoint,
- :notice,
- activity.id
- ),
+ url: Router.Helpers.o_status_url(Endpoint, :notice, activity.id),
user: user
- })
- else
- Fallback.RedirectController.redirector(conn, nil)
- end
+ }
+ )
- _ ->
+ format == "html" ->
+ RedirectController.redirector(conn, nil)
+
+ true ->
represent_activity(conn, format, activity, user)
end
else
- {:public?, false} ->
+ reason when reason in [{:public?, false}, {:activity, nil}] ->
conn
|> put_status(404)
- |> Fallback.RedirectController.redirector(nil, 404)
-
- {:activity, nil} ->
- conn
- |> Fallback.RedirectController.redirector(nil, 404)
+ |> RedirectController.redirector(nil, 404)
e ->
e
@@ -204,13 +194,13 @@ defmodule Pleroma.Web.OStatus.OStatusController do
"content-security-policy",
"default-src 'none';style-src 'self' 'unsafe-inline';img-src 'self' data: https:; media-src 'self' https:;"
)
- |> put_view(Pleroma.Web.Metadata.PlayerView)
+ |> put_view(PlayerView)
|> render("player.html", url)
else
_error ->
conn
|> put_status(404)
- |> Fallback.RedirectController.redirector(nil, 404)
+ |> RedirectController.redirector(nil, 404)
end
end
@@ -248,6 +238,8 @@ defmodule Pleroma.Web.OStatus.OStatusController do
render_error(conn, :not_found, "Not found")
end
+ def errors(conn, {:fetch_user, nil}), do: errors(conn, {:error, :not_found})
+
def errors(conn, _) do
render_error(conn, :internal_server_error, "Something went wrong")
end
diff --git a/lib/pleroma/web/rich_media/parsers/ttl/aws_signed_url.ex b/lib/pleroma/web/rich_media/parsers/ttl/aws_signed_url.ex
index 014c0935f..0dc1efdaf 100644
--- a/lib/pleroma/web/rich_media/parsers/ttl/aws_signed_url.ex
+++ b/lib/pleroma/web/rich_media/parsers/ttl/aws_signed_url.ex
@@ -19,8 +19,7 @@ defmodule Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl do
defp is_aws_signed_url(image) when is_binary(image) do
%URI{host: host, query: query} = URI.parse(image)
- if String.contains?(host, "amazonaws.com") and
- String.contains?(query, "X-Amz-Expires") do
+ if String.contains?(host, "amazonaws.com") and String.contains?(query, "X-Amz-Expires") do
image
else
nil
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 0717e9aa0..c8c1c22dd 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -196,6 +196,8 @@ defmodule Pleroma.Web.Router do
get("/config", AdminAPIController, :config_show)
post("/config", AdminAPIController, :config_update)
+ get("/config/migrate_to_db", AdminAPIController, :migrate_to_db)
+ get("/config/migrate_from_db", AdminAPIController, :migrate_from_db)
end
scope "/", Pleroma.Web.TwitterAPI do
@@ -412,6 +414,12 @@ defmodule Pleroma.Web.Router do
get("/accounts/search", SearchController, :account_search)
+ post(
+ "/pleroma/accounts/confirmation_resend",
+ MastodonAPIController,
+ :account_confirmation_resend
+ )
+
scope [] do
pipe_through(:oauth_read_or_public)
@@ -694,7 +702,7 @@ defmodule Pleroma.Web.Router do
post("/auth/password", MastodonAPIController, :password_reset)
scope [] do
- pipe_through(:oauth_read_or_public)
+ pipe_through(:oauth_read)
get("/web/*path", MastodonAPIController, :index)
end
end
@@ -731,68 +739,3 @@ defmodule Pleroma.Web.Router do
options("/*path", RedirectController, :empty)
end
end
-
-defmodule Fallback.RedirectController do
- use Pleroma.Web, :controller
- require Logger
- alias Pleroma.User
- alias Pleroma.Web.Metadata
-
- def api_not_implemented(conn, _params) do
- conn
- |> put_status(404)
- |> json(%{error: "Not implemented"})
- end
-
- def redirector(conn, _params, code \\ 200) do
- conn
- |> put_resp_content_type("text/html")
- |> send_file(code, index_file_path())
- end
-
- def redirector_with_meta(conn, %{"maybe_nickname_or_id" => maybe_nickname_or_id} = params) do
- with %User{} = user <- User.get_cached_by_nickname_or_id(maybe_nickname_or_id) do
- redirector_with_meta(conn, %{user: user})
- else
- nil ->
- redirector(conn, params)
- end
- end
-
- def redirector_with_meta(conn, params) do
- {:ok, index_content} = File.read(index_file_path())
-
- tags =
- try do
- Metadata.build_tags(params)
- rescue
- e ->
- Logger.error(
- "Metadata rendering for #{conn.request_path} failed.\n" <>
- Exception.format(:error, e, __STACKTRACE__)
- )
-
- ""
- end
-
- response = String.replace(index_content, "<!--server-generated-meta-->", tags)
-
- conn
- |> put_resp_content_type("text/html")
- |> send_resp(200, response)
- end
-
- def index_file_path do
- Pleroma.Plugs.InstanceStatic.file_path("index.html")
- end
-
- def registration_page(conn, params) do
- redirector(conn, params)
- end
-
- def empty(conn, _params) do
- conn
- |> put_status(204)
- |> text("")
- end
-end
diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
index 9e4da7dca..3405bd3b7 100644
--- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
@@ -15,11 +15,11 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
alias Pleroma.Plugs.AuthenticationPlug
alias Pleroma.User
alias Pleroma.Web
- alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.CommonAPI
- alias Pleroma.Web.OStatus
alias Pleroma.Web.WebFinger
+ plug(Pleroma.Plugs.SetFormatPlug when action in [:config, :version])
+
def help_test(conn, _params) do
json(conn, "ok")
end
@@ -60,27 +60,25 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
%Activity{id: activity_id} = Activity.get_create_by_object_ap_id(object.data["id"])
redirect(conn, to: "/notice/#{activity_id}")
else
- {err, followee} = OStatus.find_or_make_user(acct)
- avatar = User.avatar_url(followee)
- name = followee.nickname
- id = followee.id
-
- if !!user do
+ with {:ok, followee} <- User.get_or_fetch(acct) do
conn
- |> render("follow.html", %{error: err, acct: acct, avatar: avatar, name: name, id: id})
- else
- conn
- |> render("follow_login.html", %{
+ |> render(follow_template(user), %{
error: false,
acct: acct,
- avatar: avatar,
- name: name,
- id: id
+ avatar: User.avatar_url(followee),
+ name: followee.nickname,
+ id: followee.id
})
+ else
+ {:error, _reason} ->
+ render(conn, follow_template(user), %{error: :error})
end
end
end
+ defp follow_template(%User{} = _user), do: "follow.html"
+ defp follow_template(_), do: "follow_login.html"
+
defp is_status?(acct) do
case Pleroma.Object.Fetcher.fetch_and_contain_remote_object_from_id(acct) do
{:ok, %{"type" => type}} when type in ["Article", "Note", "Video", "Page", "Question"] ->
@@ -94,50 +92,53 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
def do_remote_follow(conn, %{
"authorization" => %{"name" => username, "password" => password, "id" => id}
}) do
- followee = User.get_cached_by_id(id)
- avatar = User.avatar_url(followee)
- name = followee.nickname
-
- with %User{} = user <- User.get_cached_by_nickname(username),
- true <- AuthenticationPlug.checkpw(password, user.password_hash),
- %User{} = _followed <- User.get_cached_by_id(id),
- {:ok, follower} <- User.follow(user, followee),
- {:ok, _activity} <- ActivityPub.follow(follower, followee) do
+ with %User{} = followee <- User.get_cached_by_id(id),
+ {_, %User{} = user, _} <- {:auth, User.get_cached_by_nickname(username), followee},
+ {_, true, _} <- {
+ :auth,
+ AuthenticationPlug.checkpw(password, user.password_hash),
+ followee
+ },
+ {:ok, _follower, _followee, _activity} <- CommonAPI.follow(user, followee) do
conn
|> render("followed.html", %{error: false})
else
# Was already following user
{:error, "Could not follow user:" <> _rest} ->
- render(conn, "followed.html", %{error: false})
+ render(conn, "followed.html", %{error: "Error following account"})
- _e ->
+ {:auth, _, followee} ->
conn
|> render("follow_login.html", %{
error: "Wrong username or password",
id: id,
- name: name,
- avatar: avatar
+ name: followee.nickname,
+ avatar: User.avatar_url(followee)
})
+
+ e ->
+ Logger.debug("Remote follow failed with error #{inspect(e)}")
+ render(conn, "followed.html", %{error: "Something went wrong."})
end
end
def do_remote_follow(%{assigns: %{user: user}} = conn, %{"user" => %{"id" => id}}) do
- with %User{} = followee <- User.get_cached_by_id(id),
- {:ok, follower} <- User.follow(user, followee),
- {:ok, _activity} <- ActivityPub.follow(follower, followee) do
+ with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)},
+ {:ok, _follower, _followee, _activity} <- CommonAPI.follow(user, followee) do
conn
|> render("followed.html", %{error: false})
else
# Was already following user
{:error, "Could not follow user:" <> _rest} ->
- conn
- |> render("followed.html", %{error: false})
+ render(conn, "followed.html", %{error: "Error following account"})
+
+ {:fetch_user, error} ->
+ Logger.debug("Remote follow failed with error #{inspect(error)}")
+ render(conn, "followed.html", %{error: "Could not find user"})
e ->
Logger.debug("Remote follow failed with error #{inspect(e)}")
-
- conn
- |> render("followed.html", %{error: inspect(e)})
+ render(conn, "followed.html", %{error: "Something went wrong."})
end
end
@@ -152,67 +153,70 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
end
end
- def config(conn, _params) do
+ def config(%{assigns: %{format: "xml"}} = conn, _params) do
instance = Pleroma.Config.get(:instance)
- case get_format(conn) do
- "xml" ->
- response = """
- <config>
- <site>
- <name>#{Keyword.get(instance, :name)}</name>
- <site>#{Web.base_url()}</site>
- <textlimit>#{Keyword.get(instance, :limit)}</textlimit>
- <closed>#{!Keyword.get(instance, :registrations_open)}</closed>
- </site>
- </config>
- """
+ response = """
+ <config>
+ <site>
+ <name>#{Keyword.get(instance, :name)}</name>
+ <site>#{Web.base_url()}</site>
+ <textlimit>#{Keyword.get(instance, :limit)}</textlimit>
+ <closed>#{!Keyword.get(instance, :registrations_open)}</closed>
+ </site>
+ </config>
+ """
- conn
- |> put_resp_content_type("application/xml")
- |> send_resp(200, response)
+ conn
+ |> put_resp_content_type("application/xml")
+ |> send_resp(200, response)
+ end
- _ ->
- vapid_public_key = Keyword.get(Pleroma.Web.Push.vapid_config(), :public_key)
-
- uploadlimit = %{
- uploadlimit: to_string(Keyword.get(instance, :upload_limit)),
- avatarlimit: to_string(Keyword.get(instance, :avatar_upload_limit)),
- backgroundlimit: to_string(Keyword.get(instance, :background_upload_limit)),
- bannerlimit: to_string(Keyword.get(instance, :banner_upload_limit))
- }
-
- data = %{
- name: Keyword.get(instance, :name),
- description: Keyword.get(instance, :description),
- server: Web.base_url(),
- textlimit: to_string(Keyword.get(instance, :limit)),
- uploadlimit: uploadlimit,
- closed: if(Keyword.get(instance, :registrations_open), do: "0", else: "1"),
- private: if(Keyword.get(instance, :public, true), do: "0", else: "1"),
- vapidPublicKey: vapid_public_key,
- accountActivationRequired:
- if(Keyword.get(instance, :account_activation_required, false), do: "1", else: "0"),
- invitesEnabled: if(Keyword.get(instance, :invites_enabled, false), do: "1", else: "0"),
- safeDMMentionsEnabled:
- if(Pleroma.Config.get([:instance, :safe_dm_mentions]), do: "1", else: "0")
- }
+ def config(conn, _params) do
+ instance = Pleroma.Config.get(:instance)
+ vapid_public_key = Keyword.get(Pleroma.Web.Push.vapid_config(), :public_key)
+
+ uploadlimit = %{
+ uploadlimit: to_string(Keyword.get(instance, :upload_limit)),
+ avatarlimit: to_string(Keyword.get(instance, :avatar_upload_limit)),
+ backgroundlimit: to_string(Keyword.get(instance, :background_upload_limit)),
+ bannerlimit: to_string(Keyword.get(instance, :banner_upload_limit))
+ }
+
+ data = %{
+ name: Keyword.get(instance, :name),
+ description: Keyword.get(instance, :description),
+ server: Web.base_url(),
+ textlimit: to_string(Keyword.get(instance, :limit)),
+ uploadlimit: uploadlimit,
+ closed: bool_to_val(Keyword.get(instance, :registrations_open), "0", "1"),
+ private: bool_to_val(Keyword.get(instance, :public, true), "0", "1"),
+ vapidPublicKey: vapid_public_key,
+ accountActivationRequired:
+ bool_to_val(Keyword.get(instance, :account_activation_required, false)),
+ invitesEnabled: bool_to_val(Keyword.get(instance, :invites_enabled, false)),
+ safeDMMentionsEnabled: bool_to_val(Pleroma.Config.get([:instance, :safe_dm_mentions]))
+ }
+
+ managed_config = Keyword.get(instance, :managed_config)
+
+ data =
+ if managed_config do
pleroma_fe = Pleroma.Config.get([:frontend_configurations, :pleroma_fe])
+ Map.put(data, "pleromafe", pleroma_fe)
+ else
+ data
+ end
- managed_config = Keyword.get(instance, :managed_config)
-
- data =
- if managed_config do
- data |> Map.put("pleromafe", pleroma_fe)
- else
- data
- end
-
- json(conn, %{site: data})
- end
+ json(conn, %{site: data})
end
+ defp bool_to_val(true), do: "1"
+ defp bool_to_val(_), do: "0"
+ defp bool_to_val(true, val, _), do: val
+ defp bool_to_val(_, _, val), do: val
+
def frontend_configurations(conn, _params) do
config =
Pleroma.Config.get(:frontend_configurations, %{})
@@ -221,20 +225,16 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
json(conn, config)
end
- def version(conn, _params) do
+ def version(%{assigns: %{format: "xml"}} = conn, _params) do
version = Pleroma.Application.named_version()
- case get_format(conn) do
- "xml" ->
- response = "<version>#{version}</version>"
-
- conn
- |> put_resp_content_type("application/xml")
- |> send_resp(200, response)
+ conn
+ |> put_resp_content_type("application/xml")
+ |> send_resp(200, "<version>#{version}</version>")
+ end
- _ ->
- json(conn, version)
- end
+ def version(conn, _params) do
+ json(conn, Pleroma.Application.named_version())
end
def emoji(conn, _params) do
diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex
index bb5dda204..80082ea84 100644
--- a/lib/pleroma/web/twitter_api/twitter_api.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api.ex
@@ -15,6 +15,8 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
import Ecto.Query
+ require Pleroma.Constants
+
def create_status(%User{} = user, %{"status" => _} = data) do
CommonAPI.post(user, data)
end
@@ -286,7 +288,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
from(
[a, o] in Activity.with_preloaded_object(Activity),
where: fragment("?->>'type' = 'Create'", a.data),
- where: "https://www.w3.org/ns/activitystreams#Public" in a.recipients,
+ where: ^Pleroma.Constants.as_public() in a.recipients,
where:
fragment(
"to_tsvector('english', ?->>'content') @@ plainto_tsquery('english', ?)",
diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex
index e84af84dc..abae63877 100644
--- a/lib/pleroma/web/twitter_api/views/activity_view.ex
+++ b/lib/pleroma/web/twitter_api/views/activity_view.ex
@@ -19,6 +19,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
import Ecto.Query
require Logger
+ require Pleroma.Constants
defp query_context_ids([]), do: []
@@ -91,7 +92,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
String.ends_with?(ap_id, "/followers") ->
nil
- ap_id == "https://www.w3.org/ns/activitystreams#Public" ->
+ ap_id == Pleroma.Constants.as_public() ->
nil
user = User.get_cached_by_ap_id(ap_id) ->
diff --git a/lib/pleroma/web/twitter_api/views/notification_view.ex b/lib/pleroma/web/twitter_api/views/notification_view.ex
index e7c7a7496..085cd5aa3 100644
--- a/lib/pleroma/web/twitter_api/views/notification_view.ex
+++ b/lib/pleroma/web/twitter_api/views/notification_view.ex
@@ -10,6 +10,8 @@ defmodule Pleroma.Web.TwitterAPI.NotificationView do
alias Pleroma.Web.TwitterAPI.ActivityView
alias Pleroma.Web.TwitterAPI.UserView
+ require Pleroma.Constants
+
defp get_user(ap_id, opts) do
cond do
user = opts[:users][ap_id] ->
@@ -18,7 +20,7 @@ defmodule Pleroma.Web.TwitterAPI.NotificationView do
String.ends_with?(ap_id, "/followers") ->
nil
- ap_id == "https://www.w3.org/ns/activitystreams#Public" ->
+ ap_id == Pleroma.Constants.as_public() ->
nil
true ->
diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex
index fa34c7ced..ecb39ee50 100644
--- a/lib/pleroma/web/web_finger/web_finger.ex
+++ b/lib/pleroma/web/web_finger/web_finger.ex
@@ -86,11 +86,17 @@ defmodule Pleroma.Web.WebFinger do
|> XmlBuilder.to_doc()
end
- defp get_magic_key(magic_key) do
- "data:application/magic-public-key," <> magic_key = magic_key
+ defp get_magic_key("data:application/magic-public-key," <> magic_key) do
{:ok, magic_key}
- rescue
- MatchError -> {:error, "Missing magic key data."}
+ end
+
+ defp get_magic_key(nil) do
+ Logger.debug("Undefined magic key.")
+ {:ok, nil}
+ end
+
+ defp get_magic_key(_) do
+ {:error, "Missing magic key data."}
end
defp webfinger_from_xml(doc) do
@@ -187,6 +193,7 @@ defmodule Pleroma.Web.WebFinger do
end
end
+ @spec finger(String.t()) :: {:ok, map()} | {:error, any()}
def finger(account) do
account = String.trim_leading(account, "@")
@@ -220,8 +227,6 @@ defmodule Pleroma.Web.WebFinger do
else
with {:ok, doc} <- Jason.decode(body) do
webfinger_from_json(doc)
- else
- {:error, e} -> e
end
end
else
diff --git a/lib/pleroma/web/web_finger/web_finger_controller.ex b/lib/pleroma/web/web_finger/web_finger_controller.ex
index b77c75ec5..896eb15f9 100644
--- a/lib/pleroma/web/web_finger/web_finger_controller.ex
+++ b/lib/pleroma/web/web_finger/web_finger_controller.ex
@@ -7,6 +7,7 @@ defmodule Pleroma.Web.WebFinger.WebFingerController do
alias Pleroma.Web.WebFinger
+ plug(Pleroma.Plugs.SetFormatPlug)
plug(Pleroma.Web.FederatingPlug)
def host_meta(conn, _params) do
@@ -17,30 +18,28 @@ defmodule Pleroma.Web.WebFinger.WebFingerController do
|> send_resp(200, xml)
end
- def webfinger(conn, %{"resource" => resource}) do
- case get_format(conn) do
- n when n in ["xml", "xrd+xml"] ->
- with {:ok, response} <- WebFinger.webfinger(resource, "XML") do
- conn
- |> put_resp_content_type("application/xrd+xml")
- |> send_resp(200, response)
- else
- _e -> send_resp(conn, 404, "Couldn't find user")
- end
-
- n when n in ["json", "jrd+json"] ->
- with {:ok, response} <- WebFinger.webfinger(resource, "JSON") do
- json(conn, response)
- else
- _e -> send_resp(conn, 404, "Couldn't find user")
- end
-
- _ ->
- send_resp(conn, 404, "Unsupported format")
+ def webfinger(%{assigns: %{format: format}} = conn, %{"resource" => resource})
+ when format in ["xml", "xrd+xml"] do
+ with {:ok, response} <- WebFinger.webfinger(resource, "XML") do
+ conn
+ |> put_resp_content_type("application/xrd+xml")
+ |> send_resp(200, response)
+ else
+ _e -> send_resp(conn, 404, "Couldn't find user")
end
end
- def webfinger(conn, _params) do
- send_resp(conn, 400, "Bad Request")
+ def webfinger(%{assigns: %{format: format}} = conn, %{"resource" => resource})
+ when format in ["json", "jrd+json"] do
+ with {:ok, response} <- WebFinger.webfinger(resource, "JSON") do
+ json(conn, response)
+ else
+ _e ->
+ conn
+ |> put_status(404)
+ |> json("Couldn't find user")
+ end
end
+
+ def webfinger(conn, _params), do: send_resp(conn, 400, "Bad Request")
end