Merge branch 'develop' into feature/matstodon-statuses-by-name
This commit is contained in:
commit
9169f331b6
59 changed files with 1184 additions and 191 deletions
|
|
@ -140,6 +140,11 @@ defmodule Pleroma.Application do
|
|||
id: :federator_init,
|
||||
start: {Task, :start_link, [&Pleroma.Web.Federator.init/0]},
|
||||
restart: :temporary
|
||||
},
|
||||
%{
|
||||
id: :internal_fetch_init,
|
||||
start: {Task, :start_link, [&Pleroma.Web.ActivityPub.InternalFetchActor.init/0]},
|
||||
restart: :temporary
|
||||
}
|
||||
] ++
|
||||
streamer_child() ++
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ defmodule Pleroma.Object.Fetcher do
|
|||
alias Pleroma.HTTP
|
||||
alias Pleroma.Object
|
||||
alias Pleroma.Object.Containment
|
||||
alias Pleroma.Signature
|
||||
alias Pleroma.Web.ActivityPub.InternalFetchActor
|
||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||
alias Pleroma.Web.OStatus
|
||||
|
||||
|
|
@ -82,15 +84,52 @@ defmodule Pleroma.Object.Fetcher do
|
|||
end
|
||||
end
|
||||
|
||||
defp make_signature(id, date) do
|
||||
uri = URI.parse(id)
|
||||
|
||||
signature =
|
||||
InternalFetchActor.get_actor()
|
||||
|> Signature.sign(%{
|
||||
"(request-target)": "get #{uri.path}",
|
||||
host: uri.host,
|
||||
date: date
|
||||
})
|
||||
|
||||
[{:Signature, signature}]
|
||||
end
|
||||
|
||||
defp sign_fetch(headers, id, date) do
|
||||
if Pleroma.Config.get([:activitypub, :sign_object_fetches]) do
|
||||
headers ++ make_signature(id, date)
|
||||
else
|
||||
headers
|
||||
end
|
||||
end
|
||||
|
||||
defp maybe_date_fetch(headers, date) do
|
||||
if Pleroma.Config.get([:activitypub, :sign_object_fetches]) do
|
||||
headers ++ [{:Date, date}]
|
||||
else
|
||||
headers
|
||||
end
|
||||
end
|
||||
|
||||
def fetch_and_contain_remote_object_from_id(id) do
|
||||
Logger.info("Fetching object #{id} via AP")
|
||||
|
||||
date =
|
||||
NaiveDateTime.utc_now()
|
||||
|> Timex.format!("{WDshort}, {0D} {Mshort} {YYYY} {h24}:{m}:{s} GMT")
|
||||
|
||||
headers =
|
||||
[{:Accept, "application/activity+json"}]
|
||||
|> maybe_date_fetch(date)
|
||||
|> sign_fetch(id, date)
|
||||
|
||||
Logger.debug("Fetch headers: #{inspect(headers)}")
|
||||
|
||||
with true <- String.starts_with?(id, "http"),
|
||||
{:ok, %{body: body, status: code}} when code in 200..299 <-
|
||||
HTTP.get(
|
||||
id,
|
||||
[{:Accept, "application/activity+json"}]
|
||||
),
|
||||
{:ok, %{body: body, status: code}} when code in 200..299 <- HTTP.get(id, headers),
|
||||
{:ok, data} <- Jason.decode(body),
|
||||
:ok <- Containment.contain_origin_from_id(id, data) do
|
||||
{:ok, data}
|
||||
|
|
|
|||
|
|
@ -8,22 +8,19 @@ defmodule Pleroma.Plugs.AuthenticationPlug do
|
|||
alias Pleroma.User
|
||||
require Logger
|
||||
|
||||
def init(options) do
|
||||
options
|
||||
def init(options), do: options
|
||||
|
||||
def checkpw(password, "$6" <> _ = password_hash) do
|
||||
:crypt.crypt(password, password_hash) == password_hash
|
||||
end
|
||||
|
||||
def checkpw(password, password_hash) do
|
||||
cond do
|
||||
String.starts_with?(password_hash, "$pbkdf2") ->
|
||||
Pbkdf2.checkpw(password, password_hash)
|
||||
def checkpw(password, "$pbkdf2" <> _ = password_hash) do
|
||||
Pbkdf2.checkpw(password, password_hash)
|
||||
end
|
||||
|
||||
String.starts_with?(password_hash, "$6") ->
|
||||
:crypt.crypt(password, password_hash) == password_hash
|
||||
|
||||
true ->
|
||||
Logger.error("Password hash not recognized")
|
||||
false
|
||||
end
|
||||
def checkpw(_password, _password_hash) do
|
||||
Logger.error("Password hash not recognized")
|
||||
false
|
||||
end
|
||||
|
||||
def call(%{assigns: %{user: %User{}}} = conn, _), do: conn
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do
|
||||
alias Pleroma.Web.ActivityPub.Utils
|
||||
import Plug.Conn
|
||||
require Logger
|
||||
|
||||
|
|
@ -16,38 +15,30 @@ defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do
|
|||
end
|
||||
|
||||
def call(conn, _opts) do
|
||||
user = Utils.get_ap_id(conn.params["actor"])
|
||||
Logger.debug("Checking sig for #{user}")
|
||||
[signature | _] = get_req_header(conn, "signature")
|
||||
|
||||
cond do
|
||||
signature && String.contains?(signature, user) ->
|
||||
# set (request-target) header to the appropriate value
|
||||
# we also replace the digest header with the one we computed
|
||||
conn =
|
||||
conn
|
||||
|> put_req_header(
|
||||
"(request-target)",
|
||||
String.downcase("#{conn.method}") <> " #{conn.request_path}"
|
||||
)
|
||||
|
||||
conn =
|
||||
if conn.assigns[:digest] do
|
||||
conn
|
||||
|> put_req_header("digest", conn.assigns[:digest])
|
||||
else
|
||||
conn
|
||||
end
|
||||
|
||||
assign(conn, :valid_signature, HTTPSignatures.validate_conn(conn))
|
||||
|
||||
signature ->
|
||||
Logger.debug("Signature not from actor")
|
||||
assign(conn, :valid_signature, false)
|
||||
|
||||
true ->
|
||||
Logger.debug("No signature header!")
|
||||
if signature do
|
||||
# set (request-target) header to the appropriate value
|
||||
# we also replace the digest header with the one we computed
|
||||
conn =
|
||||
conn
|
||||
|> put_req_header(
|
||||
"(request-target)",
|
||||
String.downcase("#{conn.method}") <> " #{conn.request_path}"
|
||||
)
|
||||
|
||||
conn =
|
||||
if conn.assigns[:digest] do
|
||||
conn
|
||||
|> put_req_header("digest", conn.assigns[:digest])
|
||||
else
|
||||
conn
|
||||
end
|
||||
|
||||
assign(conn, :valid_signature, HTTPSignatures.validate_conn(conn))
|
||||
else
|
||||
Logger.debug("No signature header!")
|
||||
conn
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
70
lib/pleroma/plugs/mapped_signature_to_identity_plug.ex
Normal file
70
lib/pleroma/plugs/mapped_signature_to_identity_plug.ex
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.Plugs.MappedSignatureToIdentityPlug do
|
||||
alias Pleroma.Signature
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.Utils
|
||||
|
||||
import Plug.Conn
|
||||
require Logger
|
||||
|
||||
def init(options), do: options
|
||||
|
||||
defp key_id_from_conn(conn) do
|
||||
with %{"keyId" => key_id} <- HTTPSignatures.signature_for_conn(conn) do
|
||||
Signature.key_id_to_actor_id(key_id)
|
||||
else
|
||||
_ ->
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
defp user_from_key_id(conn) do
|
||||
with key_actor_id when is_binary(key_actor_id) <- key_id_from_conn(conn),
|
||||
{:ok, %User{} = user} <- User.get_or_fetch_by_ap_id(key_actor_id) do
|
||||
user
|
||||
else
|
||||
_ ->
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def call(%{assigns: %{user: _}} = conn, _opts), do: conn
|
||||
|
||||
# if this has payload make sure it is signed by the same actor that made it
|
||||
def call(%{assigns: %{valid_signature: true}, params: %{"actor" => actor}} = conn, _opts) do
|
||||
with actor_id <- Utils.get_ap_id(actor),
|
||||
{:user, %User{} = user} <- {:user, user_from_key_id(conn)},
|
||||
{:user_match, true} <- {:user_match, user.ap_id == actor_id} do
|
||||
assign(conn, :user, user)
|
||||
else
|
||||
{:user_match, false} ->
|
||||
Logger.debug("Failed to map identity from signature (payload actor mismatch)")
|
||||
Logger.debug("key_id=#{key_id_from_conn(conn)}, actor=#{actor}")
|
||||
assign(conn, :valid_signature, false)
|
||||
|
||||
# remove me once testsuite uses mapped capabilities instead of what we do now
|
||||
{:user, nil} ->
|
||||
Logger.debug("Failed to map identity from signature (lookup failure)")
|
||||
Logger.debug("key_id=#{key_id_from_conn(conn)}, actor=#{actor}")
|
||||
conn
|
||||
end
|
||||
end
|
||||
|
||||
# no payload, probably a signed fetch
|
||||
def call(%{assigns: %{valid_signature: true}} = conn, _opts) do
|
||||
with %User{} = user <- user_from_key_id(conn) do
|
||||
assign(conn, :user, user)
|
||||
else
|
||||
_ ->
|
||||
Logger.debug("Failed to map identity from signature (no payload actor mismatch)")
|
||||
Logger.debug("key_id=#{key_id_from_conn(conn)}")
|
||||
assign(conn, :valid_signature, false)
|
||||
end
|
||||
end
|
||||
|
||||
# no signature at all
|
||||
def call(conn, _opts), do: conn
|
||||
end
|
||||
|
|
@ -8,10 +8,16 @@ defmodule Pleroma.Signature do
|
|||
alias Pleroma.Keys
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
alias Pleroma.Web.ActivityPub.Utils
|
||||
|
||||
def key_id_to_actor_id(key_id) do
|
||||
URI.parse(key_id)
|
||||
|> Map.put(:fragment, nil)
|
||||
|> URI.to_string()
|
||||
end
|
||||
|
||||
def fetch_public_key(conn) do
|
||||
with actor_id <- Utils.get_ap_id(conn.params["actor"]),
|
||||
with %{"keyId" => kid} <- HTTPSignatures.signature_for_conn(conn),
|
||||
actor_id <- key_id_to_actor_id(kid),
|
||||
{:ok, public_key} <- User.get_public_key_for_ap_id(actor_id) do
|
||||
{:ok, public_key}
|
||||
else
|
||||
|
|
@ -21,7 +27,8 @@ defmodule Pleroma.Signature do
|
|||
end
|
||||
|
||||
def refetch_public_key(conn) do
|
||||
with actor_id <- Utils.get_ap_id(conn.params["actor"]),
|
||||
with %{"keyId" => kid} <- HTTPSignatures.signature_for_conn(conn),
|
||||
actor_id <- key_id_to_actor_id(kid),
|
||||
{:ok, _user} <- ActivityPub.make_user_from_ap_id(actor_id),
|
||||
{:ok, public_key} <- User.get_public_key_for_ap_id(actor_id) do
|
||||
{:ok, public_key}
|
||||
|
|
|
|||
|
|
@ -6,10 +6,19 @@ defmodule Pleroma.Upload.Filter.Dedupe do
|
|||
@behaviour Pleroma.Upload.Filter
|
||||
alias Pleroma.Upload
|
||||
|
||||
def filter(%Upload{name: name} = upload) do
|
||||
extension = String.split(name, ".") |> List.last()
|
||||
shasum = :crypto.hash(:sha256, File.read!(upload.tempfile)) |> Base.encode16(case: :lower)
|
||||
def filter(%Upload{name: name, tempfile: tempfile} = upload) do
|
||||
extension =
|
||||
name
|
||||
|> String.split(".")
|
||||
|> List.last()
|
||||
|
||||
shasum =
|
||||
:crypto.hash(:sha256, File.read!(tempfile))
|
||||
|> Base.encode16(case: :lower)
|
||||
|
||||
filename = shasum <> "." <> extension
|
||||
{:ok, %Upload{upload | id: shasum, path: filename}}
|
||||
end
|
||||
|
||||
def filter(_), do: :ok
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
defmodule Pleroma.Upload.Filter.Mogrifun do
|
||||
@behaviour Pleroma.Upload.Filter
|
||||
alias Pleroma.Upload.Filter
|
||||
|
||||
@filters [
|
||||
{"implode", "1"},
|
||||
|
|
@ -34,31 +35,10 @@ defmodule Pleroma.Upload.Filter.Mogrifun do
|
|||
]
|
||||
|
||||
def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _}) do
|
||||
filter = Enum.random(@filters)
|
||||
|
||||
file
|
||||
|> Mogrify.open()
|
||||
|> mogrify_filter(filter)
|
||||
|> Mogrify.save(in_place: true)
|
||||
Filter.Mogrify.do_filter(file, [Enum.random(@filters)])
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
def filter(_), do: :ok
|
||||
|
||||
defp mogrify_filter(mogrify, [filter | rest]) do
|
||||
mogrify
|
||||
|> mogrify_filter(filter)
|
||||
|> mogrify_filter(rest)
|
||||
end
|
||||
|
||||
defp mogrify_filter(mogrify, []), do: mogrify
|
||||
|
||||
defp mogrify_filter(mogrify, {action, options}) do
|
||||
Mogrify.custom(mogrify, action, options)
|
||||
end
|
||||
|
||||
defp mogrify_filter(mogrify, string) when is_binary(string) do
|
||||
Mogrify.custom(mogrify, string)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -11,16 +11,19 @@ defmodule Pleroma.Upload.Filter.Mogrify do
|
|||
def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _}) do
|
||||
filters = Pleroma.Config.get!([__MODULE__, :args])
|
||||
|
||||
file
|
||||
|> Mogrify.open()
|
||||
|> mogrify_filter(filters)
|
||||
|> Mogrify.save(in_place: true)
|
||||
|
||||
do_filter(file, filters)
|
||||
:ok
|
||||
end
|
||||
|
||||
def filter(_), do: :ok
|
||||
|
||||
def do_filter(file, filters) do
|
||||
file
|
||||
|> Mogrify.open()
|
||||
|> mogrify_filter(filters)
|
||||
|> Mogrify.save(in_place: true)
|
||||
end
|
||||
|
||||
defp mogrify_filter(mogrify, nil), do: mogrify
|
||||
|
||||
defp mogrify_filter(mogrify, [filter | rest]) do
|
||||
|
|
|
|||
|
|
@ -68,7 +68,14 @@ defmodule Pleroma.Uploaders.Uploader do
|
|||
{:error, error}
|
||||
end
|
||||
after
|
||||
30_000 -> {:error, dgettext("errors", "Uploader callback timeout")}
|
||||
callback_timeout() -> {:error, dgettext("errors", "Uploader callback timeout")}
|
||||
end
|
||||
end
|
||||
|
||||
defp callback_timeout do
|
||||
case Mix.env() do
|
||||
:test -> 1_000
|
||||
_ -> 30_000
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1157,19 +1157,18 @@ defmodule Pleroma.User do
|
|||
end
|
||||
end
|
||||
|
||||
def get_or_create_instance_user do
|
||||
relay_uri = "#{Pleroma.Web.Endpoint.url()}/relay"
|
||||
|
||||
if user = get_cached_by_ap_id(relay_uri) do
|
||||
@doc "Creates an internal service actor by URI if missing. Optionally takes nickname for addressing."
|
||||
def get_or_create_service_actor_by_ap_id(uri, nickname \\ nil) do
|
||||
if user = get_cached_by_ap_id(uri) do
|
||||
user
|
||||
else
|
||||
changes =
|
||||
%User{info: %User.Info{}}
|
||||
|> cast(%{}, [:ap_id, :nickname, :local])
|
||||
|> put_change(:ap_id, relay_uri)
|
||||
|> put_change(:nickname, nil)
|
||||
|> put_change(:ap_id, uri)
|
||||
|> put_change(:nickname, nickname)
|
||||
|> put_change(:local, true)
|
||||
|> put_change(:follower_address, relay_uri <> "/followers")
|
||||
|> put_change(:follower_address, uri <> "/followers")
|
||||
|
||||
{:ok, user} = Repo.insert(changes)
|
||||
user
|
||||
|
|
@ -1411,4 +1410,8 @@ defmodule Pleroma.User do
|
|||
end
|
||||
|
||||
defp put_password_hash(changeset), do: changeset
|
||||
|
||||
def is_internal_user?(%User{nickname: nil}), do: true
|
||||
def is_internal_user?(%User{local: true, nickname: "internal." <> _}), do: true
|
||||
def is_internal_user?(_), do: false
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
|||
alias Pleroma.Object.Fetcher
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||
alias Pleroma.Web.ActivityPub.InternalFetchActor
|
||||
alias Pleroma.Web.ActivityPub.ObjectView
|
||||
alias Pleroma.Web.ActivityPub.Relay
|
||||
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||
|
|
@ -206,9 +207,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
|||
json(conn, dgettext("errors", "error"))
|
||||
end
|
||||
|
||||
def relay(conn, _params) do
|
||||
with %User{} = user <- Relay.get_actor(),
|
||||
{:ok, user} <- User.ensure_keys_present(user) do
|
||||
defp represent_service_actor(%User{} = user, conn) do
|
||||
with {:ok, user} <- User.ensure_keys_present(user) do
|
||||
conn
|
||||
|> put_resp_header("content-type", "application/activity+json")
|
||||
|> json(UserView.render("user.json", %{user: user}))
|
||||
|
|
@ -217,6 +217,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
|||
end
|
||||
end
|
||||
|
||||
defp represent_service_actor(nil, _), do: {:error, :not_found}
|
||||
|
||||
def relay(conn, _params) do
|
||||
Relay.get_actor()
|
||||
|> represent_service_actor(conn)
|
||||
end
|
||||
|
||||
def internal_fetch(conn, _params) do
|
||||
InternalFetchActor.get_actor()
|
||||
|> represent_service_actor(conn)
|
||||
end
|
||||
|
||||
def whoami(%{assigns: %{user: %User{} = user}} = conn, _params) do
|
||||
conn
|
||||
|> put_resp_header("content-type", "application/activity+json")
|
||||
|
|
|
|||
20
lib/pleroma/web/activity_pub/internal_fetch_actor.ex
Normal file
20
lib/pleroma/web/activity_pub/internal_fetch_actor.ex
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.InternalFetchActor do
|
||||
alias Pleroma.User
|
||||
|
||||
require Logger
|
||||
|
||||
def init do
|
||||
# Wait for everything to settle.
|
||||
Process.sleep(1000 * 5)
|
||||
get_actor()
|
||||
end
|
||||
|
||||
def get_actor do
|
||||
"#{Pleroma.Web.Endpoint.url()}/internal/fetch"
|
||||
|> User.get_or_create_service_actor_by_ap_id("internal.fetch")
|
||||
end
|
||||
end
|
||||
24
lib/pleroma/web/activity_pub/mrf/mention_policy.ex
Normal file
24
lib/pleroma/web/activity_pub/mrf/mention_policy.ex
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# Pleroma: A lightweight social networking server
|
||||
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicy do
|
||||
@moduledoc "Block messages which mention a user"
|
||||
|
||||
@behaviour Pleroma.Web.ActivityPub.MRF
|
||||
|
||||
@impl true
|
||||
def filter(%{"type" => "Create"} = message) do
|
||||
reject_actors = Pleroma.Config.get([:mrf_mention, :actors], [])
|
||||
recipients = (message["to"] || []) ++ (message["cc"] || [])
|
||||
|
||||
if Enum.any?(recipients, fn recipient -> Enum.member?(reject_actors, recipient) end) do
|
||||
{:reject, nil}
|
||||
else
|
||||
{:ok, message}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def filter(message), do: {:ok, message}
|
||||
end
|
||||
|
|
@ -131,7 +131,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|
|||
%User{ap_id: ap_id} =
|
||||
Enum.find(recipients, fn %{info: %{source_data: data}} -> data["inbox"] == inbox end)
|
||||
|
||||
# Get all the recipients on the same host and add them to cc. Otherwise it a remote
|
||||
# Get all the recipients on the same host and add them to cc. Otherwise, a remote
|
||||
# instance would only accept a first message for the first recipient and ignore the rest.
|
||||
cc = get_cc_ap_ids(ap_id, recipients)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ defmodule Pleroma.Web.ActivityPub.Relay do
|
|||
require Logger
|
||||
|
||||
def get_actor do
|
||||
User.get_or_create_instance_user()
|
||||
"#{Pleroma.Web.Endpoint.url()}/relay"
|
||||
|> User.get_or_create_service_actor_by_ap_id()
|
||||
end
|
||||
|
||||
def follow(target_instance) do
|
||||
|
|
|
|||
|
|
@ -31,8 +31,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
|
||||
def render("endpoints.json", _), do: %{}
|
||||
|
||||
# the instance itself is not a Person, but instead an Application
|
||||
def render("user.json", %{user: %{nickname: nil} = user}) do
|
||||
def render("service.json", %{user: user}) do
|
||||
{:ok, user} = User.ensure_keys_present(user)
|
||||
{:ok, _, public_key} = Keys.keys_from_pem(user.info.keys)
|
||||
public_key = :public_key.pem_entry_encode(:SubjectPublicKeyInfo, public_key)
|
||||
|
|
@ -47,7 +46,8 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
"followers" => "#{user.ap_id}/followers",
|
||||
"inbox" => "#{user.ap_id}/inbox",
|
||||
"name" => "Pleroma",
|
||||
"summary" => "Virtual actor for Pleroma relay",
|
||||
"summary" =>
|
||||
"An internal service actor for this Pleroma instance. No user-serviceable parts inside.",
|
||||
"url" => user.ap_id,
|
||||
"manuallyApprovesFollowers" => false,
|
||||
"publicKey" => %{
|
||||
|
|
@ -60,6 +60,13 @@ defmodule Pleroma.Web.ActivityPub.UserView do
|
|||
|> Map.merge(Utils.make_json_ld_header())
|
||||
end
|
||||
|
||||
# the instance itself is not a Person, but instead an Application
|
||||
def render("user.json", %{user: %User{nickname: nil} = user}),
|
||||
do: render("service.json", %{user: user})
|
||||
|
||||
def render("user.json", %{user: %User{nickname: "internal." <> _} = user}),
|
||||
do: render("service.json", %{user: user})
|
||||
|
||||
def render("user.json", %{user: user}) do
|
||||
{:ok, user} = User.ensure_keys_present(user)
|
||||
{:ok, _, public_key} = Keys.keys_from_pem(user.info.keys)
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
|
||||
require Logger
|
||||
|
||||
@rate_limited_relations_actions ~w(follow unfollow)a
|
||||
|
||||
@rate_limited_status_actions ~w(reblog_status unreblog_status fav_status unfav_status
|
||||
post_status delete_status)a
|
||||
|
||||
|
|
@ -62,9 +64,16 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
when action in ~w(fav_status unfav_status)a
|
||||
)
|
||||
|
||||
plug(
|
||||
RateLimiter,
|
||||
{:relations_id_action, params: ["id", "uri"]} when action in @rate_limited_relations_actions
|
||||
)
|
||||
|
||||
plug(RateLimiter, :relations_actions when action in @rate_limited_relations_actions)
|
||||
plug(RateLimiter, :statuses_actions when action in @rate_limited_status_actions)
|
||||
plug(RateLimiter, :app_account_creation when action == :account_register)
|
||||
plug(RateLimiter, :search when action in [:search, :search2, :account_search])
|
||||
plug(RateLimiter, :password_reset when action == :password_reset)
|
||||
|
||||
@local_mastodon_name "Mastodon-Local"
|
||||
|
||||
|
|
@ -1808,6 +1817,22 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|
|||
end
|
||||
end
|
||||
|
||||
def password_reset(conn, params) do
|
||||
nickname_or_email = params["email"] || params["nickname"]
|
||||
|
||||
with {:ok, _} <- TwitterAPI.password_reset(nickname_or_email) do
|
||||
conn
|
||||
|> put_status(:no_content)
|
||||
|> json("")
|
||||
else
|
||||
{:error, "unknown user"} ->
|
||||
send_resp(conn, :not_found, "")
|
||||
|
||||
{:error, _} ->
|
||||
send_resp(conn, :bad_request, "")
|
||||
end
|
||||
end
|
||||
|
||||
def try_render(conn, target, params)
|
||||
when is_binary(target) do
|
||||
case render(conn, target, params) do
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
|||
following: User.following?(user, target),
|
||||
followed_by: User.following?(target, user),
|
||||
blocking: User.blocks?(user, target),
|
||||
blocked_by: User.blocks?(target, user),
|
||||
muting: User.mutes?(user, target),
|
||||
muting_notifications: User.muted_notifications?(user, target),
|
||||
subscribing: User.subscribed_to?(user, target),
|
||||
|
|
@ -136,6 +137,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
|||
|> maybe_put_notification_settings(user, opts[:for])
|
||||
|> maybe_put_settings_store(user, opts[:for], opts)
|
||||
|> maybe_put_chat_token(user, opts[:for], opts)
|
||||
|> maybe_put_activation_status(user, opts[:for])
|
||||
end
|
||||
|
||||
defp username_from_nickname(string) when is_binary(string) do
|
||||
|
|
@ -196,6 +198,12 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
|
|||
|
||||
defp maybe_put_notification_settings(data, _, _), do: data
|
||||
|
||||
defp maybe_put_activation_status(data, user, %User{info: %{is_admin: true}}) do
|
||||
Kernel.put_in(data, [:pleroma, :deactivated], user.info.deactivated)
|
||||
end
|
||||
|
||||
defp maybe_put_activation_status(data, _, _), do: data
|
||||
|
||||
defp image_url(%{"url" => [%{"href" => href} | _]}), do: href
|
||||
defp image_url(_), do: nil
|
||||
end
|
||||
|
|
|
|||
|
|
@ -382,7 +382,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
|
|||
%{
|
||||
# Mastodon uses separate ids for polls, but an object can't have
|
||||
# more than one poll embedded so object id is fine
|
||||
id: object.id,
|
||||
id: to_string(object.id),
|
||||
expires_at: Utils.to_masto_date(end_time),
|
||||
expired: expired,
|
||||
multiple: multiple,
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyController do
|
|||
def filename_matches(%{"filename" => _} = _, path, url) do
|
||||
filename = MediaProxy.filename(url)
|
||||
|
||||
if filename && Path.basename(path) != filename do
|
||||
if filename && does_not_match(path, filename) do
|
||||
{:wrong_filename, filename}
|
||||
else
|
||||
:ok
|
||||
|
|
@ -38,4 +38,9 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyController do
|
|||
end
|
||||
|
||||
def filename_matches(_, _, _), do: :ok
|
||||
|
||||
defp does_not_match(path, filename) do
|
||||
basename = Path.basename(path)
|
||||
basename != filename and URI.decode(basename) != filename and URI.encode(basename) != filename
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -586,7 +586,7 @@ defmodule Pleroma.Web.Router do
|
|||
end
|
||||
end
|
||||
|
||||
pipeline :ap_relay do
|
||||
pipeline :ap_service_actor do
|
||||
plug(:accepts, ["activity+json", "json"])
|
||||
end
|
||||
|
||||
|
|
@ -617,6 +617,7 @@ defmodule Pleroma.Web.Router do
|
|||
pipeline :activitypub do
|
||||
plug(:accepts, ["activity+json", "json"])
|
||||
plug(Pleroma.Web.Plugs.HTTPSignaturePlug)
|
||||
plug(Pleroma.Web.Plugs.MappedSignatureToIdentityPlug)
|
||||
end
|
||||
|
||||
scope "/", Pleroma.Web.ActivityPub do
|
||||
|
|
@ -663,8 +664,17 @@ defmodule Pleroma.Web.Router do
|
|||
end
|
||||
|
||||
scope "/relay", Pleroma.Web.ActivityPub do
|
||||
pipe_through(:ap_relay)
|
||||
pipe_through(:ap_service_actor)
|
||||
|
||||
get("/", ActivityPubController, :relay)
|
||||
post("/inbox", ActivityPubController, :inbox)
|
||||
end
|
||||
|
||||
scope "/internal/fetch", Pleroma.Web.ActivityPub do
|
||||
pipe_through(:ap_service_actor)
|
||||
|
||||
get("/", ActivityPubController, :internal_fetch)
|
||||
post("/inbox", ActivityPubController, :inbox)
|
||||
end
|
||||
|
||||
scope "/", Pleroma.Web.ActivityPub do
|
||||
|
|
@ -691,6 +701,8 @@ defmodule Pleroma.Web.Router do
|
|||
get("/web/login", MastodonAPIController, :login)
|
||||
delete("/auth/sign_out", MastodonAPIController, :logout)
|
||||
|
||||
post("/auth/password", MastodonAPIController, :password_reset)
|
||||
|
||||
scope [] do
|
||||
pipe_through(:oauth_read_or_public)
|
||||
get("/web/*path", MastodonAPIController, :index)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|
|||
require Logger
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.Config
|
||||
alias Pleroma.Emoji
|
||||
alias Pleroma.Healthcheck
|
||||
alias Pleroma.Notification
|
||||
alias Pleroma.Plugs.AuthenticationPlug
|
||||
alias Pleroma.User
|
||||
|
|
@ -23,7 +25,8 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|
|||
end
|
||||
|
||||
def remote_subscribe(conn, %{"nickname" => nick, "profile" => _}) do
|
||||
with %User{} = user <- User.get_cached_by_nickname(nick), avatar = User.avatar_url(user) do
|
||||
with %User{} = user <- User.get_cached_by_nickname(nick),
|
||||
avatar = User.avatar_url(user) do
|
||||
conn
|
||||
|> render("subscribe.html", %{nickname: nick, avatar: avatar, error: false})
|
||||
else
|
||||
|
|
@ -338,20 +341,21 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|
|||
end
|
||||
|
||||
def healthcheck(conn, _params) do
|
||||
info =
|
||||
if Pleroma.Config.get([:instance, :healthcheck]) do
|
||||
Pleroma.Healthcheck.system_info()
|
||||
else
|
||||
%{}
|
||||
end
|
||||
with true <- Config.get([:instance, :healthcheck]),
|
||||
%{healthy: true} = info <- Healthcheck.system_info() do
|
||||
json(conn, info)
|
||||
else
|
||||
%{healthy: false} = info ->
|
||||
service_unavailable(conn, info)
|
||||
|
||||
conn =
|
||||
if info[:healthy] do
|
||||
conn
|
||||
else
|
||||
Plug.Conn.put_status(conn, :service_unavailable)
|
||||
end
|
||||
_ ->
|
||||
service_unavailable(conn, %{})
|
||||
end
|
||||
end
|
||||
|
||||
json(conn, info)
|
||||
defp service_unavailable(conn, info) do
|
||||
conn
|
||||
|> put_status(:service_unavailable)
|
||||
|> json(info)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -221,6 +221,8 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
|
|||
user
|
||||
|> UserEmail.password_reset_email(token_record.token)
|
||||
|> Mailer.deliver_async()
|
||||
|
||||
{:ok, :enqueued}
|
||||
else
|
||||
false ->
|
||||
{:error, "bad user identifier"}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
|
|||
|
||||
require Logger
|
||||
|
||||
plug(Pleroma.Plugs.RateLimiter, :password_reset when action == :password_reset)
|
||||
plug(:only_if_public_instance when action in [:public_timeline, :public_and_external_timeline])
|
||||
action_fallback(:errors)
|
||||
|
||||
|
|
@ -437,6 +438,12 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
|
|||
|
||||
with {:ok, _} <- TwitterAPI.password_reset(nickname_or_email) do
|
||||
json_response(conn, :no_content, "")
|
||||
else
|
||||
{:error, "unknown user"} ->
|
||||
send_resp(conn, :not_found, "")
|
||||
|
||||
{:error, _} ->
|
||||
send_resp(conn, :bad_request, "")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -11,10 +11,6 @@ defmodule Pleroma.Web.UploaderController do
|
|||
process_callback(conn, :global.whereis_name({Uploader, upload_path}), params)
|
||||
end
|
||||
|
||||
def callbacks(conn, _) do
|
||||
render_error(conn, :bad_request, "bad request")
|
||||
end
|
||||
|
||||
defp process_callback(conn, pid, params) when is_pid(pid) do
|
||||
send(pid, {Uploader, self(), conn, params})
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ defmodule Pleroma.Web.WebFinger do
|
|||
|
||||
def webfinger(resource, fmt) when fmt in ["XML", "JSON"] do
|
||||
host = Pleroma.Web.Endpoint.host()
|
||||
regex = ~r/(acct:)?(?<username>\w+)@#{host}/
|
||||
regex = ~r/(acct:)?(?<username>[a-z0-9A-Z_\.-]+)@#{host}/
|
||||
|
||||
with %{"username" => username} <- Regex.named_captures(regex, resource),
|
||||
%User{} = user <- User.get_cached_by_nickname(username) do
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue