aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/mix/tasks/deactivate_user.ex13
-rw-r--r--lib/mix/tasks/sample_psql.eex1
-rw-r--r--lib/pleroma/formatter.ex1
-rw-r--r--lib/pleroma/notification.ex3
-rw-r--r--lib/pleroma/plugs/http_signature.ex3
-rw-r--r--lib/pleroma/user.ex25
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub.ex90
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub_controller.ex2
-rw-r--r--lib/pleroma/web/activity_pub/mrf.ex24
-rw-r--r--lib/pleroma/web/activity_pub/mrf/drop_policy.ex2
-rw-r--r--lib/pleroma/web/activity_pub/mrf/noop_policy.ex3
-rw-r--r--lib/pleroma/web/activity_pub/mrf/simple_policy.ex2
-rw-r--r--lib/pleroma/web/activity_pub/transmogrifier.ex51
-rw-r--r--lib/pleroma/web/activity_pub/utils.ex81
-rw-r--r--lib/pleroma/web/common_api/common_api.ex10
-rw-r--r--lib/pleroma/web/common_api/utils.ex11
-rw-r--r--lib/pleroma/web/federator/federator.ex3
-rw-r--r--lib/pleroma/web/http_signatures/http_signatures.ex5
-rw-r--r--lib/pleroma/web/mastodon_api/mastodon_api_controller.ex24
-rw-r--r--lib/pleroma/web/ostatus/activity_representer.ex44
-rw-r--r--lib/pleroma/web/router.ex2
-rw-r--r--lib/pleroma/web/salmon/salmon.ex11
-rw-r--r--lib/pleroma/web/twitter_api/controllers/util_controller.ex12
-rw-r--r--lib/pleroma/web/twitter_api/representers/activity_representer.ex3
-rw-r--r--lib/pleroma/web/twitter_api/twitter_api.ex22
-rw-r--r--lib/pleroma/web/twitter_api/twitter_api_controller.ex12
-rw-r--r--lib/pleroma/web/twitter_api/views/activity_view.ex3
-rw-r--r--lib/pleroma/web/web_finger/web_finger.ex10
28 files changed, 401 insertions, 72 deletions
diff --git a/lib/mix/tasks/deactivate_user.ex b/lib/mix/tasks/deactivate_user.ex
new file mode 100644
index 000000000..96b3db6e4
--- /dev/null
+++ b/lib/mix/tasks/deactivate_user.ex
@@ -0,0 +1,13 @@
+defmodule Mix.Tasks.DeactivateUser do
+ use Mix.Task
+ alias Pleroma.User
+
+ @shortdoc "Toggle deactivation status for a user"
+ def run([nickname]) do
+ Mix.Task.run("app.start")
+
+ with user <- User.get_by_nickname(nickname) do
+ User.deactivate(user)
+ end
+ end
+end
diff --git a/lib/mix/tasks/sample_psql.eex b/lib/mix/tasks/sample_psql.eex
index 18e322efc..bc22f166c 100644
--- a/lib/mix/tasks/sample_psql.eex
+++ b/lib/mix/tasks/sample_psql.eex
@@ -6,3 +6,4 @@ ALTER DATABASE pleroma_dev OWNER TO pleroma;
\c pleroma_dev;
--Extensions made by ecto.migrate that need superuser access
CREATE EXTENSION IF NOT EXISTS citext;
+CREATE EXTENSION IF NOT EXISTS pg_trgm;
diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex
index 456416fbd..53e2c204f 100644
--- a/lib/pleroma/formatter.ex
+++ b/lib/pleroma/formatter.ex
@@ -160,6 +160,7 @@ defmodule Pleroma.Formatter do
links =
Regex.scan(@link_regex, text)
|> Enum.map(fn [url] -> {Ecto.UUID.generate(), url} end)
+ |> Enum.sort_by(fn {_, url} -> -String.length(url) end)
uuid_text =
links
diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex
index e26e49c8c..e0dcd9823 100644
--- a/lib/pleroma/notification.ex
+++ b/lib/pleroma/notification.ex
@@ -91,7 +91,8 @@ defmodule Pleroma.Notification do
# TODO move to sql, too.
def create_notification(%Activity{} = activity, %User{} = user) do
- unless User.blocks?(user, %{ap_id: activity.data["actor"]}) do
+ unless User.blocks?(user, %{ap_id: activity.data["actor"]}) or
+ user.ap_id == activity.data["actor"] do
notification = %Notification{user_id: user.id, activity: activity}
{:ok, notification} = Repo.insert(notification)
Pleroma.Web.Streamer.stream("user", notification)
diff --git a/lib/pleroma/plugs/http_signature.ex b/lib/pleroma/plugs/http_signature.ex
index efde652f5..2d0e10cad 100644
--- a/lib/pleroma/plugs/http_signature.ex
+++ b/lib/pleroma/plugs/http_signature.ex
@@ -1,5 +1,6 @@
defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do
alias Pleroma.Web.HTTPSignatures
+ alias Pleroma.Web.ActivityPub.Utils
import Plug.Conn
require Logger
@@ -12,7 +13,7 @@ defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do
end
def call(conn, _opts) do
- user = conn.params["actor"]
+ user = Utils.normalize_actor(conn.params["actor"])
Logger.debug("Checking sig for #{user}")
[signature | _] = get_req_header(conn, "signature")
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index 207674999..6a8129ac8 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -21,6 +21,7 @@ defmodule Pleroma.User do
field(:local, :boolean, default: true)
field(:info, :map, default: %{})
field(:follower_address, :string)
+ field(:search_distance, :float, virtual: true)
has_many(:notifications, Notification)
timestamps()
@@ -399,16 +400,24 @@ defmodule Pleroma.User do
User.get_or_fetch_by_nickname(query)
end
- q =
+ inner =
from(
u in User,
- where:
- fragment(
- "(to_tsvector('english', ?) || to_tsvector('english', ?)) @@ plainto_tsquery('english', ?)",
- u.nickname,
- u.name,
- ^query
- ),
+ select_merge: %{
+ search_distance:
+ fragment(
+ "? <-> (? || ?)",
+ ^query,
+ u.nickname,
+ u.name
+ )
+ }
+ )
+
+ q =
+ from(
+ s in subquery(inner),
+ order_by: s.search_distance,
limit: 20
)
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 4ce2e6052..f07e26afd 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -1,6 +1,6 @@
defmodule Pleroma.Web.ActivityPub.ActivityPub do
alias Pleroma.{Activity, Repo, Object, Upload, User, Notification}
- alias Pleroma.Web.ActivityPub.Transmogrifier
+ alias Pleroma.Web.ActivityPub.{Transmogrifier, MRF}
alias Pleroma.Web.WebFinger
alias Pleroma.Web.Federator
alias Pleroma.Web.OStatus
@@ -11,16 +11,29 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
@httpoison Application.get_env(:pleroma, :httpoison)
@instance Application.get_env(:pleroma, :instance)
- @rewrite_policy Keyword.get(@instance, :rewrite_policy)
def get_recipients(data) do
(data["to"] || []) ++ (data["cc"] || [])
end
+ defp check_actor_is_active(actor) do
+ if not is_nil(actor) do
+ with user <- User.get_cached_by_ap_id(actor),
+ nil <- user.info["deactivated"] do
+ :ok
+ else
+ _e -> :reject
+ end
+ else
+ :ok
+ end
+ end
+
def insert(map, local \\ true) when is_map(map) do
with nil <- Activity.get_by_ap_id(map["id"]),
map <- lazy_put_activity_defaults(map),
- {:ok, map} <- @rewrite_policy.filter(map),
+ :ok <- check_actor_is_active(map["actor"]),
+ {:ok, map} <- MRF.filter(map),
:ok <- insert_full_object(map) do
{:ok, activity} =
Repo.insert(%Activity{
@@ -127,11 +140,19 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
end
- def unlike(%User{} = actor, %Object{} = object) do
- with %Activity{} = activity <- get_existing_like(actor.ap_id, object),
- {:ok, _activity} <- Repo.delete(activity),
- {:ok, object} <- remove_like_from_object(activity, object) do
- {:ok, object}
+ def unlike(
+ %User{} = actor,
+ %Object{} = object,
+ activity_id \\ nil,
+ local \\ true
+ ) do
+ with %Activity{} = like_activity <- get_existing_like(actor.ap_id, object),
+ unlike_data <- make_unlike_data(actor, like_activity, activity_id),
+ {:ok, unlike_activity} <- insert(unlike_data, local),
+ {:ok, _activity} <- Repo.delete(like_activity),
+ {:ok, object} <- remove_like_from_object(like_activity, object),
+ :ok <- maybe_federate(unlike_activity) do
+ {:ok, unlike_activity, like_activity, object}
else
_e -> {:ok, object}
end
@@ -154,6 +175,24 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
end
+ def unannounce(
+ %User{} = actor,
+ %Object{} = object,
+ activity_id \\ nil,
+ local \\ true
+ ) do
+ with %Activity{} = announce_activity <- get_existing_announce(actor.ap_id, object),
+ unannounce_data <- make_unannounce_data(actor, announce_activity, activity_id),
+ {:ok, unannounce_activity} <- insert(unannounce_data, local),
+ :ok <- maybe_federate(unannounce_activity),
+ {:ok, _activity} <- Repo.delete(announce_activity),
+ {:ok, object} <- remove_announce_from_object(announce_activity, object) do
+ {:ok, unannounce_activity, announce_activity, object}
+ else
+ _e -> {:ok, object}
+ end
+ end
+
def follow(follower, followed, activity_id \\ nil, local \\ true) do
with data <- make_follow_data(follower, followed, activity_id),
{:ok, activity} <- insert(data, local),
@@ -221,11 +260,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
Repo.all(query)
end
- # TODO: Make this work properly with unlisted.
def fetch_public_activities(opts \\ %{}) do
q = fetch_activities_query(["https://www.w3.org/ns/activitystreams#Public"], opts)
q
+ |> restrict_unlisted()
|> Repo.all()
|> Enum.reverse()
end
@@ -254,6 +293,25 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp restrict_visibility(query, _visibility), do: query
+ def fetch_user_activities(user, reading_user, params \\ %{}) do
+ params =
+ params
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("actor_id", user.ap_id)
+ |> Map.put("whole_db", true)
+
+ recipients =
+ if reading_user do
+ ["https://www.w3.org/ns/activitystreams#Public"] ++
+ [reading_user.ap_id | reading_user.following]
+ else
+ ["https://www.w3.org/ns/activitystreams#Public"]
+ end
+
+ fetch_activities(recipients, params)
+ |> Enum.reverse()
+ end
+
defp restrict_since(query, %{"since_id" => since_id}) do
from(activity in query, where: activity.id > ^since_id)
end
@@ -356,6 +414,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp restrict_blocked(query, _), do: query
+ defp restrict_unlisted(query) do
+ from(
+ activity in query,
+ where:
+ fragment(
+ "not (coalesce(?->'cc', '{}'::jsonb) \\?| ?)",
+ activity.data,
+ ^["https://www.w3.org/ns/activitystreams#Public"]
+ )
+ )
+ end
+
def fetch_activities_query(recipients, opts \\ %{}) do
base_query =
from(
@@ -406,6 +476,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
"url" => [%{"href" => data["image"]["url"]}]
}
+ data = Transmogrifier.maybe_fix_user_object(data)
+
user_data = %{
ap_id: data["id"],
info: %{
diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
index 80aae4f0f..c7d50893f 100644
--- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
@@ -93,7 +93,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
Logger.info("Signature not from author, relayed message, fetching from source")
ActivityPub.fetch_object_from_id(params["object"]["id"])
else
- Logger.info("Signature error")
+ Logger.info("Signature error - make sure you are forwarding the HTTP Host header!")
Logger.info("Could not validate #{params["actor"]}")
Logger.info(inspect(conn.req_headers))
end
diff --git a/lib/pleroma/web/activity_pub/mrf.ex b/lib/pleroma/web/activity_pub/mrf.ex
new file mode 100644
index 000000000..0a4e2bf80
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/mrf.ex
@@ -0,0 +1,24 @@
+defmodule Pleroma.Web.ActivityPub.MRF do
+ @callback filter(Map.t()) :: {:ok | :reject, Map.t()}
+
+ def filter(object) do
+ get_policies()
+ |> Enum.reduce({:ok, object}, fn
+ policy, {:ok, object} ->
+ policy.filter(object)
+
+ _, error ->
+ error
+ end)
+ end
+
+ def get_policies() do
+ Application.get_env(:pleroma, :instance, [])
+ |> Keyword.get(:rewrite_policy, [])
+ |> get_policies()
+ end
+
+ defp get_policies(policy) when is_atom(policy), do: [policy]
+ defp get_policies(policies) when is_list(policies), do: policies
+ defp get_policies(_), do: []
+end
diff --git a/lib/pleroma/web/activity_pub/mrf/drop_policy.ex b/lib/pleroma/web/activity_pub/mrf/drop_policy.ex
index 4333bca28..811947943 100644
--- a/lib/pleroma/web/activity_pub/mrf/drop_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/drop_policy.ex
@@ -1,6 +1,8 @@
defmodule Pleroma.Web.ActivityPub.MRF.DropPolicy do
require Logger
+ @behaviour Pleroma.Web.ActivityPub.MRF
+ @impl true
def filter(object) do
Logger.info("REJECTING #{inspect(object)}")
{:reject, object}
diff --git a/lib/pleroma/web/activity_pub/mrf/noop_policy.ex b/lib/pleroma/web/activity_pub/mrf/noop_policy.ex
index 9dd3acb04..e26f60d26 100644
--- a/lib/pleroma/web/activity_pub/mrf/noop_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/noop_policy.ex
@@ -1,4 +1,7 @@
defmodule Pleroma.Web.ActivityPub.MRF.NoOpPolicy do
+ @behaviour Pleroma.Web.ActivityPub.MRF
+
+ @impl true
def filter(object) do
{:ok, object}
end
diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex
index d840d759d..8d770387d 100644
--- a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex
@@ -1,5 +1,6 @@
defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
alias Pleroma.User
+ @behaviour Pleroma.Web.ActivityPub.MRF
@mrf_policy Application.get_env(:pleroma, :mrf_simple)
@@ -69,6 +70,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
end
end
+ @impl true
def filter(object) do
actor_info = URI.parse(object["actor"])
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index 5f86f67cd..a31452a63 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -223,9 +223,45 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
end
+ def handle_incoming(
+ %{
+ "type" => "Undo",
+ "object" => %{"type" => "Announce", "object" => object_id},
+ "actor" => actor,
+ "id" => id
+ } = data
+ ) do
+ with %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
+ {:ok, object} <-
+ get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id),
+ {:ok, activity, _, _} <- ActivityPub.unannounce(actor, object, id, false) do
+ {:ok, activity}
+ else
+ e -> :error
+ end
+ end
+
+ def handle_incoming(
+ %{
+ "type" => "Undo",
+ "object" => %{"type" => "Like", "object" => object_id},
+ "actor" => actor,
+ "id" => id
+ } = data
+ ) do
+ with %User{} = actor <- User.get_or_fetch_by_ap_id(actor),
+ {:ok, object} <-
+ get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id),
+ {:ok, activity, _, _} <- ActivityPub.unlike(actor, object, id, false) do
+ {:ok, activity}
+ else
+ e -> :error
+ end
+ end
+
# TODO
# Accept
- # Undo
+ # Undo for non-Announce
def handle_incoming(_), do: :error
@@ -477,4 +513,17 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
Repo.delete_all(q)
end
end
+
+ def maybe_fix_user_url(data) do
+ if is_map(data["url"]) do
+ data = Map.put(data, "url", data["url"]["href"])
+ end
+
+ data
+ end
+
+ def maybe_fix_user_object(data) do
+ data
+ |> maybe_fix_user_url
+ end
end
diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex
index 7b2bf8fa7..937f032c3 100644
--- a/lib/pleroma/web/activity_pub/utils.ex
+++ b/lib/pleroma/web/activity_pub/utils.ex
@@ -5,6 +5,22 @@ defmodule Pleroma.Web.ActivityPub.Utils do
alias Ecto.{Changeset, UUID}
import Ecto.Query
+ # Some implementations send the actor URI as the actor field, others send the entire actor object,
+ # so figure out what the actor's URI is based on what we have.
+ def normalize_actor(actor) do
+ cond do
+ is_binary(actor) ->
+ actor
+
+ is_map(actor) ->
+ actor["id"]
+ end
+ end
+
+ def normalize_params(params) do
+ Map.put(params, "actor", normalize_actor(params["actor"]))
+ end
+
def make_json_ld_header do
%{
"@context" => [
@@ -238,6 +254,28 @@ defmodule Pleroma.Web.ActivityPub.Utils do
#### Announce-related helpers
@doc """
+ Retruns an existing announce activity if the notice has already been announced
+ """
+ def get_existing_announce(actor, %{data: %{"id" => id}}) do
+ query =
+ from(
+ activity in Activity,
+ where: fragment("(?)->>'actor' = ?", activity.data, ^actor),
+ # this is to use the index
+ where:
+ fragment(
+ "coalesce((?)->'object'->>'id', (?)->>'object') = ?",
+ activity.data,
+ activity.data,
+ ^id
+ ),
+ where: fragment("(?)->>'type' = 'Announce'", activity.data)
+ )
+
+ Repo.one(query)
+ end
+
+ @doc """
Make announce activity data for the given actor and object
"""
def make_announce_data(
@@ -257,12 +295,55 @@ defmodule Pleroma.Web.ActivityPub.Utils do
if activity_id, do: Map.put(data, "id", activity_id), else: data
end
+ @doc """
+ Make unannounce activity data for the given actor and object
+ """
+ def make_unannounce_data(
+ %User{ap_id: ap_id} = user,
+ %Activity{data: %{"context" => context}} = activity,
+ activity_id
+ ) do
+ data = %{
+ "type" => "Undo",
+ "actor" => ap_id,
+ "object" => activity.data,
+ "to" => [user.follower_address, activity.data["actor"]],
+ "cc" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "context" => context
+ }
+
+ if activity_id, do: Map.put(data, "id", activity_id), else: data
+ end
+
+ def make_unlike_data(
+ %User{ap_id: ap_id} = user,
+ %Activity{data: %{"context" => context}} = activity,
+ activity_id
+ ) do
+ data = %{
+ "type" => "Undo",
+ "actor" => ap_id,
+ "object" => activity.data,
+ "to" => [user.follower_address, activity.data["actor"]],
+ "cc" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "context" => context
+ }
+
+ if activity_id, do: Map.put(data, "id", activity_id), else: data
+ end
+
def add_announce_to_object(%Activity{data: %{"actor" => actor}}, object) do
with announcements <- [actor | object.data["announcements"] || []] |> Enum.uniq() do
update_element_in_object("announcement", announcements, object)
end
end
+ def remove_announce_from_object(%Activity{data: %{"actor" => actor}}, object) do
+ with announcements <- (object.data["announcements"] || []) |> List.delete(actor) do
+ update_element_in_object("announcement", announcements, object)
+ end
+ end
+
#### Unfollow-related helpers
def make_unfollow_data(follower, followed, follow_activity) do
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index 14a68929d..8845419c2 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -24,6 +24,16 @@ defmodule Pleroma.Web.CommonAPI do
end
end
+ def unrepeat(id_or_ap_id, user) do
+ with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
+ object <- Object.get_by_ap_id(activity.data["object"]["id"]) do
+ ActivityPub.unannounce(user, object)
+ else
+ _ ->
+ {:error, "Could not unrepeat"}
+ end
+ end
+
def favorite(id_or_ap_id, user) do
with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
false <- activity.data["actor"] == user.ap_id,
diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex
index 57f8be894..e774743a2 100644
--- a/lib/pleroma/web/common_api/utils.ex
+++ b/lib/pleroma/web/common_api/utils.ex
@@ -1,7 +1,9 @@
defmodule Pleroma.Web.CommonAPI.Utils do
alias Pleroma.{Repo, Object, Formatter, Activity}
alias Pleroma.Web.ActivityPub.Utils
+ alias Pleroma.User
alias Calendar.Strftime
+ alias Comeonin.Pbkdf2
# This is a hack for twidere.
def get_by_id_or_ap_id(id) do
@@ -184,4 +186,13 @@ defmodule Pleroma.Web.CommonAPI.Utils do
String.slice(name, 0..30) <> "…"
end
end
+
+ def confirm_current_password(user, params) do
+ with %User{local: true} = db_user <- Repo.get(User, user.id),
+ true <- Pbkdf2.checkpw(params["password"], db_user.password_hash) do
+ {:ok, db_user}
+ else
+ _ -> {:error, "Invalid password."}
+ end
+ end
end
diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex
index f84af2f15..8ca530031 100644
--- a/lib/pleroma/web/federator/federator.ex
+++ b/lib/pleroma/web/federator/federator.ex
@@ -5,6 +5,7 @@ defmodule Pleroma.Web.Federator do
alias Pleroma.Web.{WebFinger, Websub}
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Transmogrifier
+ alias Pleroma.Web.ActivityPub.Utils
require Logger
@websub Application.get_env(:pleroma, :websub)
@@ -91,6 +92,8 @@ defmodule Pleroma.Web.Federator do
def handle(:incoming_ap_doc, params) do
Logger.info("Handling incoming AP activity")
+ params = Utils.normalize_params(params)
+
with {:ok, _user} <- ap_enabled_actor(params["actor"]),
nil <- Activity.get_by_ap_id(params["id"]),
{:ok, _activity} <- Transmogrifier.handle_incoming(params) do
diff --git a/lib/pleroma/web/http_signatures/http_signatures.ex b/lib/pleroma/web/http_signatures/http_signatures.ex
index 9035f5eb6..4e0adbc1d 100644
--- a/lib/pleroma/web/http_signatures/http_signatures.ex
+++ b/lib/pleroma/web/http_signatures/http_signatures.ex
@@ -1,6 +1,7 @@
# https://tools.ietf.org/html/draft-cavage-http-signatures-08
defmodule Pleroma.Web.HTTPSignatures do
alias Pleroma.User
+ alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.ActivityPub
require Logger
@@ -31,14 +32,14 @@ defmodule Pleroma.Web.HTTPSignatures do
def validate_conn(conn) do
# TODO: How to get the right key and see if it is actually valid for that request.
# For now, fetch the key for the actor.
- with actor_id <- conn.params["actor"],
+ with actor_id <- Utils.normalize_actor(conn.params["actor"]),
{:ok, public_key} <- User.get_public_key_for_ap_id(actor_id) do
if validate_conn(conn, public_key) do
true
else
Logger.debug("Could not validate, re-fetching user and trying one more time")
# Fetch user anew and try one more time
- with actor_id <- conn.params["actor"],
+ with actor_id <- Utils.normalize_actor(conn.params["actor"]),
{:ok, _user} <- ActivityPub.make_user_from_ap_id(actor_id),
{:ok, public_key} <- User.get_public_key_for_ap_id(actor_id) do
validate_conn(conn, public_key)
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index d190cdc3f..c38412911 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -204,21 +204,14 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
|> render(StatusView, "index.json", %{activities: activities, for: user, as: :activity})
end
- def user_statuses(%{assigns: %{user: user}} = conn, params) do
- with %User{ap_id: ap_id} <- Repo.get(User, params["id"]) do
- params =
- params
- |> Map.put("type", ["Create", "Announce"])
- |> Map.put("actor_id", ap_id)
- |> Map.put("whole_db", true)
-
+ def user_statuses(%{assigns: %{user: reading_user}} = conn, params) do
+ with %User{} = user <- Repo.get(User, params["id"]) do
+ # Since Pleroma has no "pinned" posts feature, we'll just set an empty list here
activities =
if params["pinned"] == "true" do
- # Since Pleroma has no "pinned" posts feature, we'll just set an empty list here
[]
else
- ActivityPub.fetch_public_activities(params)
- |> Enum.reverse()
+ ActivityPub.fetch_user_activities(user, reading_user, params)
end
conn
@@ -317,6 +310,13 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
end
+ def unreblog_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
+ with {:ok, _, _, %{data: %{"id" => id}}} = CommonAPI.unrepeat(ap_id_or_id, user),
+ %Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id) do
+ render(conn, StatusView, "status.json", %{activity: activity, for: user, as: :activity})
+ end
+ end
+
def fav_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
with {:ok, _fav, %{data: %{"id" => id}}} = CommonAPI.favorite(ap_id_or_id, user),
%Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id) do
@@ -325,7 +325,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
end
def unfav_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
- with {:ok, %{data: %{"id" => id}}} = CommonAPI.unfavorite(ap_id_or_id, user),
+ with {:ok, _, _, %{data: %{"id" => id}}} = CommonAPI.unfavorite(ap_id_or_id, user),
%Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id) do
render(conn, StatusView, "status.json", %{activity: activity, for: user, as: :activity})
end
diff --git a/lib/pleroma/web/ostatus/activity_representer.ex b/lib/pleroma/web/ostatus/activity_representer.ex
index e8841a856..64cadba1b 100644
--- a/lib/pleroma/web/ostatus/activity_representer.ex
+++ b/lib/pleroma/web/ostatus/activity_representer.ex
@@ -239,27 +239,35 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do
inserted_at = activity.data["published"]
author = if with_author, do: [{:author, UserRepresenter.to_simple_form(user)}], else: []
- follow_activity = Activity.get_by_ap_id(activity.data["object"])
+
+ follow_activity =
+ if is_map(activity.data["object"]) do
+ Activity.get_by_ap_id(activity.data["object"]["id"])
+ else
+ Activity.get_by_ap_id(activity.data["object"])
+ end
mentions = (activity.recipients || []) |> get_mentions
- [
- {:"activity:object-type", ['http://activitystrea.ms/schema/1.0/activity']},
- {:"activity:verb", ['http://activitystrea.ms/schema/1.0/unfollow']},
- {:id, h.(activity.data["id"])},
- {:title, ['#{user.nickname} stopped following #{follow_activity.data["object"]}']},
- {:content, [type: 'html'],
- ['#{user.nickname} stopped following #{follow_activity.data["object"]}']},
- {:published, h.(inserted_at)},
- {:updated, h.(updated_at)},
- {:"activity:object",
- [
- {:"activity:object-type", ['http://activitystrea.ms/schema/1.0/person']},
- {:id, h.(follow_activity.data["object"])},
- {:uri, h.(follow_activity.data["object"])}
- ]},
- {:link, [rel: 'self', type: ['application/atom+xml'], href: h.(activity.data["id"])], []}
- ] ++ mentions ++ author
+ if follow_activity do
+ [
+ {:"activity:object-type", ['http://activitystrea.ms/schema/1.0/activity']},
+ {:"activity:verb", ['http://activitystrea.ms/schema/1.0/unfollow']},
+ {:id, h.(activity.data["id"])},
+ {:title, ['#{user.nickname} stopped following #{follow_activity.data["object"]}']},
+ {:content, [type: 'html'],
+ ['#{user.nickname} stopped following #{follow_activity.data["object"]}']},
+ {:published, h.(inserted_at)},
+ {:updated, h.(updated_at)},
+ {:"activity:object",
+ [
+ {:"activity:object-type", ['http://activitystrea.ms/schema/1.0/person']},
+ {:id, h.(follow_activity.data["object"])},
+ {:uri, h.(follow_activity.data["object"])}
+ ]},
+ {:link, [rel: 'self', type: ['application/atom+xml'], href: h.(activity.data["id"])], []}
+ ] ++ mentions ++ author
+ end
end
def to_simple_form(%{data: %{"type" => "Delete"}} = activity, user, with_author) do
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index dbef19d44..87fd664f6 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -73,6 +73,7 @@ defmodule Pleroma.Web.Router do
scope "/api/pleroma", Pleroma.Web.TwitterAPI do
pipe_through(:authenticated_api)
post("/follow_import", UtilController, :follow_import)
+ post("/delete_account", UtilController, :delete_account)
end
scope "/oauth", Pleroma.Web.OAuth do
@@ -114,6 +115,7 @@ defmodule Pleroma.Web.Router do
delete("/statuses/:id", MastodonAPIController, :delete_status)
post("/statuses/:id/reblog", MastodonAPIController, :reblog_status)
+ post("/statuses/:id/unreblog", MastodonAPIController, :unreblog_status)
post("/statuses/:id/favourite", MastodonAPIController, :fav_status)
post("/statuses/:id/unfavourite", MastodonAPIController, :unfav_status)
diff --git a/lib/pleroma/web/salmon/salmon.ex b/lib/pleroma/web/salmon/salmon.ex
index 10542fd00..562ec3d9c 100644
--- a/lib/pleroma/web/salmon/salmon.ex
+++ b/lib/pleroma/web/salmon/salmon.ex
@@ -187,13 +187,14 @@ defmodule Pleroma.Web.Salmon do
def publish(%{info: %{"keys" => keys}} = user, %{data: %{"type" => type}} = activity, poster)
when type in @supported_activities do
- feed =
- ActivityRepresenter.to_simple_form(activity, user, true)
- |> ActivityRepresenter.wrap_with_entry()
- |> :xmerl.export_simple(:xmerl_xml)
- |> to_string
+ feed = ActivityRepresenter.to_simple_form(activity, user, true)
if feed do
+ feed =
+ ActivityRepresenter.wrap_with_entry(feed)
+ |> :xmerl.export_simple(:xmerl_xml)
+ |> to_string
+
{:ok, private, _} = keys_from_pem(keys)
{:ok, feed} = encode(private, feed)
diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
index ea540b34c..23e7408a0 100644
--- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
@@ -4,6 +4,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
alias Pleroma.Web
alias Pleroma.Web.OStatus
alias Pleroma.Web.WebFinger
+ alias Pleroma.Web.CommonAPI
alias Comeonin.Pbkdf2
alias Pleroma.Formatter
alias Pleroma.Web.ActivityPub.ActivityPub
@@ -195,4 +196,15 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
json(conn, "job started")
end
+
+ def delete_account(%{assigns: %{user: user}} = conn, params) do
+ case CommonAPI.Utils.confirm_current_password(user, params) do
+ {:ok, user} ->
+ Task.start(fn -> User.delete(user) end)
+ json(conn, %{status: "success"})
+
+ {:error, msg} ->
+ json(conn, %{error: msg})
+ end
+ end
end
diff --git a/lib/pleroma/web/twitter_api/representers/activity_representer.ex b/lib/pleroma/web/twitter_api/representers/activity_representer.ex
index 9a4954de8..c2e1f07a5 100644
--- a/lib/pleroma/web/twitter_api/representers/activity_representer.ex
+++ b/lib/pleroma/web/twitter_api/representers/activity_representer.ex
@@ -197,7 +197,8 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
"external_url" => object["external_url"] || object["id"],
"tags" => tags,
"activity_type" => "post",
- "possibly_sensitive" => possibly_sensitive
+ "possibly_sensitive" => possibly_sensitive,
+ "visibility" => Pleroma.Web.MastodonAPI.StatusView.get_visibility(object)
}
end
diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex
index 44ea40a4e..722e436e2 100644
--- a/lib/pleroma/web/twitter_api/twitter_api.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api.ex
@@ -11,6 +11,18 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
CommonAPI.post(user, data)
end
+ def delete(%User{} = user, id) do
+ # TwitterAPI does not have an "unretweet" endpoint; instead this is done
+ # via the "destroy" endpoint. Therefore, we need to handle
+ # when the status to "delete" is actually an Announce (repeat) object.
+ with %Activity{data: %{"type" => type}} <- Repo.get(Activity, id) do
+ case type do
+ "Announce" -> unrepeat(user, id)
+ _ -> CommonAPI.delete(id, user)
+ end
+ end
+ end
+
def follow(%User{} = follower, params) do
with {:ok, %User{} = followed} <- get_user(params),
{:ok, follower} <- User.follow(follower, followed),
@@ -63,15 +75,21 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
end
end
+ defp unrepeat(%User{} = user, ap_id_or_id) do
+ with {:ok, _unannounce, activity, _object} <- CommonAPI.unrepeat(ap_id_or_id, user) do
+ {:ok, activity}
+ end
+ end
+
def fav(%User{} = user, ap_id_or_id) do
- with {:ok, _announce, %{data: %{"id" => id}}} = CommonAPI.favorite(ap_id_or_id, user),
+ with {:ok, _fav, %{data: %{"id" => id}}} = CommonAPI.favorite(ap_id_or_id, user),
%Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id) do
{:ok, activity}
end
end
def unfav(%User{} = user, ap_id_or_id) do
- with {:ok, %{data: %{"id" => id}}} = CommonAPI.unfavorite(ap_id_or_id, user),
+ with {:ok, _unfav, _fav, %{data: %{"id" => id}}} = CommonAPI.unfavorite(ap_id_or_id, user),
%Activity{} = activity <- Activity.get_create_activity_by_object_ap_id(id) do
{:ok, activity}
end
diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
index 960925f42..dd1dc241d 100644
--- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
@@ -96,13 +96,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
def user_timeline(%{assigns: %{user: user}} = conn, params) do
case TwitterAPI.get_user(user, params) do
{:ok, target_user} ->
- params =
- params
- |> Map.put("type", ["Create", "Announce"])
- |> Map.put("actor_id", target_user.ap_id)
- |> Map.put("whole_db", true)
-
- activities = ActivityPub.fetch_public_activities(params)
+ activities = ActivityPub.fetch_user_activities(target_user, user, params)
conn
|> render(ActivityView, "index.json", %{activities: activities, for: user})
@@ -157,8 +151,8 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
end
def delete_post(%{assigns: %{user: user}} = conn, %{"id" => id}) do
- with {:ok, delete} <- CommonAPI.delete(id, user) do
- render(conn, ActivityView, "activity.json", %{activity: delete, for: user})
+ with {:ok, activity} <- TwitterAPI.delete(user, id) do
+ render(conn, ActivityView, "activity.json", %{activity: activity, for: user})
end
end
diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex
index 580d4648c..62ce3b7b5 100644
--- a/lib/pleroma/web/twitter_api/views/activity_view.ex
+++ b/lib/pleroma/web/twitter_api/views/activity_view.ex
@@ -262,7 +262,8 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
"external_url" => object["external_url"] || object["id"],
"tags" => tags,
"activity_type" => "post",
- "possibly_sensitive" => possibly_sensitive
+ "possibly_sensitive" => possibly_sensitive,
+ "visibility" => Pleroma.Web.MastodonAPI.StatusView.get_visibility(object)
}
end
end
diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex
index 6ffa80a43..9c6f1cb68 100644
--- a/lib/pleroma/web/web_finger/web_finger.ex
+++ b/lib/pleroma/web/web_finger/web_finger.ex
@@ -87,6 +87,11 @@ defmodule Pleroma.Web.WebFinger do
},
%{"rel" => "self", "type" => "application/activity+json", "href" => user.ap_id},
%{
+ "rel" => "self",
+ "type" => "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"",
+ "href" => user.ap_id
+ },
+ %{
"rel" => "http://ostatus.org/schema/1.0/subscribe",
"template" => OStatus.remote_follow_path()
}
@@ -183,6 +188,9 @@ defmodule Pleroma.Web.WebFinger do
{"application/activity+json", "self"} ->
Map.put(data, "ap_id", link["href"])
+ {"application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"", "self"} ->
+ Map.put(data, "ap_id", link["href"])
+
{_, "magic-public-key"} ->
"data:application/magic-public-key," <> magic_key = link["href"]
Map.put(data, "magic_key", magic_key)
@@ -206,7 +214,7 @@ defmodule Pleroma.Web.WebFinger do
end
def get_template_from_xml(body) do
- xpath = "//Link[@rel='lrdd' and @type='application/xrd+xml']/@template"
+ xpath = "//Link[@rel='lrdd']/@template"
with doc when doc != :error <- XML.parse_document(body),
template when template != nil <- XML.string_from_xpath(xpath, doc) do