Page MenuHomePhorge

No OneTemporary

Size
72 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex
index 01824aa18..ce7ba9b80 100644
--- a/lib/mix/tasks/pleroma/user.ex
+++ b/lib/mix/tasks/pleroma/user.ex
@@ -1,413 +1,413 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.Tasks.Pleroma.User do
use Mix.Task
import Mix.Pleroma
alias Ecto.Changeset
alias Pleroma.User
alias Pleroma.UserInviteToken
alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.Pipeline
@shortdoc "Manages Pleroma users"
@moduledoc File.read!("docs/administration/CLI_tasks/user.md")
def run(["new", nickname, email | rest]) do
{options, [], []} =
OptionParser.parse(
rest,
strict: [
name: :string,
bio: :string,
password: :string,
moderator: :boolean,
admin: :boolean,
assume_yes: :boolean
],
aliases: [
y: :assume_yes
]
)
name = Keyword.get(options, :name, nickname)
bio = Keyword.get(options, :bio, "")
{password, generated_password?} =
case Keyword.get(options, :password) do
nil ->
{:crypto.strong_rand_bytes(16) |> Base.encode64(), true}
password ->
{password, false}
end
moderator? = Keyword.get(options, :moderator, false)
admin? = Keyword.get(options, :admin, false)
assume_yes? = Keyword.get(options, :assume_yes, false)
shell_info("""
A user will be created with the following information:
- nickname: #{nickname}
- email: #{email}
- password: #{
if(generated_password?, do: "[generated; a reset link will be created]", else: password)
}
- name: #{name}
- bio: #{bio}
- moderator: #{if(moderator?, do: "true", else: "false")}
- admin: #{if(admin?, do: "true", else: "false")}
""")
proceed? = assume_yes? or shell_yes?("Continue?")
if proceed? do
start_pleroma()
params = %{
nickname: nickname,
email: email,
password: password,
password_confirmation: password,
name: name,
bio: bio
}
changeset = User.register_changeset(%User{}, params, need_confirmation: false)
{:ok, _user} = User.register(changeset)
shell_info("User #{nickname} created")
if moderator? do
run(["set", nickname, "--moderator"])
end
if admin? do
run(["set", nickname, "--admin"])
end
if generated_password? do
run(["reset_password", nickname])
end
else
shell_info("User will not be created.")
end
end
def run(["rm", nickname]) do
start_pleroma()
with %User{local: true} = user <- User.get_cached_by_nickname(nickname),
{:ok, delete_data, _} <- Builder.delete(user, user.ap_id),
{:ok, _delete, _} <- Pipeline.common_pipeline(delete_data, local: true) do
shell_info("User #{nickname} deleted.")
else
_ -> shell_error("No local user #{nickname}")
end
end
def run(["toggle_activated", nickname]) do
start_pleroma()
with %User{} = user <- User.get_cached_by_nickname(nickname) do
{:ok, user} = User.deactivate(user, !user.deactivated)
shell_info(
"Activation status of #{nickname}: #{if(user.deactivated, do: "de", else: "")}activated"
)
else
_ ->
shell_error("No user #{nickname}")
end
end
def run(["reset_password", nickname]) do
start_pleroma()
with %User{local: true} = user <- User.get_cached_by_nickname(nickname),
{:ok, token} <- Pleroma.PasswordResetToken.create_token(user) do
shell_info("Generated password reset token for #{user.nickname}")
IO.puts(
"URL: #{
Pleroma.Web.Router.Helpers.reset_password_url(
Pleroma.Web.Endpoint,
:reset,
token.token
)
}"
)
else
_ ->
shell_error("No local user #{nickname}")
end
end
def run(["reset_mfa", nickname]) do
start_pleroma()
with %User{local: true} = user <- User.get_cached_by_nickname(nickname),
{:ok, _token} <- Pleroma.MFA.disable(user) do
shell_info("Multi-Factor Authentication disabled for #{user.nickname}")
else
_ ->
shell_error("No local user #{nickname}")
end
end
def run(["deactivate", nickname]) do
start_pleroma()
with %User{} = user <- User.get_cached_by_nickname(nickname) do
shell_info("Deactivating #{user.nickname}")
User.deactivate(user)
:timer.sleep(500)
user = User.get_cached_by_id(user.id)
if Enum.empty?(Enum.filter(User.get_friends(user), & &1.local)) do
shell_info("Successfully unsubscribed all local followers from #{user.nickname}")
end
else
_ ->
shell_error("No user #{nickname}")
end
end
def run(["deactivate_all_from_instance", instance]) do
start_pleroma()
Pleroma.User.Query.build(%{nickname: "@#{instance}"})
|> Pleroma.RepoStreamer.chunk_stream(500)
|> Stream.each(fn users ->
users
|> Enum.each(fn user ->
run(["deactivate", user.nickname])
end)
end)
|> Stream.run()
end
def run(["set", nickname | rest]) do
start_pleroma()
{options, [], []} =
OptionParser.parse(
rest,
strict: [
moderator: :boolean,
admin: :boolean,
locked: :boolean
]
)
with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do
user =
case Keyword.get(options, :moderator) do
nil -> user
value -> set_moderator(user, value)
end
user =
case Keyword.get(options, :locked) do
nil -> user
value -> set_locked(user, value)
end
_user =
case Keyword.get(options, :admin) do
nil -> user
value -> set_admin(user, value)
end
else
_ ->
shell_error("No local user #{nickname}")
end
end
def run(["tag", nickname | tags]) do
start_pleroma()
with %User{} = user <- User.get_cached_by_nickname(nickname) do
user = user |> User.tag(tags)
shell_info("Tags of #{user.nickname}: #{inspect(user.tags)}")
else
_ ->
shell_error("Could not change user tags for #{nickname}")
end
end
def run(["untag", nickname | tags]) do
start_pleroma()
with %User{} = user <- User.get_cached_by_nickname(nickname) do
user = user |> User.untag(tags)
shell_info("Tags of #{user.nickname}: #{inspect(user.tags)}")
else
_ ->
shell_error("Could not change user tags for #{nickname}")
end
end
def run(["invite" | rest]) do
{options, [], []} =
OptionParser.parse(rest,
strict: [
expires_at: :string,
max_use: :integer
]
)
options =
options
|> Keyword.update(:expires_at, {:ok, nil}, fn
nil -> {:ok, nil}
val -> Date.from_iso8601(val)
end)
|> Enum.into(%{})
start_pleroma()
with {:ok, val} <- options[:expires_at],
options = Map.put(options, :expires_at, val),
{:ok, invite} <- UserInviteToken.create_invite(options) do
shell_info("Generated user invite token " <> String.replace(invite.invite_type, "_", " "))
url =
- Pleroma.Web.Router.Helpers.redirect_url(
+ Pleroma.Web.Router.Helpers.frontend_url(
Pleroma.Web.Endpoint,
:registration_page,
invite.token
)
IO.puts(url)
else
error ->
shell_error("Could not create invite token: #{inspect(error)}")
end
end
def run(["invites"]) do
start_pleroma()
shell_info("Invites list:")
UserInviteToken.list_invites()
|> Enum.each(fn invite ->
expire_info =
with expires_at when not is_nil(expires_at) <- invite.expires_at do
" | Expires at: #{Date.to_string(expires_at)}"
end
using_info =
with max_use when not is_nil(max_use) <- invite.max_use do
" | Max use: #{max_use} Left use: #{max_use - invite.uses}"
end
shell_info(
"ID: #{invite.id} | Token: #{invite.token} | Token type: #{invite.invite_type} | Used: #{
invite.used
}#{expire_info}#{using_info}"
)
end)
end
def run(["revoke_invite", token]) do
start_pleroma()
with {:ok, invite} <- UserInviteToken.find_by_token(token),
{:ok, _} <- UserInviteToken.update_invite(invite, %{used: true}) do
shell_info("Invite for token #{token} was revoked.")
else
_ -> shell_error("No invite found with token #{token}")
end
end
def run(["delete_activities", nickname]) do
start_pleroma()
with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do
User.delete_user_activities(user)
shell_info("User #{nickname} statuses deleted.")
else
_ ->
shell_error("No local user #{nickname}")
end
end
def run(["toggle_confirmed", nickname]) do
start_pleroma()
with %User{} = user <- User.get_cached_by_nickname(nickname) do
{:ok, user} = User.toggle_confirmation(user)
message = if user.confirmation_pending, do: "needs", else: "doesn't need"
shell_info("#{nickname} #{message} confirmation.")
else
_ ->
shell_error("No local user #{nickname}")
end
end
def run(["sign_out", nickname]) do
start_pleroma()
with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do
User.global_sign_out(user)
shell_info("#{nickname} signed out from all apps.")
else
_ ->
shell_error("No local user #{nickname}")
end
end
def run(["list"]) do
start_pleroma()
Pleroma.User.Query.build(%{local: true})
|> Pleroma.RepoStreamer.chunk_stream(500)
|> Stream.each(fn users ->
users
|> Enum.each(fn user ->
shell_info(
"#{user.nickname} moderator: #{user.is_moderator}, admin: #{user.is_admin}, locked: #{
user.locked
}, deactivated: #{user.deactivated}"
)
end)
end)
|> Stream.run()
end
defp set_moderator(user, value) do
{:ok, user} =
user
|> Changeset.change(%{is_moderator: value})
|> User.update_and_set_cache()
shell_info("Moderator status of #{user.nickname}: #{user.is_moderator}")
user
end
defp set_admin(user, value) do
{:ok, user} = User.admin_api_update(user, %{is_admin: value})
shell_info("Admin status of #{user.nickname}: #{user.is_admin}")
user
end
defp set_locked(user, value) do
{:ok, user} =
user
|> Changeset.change(%{locked: value})
|> User.update_and_set_cache()
shell_info("Locked status of #{user.nickname}: #{user.locked}")
user
end
end
diff --git a/lib/pleroma/emails/user_email.ex b/lib/pleroma/emails/user_email.ex
index 313533859..1a1f6fb4b 100644
--- a/lib/pleroma/emails/user_email.ex
+++ b/lib/pleroma/emails/user_email.ex
@@ -1,183 +1,183 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Emails.UserEmail do
@moduledoc "User emails"
use Phoenix.Swoosh, view: Pleroma.Web.EmailView, layout: {Pleroma.Web.LayoutView, :email}
alias Pleroma.Config
alias Pleroma.User
alias Pleroma.Web.Endpoint
alias Pleroma.Web.Router
import Pleroma.Config.Helpers, only: [instance_name: 0, sender: 0]
defp recipient(email, nil), do: email
defp recipient(email, name), do: {name, email}
defp recipient(%User{} = user), do: recipient(user.email, user.name)
@spec welcome(User.t(), map()) :: Swoosh.Email.t()
def welcome(user, opts \\ %{}) do
new()
|> to(recipient(user))
|> from(Map.get(opts, :sender, sender()))
|> subject(Map.get(opts, :subject, "Welcome to #{instance_name()}!"))
|> html_body(Map.get(opts, :html, "Welcome to #{instance_name()}!"))
|> text_body(Map.get(opts, :text, "Welcome to #{instance_name()}!"))
end
def password_reset_email(user, token) when is_binary(token) do
password_reset_url = Router.Helpers.reset_password_url(Endpoint, :reset, token)
html_body = """
<h3>Reset your password at #{instance_name()}</h3>
<p>Someone has requested password change for your account at #{instance_name()}.</p>
<p>If it was you, visit the following link to proceed: <a href="#{password_reset_url}">reset password</a>.</p>
<p>If it was someone else, nothing to worry about: your data is secure and your password has not been changed.</p>
"""
new()
|> to(recipient(user))
|> from(sender())
|> subject("Password reset")
|> html_body(html_body)
end
def user_invitation_email(
user,
%Pleroma.UserInviteToken{} = user_invite_token,
to_email,
to_name \\ nil
) do
registration_url =
- Router.Helpers.redirect_url(
+ Router.Helpers.frontend_url(
Endpoint,
:registration_page,
user_invite_token.token
)
html_body = """
<h3>You are invited to #{instance_name()}</h3>
<p>#{user.name} invites you to join #{instance_name()}, an instance of Pleroma federated social networking platform.</p>
<p>Click the following link to register: <a href="#{registration_url}">accept invitation</a>.</p>
"""
new()
|> to(recipient(to_email, to_name))
|> from(sender())
|> subject("Invitation to #{instance_name()}")
|> html_body(html_body)
end
def account_confirmation_email(user) do
confirmation_url =
Router.Helpers.confirm_email_url(
Endpoint,
:confirm_email,
user.id,
to_string(user.confirmation_token)
)
html_body = """
<h3>Welcome to #{instance_name()}!</h3>
<p>Email confirmation is required to activate the account.</p>
<p>Click the following link to proceed: <a href="#{confirmation_url}">activate your account</a>.</p>
"""
new()
|> to(recipient(user))
|> from(sender())
|> subject("#{instance_name()} account confirmation")
|> html_body(html_body)
end
@doc """
Email used in digest email notifications
Includes Mentions and New Followers data
If there are no mentions (even when new followers exist), the function will return nil
"""
@spec digest_email(User.t()) :: Swoosh.Email.t() | nil
def digest_email(user) do
notifications = Pleroma.Notification.for_user_since(user, user.last_digest_emailed_at)
mentions =
notifications
|> Enum.filter(&(&1.activity.data["type"] == "Create"))
|> Enum.map(fn notification ->
object = Pleroma.Object.normalize(notification.activity)
object = update_in(object.data["content"], &format_links/1)
%{
data: notification,
object: object,
from: User.get_by_ap_id(notification.activity.actor)
}
end)
followers =
notifications
|> Enum.filter(&(&1.activity.data["type"] == "Follow"))
|> Enum.map(fn notification ->
%{
data: notification,
object: Pleroma.Object.normalize(notification.activity),
from: User.get_by_ap_id(notification.activity.actor)
}
end)
unless Enum.empty?(mentions) do
styling = Config.get([__MODULE__, :styling])
logo = Config.get([__MODULE__, :logo])
html_data = %{
instance: instance_name(),
user: user,
mentions: mentions,
followers: followers,
unsubscribe_link: unsubscribe_url(user, "digest"),
styling: styling
}
logo_path =
if is_nil(logo) do
Path.join(:code.priv_dir(:pleroma), "static/static/logo.png")
else
Path.join(Config.get([:instance, :static_dir]), logo)
end
new()
|> to(recipient(user))
|> from(sender())
|> subject("Your digest from #{instance_name()}")
|> put_layout(false)
|> render_body("digest.html", html_data)
|> attachment(Swoosh.Attachment.new(logo_path, filename: "logo.png", type: :inline))
end
end
defp format_links(str) do
re = ~r/<a.+href=['"].*>/iU
%{link_color: color} = Config.get([__MODULE__, :styling])
Regex.replace(re, str, fn link ->
String.replace(link, "<a", "<a style=\"color: #{color};text-decoration: none;\"")
end)
end
@doc """
Generate unsubscribe link for given user and notifications type.
The link contains JWT token with the data, and subscription can be modified without
authorization.
"""
@spec unsubscribe_url(User.t(), String.t()) :: String.t()
def unsubscribe_url(user, notifications_type) do
token =
%{"sub" => user.id, "act" => %{"unsubscribe" => notifications_type}, "exp" => false}
|> Pleroma.JWT.generate_and_sign!()
|> Base.encode64()
Router.Helpers.subscription_url(Endpoint, :unsubscribe, token)
end
end
diff --git a/lib/pleroma/plugs/frontend_static.ex b/lib/pleroma/plugs/frontend_static.ex
index f549ca75f..815f3bb20 100644
--- a/lib/pleroma/plugs/frontend_static.ex
+++ b/lib/pleroma/plugs/frontend_static.ex
@@ -1,54 +1,52 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Plugs.FrontendStatic do
require Pleroma.Constants
@moduledoc """
This is a shim to call `Plug.Static` but with runtime `from` configuration`. It dispatches to the different frontends.
"""
@behaviour Plug
def file_path(path, frontend_type \\ :primary) do
if configuration = Pleroma.Config.get([:frontends, frontend_type]) do
instance_static_path = Pleroma.Config.get([:instance, :static_dir], "instance/static")
Path.join([
instance_static_path,
"frontends",
configuration["name"],
configuration["ref"],
path
])
- else
- nil
end
end
def init(opts) do
opts
|> Keyword.put(:from, "__unconfigured_frontend_static_plug")
|> Plug.Static.init()
end
def call(conn, opts) do
frontend_type = Map.get(opts, :frontend_type, :primary)
path = file_path("", frontend_type)
if path do
conn
|> call_static(opts, path)
else
conn
end
end
defp call_static(conn, opts, from) do
opts =
opts
|> Map.put(:from, from)
Plug.Static.call(conn, opts)
end
end
diff --git a/lib/pleroma/web/controller/frontend_controller.ex b/lib/pleroma/web/controller/frontend_controller.ex
index fc717fa29..5fa4e6391 100644
--- a/lib/pleroma/web/controller/frontend_controller.ex
+++ b/lib/pleroma/web/controller/frontend_controller.ex
@@ -1,87 +1,125 @@
defmodule Pleroma.Web.FrontendController do
use Pleroma.Web, :controller
defmacro __using__(_opts) do
quote do
require Logger
+ alias Pleroma.User
def fallback(conn, _params) do
conn
|> put_status(404)
|> text("Not found")
end
+ def registration_page(conn, params) do
+ redirector(conn, params)
+ end
+
+ def api_not_implemented(conn, _params) do
+ conn
+ |> put_status(404)
+ |> json(%{error: "Not implemented"})
+ end
+
+ def empty(conn, _params) do
+ conn
+ |> put_status(204)
+ |> text("")
+ end
+
+ def redirector(conn, _params) do
+ {:ok, path} = Pleroma.Frontend.file_path("index.html")
+
+ conn
+ |> put_resp_content_type("text/html")
+ |> send_file(conn.status || 200, path)
+ end
+
def redirector_with_preload(conn, %{"path" => ["pleroma", "admin"]}) do
redirect(conn, to: "/pleroma/admin/")
end
def redirector_with_preload(conn, params) do
index_with_generated_data(conn, params, [:preload])
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
+ index_with_generated_data(conn, params, [:metadata, :preload])
+ end
+
def index_with_generated_data(conn, params, generators) do
{:ok, path} = Pleroma.Frontend.file_path("index.html")
{:ok, index_content} = File.read(path)
generated =
Enum.reduce(generators, "", fn generator, acc ->
acc <> generate_data(conn, params, generator)
end)
response = String.replace(index_content, "<!--server-generated-meta-->", generated)
html(conn, response)
end
defp generate_data(conn, params, :preload) do
try do
Pleroma.Web.Preload.build_tags(conn, params)
rescue
e ->
Logger.error(
"Preloading for #{conn.request_path} failed.\n" <>
Exception.format(:error, e, __STACKTRACE__)
)
""
end
end
defp generate_data(conn, params, :metadata) do
try do
Pleroma.Web.Metadata.build_tags(params)
rescue
e ->
Logger.error(
"Metadata rendering for #{conn.request_path} failed.\n" <>
Exception.format(:error, e, __STACKTRACE__)
)
""
end
end
defoverridable redirector_with_preload: 2, fallback: 2
end
end
defp action(conn, _opts) do
fe_config = conn.private[:frontend] || Pleroma.Frontend.get_config(:primary)
action_name = action_name(conn)
{controller, action} =
cond do
function_exported?(fe_config["controller"], action_name, 2) ->
{fe_config["controller"], action_name}
true ->
{fe_config["controller"], :fallback}
end
conn
|> put_private(:frontend, fe_config)
|> put_view(Phoenix.Controller.__view__(controller))
|> controller.call(controller.init(action))
end
end
diff --git a/lib/pleroma/web/fallback_redirect_controller.ex b/lib/pleroma/web/fallback_redirect_controller.ex
deleted file mode 100644
index a59c2a02e..000000000
--- a/lib/pleroma/web/fallback_redirect_controller.ex
+++ /dev/null
@@ -1,109 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 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
- alias Pleroma.Web.Preload
-
- 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 = build_tags(conn, params)
- preloads = preload_data(conn, params)
-
- response =
- index_content
- |> String.replace("<!--server-generated-meta-->", tags <> preloads)
-
- conn
- |> put_resp_content_type("text/html")
- |> send_resp(200, response)
- end
-
- def redirector_with_preload(conn, %{"path" => ["pleroma", "admin"]}) do
- redirect(conn, to: "/pleroma/admin/")
- end
-
- def redirector_with_preload(conn, params) do
- {:ok, index_content} = File.read(index_file_path())
- preloads = preload_data(conn, params)
-
- response =
- index_content
- |> String.replace("<!--server-generated-meta-->", preloads)
-
- conn
- |> put_resp_content_type("text/html")
- |> send_resp(200, response)
- end
-
- def registration_page(conn, params) do
- redirector(conn, params)
- end
-
- def empty(conn, _params) do
- conn
- |> put_status(204)
- |> text("")
- end
-
- defp index_file_path do
- {:ok, file} = Pleroma.Frontend.file_path("index.html", :primary)
- file
- end
-
- defp build_tags(conn, params) do
- try do
- Metadata.build_tags(params)
- rescue
- e ->
- Logger.error(
- "Metadata rendering for #{conn.request_path} failed.\n" <>
- Exception.format(:error, e, __STACKTRACE__)
- )
-
- ""
- end
- end
-
- defp preload_data(conn, params) do
- try do
- Preload.build_tags(conn, params)
- rescue
- e ->
- Logger.error(
- "Preloading for #{conn.request_path} failed.\n" <>
- Exception.format(:error, e, __STACKTRACE__)
- )
-
- ""
- end
- end
-end
diff --git a/lib/pleroma/web/feed/user_controller.ex b/lib/pleroma/web/feed/user_controller.ex
index d56f43818..47c3dba35 100644
--- a/lib/pleroma/web/feed/user_controller.ex
+++ b/lib/pleroma/web/feed/user_controller.ex
@@ -1,79 +1,80 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Feed.UserController do
use Pleroma.Web, :controller
- alias Fallback.RedirectController
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.ActivityPubController
alias Pleroma.Web.Feed.FeedView
plug(Pleroma.Plugs.SetFormatPlug when action in [:feed_redirect])
action_fallback(:errors)
def feed_redirect(%{assigns: %{format: "html"}} = conn, %{"nickname" => nickname}) do
with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname_or_id(nickname)} do
- RedirectController.redirector_with_meta(conn, %{user: user})
+ conn
+ |> Map.put(:params, %{user: user})
+ |> Pleroma.Web.FrontendController.call(:redirector_with_meta)
end
end
def feed_redirect(%{assigns: %{format: format}} = conn, _params)
when format in ["json", "activity+json"] do
with %{halted: false} = conn <-
Pleroma.Plugs.EnsureAuthenticatedPlug.call(conn,
unless_func: &Pleroma.Web.FederatingPlug.federating?/1
) do
ActivityPubController.call(conn, :user)
end
end
def feed_redirect(conn, %{"nickname" => nickname}) do
with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname(nickname)} do
redirect(conn, external: "#{user_feed_url(conn, :feed, user.nickname)}.atom")
end
end
def feed(conn, %{"nickname" => nickname} = params) do
format = get_format(conn)
format =
if format in ["rss", "atom"] do
format
else
"atom"
end
with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname(nickname)} do
activities =
%{
type: ["Create"],
actor_id: user.ap_id
}
|> Pleroma.Maps.put_if_present(:max_id, params["max_id"])
|> ActivityPub.fetch_public_or_unlisted_activities()
conn
|> put_resp_content_type("application/#{format}+xml")
|> put_view(FeedView)
|> render("user.#{format}",
user: user,
activities: activities,
feed_config: Pleroma.Config.get([:feed])
)
end
end
def errors(conn, {:error, :not_found}) 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
end
diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex
index de1b0b3f0..e6ce1d350 100644
--- a/lib/pleroma/web/ostatus/ostatus_controller.ex
+++ b/lib/pleroma/web/ostatus/ostatus_controller.ex
@@ -1,151 +1,151 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OStatus.OStatusController do
use Pleroma.Web, :controller
- alias Fallback.RedirectController
alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.Plugs.RateLimiter
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPubController
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.Endpoint
alias Pleroma.Web.Metadata.PlayerView
alias Pleroma.Web.Router
plug(Pleroma.Plugs.EnsureAuthenticatedPlug,
unless_func: &Pleroma.Web.FederatingPlug.federating?/1
)
plug(
RateLimiter,
[name: :ap_routes, params: ["uuid"]] when action in [:object, :activity]
)
plug(
Pleroma.Plugs.SetFormatPlug
when action in [:object, :activity, :notice]
)
action_fallback(:errors)
def object(%{assigns: %{format: format}} = conn, _params)
when format in ["json", "activity+json"] do
ActivityPubController.call(conn, :object)
end
def object(%{assigns: %{format: format}} = conn, _params) do
with id <- Endpoint.url() <> conn.request_path,
{_, %Activity{} = activity} <-
{:activity, Activity.get_create_by_object_ap_id_with_object(id)},
{_, true} <- {:public?, Visibility.is_public?(activity)} do
case format do
_ -> redirect(conn, to: "/notice/#{activity.id}")
end
else
reason when reason in [{:public?, false}, {:activity, nil}] ->
{:error, :not_found}
e ->
e
end
end
def activity(%{assigns: %{format: format}} = conn, _params)
when format in ["json", "activity+json"] do
ActivityPubController.call(conn, :activity)
end
def activity(%{assigns: %{format: format}} = conn, _params) do
with id <- Endpoint.url() <> conn.request_path,
{_, %Activity{} = activity} <- {:activity, Activity.normalize(id)},
{_, true} <- {:public?, Visibility.is_public?(activity)} do
case format do
_ -> redirect(conn, to: "/notice/#{activity.id}")
end
else
reason when reason in [{:public?, false}, {:activity, nil}] ->
{:error, :not_found}
e ->
e
end
end
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
cond do
format in ["json", "activity+json"] ->
if activity.local do
%{data: %{"id" => redirect_url}} = Object.normalize(activity)
redirect(conn, external: redirect_url)
else
{:error, :not_found}
end
activity.data["type"] == "Create" ->
%Object{} = object = Object.normalize(activity)
- RedirectController.redirector_with_meta(
- conn,
- %{
- activity_id: activity.id,
- object: object,
- url: Router.Helpers.o_status_url(Endpoint, :notice, activity.id),
- user: user
- }
- )
+ params = %{
+ activity_id: activity.id,
+ object: object,
+ url: Router.Helpers.o_status_url(Endpoint, :notice, activity.id),
+ user: user
+ }
+
+ conn
+ |> Map.put(:params, params)
+ |> Pleroma.Web.FrontendController.call(:redirector_with_meta)
true ->
- RedirectController.redirector(conn, nil)
+ Pleroma.Web.FrontendController.call(conn, :redirector)
end
else
reason when reason in [{:public?, false}, {:activity, nil}] ->
conn
|> put_status(404)
- |> RedirectController.redirector(nil, 404)
+ |> Pleroma.Web.FrontendController.call(:redirector)
e ->
e
end
end
# Returns an HTML embedded <audio> or <video> player suitable for embed iframes.
def notice_player(conn, %{"id" => id}) do
with %Activity{data: %{"type" => "Create"}} = activity <- Activity.get_by_id_with_object(id),
true <- Visibility.is_public?(activity),
%Object{} = object <- Object.normalize(activity),
%{data: %{"attachment" => [%{"url" => [url | _]} | _]}} <- object,
true <- String.starts_with?(url["mediaType"], ["audio", "video"]) do
conn
|> put_layout(:metadata_player)
|> put_resp_header("x-frame-options", "ALLOW")
|> put_resp_header(
"content-security-policy",
"default-src 'none';style-src 'self' 'unsafe-inline';img-src 'self' data: https:; media-src 'self' https:;"
)
|> put_view(PlayerView)
|> render("player.html", url)
else
_error ->
conn
|> put_status(404)
- |> RedirectController.redirector(nil, 404)
+ |> Pleroma.Web.FrontendController.call(:redirector)
end
end
defp errors(conn, {:error, :not_found}) do
render_error(conn, :not_found, "Not found")
end
defp errors(conn, {:fetch_user, nil}), do: errors(conn, {:error, :not_found})
defp errors(conn, _) do
render_error(conn, :internal_server_error, "Something went wrong")
end
end
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index b8c93a389..3cf5728f0 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -1,726 +1,725 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Router do
use Pleroma.Web, :router
pipeline :browser do
plug(:accepts, ["html"])
plug(:fetch_session)
end
pipeline :oauth do
plug(:fetch_session)
plug(Pleroma.Plugs.OAuthPlug)
plug(Pleroma.Plugs.UserEnabledPlug)
end
pipeline :expect_authentication do
plug(Pleroma.Plugs.ExpectAuthenticatedCheckPlug)
end
pipeline :expect_public_instance_or_authentication do
plug(Pleroma.Plugs.ExpectPublicOrAuthenticatedCheckPlug)
end
pipeline :authenticate do
plug(Pleroma.Plugs.OAuthPlug)
plug(Pleroma.Plugs.BasicAuthDecoderPlug)
plug(Pleroma.Plugs.UserFetcherPlug)
plug(Pleroma.Plugs.SessionAuthenticationPlug)
plug(Pleroma.Plugs.LegacyAuthenticationPlug)
plug(Pleroma.Plugs.AuthenticationPlug)
end
pipeline :after_auth do
plug(Pleroma.Plugs.UserEnabledPlug)
plug(Pleroma.Plugs.SetUserSessionIdPlug)
plug(Pleroma.Plugs.EnsureUserKeyPlug)
end
pipeline :base_api do
plug(:accepts, ["json"])
plug(:fetch_session)
plug(:authenticate)
plug(OpenApiSpex.Plug.PutApiSpec, module: Pleroma.Web.ApiSpec)
end
pipeline :api do
plug(:expect_public_instance_or_authentication)
plug(:base_api)
plug(:after_auth)
plug(Pleroma.Plugs.IdempotencyPlug)
end
pipeline :authenticated_api do
plug(:expect_authentication)
plug(:base_api)
plug(:after_auth)
plug(Pleroma.Plugs.EnsureAuthenticatedPlug)
plug(Pleroma.Plugs.IdempotencyPlug)
end
pipeline :admin_api do
plug(:expect_authentication)
plug(:base_api)
plug(Pleroma.Plugs.AdminSecretAuthenticationPlug)
plug(:after_auth)
plug(Pleroma.Plugs.EnsureAuthenticatedPlug)
plug(Pleroma.Plugs.UserIsAdminPlug)
plug(Pleroma.Plugs.IdempotencyPlug)
end
pipeline :mastodon_html do
plug(:browser)
plug(:authenticate)
plug(:after_auth)
end
pipeline :pleroma_html do
plug(:browser)
plug(:authenticate)
plug(Pleroma.Plugs.EnsureUserKeyPlug)
end
pipeline :well_known do
plug(:accepts, ["json", "jrd+json", "xml", "xrd+xml"])
end
pipeline :config do
plug(:accepts, ["json", "xml"])
plug(OpenApiSpex.Plug.PutApiSpec, module: Pleroma.Web.ApiSpec)
end
pipeline :pleroma_api do
plug(:accepts, ["html", "json"])
plug(OpenApiSpex.Plug.PutApiSpec, module: Pleroma.Web.ApiSpec)
end
pipeline :mailbox_preview do
plug(:accepts, ["html"])
plug(:put_secure_browser_headers, %{
"content-security-policy" =>
"default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline' 'unsafe-eval'"
})
end
pipeline :http_signature do
plug(Pleroma.Web.Plugs.HTTPSignaturePlug)
plug(Pleroma.Web.Plugs.MappedSignatureToIdentityPlug)
end
scope "/api/pleroma", Pleroma.Web.TwitterAPI do
pipe_through(:pleroma_api)
get("/password_reset/:token", PasswordController, :reset, as: :reset_password)
post("/password_reset", PasswordController, :do_reset, as: :reset_password)
get("/emoji", UtilController, :emoji)
get("/captcha", UtilController, :captcha)
get("/healthcheck", UtilController, :healthcheck)
end
scope "/api/pleroma", Pleroma.Web do
pipe_through(:pleroma_api)
post("/uploader_callback/:upload_path", UploaderController, :callback)
end
scope "/api/pleroma/admin", Pleroma.Web.AdminAPI do
pipe_through(:admin_api)
post("/users/follow", AdminAPIController, :user_follow)
post("/users/unfollow", AdminAPIController, :user_unfollow)
put("/users/disable_mfa", AdminAPIController, :disable_mfa)
delete("/users", AdminAPIController, :user_delete)
post("/users", AdminAPIController, :users_create)
patch("/users/:nickname/toggle_activation", AdminAPIController, :user_toggle_activation)
patch("/users/activate", AdminAPIController, :user_activate)
patch("/users/deactivate", AdminAPIController, :user_deactivate)
put("/users/tag", AdminAPIController, :tag_users)
delete("/users/tag", AdminAPIController, :untag_users)
get("/users/:nickname/permission_group", AdminAPIController, :right_get)
get("/users/:nickname/permission_group/:permission_group", AdminAPIController, :right_get)
post("/users/:nickname/permission_group/:permission_group", AdminAPIController, :right_add)
delete(
"/users/:nickname/permission_group/:permission_group",
AdminAPIController,
:right_delete
)
post("/users/permission_group/:permission_group", AdminAPIController, :right_add_multiple)
delete(
"/users/permission_group/:permission_group",
AdminAPIController,
:right_delete_multiple
)
get("/relay", RelayController, :index)
post("/relay", RelayController, :follow)
delete("/relay", RelayController, :unfollow)
post("/users/invite_token", InviteController, :create)
get("/users/invites", InviteController, :index)
post("/users/revoke_invite", InviteController, :revoke)
post("/users/email_invite", InviteController, :email)
get("/users/:nickname/password_reset", AdminAPIController, :get_password_reset)
patch("/users/force_password_reset", AdminAPIController, :force_password_reset)
get("/users/:nickname/credentials", AdminAPIController, :show_user_credentials)
patch("/users/:nickname/credentials", AdminAPIController, :update_user_credentials)
get("/users", AdminAPIController, :list_users)
get("/users/:nickname", AdminAPIController, :user_show)
get("/users/:nickname/statuses", AdminAPIController, :list_user_statuses)
get("/instances/:instance/statuses", AdminAPIController, :list_instance_statuses)
patch("/users/confirm_email", AdminAPIController, :confirm_email)
patch("/users/resend_confirmation_email", AdminAPIController, :resend_confirmation_email)
get("/reports", ReportController, :index)
get("/reports/:id", ReportController, :show)
patch("/reports", ReportController, :update)
post("/reports/:id/notes", ReportController, :notes_create)
delete("/reports/:report_id/notes/:id", ReportController, :notes_delete)
get("/statuses/:id", StatusController, :show)
put("/statuses/:id", StatusController, :update)
delete("/statuses/:id", StatusController, :delete)
get("/statuses", StatusController, :index)
get("/config", ConfigController, :show)
post("/config", ConfigController, :update)
get("/config/descriptions", ConfigController, :descriptions)
get("/need_reboot", AdminAPIController, :need_reboot)
get("/restart", AdminAPIController, :restart)
get("/moderation_log", AdminAPIController, :list_log)
post("/reload_emoji", AdminAPIController, :reload_emoji)
get("/stats", AdminAPIController, :stats)
get("/oauth_app", OAuthAppController, :index)
post("/oauth_app", OAuthAppController, :create)
patch("/oauth_app/:id", OAuthAppController, :update)
delete("/oauth_app/:id", OAuthAppController, :delete)
get("/media_proxy_caches", MediaProxyCacheController, :index)
post("/media_proxy_caches/delete", MediaProxyCacheController, :delete)
post("/media_proxy_caches/purge", MediaProxyCacheController, :purge)
end
scope "/api/pleroma/emoji", Pleroma.Web.PleromaAPI do
# Modifying packs
scope "/packs" do
pipe_through(:admin_api)
get("/import", EmojiPackController, :import_from_filesystem)
get("/remote", EmojiPackController, :remote)
post("/download", EmojiPackController, :download)
post("/:name", EmojiPackController, :create)
patch("/:name", EmojiPackController, :update)
delete("/:name", EmojiPackController, :delete)
post("/:name/files", EmojiPackController, :add_file)
patch("/:name/files", EmojiPackController, :update_file)
delete("/:name/files", EmojiPackController, :delete_file)
end
# Pack info / downloading
scope "/packs" do
pipe_through(:api)
get("/", EmojiPackController, :index)
get("/:name", EmojiPackController, :show)
get("/:name/archive", EmojiPackController, :archive)
end
end
scope "/", Pleroma.Web.TwitterAPI do
pipe_through(:pleroma_html)
post("/main/ostatus", UtilController, :remote_subscribe)
get("/ostatus_subscribe", RemoteFollowController, :follow)
post("/ostatus_subscribe", RemoteFollowController, :do_follow)
end
scope "/api/pleroma", Pleroma.Web.TwitterAPI do
pipe_through(:authenticated_api)
post("/change_email", UtilController, :change_email)
post("/change_password", UtilController, :change_password)
post("/delete_account", UtilController, :delete_account)
put("/notification_settings", UtilController, :update_notificaton_settings)
post("/disable_account", UtilController, :disable_account)
post("/blocks_import", UtilController, :blocks_import)
post("/follow_import", UtilController, :follow_import)
end
scope "/api/pleroma", Pleroma.Web.PleromaAPI do
pipe_through(:authenticated_api)
get("/accounts/mfa", TwoFactorAuthenticationController, :settings)
get("/accounts/mfa/backup_codes", TwoFactorAuthenticationController, :backup_codes)
get("/accounts/mfa/setup/:method", TwoFactorAuthenticationController, :setup)
post("/accounts/mfa/confirm/:method", TwoFactorAuthenticationController, :confirm)
delete("/accounts/mfa/:method", TwoFactorAuthenticationController, :disable)
end
scope "/oauth", Pleroma.Web.OAuth do
scope [] do
pipe_through(:oauth)
get("/authorize", OAuthController, :authorize)
end
post("/authorize", OAuthController, :create_authorization)
post("/token", OAuthController, :token_exchange)
post("/revoke", OAuthController, :token_revoke)
get("/registration_details", OAuthController, :registration_details)
post("/mfa/challenge", MFAController, :challenge)
post("/mfa/verify", MFAController, :verify, as: :mfa_verify)
get("/mfa", MFAController, :show)
scope [] do
pipe_through(:browser)
get("/prepare_request", OAuthController, :prepare_request)
get("/:provider", OAuthController, :request)
get("/:provider/callback", OAuthController, :callback)
post("/register", OAuthController, :register)
end
end
scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do
pipe_through(:api)
get("/statuses/:id/reactions/:emoji", EmojiReactionController, :index)
get("/statuses/:id/reactions", EmojiReactionController, :index)
end
scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do
scope [] do
pipe_through(:authenticated_api)
post("/chats/by-account-id/:id", ChatController, :create)
get("/chats", ChatController, :index)
get("/chats/:id", ChatController, :show)
get("/chats/:id/messages", ChatController, :messages)
post("/chats/:id/messages", ChatController, :post_chat_message)
delete("/chats/:id/messages/:message_id", ChatController, :delete_message)
post("/chats/:id/read", ChatController, :mark_as_read)
post("/chats/:id/messages/:message_id/read", ChatController, :mark_message_as_read)
get("/conversations/:id/statuses", ConversationController, :statuses)
get("/conversations/:id", ConversationController, :show)
post("/conversations/read", ConversationController, :mark_as_read)
patch("/conversations/:id", ConversationController, :update)
put("/statuses/:id/reactions/:emoji", EmojiReactionController, :create)
delete("/statuses/:id/reactions/:emoji", EmojiReactionController, :delete)
post("/notifications/read", NotificationController, :mark_as_read)
get("/mascot", MascotController, :show)
put("/mascot", MascotController, :update)
post("/scrobble", ScrobbleController, :create)
end
scope [] do
pipe_through(:api)
get("/accounts/:id/favourites", AccountController, :favourites)
end
scope [] do
pipe_through(:authenticated_api)
post("/accounts/:id/subscribe", AccountController, :subscribe)
post("/accounts/:id/unsubscribe", AccountController, :unsubscribe)
end
post("/accounts/confirmation_resend", AccountController, :confirmation_resend)
end
scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do
pipe_through(:api)
get("/accounts/:id/scrobbles", ScrobbleController, :index)
end
scope "/api/v1", Pleroma.Web.MastodonAPI do
pipe_through(:authenticated_api)
get("/accounts/verify_credentials", AccountController, :verify_credentials)
patch("/accounts/update_credentials", AccountController, :update_credentials)
get("/accounts/relationships", AccountController, :relationships)
get("/accounts/:id/lists", AccountController, :lists)
get("/accounts/:id/identity_proofs", AccountController, :identity_proofs)
get("/endorsements", AccountController, :endorsements)
get("/blocks", AccountController, :blocks)
get("/mutes", AccountController, :mutes)
post("/follows", AccountController, :follow_by_uri)
post("/accounts/:id/follow", AccountController, :follow)
post("/accounts/:id/unfollow", AccountController, :unfollow)
post("/accounts/:id/block", AccountController, :block)
post("/accounts/:id/unblock", AccountController, :unblock)
post("/accounts/:id/mute", AccountController, :mute)
post("/accounts/:id/unmute", AccountController, :unmute)
get("/apps/verify_credentials", AppController, :verify_credentials)
get("/conversations", ConversationController, :index)
post("/conversations/:id/read", ConversationController, :mark_as_read)
get("/domain_blocks", DomainBlockController, :index)
post("/domain_blocks", DomainBlockController, :create)
delete("/domain_blocks", DomainBlockController, :delete)
get("/filters", FilterController, :index)
post("/filters", FilterController, :create)
get("/filters/:id", FilterController, :show)
put("/filters/:id", FilterController, :update)
delete("/filters/:id", FilterController, :delete)
get("/follow_requests", FollowRequestController, :index)
post("/follow_requests/:id/authorize", FollowRequestController, :authorize)
post("/follow_requests/:id/reject", FollowRequestController, :reject)
get("/lists", ListController, :index)
get("/lists/:id", ListController, :show)
get("/lists/:id/accounts", ListController, :list_accounts)
delete("/lists/:id", ListController, :delete)
post("/lists", ListController, :create)
put("/lists/:id", ListController, :update)
post("/lists/:id/accounts", ListController, :add_to_list)
delete("/lists/:id/accounts", ListController, :remove_from_list)
get("/markers", MarkerController, :index)
post("/markers", MarkerController, :upsert)
post("/media", MediaController, :create)
get("/media/:id", MediaController, :show)
put("/media/:id", MediaController, :update)
get("/notifications", NotificationController, :index)
get("/notifications/:id", NotificationController, :show)
post("/notifications/:id/dismiss", NotificationController, :dismiss)
post("/notifications/clear", NotificationController, :clear)
delete("/notifications/destroy_multiple", NotificationController, :destroy_multiple)
# Deprecated: was removed in Mastodon v3, use `/notifications/:id/dismiss` instead
post("/notifications/dismiss", NotificationController, :dismiss_via_body)
post("/polls/:id/votes", PollController, :vote)
post("/reports", ReportController, :create)
get("/scheduled_statuses", ScheduledActivityController, :index)
get("/scheduled_statuses/:id", ScheduledActivityController, :show)
put("/scheduled_statuses/:id", ScheduledActivityController, :update)
delete("/scheduled_statuses/:id", ScheduledActivityController, :delete)
# Unlike `GET /api/v1/accounts/:id/favourites`, demands authentication
get("/favourites", StatusController, :favourites)
get("/bookmarks", StatusController, :bookmarks)
post("/statuses", StatusController, :create)
delete("/statuses/:id", StatusController, :delete)
post("/statuses/:id/reblog", StatusController, :reblog)
post("/statuses/:id/unreblog", StatusController, :unreblog)
post("/statuses/:id/favourite", StatusController, :favourite)
post("/statuses/:id/unfavourite", StatusController, :unfavourite)
post("/statuses/:id/pin", StatusController, :pin)
post("/statuses/:id/unpin", StatusController, :unpin)
post("/statuses/:id/bookmark", StatusController, :bookmark)
post("/statuses/:id/unbookmark", StatusController, :unbookmark)
post("/statuses/:id/mute", StatusController, :mute_conversation)
post("/statuses/:id/unmute", StatusController, :unmute_conversation)
post("/push/subscription", SubscriptionController, :create)
get("/push/subscription", SubscriptionController, :show)
put("/push/subscription", SubscriptionController, :update)
delete("/push/subscription", SubscriptionController, :delete)
get("/suggestions", SuggestionController, :index)
get("/timelines/home", TimelineController, :home)
get("/timelines/direct", TimelineController, :direct)
get("/timelines/list/:list_id", TimelineController, :list)
end
scope "/api/web", Pleroma.Web do
pipe_through(:authenticated_api)
# Backend-obscure settings blob for MastoFE, don't parse/reuse elsewhere
put("/settings", MastoFEController, :put_settings)
end
scope "/api/v1", Pleroma.Web.MastodonAPI do
pipe_through(:api)
get("/accounts/search", SearchController, :account_search)
get("/search", SearchController, :search)
get("/accounts/:id/statuses", AccountController, :statuses)
get("/accounts/:id/followers", AccountController, :followers)
get("/accounts/:id/following", AccountController, :following)
get("/accounts/:id", AccountController, :show)
post("/accounts", AccountController, :create)
get("/instance", InstanceController, :show)
get("/instance/peers", InstanceController, :peers)
post("/apps", AppController, :create)
get("/statuses", StatusController, :index)
get("/statuses/:id", StatusController, :show)
get("/statuses/:id/context", StatusController, :context)
get("/statuses/:id/card", StatusController, :card)
get("/statuses/:id/favourited_by", StatusController, :favourited_by)
get("/statuses/:id/reblogged_by", StatusController, :reblogged_by)
get("/custom_emojis", CustomEmojiController, :index)
get("/trends", MastodonAPIController, :empty_array)
get("/timelines/public", TimelineController, :public)
get("/timelines/tag/:tag", TimelineController, :hashtag)
get("/polls/:id", PollController, :show)
end
scope "/api/v2", Pleroma.Web.MastodonAPI do
pipe_through(:api)
get("/search", SearchController, :search2)
post("/media", MediaController, :create2)
end
scope "/api", Pleroma.Web do
pipe_through(:config)
get("/pleroma/frontend_configurations", TwitterAPI.UtilController, :frontend_configurations)
end
scope "/api", Pleroma.Web do
pipe_through(:api)
get(
"/account/confirm_email/:user_id/:token",
TwitterAPI.Controller,
:confirm_email,
as: :confirm_email
)
end
scope "/api" do
pipe_through(:base_api)
get("/openapi", OpenApiSpex.Plug.RenderSpec, [])
end
scope "/api", Pleroma.Web, as: :authenticated_twitter_api do
pipe_through(:authenticated_api)
get("/oauth_tokens", TwitterAPI.Controller, :oauth_tokens)
delete("/oauth_tokens/:id", TwitterAPI.Controller, :revoke_token)
post(
"/qvitter/statuses/notifications/read",
TwitterAPI.Controller,
:mark_notifications_as_read
)
end
pipeline :ostatus do
plug(:accepts, ["html", "xml", "rss", "atom", "activity+json", "json"])
plug(Pleroma.Plugs.StaticFEPlug)
end
pipeline :oembed do
plug(:accepts, ["json", "xml"])
end
scope "/", Pleroma.Web do
pipe_through([:ostatus, :http_signature])
get("/objects/:uuid", OStatus.OStatusController, :object)
get("/activities/:uuid", OStatus.OStatusController, :activity)
get("/notice/:id", OStatus.OStatusController, :notice)
get("/notice/:id/embed_player", OStatus.OStatusController, :notice_player)
# Mastodon compatibility routes
get("/users/:nickname/statuses/:id", OStatus.OStatusController, :object)
get("/users/:nickname/statuses/:id/activity", OStatus.OStatusController, :activity)
get("/users/:nickname/feed", Feed.UserController, :feed, as: :user_feed)
get("/users/:nickname", Feed.UserController, :feed_redirect, as: :user_feed)
get("/tags/:tag", Feed.TagController, :feed, as: :tag_feed)
end
scope "/", Pleroma.Web do
pipe_through(:browser)
get("/mailer/unsubscribe/:token", Mailer.SubscriptionController, :unsubscribe)
end
pipeline :ap_service_actor do
plug(:accepts, ["activity+json", "json"])
end
# Server to Server (S2S) AP interactions
pipeline :activitypub do
plug(:ap_service_actor)
plug(:http_signature)
end
# Client to Server (C2S) AP interactions
pipeline :activitypub_client do
plug(:ap_service_actor)
plug(:fetch_session)
plug(:authenticate)
plug(:after_auth)
end
scope "/", Pleroma.Web.ActivityPub do
pipe_through([:activitypub_client])
get("/api/ap/whoami", ActivityPubController, :whoami)
get("/users/:nickname/inbox", ActivityPubController, :read_inbox)
get("/users/:nickname/outbox", ActivityPubController, :outbox)
post("/users/:nickname/outbox", ActivityPubController, :update_outbox)
post("/api/ap/upload_media", ActivityPubController, :upload_media)
# The following two are S2S as well, see `ActivityPub.fetch_follow_information_for_user/1`:
get("/users/:nickname/followers", ActivityPubController, :followers)
get("/users/:nickname/following", ActivityPubController, :following)
end
scope "/", Pleroma.Web.ActivityPub do
pipe_through(:activitypub)
post("/inbox", ActivityPubController, :inbox)
post("/users/:nickname/inbox", ActivityPubController, :inbox)
end
scope "/relay", Pleroma.Web.ActivityPub do
pipe_through(:ap_service_actor)
get("/", ActivityPubController, :relay)
scope [] do
pipe_through(:http_signature)
post("/inbox", ActivityPubController, :inbox)
end
get("/following", ActivityPubController, :relay_following)
get("/followers", ActivityPubController, :relay_followers)
end
scope "/internal/fetch", Pleroma.Web.ActivityPub do
pipe_through(:ap_service_actor)
get("/", ActivityPubController, :internal_fetch)
post("/inbox", ActivityPubController, :inbox)
end
scope "/.well-known", Pleroma.Web do
pipe_through(:well_known)
get("/host-meta", WebFinger.WebFingerController, :host_meta)
get("/webfinger", WebFinger.WebFingerController, :webfinger)
get("/nodeinfo", Nodeinfo.NodeinfoController, :schemas)
end
scope "/nodeinfo", Pleroma.Web do
get("/:version", Nodeinfo.NodeinfoController, :nodeinfo)
end
scope "/", Pleroma.Web do
pipe_through(:api)
get("/web/manifest.json", MastoFEController, :manifest)
end
scope "/", Pleroma.Web do
pipe_through(:mastodon_html)
get("/web/login", MastodonAPI.AuthController, :login)
delete("/auth/sign_out", MastodonAPI.AuthController, :logout)
post("/auth/password", MastodonAPI.AuthController, :password_reset)
get("/web/*path", MastoFEController, :index)
get("/embed/:id", EmbedController, :show)
end
scope "/proxy/", Pleroma.Web.MediaProxy do
get("/:sig/:url", MediaProxyController, :remote)
get("/:sig/:url/:filename", MediaProxyController, :remote)
end
if Pleroma.Config.get(:env) == :dev do
scope "/dev" do
pipe_through([:mailbox_preview])
forward("/mailbox", Plug.Swoosh.MailboxPreview, base_path: "/dev/mailbox")
end
end
# Test-only routes needed to test action dispatching and plug chain execution
if Pleroma.Config.get(:env) == :test do
@test_actions [
:do_oauth_check,
:fallback_oauth_check,
:skip_oauth_check,
:fallback_oauth_skip_publicity_check,
:skip_oauth_skip_publicity_check,
:missing_oauth_check_definition
]
scope "/test/api", Pleroma.Tests do
pipe_through(:api)
for action <- @test_actions do
get("/#{action}", AuthTestController, action)
end
end
scope "/test/authenticated_api", Pleroma.Tests do
pipe_through(:authenticated_api)
for action <- @test_actions do
get("/#{action}", AuthTestController, action)
end
end
end
scope "/", Pleroma.Web.MongooseIM do
get("/user_exists", MongooseIMController, :user_exists)
get("/check_password", MongooseIMController, :check_password)
end
scope "/" do
- get("/registration/:token", Fallback.RedirectController, :registration_page)
- get("/:maybe_nickname_or_id", Fallback.RedirectController, :redirector_with_meta)
- get("/api*path", Fallback.RedirectController, :api_not_implemented)
- # get("/*path", RedirectController, :redirector_with_preload)
+ get("/registration/:token", Pleroma.Web.FrontendController, :registration_page)
+ get("/:maybe_nickname_or_id", Pleroma.Web.FrontendController, :redirector_with_meta)
+ get("/api*path", Pleroma.Web.FrontendController, :api_not_implemented)
get("/*path", Pleroma.Web.FrontendController, :redirector_with_preload)
- options("/*path", Fallback.RedirectController, :empty)
+ options("/*path", Pleroma.Web.FrontendController, :empty)
end
end
diff --git a/test/emails/user_email_test.exs b/test/emails/user_email_test.exs
index a75623bb4..c6044a8a5 100644
--- a/test/emails/user_email_test.exs
+++ b/test/emails/user_email_test.exs
@@ -1,48 +1,48 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Emails.UserEmailTest do
use Pleroma.DataCase
alias Pleroma.Emails.UserEmail
alias Pleroma.Web.Endpoint
alias Pleroma.Web.Router
import Pleroma.Factory
test "build password reset email" do
config = Pleroma.Config.get(:instance)
user = insert(:user)
email = UserEmail.password_reset_email(user, "test_token")
assert email.from == {config[:name], config[:notify_email]}
assert email.to == [{user.name, user.email}]
assert email.subject == "Password reset"
assert email.html_body =~ Router.Helpers.reset_password_url(Endpoint, :reset, "test_token")
end
test "build user invitation email" do
config = Pleroma.Config.get(:instance)
user = insert(:user)
token = %Pleroma.UserInviteToken{token: "test-token"}
email = UserEmail.user_invitation_email(user, token, "test@test.com", "Jonh")
assert email.from == {config[:name], config[:notify_email]}
assert email.subject == "Invitation to Pleroma"
assert email.to == [{"Jonh", "test@test.com"}]
assert email.html_body =~
- Router.Helpers.redirect_url(Endpoint, :registration_page, token.token)
+ Router.Helpers.frontend_url(Endpoint, :registration_page, token.token)
end
test "build account confirmation email" do
config = Pleroma.Config.get(:instance)
user = insert(:user, confirmation_token: "conf-token")
email = UserEmail.account_confirmation_email(user)
assert email.from == {config[:name], config[:notify_email]}
assert email.to == [{user.name, user.email}]
assert email.subject == "#{config[:name]} account confirmation"
assert email.html_body =~
Router.Helpers.confirm_email_url(Endpoint, :confirm_email, user.id, "conf-token")
end
end
diff --git a/test/web/fallback_test.exs b/test/web/controllers/frontend/pleroma_controller_test.exs
similarity index 92%
rename from test/web/fallback_test.exs
rename to test/web/controllers/frontend/pleroma_controller_test.exs
index a65865860..7c91d4581 100644
--- a/test/web/fallback_test.exs
+++ b/test/web/controllers/frontend/pleroma_controller_test.exs
@@ -1,80 +1,76 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.FallbackTest do
+defmodule Pleroma.Web.Frontend.PleromaControllerTest do
use Pleroma.Web.ConnCase
import Pleroma.Factory
+ test "GET /pleroma/admin -> /pleroma/admin/", %{conn: conn} do
+ assert redirected_to(get(conn, "/pleroma/admin")) =~ "/pleroma/admin/"
+ end
+
describe "neither preloaded data nor metadata attached to" do
test "GET /registration/:token", %{conn: conn} do
response = get(conn, "/registration/foo")
assert html_response(response, 200) =~ "<!--server-generated-meta-->"
end
test "GET /*path", %{conn: conn} do
assert conn
|> get("/foo")
|> html_response(200) =~ "<!--server-generated-meta-->"
end
end
describe "preloaded data and metadata attached to" do
test "GET /:maybe_nickname_or_id", %{conn: conn} do
user = insert(:user)
user_missing = get(conn, "/foo")
user_present = get(conn, "/#{user.nickname}")
assert(html_response(user_missing, 200) =~ "<!--server-generated-meta-->")
refute html_response(user_present, 200) =~ "<!--server-generated-meta-->"
assert html_response(user_present, 200) =~ "initial-results"
end
test "GET /*path", %{conn: conn} do
assert conn
|> get("/foo")
|> html_response(200) =~ "<!--server-generated-meta-->"
refute conn
|> get("/foo/bar")
|> html_response(200) =~ "<!--server-generated-meta-->"
end
end
describe "preloaded data is attached to" do
test "GET /main/public", %{conn: conn} do
public_page = get(conn, "/main/public")
refute html_response(public_page, 200) =~ "<!--server-generated-meta-->"
assert html_response(public_page, 200) =~ "initial-results"
end
test "GET /main/all", %{conn: conn} do
public_page = get(conn, "/main/all")
refute html_response(public_page, 200) =~ "<!--server-generated-meta-->"
assert html_response(public_page, 200) =~ "initial-results"
end
end
test "GET /api*path", %{conn: conn} do
assert conn
|> get("/api/foo")
|> json_response(404) == %{"error" => "Not implemented"}
end
- test "GET /pleroma/admin -> /pleroma/admin/", %{conn: conn} do
- assert redirected_to(get(conn, "/pleroma/admin")) =~ "/pleroma/admin/"
- end
-
test "OPTIONS /*path", %{conn: conn} do
assert conn
|> options("/foo")
|> response(204) == ""
assert conn
|> options("/foo/bar")
|> response(204) == ""
end
end
diff --git a/test/web/feed/user_controller_test.exs b/test/web/feed/user_controller_test.exs
index fa2ed1ea5..5bbb90eb4 100644
--- a/test/web/feed/user_controller_test.exs
+++ b/test/web/feed/user_controller_test.exs
@@ -1,238 +1,240 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Feed.UserControllerTest do
use Pleroma.Web.ConnCase
import Pleroma.Factory
import SweetXml
alias Pleroma.Config
alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Web.CommonAPI
setup do: clear_config([:instance, :federating], true)
describe "feed" do
setup do: clear_config([:feed])
test "gets an atom feed", %{conn: conn} do
Config.put(
[:feed, :post_title],
%{max_length: 10, omission: "..."}
)
activity = insert(:note_activity)
note =
insert(:note,
data: %{
"content" => "This is :moominmamma: note ",
"attachment" => [
%{
"url" => [
%{"mediaType" => "image/png", "href" => "https://pleroma.gov/image.png"}
]
}
],
"inReplyTo" => activity.data["id"]
}
)
note_activity = insert(:note_activity, note: note)
user = User.get_cached_by_ap_id(note_activity.data["actor"])
note2 =
insert(:note,
user: user,
data: %{
"content" => "42 This is :moominmamma: note ",
"inReplyTo" => activity.data["id"]
}
)
note_activity2 = insert(:note_activity, note: note2)
object = Object.normalize(note_activity)
resp =
conn
|> put_req_header("accept", "application/atom+xml")
|> get(user_feed_path(conn, :feed, user.nickname))
|> response(200)
activity_titles =
resp
|> SweetXml.parse()
|> SweetXml.xpath(~x"//entry/title/text()"l)
assert activity_titles == ['42 This...', 'This is...']
assert resp =~ object.data["content"]
resp =
conn
|> put_req_header("accept", "application/atom+xml")
|> get("/users/#{user.nickname}/feed", %{"max_id" => note_activity2.id})
|> response(200)
activity_titles =
resp
|> SweetXml.parse()
|> SweetXml.xpath(~x"//entry/title/text()"l)
assert activity_titles == ['This is...']
end
test "gets a rss feed", %{conn: conn} do
Pleroma.Config.put(
[:feed, :post_title],
%{max_length: 10, omission: "..."}
)
activity = insert(:note_activity)
note =
insert(:note,
data: %{
"content" => "This is :moominmamma: note ",
"attachment" => [
%{
"url" => [
%{"mediaType" => "image/png", "href" => "https://pleroma.gov/image.png"}
]
}
],
"inReplyTo" => activity.data["id"]
}
)
note_activity = insert(:note_activity, note: note)
user = User.get_cached_by_ap_id(note_activity.data["actor"])
note2 =
insert(:note,
user: user,
data: %{
"content" => "42 This is :moominmamma: note ",
"inReplyTo" => activity.data["id"]
}
)
note_activity2 = insert(:note_activity, note: note2)
object = Object.normalize(note_activity)
resp =
conn
|> put_req_header("accept", "application/rss+xml")
|> get("/users/#{user.nickname}/feed.rss")
|> response(200)
activity_titles =
resp
|> SweetXml.parse()
|> SweetXml.xpath(~x"//item/title/text()"l)
assert activity_titles == ['42 This...', 'This is...']
assert resp =~ object.data["content"]
resp =
conn
|> put_req_header("accept", "application/rss+xml")
|> get("/users/#{user.nickname}/feed.rss", %{"max_id" => note_activity2.id})
|> response(200)
activity_titles =
resp
|> SweetXml.parse()
|> SweetXml.xpath(~x"//item/title/text()"l)
assert activity_titles == ['This is...']
end
test "returns 404 for a missing feed", %{conn: conn} do
conn =
conn
|> put_req_header("accept", "application/atom+xml")
|> get(user_feed_path(conn, :feed, "nonexisting"))
assert response(conn, 404)
end
test "returns feed with public and unlisted activities", %{conn: conn} do
user = insert(:user)
{:ok, _} = CommonAPI.post(user, %{status: "public", visibility: "public"})
{:ok, _} = CommonAPI.post(user, %{status: "direct", visibility: "direct"})
{:ok, _} = CommonAPI.post(user, %{status: "unlisted", visibility: "unlisted"})
{:ok, _} = CommonAPI.post(user, %{status: "private", visibility: "private"})
resp =
conn
|> put_req_header("accept", "application/atom+xml")
|> get(user_feed_path(conn, :feed, user.nickname))
|> response(200)
activity_titles =
resp
|> SweetXml.parse()
|> SweetXml.xpath(~x"//entry/title/text()"l)
|> Enum.sort()
assert activity_titles == ['public', 'unlisted']
end
end
# Note: see ActivityPubControllerTest for JSON format tests
describe "feed_redirect" do
test "with html format, it redirects to user feed", %{conn: conn} do
note_activity = insert(:note_activity)
user = User.get_cached_by_ap_id(note_activity.data["actor"])
response =
conn
|> get("/users/#{user.nickname}")
|> response(200)
- assert response ==
- Fallback.RedirectController.redirector_with_meta(
- conn,
- %{user: user}
- ).resp_body
+ expected =
+ conn
+ |> Map.put(:params, %{user: user})
+ |> Pleroma.Web.FrontendController.call(:redirector_with_meta)
+ |> Map.get(:resp_body)
+
+ assert response == expected
end
test "with html format, it returns error when user is not found", %{conn: conn} do
response =
conn
|> get("/users/jimm")
|> json_response(404)
assert response == %{"error" => "Not found"}
end
test "with non-html / non-json format, it redirects to user feed in atom format", %{
conn: conn
} do
note_activity = insert(:note_activity)
user = User.get_cached_by_ap_id(note_activity.data["actor"])
conn =
conn
|> put_req_header("accept", "application/xml")
|> get("/users/#{user.nickname}")
assert conn.status == 302
assert redirected_to(conn) == "#{Pleroma.Web.base_url()}/users/#{user.nickname}/feed.atom"
end
test "with non-html / non-json format, it returns error when user is not found", %{conn: conn} do
response =
conn
|> put_req_header("accept", "application/xml")
|> get(user_feed_path(conn, :feed, "jimm"))
|> response(404)
assert response == ~S({"error":"Not found"})
end
end
end

File Metadata

Mime Type
text/x-diff
Expires
Sun, Aug 9, 4:52 AM (1 d, 13 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1724224
Default Alt Text
(72 KB)

Event Timeline