aboutsummaryrefslogtreecommitdiff
path: root/lib/pleroma/web
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pleroma/web')
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub_controller.ex18
-rw-r--r--lib/pleroma/web/activity_pub/internal_fetch_actor.ex20
-rw-r--r--lib/pleroma/web/activity_pub/mrf/mention_policy.ex24
-rw-r--r--lib/pleroma/web/activity_pub/relay.ex3
-rw-r--r--lib/pleroma/web/activity_pub/views/user_view.ex13
-rw-r--r--lib/pleroma/web/mastodon_api/mastodon_api_controller.ex25
-rw-r--r--lib/pleroma/web/rich_media/parser.ex45
-rw-r--r--lib/pleroma/web/rich_media/parsers/ttl/aws_signed_url.ex52
-rw-r--r--lib/pleroma/web/rich_media/parsers/ttl/ttl.ex3
-rw-r--r--lib/pleroma/web/router.ex16
-rw-r--r--lib/pleroma/web/twitter_api/controllers/util_controller.ex32
-rw-r--r--lib/pleroma/web/twitter_api/twitter_api.ex2
-rw-r--r--lib/pleroma/web/twitter_api/twitter_api_controller.ex7
-rw-r--r--lib/pleroma/web/uploader_controller.ex4
-rw-r--r--lib/pleroma/web/web_finger/web_finger.ex2
15 files changed, 238 insertions, 28 deletions
diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
index e2af4ad1a..133a726c5 100644
--- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
@@ -10,6 +10,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
alias Pleroma.Object.Fetcher
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
+ alias Pleroma.Web.ActivityPub.InternalFetchActor
alias Pleroma.Web.ActivityPub.ObjectView
alias Pleroma.Web.ActivityPub.Relay
alias Pleroma.Web.ActivityPub.Transmogrifier
@@ -206,9 +207,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
json(conn, dgettext("errors", "error"))
end
- def relay(conn, _params) do
- with %User{} = user <- Relay.get_actor(),
- {:ok, user} <- User.ensure_keys_present(user) do
+ defp represent_service_actor(%User{} = user, conn) do
+ with {:ok, user} <- User.ensure_keys_present(user) do
conn
|> put_resp_header("content-type", "application/activity+json")
|> json(UserView.render("user.json", %{user: user}))
@@ -217,6 +217,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
end
end
+ defp represent_service_actor(nil, _), do: {:error, :not_found}
+
+ def relay(conn, _params) do
+ Relay.get_actor()
+ |> represent_service_actor(conn)
+ end
+
+ def internal_fetch(conn, _params) do
+ InternalFetchActor.get_actor()
+ |> represent_service_actor(conn)
+ end
+
def whoami(%{assigns: %{user: %User{} = user}} = conn, _params) do
conn
|> put_resp_header("content-type", "application/activity+json")
diff --git a/lib/pleroma/web/activity_pub/internal_fetch_actor.ex b/lib/pleroma/web/activity_pub/internal_fetch_actor.ex
new file mode 100644
index 000000000..9213ddde7
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/internal_fetch_actor.ex
@@ -0,0 +1,20 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.InternalFetchActor do
+ alias Pleroma.User
+
+ require Logger
+
+ def init do
+ # Wait for everything to settle.
+ Process.sleep(1000 * 5)
+ get_actor()
+ end
+
+ def get_actor do
+ "#{Pleroma.Web.Endpoint.url()}/internal/fetch"
+ |> User.get_or_create_service_actor_by_ap_id("internal.fetch")
+ end
+end
diff --git a/lib/pleroma/web/activity_pub/mrf/mention_policy.ex b/lib/pleroma/web/activity_pub/mrf/mention_policy.ex
new file mode 100644
index 000000000..1842e1aeb
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/mrf/mention_policy.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.Web.ActivityPub.MRF.MentionPolicy do
+ @moduledoc "Block messages which mention a user"
+
+ @behaviour Pleroma.Web.ActivityPub.MRF
+
+ @impl true
+ def filter(%{"type" => "Create"} = message) do
+ reject_actors = Pleroma.Config.get([:mrf_mention, :actors], [])
+ recipients = (message["to"] || []) ++ (message["cc"] || [])
+
+ if Enum.any?(recipients, fn recipient -> Enum.member?(reject_actors, recipient) end) do
+ {:reject, nil}
+ else
+ {:ok, message}
+ end
+ end
+
+ @impl true
+ def filter(message), do: {:ok, message}
+end
diff --git a/lib/pleroma/web/activity_pub/relay.ex b/lib/pleroma/web/activity_pub/relay.ex
index 93808517b..1ebfcdd86 100644
--- a/lib/pleroma/web/activity_pub/relay.ex
+++ b/lib/pleroma/web/activity_pub/relay.ex
@@ -10,7 +10,8 @@ defmodule Pleroma.Web.ActivityPub.Relay do
require Logger
def get_actor do
- User.get_or_create_instance_user()
+ "#{Pleroma.Web.Endpoint.url()}/relay"
+ |> User.get_or_create_service_actor_by_ap_id()
end
def follow(target_instance) do
diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex
index d9c1bcb2c..639519e0a 100644
--- a/lib/pleroma/web/activity_pub/views/user_view.ex
+++ b/lib/pleroma/web/activity_pub/views/user_view.ex
@@ -31,8 +31,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
def render("endpoints.json", _), do: %{}
- # the instance itself is not a Person, but instead an Application
- def render("user.json", %{user: %{nickname: nil} = user}) do
+ def render("service.json", %{user: user}) do
{:ok, user} = User.ensure_keys_present(user)
{:ok, _, public_key} = Keys.keys_from_pem(user.info.keys)
public_key = :public_key.pem_entry_encode(:SubjectPublicKeyInfo, public_key)
@@ -47,7 +46,8 @@ defmodule Pleroma.Web.ActivityPub.UserView do
"followers" => "#{user.ap_id}/followers",
"inbox" => "#{user.ap_id}/inbox",
"name" => "Pleroma",
- "summary" => "Virtual actor for Pleroma relay",
+ "summary" =>
+ "An internal service actor for this Pleroma instance. No user-serviceable parts inside.",
"url" => user.ap_id,
"manuallyApprovesFollowers" => false,
"publicKey" => %{
@@ -60,6 +60,13 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|> Map.merge(Utils.make_json_ld_header())
end
+ # the instance itself is not a Person, but instead an Application
+ def render("user.json", %{user: %User{nickname: nil} = user}),
+ do: render("service.json", %{user: user})
+
+ def render("user.json", %{user: %User{nickname: "internal." <> _} = user}),
+ do: render("service.json", %{user: user})
+
def render("user.json", %{user: user}) do
{:ok, user} = User.ensure_keys_present(user)
{:ok, _, public_key} = Keys.keys_from_pem(user.info.keys)
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index f4aa576f7..877430a1d 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -47,6 +47,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
require Logger
+ @rate_limited_relations_actions ~w(follow unfollow)a
+
@rate_limited_status_actions ~w(reblog_status unreblog_status fav_status unfav_status
post_status delete_status)a
@@ -62,9 +64,16 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
when action in ~w(fav_status unfav_status)a
)
+ plug(
+ RateLimiter,
+ {:relations_id_action, params: ["id", "uri"]} when action in @rate_limited_relations_actions
+ )
+
+ plug(RateLimiter, :relations_actions when action in @rate_limited_relations_actions)
plug(RateLimiter, :statuses_actions when action in @rate_limited_status_actions)
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)
@local_mastodon_name "Mastodon-Local"
@@ -1808,6 +1817,22 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
end
+ def password_reset(conn, params) do
+ nickname_or_email = params["email"] || params["nickname"]
+
+ with {:ok, _} <- TwitterAPI.password_reset(nickname_or_email) do
+ conn
+ |> put_status(:no_content)
+ |> json("")
+ else
+ {:error, "unknown user"} ->
+ send_resp(conn, :not_found, "")
+
+ {:error, _} ->
+ send_resp(conn, :bad_request, "")
+ 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/rich_media/parser.ex b/lib/pleroma/web/rich_media/parser.ex
index 0d2523338..b69b2be61 100644
--- a/lib/pleroma/web/rich_media/parser.ex
+++ b/lib/pleroma/web/rich_media/parser.ex
@@ -24,6 +24,7 @@ defmodule Pleroma.Web.RichMedia.Parser do
Cachex.fetch!(:rich_media_cache, url, fn _ ->
{:commit, parse_url(url)}
end)
+ |> set_ttl_based_on_image(url)
rescue
e ->
{:error, "Cachex error: #{inspect(e)}"}
@@ -31,6 +32,50 @@ defmodule Pleroma.Web.RichMedia.Parser do
end
end
+ @doc """
+ Set the rich media cache based on the expiration time of image.
+
+ Adopt behaviour `Pleroma.Web.RichMedia.Parser.TTL`
+
+ ## Example
+
+ defmodule MyModule do
+ @behaviour Pleroma.Web.RichMedia.Parser.TTL
+ def ttl(data, url) do
+ image_url = Map.get(data, :image)
+ # do some parsing in the url and get the ttl of the image
+ # and return ttl is unix time
+ parse_ttl_from_url(image_url)
+ end
+ end
+
+ Define the module in the config
+
+ config :pleroma, :rich_media,
+ ttl_setters: [MyModule]
+ """
+ def set_ttl_based_on_image({:ok, data}, url) do
+ with {:ok, nil} <- Cachex.ttl(:rich_media_cache, url) do
+ ttl = get_ttl_from_image(data, url)
+ Cachex.expire_at(:rich_media_cache, url, ttl * 1000)
+ {:ok, data}
+ else
+ _ ->
+ {:ok, data}
+ end
+ end
+
+ defp get_ttl_from_image(data, url) do
+ Pleroma.Config.get([:rich_media, :ttl_setters])
+ |> Enum.reduce({:ok, nil}, fn
+ module, {:ok, _ttl} ->
+ module.ttl(data, url)
+
+ _, error ->
+ error
+ end)
+ end
+
defp parse_url(url) do
try do
{:ok, %Tesla.Env{body: html}} = Pleroma.HTTP.get(url, [], adapter: @hackney_options)
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
new file mode 100644
index 000000000..014c0935f
--- /dev/null
+++ b/lib/pleroma/web/rich_media/parsers/ttl/aws_signed_url.ex
@@ -0,0 +1,52 @@
+defmodule Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrl do
+ @behaviour Pleroma.Web.RichMedia.Parser.TTL
+
+ @impl Pleroma.Web.RichMedia.Parser.TTL
+ def ttl(data, _url) do
+ image = Map.get(data, :image)
+
+ if is_aws_signed_url(image) do
+ image
+ |> parse_query_params()
+ |> format_query_params()
+ |> get_expiration_timestamp()
+ end
+ end
+
+ defp is_aws_signed_url(""), do: nil
+ defp is_aws_signed_url(nil), do: nil
+
+ defp is_aws_signed_url(image) when is_binary(image) do
+ %URI{host: host, query: query} = URI.parse(image)
+
+ if String.contains?(host, "amazonaws.com") and
+ String.contains?(query, "X-Amz-Expires") do
+ image
+ else
+ nil
+ end
+ end
+
+ defp is_aws_signed_url(_), do: nil
+
+ defp parse_query_params(image) do
+ %URI{query: query} = URI.parse(image)
+ query
+ end
+
+ defp format_query_params(query) do
+ query
+ |> String.split(~r/&|=/)
+ |> Enum.chunk_every(2)
+ |> Map.new(fn [k, v] -> {k, v} end)
+ end
+
+ defp get_expiration_timestamp(params) when is_map(params) do
+ {:ok, date} =
+ params
+ |> Map.get("X-Amz-Date")
+ |> Timex.parse("{ISO:Basic:Z}")
+
+ Timex.to_unix(date) + String.to_integer(Map.get(params, "X-Amz-Expires"))
+ end
+end
diff --git a/lib/pleroma/web/rich_media/parsers/ttl/ttl.ex b/lib/pleroma/web/rich_media/parsers/ttl/ttl.ex
new file mode 100644
index 000000000..6b3ec6d30
--- /dev/null
+++ b/lib/pleroma/web/rich_media/parsers/ttl/ttl.ex
@@ -0,0 +1,3 @@
+defmodule Pleroma.Web.RichMedia.Parser.TTL do
+ @callback ttl(Map.t(), String.t()) :: {:ok, Integer.t()} | {:error, String.t()}
+end
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index f9e5be1e2..73d601ac5 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -586,7 +586,7 @@ defmodule Pleroma.Web.Router do
end
end
- pipeline :ap_relay do
+ pipeline :ap_service_actor do
plug(:accepts, ["activity+json", "json"])
end
@@ -619,6 +619,7 @@ defmodule Pleroma.Web.Router do
pipeline :activitypub do
plug(:accepts, ["activity+json", "json"])
plug(Pleroma.Web.Plugs.HTTPSignaturePlug)
+ plug(Pleroma.Web.Plugs.MappedSignatureToIdentityPlug)
end
scope "/", Pleroma.Web.ActivityPub do
@@ -665,8 +666,17 @@ defmodule Pleroma.Web.Router do
end
scope "/relay", Pleroma.Web.ActivityPub do
- pipe_through(:ap_relay)
+ pipe_through(:ap_service_actor)
+
get("/", ActivityPubController, :relay)
+ post("/inbox", ActivityPubController, :inbox)
+ end
+
+ scope "/internal/fetch", Pleroma.Web.ActivityPub do
+ pipe_through(:ap_service_actor)
+
+ get("/", ActivityPubController, :internal_fetch)
+ post("/inbox", ActivityPubController, :inbox)
end
scope "/", Pleroma.Web.ActivityPub do
@@ -693,6 +703,8 @@ defmodule Pleroma.Web.Router do
get("/web/login", MastodonAPIController, :login)
delete("/auth/sign_out", MastodonAPIController, :logout)
+ post("/auth/password", MastodonAPIController, :password_reset)
+
scope [] do
pipe_through(:oauth_read_or_public)
get("/web/*path", MastodonAPIController, :index)
diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
index c10c66ff2..9e4da7dca 100644
--- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
@@ -8,7 +8,9 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
require Logger
alias Pleroma.Activity
+ alias Pleroma.Config
alias Pleroma.Emoji
+ alias Pleroma.Healthcheck
alias Pleroma.Notification
alias Pleroma.Plugs.AuthenticationPlug
alias Pleroma.User
@@ -23,7 +25,8 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
end
def remote_subscribe(conn, %{"nickname" => nick, "profile" => _}) do
- with %User{} = user <- User.get_cached_by_nickname(nick), avatar = User.avatar_url(user) do
+ with %User{} = user <- User.get_cached_by_nickname(nick),
+ avatar = User.avatar_url(user) do
conn
|> render("subscribe.html", %{nickname: nick, avatar: avatar, error: false})
else
@@ -338,20 +341,21 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
end
def healthcheck(conn, _params) do
- info =
- if Pleroma.Config.get([:instance, :healthcheck]) do
- Pleroma.Healthcheck.system_info()
- else
- %{}
- end
+ with true <- Config.get([:instance, :healthcheck]),
+ %{healthy: true} = info <- Healthcheck.system_info() do
+ json(conn, info)
+ else
+ %{healthy: false} = info ->
+ service_unavailable(conn, info)
- conn =
- if info[:healthy] do
- conn
- else
- Plug.Conn.put_status(conn, :service_unavailable)
- end
+ _ ->
+ service_unavailable(conn, %{})
+ end
+ end
- json(conn, info)
+ defp service_unavailable(conn, info) do
+ conn
+ |> put_status(:service_unavailable)
+ |> json(info)
end
end
diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex
index 41e1c2877..bb5dda204 100644
--- a/lib/pleroma/web/twitter_api/twitter_api.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api.ex
@@ -221,6 +221,8 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
user
|> UserEmail.password_reset_email(token_record.token)
|> Mailer.deliver_async()
+
+ {:ok, :enqueued}
else
false ->
{:error, "bad user identifier"}
diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
index 0313560a8..5dfab6a6c 100644
--- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
@@ -27,6 +27,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
require Logger
+ plug(Pleroma.Plugs.RateLimiter, :password_reset when action == :password_reset)
plug(:only_if_public_instance when action in [:public_timeline, :public_and_external_timeline])
action_fallback(:errors)
@@ -437,6 +438,12 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
with {:ok, _} <- TwitterAPI.password_reset(nickname_or_email) do
json_response(conn, :no_content, "")
+ else
+ {:error, "unknown user"} ->
+ send_resp(conn, :not_found, "")
+
+ {:error, _} ->
+ send_resp(conn, :bad_request, "")
end
end
diff --git a/lib/pleroma/web/uploader_controller.ex b/lib/pleroma/web/uploader_controller.ex
index bf09775e6..0cc172698 100644
--- a/lib/pleroma/web/uploader_controller.ex
+++ b/lib/pleroma/web/uploader_controller.ex
@@ -11,10 +11,6 @@ defmodule Pleroma.Web.UploaderController do
process_callback(conn, :global.whereis_name({Uploader, upload_path}), params)
end
- def callbacks(conn, _) do
- render_error(conn, :bad_request, "bad request")
- end
-
defp process_callback(conn, pid, params) when is_pid(pid) do
send(pid, {Uploader, self(), conn, params})
diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex
index 3fca72de8..fa34c7ced 100644
--- a/lib/pleroma/web/web_finger/web_finger.ex
+++ b/lib/pleroma/web/web_finger/web_finger.ex
@@ -32,7 +32,7 @@ defmodule Pleroma.Web.WebFinger do
def webfinger(resource, fmt) when fmt in ["XML", "JSON"] do
host = Pleroma.Web.Endpoint.host()
- regex = ~r/(acct:)?(?<username>\w+)@#{host}/
+ regex = ~r/(acct:)?(?<username>[a-z0-9A-Z_\.-]+)@#{host}/
with %{"username" => username} <- Regex.named_captures(regex, resource),
%User{} = user <- User.get_cached_by_nickname(username) do