aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/mix/tasks/relay_follow.ex10
-rw-r--r--lib/mix/tasks/relay_unfollow.ex10
-rw-r--r--lib/mix/tasks/set_admin.ex32
-rw-r--r--lib/pleroma/application.ex14
-rw-r--r--lib/pleroma/object.ex8
-rw-r--r--lib/pleroma/plugs/http_security_plug.ex7
-rw-r--r--lib/pleroma/plugs/user_is_admin_plug.ex19
-rw-r--r--lib/pleroma/upload.ex8
-rw-r--r--lib/pleroma/web/activity_pub/mrf/user_allowlist.ex23
-rw-r--r--lib/pleroma/web/activity_pub/relay.ex14
-rw-r--r--lib/pleroma/web/admin_api/admin_api_controller.ex158
-rw-r--r--lib/pleroma/web/channels/user_socket.ex7
-rw-r--r--lib/pleroma/web/endpoint.ex6
-rw-r--r--lib/pleroma/web/federator/federator.ex55
-rw-r--r--lib/pleroma/web/federator/retry_queue.ex71
-rw-r--r--lib/pleroma/web/mastodon_api/mastodon_api_controller.ex2
-rw-r--r--lib/pleroma/web/mastodon_api/mastodon_socket.ex23
-rw-r--r--lib/pleroma/web/media_proxy/media_proxy.ex6
-rw-r--r--lib/pleroma/web/nodeinfo/nodeinfo_controller.ex10
-rw-r--r--lib/pleroma/web/ostatus/ostatus_controller.ex2
-rw-r--r--lib/pleroma/web/router.ex40
-rw-r--r--lib/pleroma/web/streamer.ex44
-rw-r--r--lib/pleroma/web/templates/layout/app.html.eex4
-rw-r--r--lib/pleroma/web/twitter_api/controllers/util_controller.ex2
-rw-r--r--lib/pleroma/web/websub/websub.ex25
25 files changed, 516 insertions, 84 deletions
diff --git a/lib/mix/tasks/relay_follow.ex b/lib/mix/tasks/relay_follow.ex
index 4d57c6bca..85b1c024d 100644
--- a/lib/mix/tasks/relay_follow.ex
+++ b/lib/mix/tasks/relay_follow.ex
@@ -14,9 +14,11 @@ defmodule Mix.Tasks.RelayFollow do
def run([target]) do
Mix.Task.run("app.start")
- :ok = Relay.follow(target)
-
- # put this task to sleep to allow the genserver to push out the messages
- :timer.sleep(500)
+ with {:ok, activity} <- Relay.follow(target) do
+ # put this task to sleep to allow the genserver to push out the messages
+ :timer.sleep(500)
+ else
+ {:error, e} -> Mix.shell().error("Error while following #{target}: #{inspect(e)}")
+ end
end
end
diff --git a/lib/mix/tasks/relay_unfollow.ex b/lib/mix/tasks/relay_unfollow.ex
index bd69fd8a0..237fb771c 100644
--- a/lib/mix/tasks/relay_unfollow.ex
+++ b/lib/mix/tasks/relay_unfollow.ex
@@ -13,9 +13,11 @@ defmodule Mix.Tasks.RelayUnfollow do
def run([target]) do
Mix.Task.run("app.start")
- :ok = Relay.unfollow(target)
-
- # put this task to sleep to allow the genserver to push out the messages
- :timer.sleep(500)
+ with {:ok, activity} <- Relay.follow(target) do
+ # put this task to sleep to allow the genserver to push out the messages
+ :timer.sleep(500)
+ else
+ {:error, e} -> Mix.shell().error("Error while following #{target}: #{inspect(e)}")
+ end
end
end
diff --git a/lib/mix/tasks/set_admin.ex b/lib/mix/tasks/set_admin.ex
new file mode 100644
index 000000000..d5ccf261b
--- /dev/null
+++ b/lib/mix/tasks/set_admin.ex
@@ -0,0 +1,32 @@
+defmodule Mix.Tasks.SetAdmin do
+ use Mix.Task
+ alias Pleroma.User
+
+ @doc """
+ Sets admin status
+ Usage: set_admin nickname [true|false]
+ """
+ def run([nickname | rest]) do
+ Application.ensure_all_started(:pleroma)
+
+ status =
+ case rest do
+ [status] -> status == "true"
+ _ -> true
+ end
+
+ with %User{local: true} = user <- User.get_by_nickname(nickname) do
+ info =
+ user.info
+ |> Map.put("is_admin", !!status)
+
+ cng = User.info_changeset(user, %{info: info})
+ {:ok, user} = User.update_and_set_cache(cng)
+
+ IO.puts("Admin status of #{nickname}: #{user.info["is_admin"]}")
+ else
+ _ ->
+ IO.puts("No local user #{nickname}")
+ end
+ end
+end
diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex
index eedad7675..2d86efae5 100644
--- a/lib/pleroma/application.ex
+++ b/lib/pleroma/application.ex
@@ -1,8 +1,15 @@
defmodule Pleroma.Application do
use Application
+ @name "Pleroma"
+ @version Mix.Project.config()[:version]
+ def name, do: @name
+ def version, do: @version
+ def named_version(), do: @name <> " " <> @version
+
# See http://elixir-lang.org/docs/stable/elixir/Application.html
# for more information on OTP Applications
+ @env Mix.env()
def start(_type, _args) do
import Supervisor.Spec
import Cachex.Spec
@@ -57,10 +64,11 @@ defmodule Pleroma.Application do
id: :cachex_idem
),
worker(Pleroma.Web.Federator, []),
- worker(Pleroma.Stats, []),
- worker(Pleroma.Gopher.Server, [])
+ worker(Pleroma.Web.Federator.RetryQueue, []),
+ worker(Pleroma.Gopher.Server, []),
+ worker(Pleroma.Stats, [])
] ++
- if Mix.env() == :test,
+ if @env == :test,
do: [],
else:
[worker(Pleroma.Web.Streamer, [])] ++
diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex
index 067ecfaf4..03a75dfbd 100644
--- a/lib/pleroma/object.ex
+++ b/lib/pleroma/object.ex
@@ -31,10 +31,12 @@ defmodule Pleroma.Object do
def normalize(ap_id) when is_binary(ap_id), do: Object.get_by_ap_id(ap_id)
def normalize(_), do: nil
- def get_cached_by_ap_id(ap_id) do
- if Mix.env() == :test do
+ if Mix.env() == :test do
+ def get_cached_by_ap_id(ap_id) do
get_by_ap_id(ap_id)
- else
+ end
+ else
+ def get_cached_by_ap_id(ap_id) do
key = "object:#{ap_id}"
Cachex.fetch!(:object_cache, key, fn _ ->
diff --git a/lib/pleroma/plugs/http_security_plug.ex b/lib/pleroma/plugs/http_security_plug.ex
index 31c7332f8..4c32653ea 100644
--- a/lib/pleroma/plugs/http_security_plug.ex
+++ b/lib/pleroma/plugs/http_security_plug.ex
@@ -29,6 +29,8 @@ defmodule Pleroma.Plugs.HTTPSecurityPlug do
end
defp csp_string do
+ protocol = Config.get([Pleroma.Web.Endpoint, :protocol])
+
[
"default-src 'none'",
"base-uri 'self'",
@@ -39,7 +41,10 @@ defmodule Pleroma.Plugs.HTTPSecurityPlug do
"font-src 'self'",
"script-src 'self'",
"connect-src 'self' " <> String.replace(Pleroma.Web.Endpoint.static_url(), "http", "ws"),
- "upgrade-insecure-requests"
+ "manifest-src 'self'",
+ if @protocol == "https" do
+ "upgrade-insecure-requests"
+ end
]
|> Enum.join("; ")
end
diff --git a/lib/pleroma/plugs/user_is_admin_plug.ex b/lib/pleroma/plugs/user_is_admin_plug.ex
new file mode 100644
index 000000000..5312f1499
--- /dev/null
+++ b/lib/pleroma/plugs/user_is_admin_plug.ex
@@ -0,0 +1,19 @@
+defmodule Pleroma.Plugs.UserIsAdminPlug do
+ import Plug.Conn
+ alias Pleroma.User
+
+ def init(options) do
+ options
+ end
+
+ def call(%{assigns: %{user: %User{info: %{"is_admin" => true}}}} = conn, _) do
+ conn
+ end
+
+ def call(conn, _) do
+ conn
+ |> put_resp_content_type("application/json")
+ |> send_resp(403, Jason.encode!(%{error: "User is not admin."}))
+ |> halt
+ end
+end
diff --git a/lib/pleroma/upload.ex b/lib/pleroma/upload.ex
index 89aa779f9..238630bf3 100644
--- a/lib/pleroma/upload.ex
+++ b/lib/pleroma/upload.ex
@@ -162,7 +162,13 @@ defmodule Pleroma.Upload do
"audio/mpeg"
<<0x4F, 0x67, 0x67, 0x53, 0x00, 0x02, 0x00, 0x00>> ->
- "audio/ogg"
+ case IO.binread(f, 27) do
+ <<_::size(160), 0x80, 0x74, 0x68, 0x65, 0x6F, 0x72, 0x61>> ->
+ "video/ogg"
+
+ _ ->
+ "audio/ogg"
+ end
<<0x52, 0x49, 0x46, 0x46, _, _, _, _>> ->
"audio/wav"
diff --git a/lib/pleroma/web/activity_pub/mrf/user_allowlist.ex b/lib/pleroma/web/activity_pub/mrf/user_allowlist.ex
new file mode 100644
index 000000000..3503d8692
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/mrf/user_allowlist.ex
@@ -0,0 +1,23 @@
+defmodule Pleroma.Web.ActivityPub.MRF.UserAllowListPolicy do
+ alias Pleroma.Config
+
+ @behaviour Pleroma.Web.ActivityPub.MRF
+
+ defp filter_by_list(object, []), do: {:ok, object}
+
+ defp filter_by_list(%{"actor" => actor} = object, allow_list) do
+ if actor in allow_list do
+ {:ok, object}
+ else
+ {:reject, nil}
+ end
+ end
+
+ @impl true
+ def filter(object) do
+ actor_info = URI.parse(object["actor"])
+ allow_list = Config.get([:mrf_user_allowlist, String.to_atom(actor_info.host)], [])
+
+ filter_by_list(object, allow_list)
+ end
+end
diff --git a/lib/pleroma/web/activity_pub/relay.ex b/lib/pleroma/web/activity_pub/relay.ex
index d30853d62..fcdc6b1c0 100644
--- a/lib/pleroma/web/activity_pub/relay.ex
+++ b/lib/pleroma/web/activity_pub/relay.ex
@@ -12,11 +12,12 @@ defmodule Pleroma.Web.ActivityPub.Relay do
%User{} = target_user <- User.get_or_fetch_by_ap_id(target_instance),
{:ok, activity} <- ActivityPub.follow(local_user, target_user) do
Logger.info("relay: followed instance: #{target_instance}; id=#{activity.data["id"]}")
+ {:ok, activity}
else
- e -> Logger.error("error: #{inspect(e)}")
+ e ->
+ Logger.error("error: #{inspect(e)}")
+ {:error, e}
end
-
- :ok
end
def unfollow(target_instance) do
@@ -24,11 +25,12 @@ defmodule Pleroma.Web.ActivityPub.Relay do
%User{} = target_user <- User.get_or_fetch_by_ap_id(target_instance),
{:ok, activity} <- ActivityPub.unfollow(local_user, target_user) do
Logger.info("relay: unfollowed instance: #{target_instance}: id=#{activity.data["id"]}")
+ {:ok, activity}
else
- e -> Logger.error("error: #{inspect(e)}")
+ e ->
+ Logger.error("error: #{inspect(e)}")
+ {:error, e}
end
-
- :ok
end
def publish(%Activity{data: %{"type" => "Create"}} = activity) do
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
new file mode 100644
index 000000000..bcdb4ba37
--- /dev/null
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -0,0 +1,158 @@
+defmodule Pleroma.Web.AdminAPI.AdminAPIController do
+ use Pleroma.Web, :controller
+ alias Pleroma.{User, Repo}
+ alias Pleroma.Web.ActivityPub.Relay
+
+ require Logger
+
+ action_fallback(:errors)
+
+ def user_delete(conn, %{"nickname" => nickname}) do
+ user = User.get_by_nickname(nickname)
+
+ if user.local == true do
+ User.delete(user)
+ else
+ User.delete(user)
+ end
+
+ conn
+ |> json(nickname)
+ end
+
+ def user_create(
+ conn,
+ %{"nickname" => nickname, "email" => email, "password" => password}
+ ) do
+ new_user = %{
+ nickname: nickname,
+ name: nickname,
+ email: email,
+ password: password,
+ password_confirmation: password,
+ bio: "."
+ }
+
+ User.register_changeset(%User{}, new_user)
+ |> Repo.insert!()
+
+ conn
+ |> json(new_user.nickname)
+ end
+
+ def right_add(conn, %{"permission_group" => permission_group, "nickname" => nickname})
+ when permission_group in ["moderator", "admin"] do
+ user = User.get_by_nickname(nickname)
+
+ info =
+ user.info
+ |> Map.put("is_" <> permission_group, true)
+
+ cng = User.info_changeset(user, %{info: info})
+ {:ok, user} = User.update_and_set_cache(cng)
+
+ conn
+ |> json(user.info)
+ end
+
+ def right_get(conn, %{"nickname" => nickname}) do
+ user = User.get_by_nickname(nickname)
+
+ conn
+ |> json(user.info)
+ end
+
+ def right_add(conn, _) do
+ conn
+ |> put_status(404)
+ |> json(%{error: "No such permission_group"})
+ end
+
+ def right_delete(
+ %{assigns: %{user: %User{:nickname => admin_nickname}}} = conn,
+ %{
+ "permission_group" => permission_group,
+ "nickname" => nickname
+ }
+ )
+ when permission_group in ["moderator", "admin"] do
+ if admin_nickname == nickname do
+ conn
+ |> put_status(403)
+ |> json(%{error: "You can't revoke your own admin status."})
+ else
+ user = User.get_by_nickname(nickname)
+
+ info =
+ user.info
+ |> Map.put("is_" <> permission_group, false)
+
+ cng = User.info_changeset(user, %{info: info})
+ {:ok, user} = User.update_and_set_cache(cng)
+
+ conn
+ |> json(user.info)
+ end
+ end
+
+ def right_delete(conn, _) do
+ conn
+ |> put_status(404)
+ |> json(%{error: "No such permission_group"})
+ end
+
+ def relay_follow(conn, %{"relay_url" => target}) do
+ {status, message} = Relay.follow(target)
+
+ if status == :ok do
+ conn
+ |> json(target)
+ else
+ conn
+ |> put_status(500)
+ |> json(target)
+ end
+ end
+
+ def relay_unfollow(conn, %{"relay_url" => target}) do
+ {status, message} = Relay.unfollow(target)
+
+ if status == :ok do
+ conn
+ |> json(target)
+ else
+ conn
+ |> put_status(500)
+ |> json(target)
+ end
+ end
+
+ @shortdoc "Get a account registeration invite token (base64 string)"
+ def get_invite_token(conn, _params) do
+ {:ok, token} = Pleroma.UserInviteToken.create_token()
+
+ conn
+ |> json(token.token)
+ end
+
+ @shortdoc "Get a password reset token (base64 string) for given nickname"
+ def get_password_reset(conn, %{"nickname" => nickname}) do
+ (%User{local: true} = user) = User.get_by_nickname(nickname)
+ {:ok, token} = Pleroma.PasswordResetToken.create_token(user)
+
+ conn
+ |> json(token.token)
+ end
+
+ def errors(conn, {:param_cast, _}) do
+ conn
+ |> put_status(400)
+ |> json("Invalid parameters")
+ end
+
+ def errors(conn, _) do
+ conn
+ |> put_status(500)
+ |> json("Something went wrong")
+ end
+end
diff --git a/lib/pleroma/web/channels/user_socket.ex b/lib/pleroma/web/channels/user_socket.ex
index 21b22b409..07ddee169 100644
--- a/lib/pleroma/web/channels/user_socket.ex
+++ b/lib/pleroma/web/channels/user_socket.ex
@@ -4,9 +4,7 @@ defmodule Pleroma.Web.UserSocket do
## Channels
# channel "room:*", Pleroma.Web.RoomChannel
- if Application.get_env(:pleroma, :chat) |> Keyword.get(:enabled) do
- channel("chat:*", Pleroma.Web.ChatChannel)
- end
+ channel("chat:*", Pleroma.Web.ChatChannel)
## Transports
transport(:websocket, Phoenix.Transports.WebSocket)
@@ -24,7 +22,8 @@ defmodule Pleroma.Web.UserSocket do
# See `Phoenix.Token` documentation for examples in
# performing token verification on connect.
def connect(%{"token" => token}, socket) do
- with {:ok, user_id} <- Phoenix.Token.verify(socket, "user socket", token, max_age: 84600),
+ with true <- Pleroma.Config.get([:chat, :enabled]),
+ {:ok, user_id} <- Phoenix.Token.verify(socket, "user socket", token, max_age: 84600),
%User{} = user <- Pleroma.Repo.get(User, user_id) do
{:ok, assign(socket, :user_name, user.nickname)}
else
diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex
index 85bb4ff5f..8728c908b 100644
--- a/lib/pleroma/web/endpoint.ex
+++ b/lib/pleroma/web/endpoint.ex
@@ -1,9 +1,7 @@
defmodule Pleroma.Web.Endpoint do
use Phoenix.Endpoint, otp_app: :pleroma
- if Application.get_env(:pleroma, :chat) |> Keyword.get(:enabled) do
- socket("/socket", Pleroma.Web.UserSocket)
- end
+ socket("/socket", Pleroma.Web.UserSocket)
socket("/api/v1", Pleroma.Web.MastodonAPI.MastodonSocket)
@@ -58,7 +56,7 @@ defmodule Pleroma.Web.Endpoint do
Plug.Session,
store: :cookie,
key: cookie_name,
- signing_salt: "CqaoopA2",
+ signing_salt: {Pleroma.Config, :get, [[__MODULE__, :signing_salt], "CqaoopA2"]},
http_only: true,
secure:
Application.get_env(:pleroma, Pleroma.Web.Endpoint) |> Keyword.get(:secure_cookie_flag),
diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex
index 6554fd2ef..ac3d7c132 100644
--- a/lib/pleroma/web/federator/federator.ex
+++ b/lib/pleroma/web/federator/federator.ex
@@ -3,6 +3,7 @@ defmodule Pleroma.Web.Federator do
alias Pleroma.User
alias Pleroma.Activity
alias Pleroma.Web.{WebFinger, Websub}
+ alias Pleroma.Web.Federator.RetryQueue
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Relay
alias Pleroma.Web.ActivityPub.Transmogrifier
@@ -122,29 +123,25 @@ defmodule Pleroma.Web.Federator do
end
def handle(:publish_single_ap, params) do
- ActivityPub.publish_one(params)
- end
-
- def handle(:publish_single_websub, %{xml: xml, topic: topic, callback: callback, secret: secret}) do
- signature = @websub.sign(secret || "", xml)
- Logger.debug(fn -> "Pushing #{topic} to #{callback}" end)
-
- with {:ok, %{status_code: code}} <-
- @httpoison.post(
- callback,
- xml,
- [
- {"Content-Type", "application/atom+xml"},
- {"X-Hub-Signature", "sha1=#{signature}"}
- ],
- timeout: 10000,
- recv_timeout: 20000,
- hackney: [pool: :default]
- ) do
- Logger.debug(fn -> "Pushed to #{callback}, code #{code}" end)
- else
- e ->
- Logger.debug(fn -> "Couldn't push to #{callback}, #{inspect(e)}" end)
+ case ActivityPub.publish_one(params) do
+ {:ok, _} ->
+ :ok
+
+ {:error, _} ->
+ RetryQueue.enqueue(params, ActivityPub)
+ end
+ end
+
+ def handle(
+ :publish_single_websub,
+ %{xml: xml, topic: topic, callback: callback, secret: secret} = params
+ ) do
+ case Websub.publish_one(params) do
+ {:ok, _} ->
+ :ok
+
+ {:error, _} ->
+ RetryQueue.enqueue(params, Websub)
end
end
@@ -153,11 +150,15 @@ defmodule Pleroma.Web.Federator do
{:error, "Don't know what to do with this"}
end
- def enqueue(type, payload, priority \\ 1) do
- if Pleroma.Config.get([:instance, :federating]) do
- if Mix.env() == :test do
+ if Mix.env() == :test do
+ def enqueue(type, payload, priority \\ 1) do
+ if Pleroma.Config.get([:instance, :federating]) do
handle(type, payload)
- else
+ end
+ end
+ else
+ def enqueue(type, payload, priority \\ 1) do
+ if Pleroma.Config.get([:instance, :federating]) do
GenServer.cast(__MODULE__, {:enqueue, type, payload, priority})
end
end
diff --git a/lib/pleroma/web/federator/retry_queue.ex b/lib/pleroma/web/federator/retry_queue.ex
new file mode 100644
index 000000000..06c094f26
--- /dev/null
+++ b/lib/pleroma/web/federator/retry_queue.ex
@@ -0,0 +1,71 @@
+defmodule Pleroma.Web.Federator.RetryQueue do
+ use GenServer
+ alias Pleroma.Web.{WebFinger, Websub}
+ alias Pleroma.Web.ActivityPub.ActivityPub
+ require Logger
+
+ @websub Application.get_env(:pleroma, :websub)
+ @ostatus Application.get_env(:pleroma, :websub)
+ @httpoison Application.get_env(:pleroma, :websub)
+ @instance Application.get_env(:pleroma, :websub)
+ # initial timeout, 5 min
+ @initial_timeout 30_000
+ @max_retries 5
+
+ def init(args) do
+ {:ok, args}
+ end
+
+ def start_link() do
+ GenServer.start_link(__MODULE__, %{delivered: 0, dropped: 0}, name: __MODULE__)
+ end
+
+ def enqueue(data, transport, retries \\ 0) do
+ GenServer.cast(__MODULE__, {:maybe_enqueue, data, transport, retries + 1})
+ end
+
+ def get_retry_params(retries) do
+ if retries > @max_retries do
+ {:drop, "Max retries reached"}
+ else
+ {:retry, growth_function(retries)}
+ end
+ end
+
+ def handle_cast({:maybe_enqueue, data, transport, retries}, %{dropped: drop_count} = state) do
+ case get_retry_params(retries) do
+ {:retry, timeout} ->
+ Process.send_after(
+ __MODULE__,
+ {:send, data, transport, retries},
+ growth_function(retries)
+ )
+
+ {:noreply, state}
+
+ {:drop, message} ->
+ Logger.debug(message)
+ {:noreply, %{state | dropped: drop_count + 1}}
+ end
+ end
+
+ def handle_info({:send, data, transport, retries}, %{delivered: delivery_count} = state) do
+ case transport.publish_one(data) do
+ {:ok, _} ->
+ {:noreply, %{state | delivered: delivery_count + 1}}
+
+ {:error, reason} ->
+ enqueue(data, transport, retries)
+ {:noreply, state}
+ end
+ end
+
+ def handle_info(unknown, state) do
+ Logger.debug("RetryQueue: don't know what to do with #{inspect(unknown)}, ignoring")
+ {:noreply, state}
+ end
+
+ defp growth_function(retries) do
+ round(@initial_timeout * :math.pow(retries, 3))
+ 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 bfd0f7ff4..3a49a96a1 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -141,7 +141,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
uri: Web.base_url(),
title: Keyword.get(instance, :name),
description: Keyword.get(instance, :description),
- version: "#{@mastodon_api_level} (compatible; #{Keyword.get(instance, :version)})",
+ version: "#{@mastodon_api_level} (compatible; #{Pleroma.Application.named_version()})",
email: Keyword.get(instance, :email),
urls: %{
streaming_api: String.replace(Pleroma.Web.Endpoint.static_url(), "http", "ws")
diff --git a/lib/pleroma/web/mastodon_api/mastodon_socket.ex b/lib/pleroma/web/mastodon_api/mastodon_socket.ex
index 0f3d5ff7c..f3c13d1aa 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_socket.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_socket.ex
@@ -11,9 +11,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonSocket do
timeout: :infinity
)
- def connect(params, socket) do
- with token when not is_nil(token) <- params["access_token"],
- %Token{user_id: user_id} <- Repo.get_by(Token, token: token),
+ def connect(%{"access_token" => token} = params, socket) do
+ with %Token{user_id: user_id} <- Repo.get_by(Token, token: token),
%User{} = user <- Repo.get(User, user_id),
stream
when stream in [
@@ -45,6 +44,24 @@ defmodule Pleroma.Web.MastodonAPI.MastodonSocket do
end
end
+ def connect(%{"stream" => stream} = params, socket)
+ when stream in ["public", "public:local", "hashtag"] do
+ topic =
+ case stream do
+ "hashtag" -> "hashtag:#{params["tag"]}"
+ _ -> stream
+ end
+
+ with socket =
+ socket
+ |> assign(:topic, topic) do
+ Pleroma.Web.Streamer.add_socket(topic, socket)
+ {:ok, socket}
+ else
+ _e -> :error
+ end
+ end
+
def id(_), do: nil
def handle(:text, message, _state) do
diff --git a/lib/pleroma/web/media_proxy/media_proxy.ex b/lib/pleroma/web/media_proxy/media_proxy.ex
index 93c36b4ed..0fc0a07b2 100644
--- a/lib/pleroma/web/media_proxy/media_proxy.ex
+++ b/lib/pleroma/web/media_proxy/media_proxy.ex
@@ -3,6 +3,8 @@ defmodule Pleroma.Web.MediaProxy do
def url(nil), do: nil
+ def url(""), do: nil
+
def url(url = "/" <> _), do: url
def url(url) do
@@ -15,10 +17,10 @@ defmodule Pleroma.Web.MediaProxy do
base64 = Base.url_encode64(url, @base64_opts)
sig = :crypto.hmac(:sha, secret, base64)
sig64 = sig |> Base.url_encode64(@base64_opts)
- filename = Path.basename(URI.parse(url).path)
+ filename = if path = URI.parse(url).path, do: "/" <> Path.basename(path), else: ""
Keyword.get(config, :base_url, Pleroma.Web.base_url()) <>
- "/proxy/#{sig64}/#{base64}/#{filename}"
+ "/proxy/#{sig64}/#{base64}#{filename}"
end
end
diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
index d58f08881..2ea75cf16 100644
--- a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
+++ b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
@@ -4,6 +4,7 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
alias Pleroma.Stats
alias Pleroma.Web
alias Pleroma.{User, Repo}
+ alias Pleroma.Config
alias Pleroma.Web.ActivityPub.MRF
plug(Pleroma.Web.FederatingPlug)
@@ -52,6 +53,10 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
|> Repo.all()
|> Enum.map(fn u -> u.ap_id end)
+ mrf_user_allowlist =
+ Config.get([:mrf_user_allowlist], [])
+ |> Enum.into(%{}, fn {k, v} -> {k, length(v)} end)
+
mrf_transparency = Keyword.get(instance, :mrf_transparency)
federation_response =
@@ -59,6 +64,7 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
%{
mrf_policies: mrf_policies,
mrf_simple: mrf_simple,
+ mrf_user_allowlist: mrf_user_allowlist,
quarantined_instances: quarantined
}
else
@@ -86,8 +92,8 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
response = %{
version: "2.0",
software: %{
- name: "pleroma",
- version: Keyword.get(instance, :version)
+ name: Pleroma.Application.name(),
+ version: Pleroma.Application.version()
},
protocols: ["ostatus", "activitypub"],
services: %{
diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex
index 34fdf9727..af6e22c2b 100644
--- a/lib/pleroma/web/ostatus/ostatus_controller.ex
+++ b/lib/pleroma/web/ostatus/ostatus_controller.ex
@@ -136,7 +136,7 @@ defmodule Pleroma.Web.OStatus.OStatusController do
"html" ->
conn
|> put_resp_content_type("text/html")
- |> send_file(200, "priv/static/index.html")
+ |> send_file(200, Application.app_dir(:pleroma, "priv/static/index.html"))
_ ->
represent_activity(conn, format, activity, user)
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index a8468ea12..d6a9d5779 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -31,6 +31,21 @@ defmodule Pleroma.Web.Router do
plug(Pleroma.Plugs.EnsureAuthenticatedPlug)
end
+ pipeline :admin_api do
+ plug(:accepts, ["json"])
+ plug(:fetch_session)
+ plug(Pleroma.Plugs.OAuthPlug)
+ plug(Pleroma.Plugs.BasicAuthDecoderPlug)
+ plug(Pleroma.Plugs.UserFetcherPlug)
+ plug(Pleroma.Plugs.SessionAuthenticationPlug)
+ plug(Pleroma.Plugs.LegacyAuthenticationPlug)
+ plug(Pleroma.Plugs.AuthenticationPlug)
+ plug(Pleroma.Plugs.UserEnabledPlug)
+ plug(Pleroma.Plugs.SetUserSessionIdPlug)
+ plug(Pleroma.Plugs.EnsureAuthenticatedPlug)
+ plug(Pleroma.Plugs.UserIsAdminPlug)
+ end
+
pipeline :mastodon_html do
plug(:accepts, ["html"])
plug(:fetch_session)
@@ -79,6 +94,23 @@ defmodule Pleroma.Web.Router do
get("/emoji", UtilController, :emoji)
end
+ scope "/api/pleroma/admin", Pleroma.Web.AdminAPI do
+ pipe_through(:admin_api)
+ delete("/user", AdminAPIController, :user_delete)
+ post("/user", AdminAPIController, :user_create)
+
+ get("/permission_group/:nickname", AdminAPIController, :right_get)
+ get("/permission_group/:nickname/:permission_group", AdminAPIController, :right_get)
+ post("/permission_group/:nickname/:permission_group", AdminAPIController, :right_add)
+ delete("/permission_group/:nickname/:permission_group", AdminAPIController, :right_delete)
+
+ post("/relay", AdminAPIController, :relay_follow)
+ delete("/relay", AdminAPIController, :relay_unfollow)
+
+ get("/invite_token", AdminAPIController, :get_invite_token)
+ get("/password_reset", AdminAPIController, :get_password_reset)
+ end
+
scope "/", Pleroma.Web.TwitterAPI do
pipe_through(:pleroma_html)
get("/ostatus_subscribe", UtilController, :remote_follow)
@@ -398,11 +430,9 @@ defmodule Fallback.RedirectController do
use Pleroma.Web, :controller
def redirector(conn, _params) do
- if Mix.env() != :test do
- conn
- |> put_resp_content_type("text/html")
- |> send_file(200, "priv/static/index.html")
- end
+ conn
+ |> put_resp_content_type("text/html")
+ |> send_file(200, Application.app_dir(:pleroma, "priv/static/index.html"))
end
def registration_page(conn, params) do
diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex
index 209450383..99b8b7063 100644
--- a/lib/pleroma/web/streamer.ex
+++ b/lib/pleroma/web/streamer.ex
@@ -73,7 +73,8 @@ defmodule Pleroma.Web.Streamer do
Pleroma.List.get_lists_from_activity(item)
|> Enum.filter(fn list ->
owner = Repo.get(User, list.user_id)
- author.follower_address in owner.following
+
+ ActivityPub.visible_for_user?(item, owner)
end)
end
@@ -169,16 +170,33 @@ defmodule Pleroma.Web.Streamer do
|> Jason.encode!()
end
+ defp represent_update(%Activity{} = activity) do
+ %{
+ event: "update",
+ payload:
+ Pleroma.Web.MastodonAPI.StatusView.render(
+ "status.json",
+ activity: activity
+ )
+ |> Jason.encode!()
+ }
+ |> Jason.encode!()
+ end
+
def push_to_socket(topics, topic, %Activity{data: %{"type" => "Announce"}} = item) do
Enum.each(topics[topic] || [], fn socket ->
# Get the current user so we have up-to-date blocks etc.
- user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id)
- blocks = user.info.blocks || []
+ if socket.assigns[:user] do
+ user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id)
+ blocks = user.info.blocks || []
- parent = Object.normalize(item.data["object"])
+ parent = Object.normalize(item.data["object"])
- unless is_nil(parent) or item.actor in blocks or parent.data["actor"] in blocks do
- send(socket.transport_pid, {:text, represent_update(item, user)})
+ unless is_nil(parent) or item.actor in blocks or parent.data["actor"] in blocks do
+ send(socket.transport_pid, {:text, represent_update(item, user)})
+ end
+ else
+ send(socket.transport_pid, {:text, represent_update(item)})
end
end)
end
@@ -186,11 +204,15 @@ defmodule Pleroma.Web.Streamer do
def push_to_socket(topics, topic, item) do
Enum.each(topics[topic] || [], fn socket ->
# Get the current user so we have up-to-date blocks etc.
- user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id)
- blocks = user.info.blocks || []
-
- unless item.actor in blocks do
- send(socket.transport_pid, {:text, represent_update(item, user)})
+ if socket.assigns[:user] do
+ user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id)
+ blocks = user.info.blocks || []
+
+ unless item.actor in blocks do
+ send(socket.transport_pid, {:text, represent_update(item, user)})
+ end
+ else
+ send(socket.transport_pid, {:text, represent_update(item)})
end
end)
end
diff --git a/lib/pleroma/web/templates/layout/app.html.eex b/lib/pleroma/web/templates/layout/app.html.eex
index 2a8dede80..2e96c1509 100644
--- a/lib/pleroma/web/templates/layout/app.html.eex
+++ b/lib/pleroma/web/templates/layout/app.html.eex
@@ -2,7 +2,9 @@
<html>
<head>
<meta charset=utf-8 />
- <title>Pleroma</title>
+ <title>
+ <%= Application.get_env(:pleroma, :instance)[:name] %>
+ </title>
<style>
body {
background-color: #282c37;
diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
index dc4a864d6..b0ed8387e 100644
--- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
@@ -197,7 +197,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
end
def version(conn, _params) do
- version = Pleroma.Config.get([:instance, :version])
+ version = Pleroma.Application.named_version()
case get_format(conn) do
"xml" ->
diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex
index 440b48665..905d8d658 100644
--- a/lib/pleroma/web/websub/websub.ex
+++ b/lib/pleroma/web/websub/websub.ex
@@ -252,4 +252,29 @@ defmodule Pleroma.Web.Websub do
Pleroma.Web.Federator.enqueue(:request_subscription, sub)
end)
end
+
+ def publish_one(%{xml: xml, topic: topic, callback: callback, secret: secret}) do
+ signature = sign(secret || "", xml)
+ Logger.info(fn -> "Pushing #{topic} to #{callback}" end)
+
+ with {:ok, %{status_code: code}} <-
+ @httpoison.post(
+ callback,
+ xml,
+ [
+ {"Content-Type", "application/atom+xml"},
+ {"X-Hub-Signature", "sha1=#{signature}"}
+ ],
+ timeout: 10000,
+ recv_timeout: 20000,
+ hackney: [pool: :default]
+ ) do
+ Logger.info(fn -> "Pushed to #{callback}, code #{code}" end)
+ {:ok, code}
+ else
+ e ->
+ Logger.debug(fn -> "Couldn't push to #{callback}, #{inspect(e)}" end)
+ {:error, e}
+ end
+ end
end