From eb84de01439c4ee25f59390e5be4ffa7f36e01b8 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Mon, 4 Mar 2019 19:55:11 +0700 Subject: allow users to disable their own account --- lib/mix/tasks/pleroma/user.ex | 20 ++++++- lib/pleroma/activity.ex | 16 +++++- lib/pleroma/gopher/server.ex | 3 +- lib/pleroma/notification.ex | 32 +++++------ lib/pleroma/user.ex | 64 +++++++++++++++++----- lib/pleroma/user/info.ex | 9 +++ lib/pleroma/web/activity_pub/activity_pub.ex | 1 + lib/pleroma/web/admin_api/admin_api_controller.ex | 10 ++++ lib/pleroma/web/common_api/utils.ex | 4 +- .../web/mastodon_api/mastodon_api_controller.ex | 12 ++-- lib/pleroma/web/router.ex | 2 + .../web/twitter_api/controllers/util_controller.ex | 11 ++++ lib/pleroma/web/twitter_api/twitter_api.ex | 20 ++++--- .../web/twitter_api/twitter_api_controller.ex | 4 +- 14 files changed, 158 insertions(+), 50 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 037e44716..297332bc4 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -23,7 +23,7 @@ defmodule Mix.Tasks.Pleroma.User do - `--password PASSWORD` - the user's password - `--moderator`/`--no-moderator` - whether the user is a moderator - `--admin`/`--no-admin` - whether the user is an admin - - `-y`, `--assume-yes`/`--no-assume-yes` - whether to assume yes to all questions + - `-y`, `--assume-yes`/`--no-assume-yes` - whether to assume yes to all questions ## Generate an invite link. @@ -37,6 +37,10 @@ defmodule Mix.Tasks.Pleroma.User do mix pleroma.user toggle_activated NICKNAME + ## Disable or enable the user's account. + + mix pleroma.user toggle_disabled NICKNAME + ## Unsubscribe local users from user's account and deactivate it mix pleroma.user unsubscribe NICKNAME @@ -170,6 +174,20 @@ defmodule Mix.Tasks.Pleroma.User do end end + def run(["toggle_disabled", nickname]) do + Common.start_pleroma() + + case User.get_by_nickname(nickname) do + %User{} = user -> + {:ok, user} = User.disable(user, !user.info.disabled) + status = if(user.info.disabled, do: "ON", else: "OFF") + Mix.shell().info("Disabled status of #{nickname}: #{status}") + + _ -> + Mix.shell().error("No user #{nickname}") + end + end + def run(["reset_password", nickname]) do Common.start_pleroma() diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index 66854dc2d..c466bff7f 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -42,7 +42,10 @@ defmodule Pleroma.Activity do end def get_by_id(id) do - Repo.get(Activity, id) + Activity + |> where([a], a.id == ^id) + |> restrict_disabled_users() + |> Repo.one() end def by_object_ap_id(ap_id) do @@ -92,6 +95,7 @@ defmodule Pleroma.Activity do def get_create_by_object_ap_id(ap_id) when is_binary(ap_id) do create_by_object_ap_id(ap_id) + |> restrict_disabled_users() |> Repo.one() end @@ -123,4 +127,14 @@ defmodule Pleroma.Activity do |> where([s], s.actor == ^actor) |> Repo.all() end + + def restrict_disabled_users(query) do + from(activity in query, + where: + fragment( + "? not in (SELECT ap_id FROM users WHERE info->'disabled' @> 'true')", + activity.actor + ) + ) + end end diff --git a/lib/pleroma/gopher/server.ex b/lib/pleroma/gopher/server.ex index ba9614029..24190574e 100644 --- a/lib/pleroma/gopher/server.ex +++ b/lib/pleroma/gopher/server.ex @@ -41,7 +41,6 @@ defmodule Pleroma.Gopher.Server.ProtocolHandler do alias Pleroma.Activity alias Pleroma.HTML alias Pleroma.User - alias Pleroma.Repo def start_link(ref, socket, transport, opts) do pid = spawn_link(__MODULE__, :init, [ref, socket, transport, opts]) @@ -110,7 +109,7 @@ defmodule Pleroma.Gopher.Server.ProtocolHandler do end def response("/notices/" <> id) do - with %Activity{} = activity <- Repo.get(Activity, id), + with %Activity{} = activity <- Activity.get_by_id(id), true <- Visibility.is_public?(activity) do activities = ActivityPub.fetch_activities_for_context(activity.data["context"]) diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index c88512567..0f9f74b1e 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -36,22 +36,22 @@ defmodule Pleroma.Notification do defp restrict_since(query, _), do: query def for_user(user, opts \\ %{}) do - query = - from( - n in Notification, - where: n.user_id == ^user.id, - order_by: [desc: n.id], - join: activity in assoc(n, :activity), - preload: [activity: activity], - limit: 20 - ) - - query = - query - |> restrict_since(opts) - |> restrict_max(opts) - - Repo.all(query) + from( + n in Notification, + where: n.user_id == ^user.id, + order_by: [desc: n.id], + join: activity in assoc(n, :activity), + preload: [activity: activity], + limit: 20, + where: + fragment( + "? not in (SELECT ap_id FROM users WHERE info->'disabled' @> 'true')", + activity.actor + ) + ) + |> restrict_since(opts) + |> restrict_max(opts) + |> Repo.all() end def set_read_up_to(%{id: user_id} = _user, id) do diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 50e7e7ccd..f02051174 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -108,10 +108,8 @@ defmodule Pleroma.User do end def user_info(%User{} = user) do - oneself = if user.local, do: 1, else: 0 - %{ - following_count: length(user.following) - oneself, + following_count: following_count(user), note_count: user.info.note_count, follower_count: user.info.follower_count, locked: user.info.locked, @@ -120,6 +118,23 @@ defmodule Pleroma.User do } end + defp restrict_disabled(query) do + from(u in query, + where: not fragment("? \\? 'disabled' AND ?->'disabled' @> 'true'", u.info, u.info) + ) + end + + def following_count(%User{following: []}), do: 0 + + def following_count(%User{following: following, id: id}) do + from(u in User, + where: u.follower_address in ^following, + where: u.id != ^id + ) + |> restrict_disabled() + |> Repo.aggregate(:count, :id) + end + def remote_user_creation(params) do params = params @@ -545,6 +560,7 @@ defmodule Pleroma.User do where: fragment("? <@ ?", ^[follower_address], u.following), where: u.id != ^id ) + |> restrict_disabled() end def get_followers_query(user, page) do @@ -572,6 +588,7 @@ defmodule Pleroma.User do where: u.follower_address in ^following, where: u.id != ^id ) + |> restrict_disabled() end def get_friends_query(user, page) do @@ -681,11 +698,10 @@ defmodule Pleroma.User do info_cng = User.Info.set_note_count(user.info, note_count) - cng = - change(user) - |> put_embed(:info, info_cng) - - update_and_set_cache(cng) + user + |> change() + |> put_embed(:info, info_cng) + |> update_and_set_cache() end def update_follower_count(%User{} = user) do @@ -694,6 +710,7 @@ defmodule Pleroma.User do |> where([u], ^user.follower_address in u.following) |> where([u], u.id != ^user.id) |> select([u], %{count: count(u.id)}) + |> restrict_disabled() User |> where(id: ^user.id) @@ -860,6 +877,7 @@ defmodule Pleroma.User do ^processed_query ) ) + |> restrict_disabled() end defp trigram_search_subquery(term) do @@ -876,6 +894,7 @@ defmodule Pleroma.User do }, where: fragment("trim(? || ' ' || coalesce(?, '')) % ?", u.nickname, u.name, ^term) ) + |> restrict_disabled() end defp boost_search_results(results, nil), do: results @@ -1062,11 +1081,10 @@ defmodule Pleroma.User do def deactivate(%User{} = user, status \\ true) do info_cng = User.Info.set_activation_status(user.info, status) - cng = - change(user) - |> put_embed(:info, info_cng) - - update_and_set_cache(cng) + user + |> change() + |> put_embed(:info, info_cng) + |> update_and_set_cache() end def delete(%User{} = user) do @@ -1100,6 +1118,26 @@ defmodule Pleroma.User do {:ok, user} end + def disable_async(user, status \\ true) do + Pleroma.Jobs.enqueue(:user, __MODULE__, [:disable_async, user, status]) + end + + def disable(%User{} = user, status \\ true) do + with {:ok, user} <- User.deactivate(user, status), + info_cng <- User.Info.set_disabled_status(user.info, status), + {:ok, user} <- + user + |> change() + |> put_embed(:info, info_cng) + |> update_and_set_cache(), + {:ok, friends} <- User.get_friends(user) do + Enum.each(friends, &update_follower_count(&1)) + {:ok, user} + end + end + + def perform(:disable_async, user, status), do: disable(user, status) + def html_filter_policy(%User{info: %{no_rich_text: true}}) do Pleroma.HTML.Scrubber.TwitterText end diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 818b64645..1ec356ba9 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -36,6 +36,7 @@ defmodule Pleroma.User.Info do field(:hide_follows, :boolean, default: false) field(:pinned_activities, {:array, :string}, default: []) field(:flavour, :string, default: nil) + field(:disabled, :boolean, default: false) # Found in the wild # ap_id -> Where is this used? @@ -54,6 +55,14 @@ defmodule Pleroma.User.Info do |> validate_required([:deactivated]) end + def set_disabled_status(info, disabled) do + params = %{disabled: disabled} + + info + |> cast(params, [:disabled]) + |> validate_required([:disabled]) + end + def add_to_note_count(info, number) do set_note_count(info, info.note_count + number) end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 783491b67..aa20990f3 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -703,6 +703,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> restrict_replies(opts) |> restrict_reblogs(opts) |> restrict_pinned(opts) + |> Activity.restrict_disabled_users() end def fetch_activities(recipients, opts \\ %{}) do diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index aae02cab8..1b94f0609 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -44,6 +44,16 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do |> json(user.nickname) end + def user_toggle_disabled(conn, %{"nickname" => nickname}) do + user = User.get_by_nickname(nickname) + + {:ok, updated_user} = User.disable(user, !user.info.disabled) + + conn + |> put_view(AccountView) + |> render("show.json", %{user: updated_user}) + end + def user_toggle_activation(conn, %{"nickname" => nickname}) do user = User.get_by_nickname(nickname) diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index e4b9102c5..60d1185d3 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -17,7 +17,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do # This is a hack for twidere. def get_by_id_or_ap_id(id) do - activity = Repo.get(Activity, id) || Activity.get_create_by_object_ap_id(id) + activity = Activity.get_by_id(id) || Activity.get_create_by_object_ap_id(id) activity && if activity.data["type"] == "Create" do @@ -30,7 +30,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do def get_replied_to_activity(""), do: nil def get_replied_to_activity(id) when not is_nil(id) do - Repo.get(Activity, id) + Activity.get_by_id(id) end def get_replied_to_activity(_), do: nil diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 056be49b0..00a0f1351 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -307,7 +307,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def get_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %Activity{} = activity <- Repo.get(Activity, id), + with %Activity{} = activity <- Activity.get_by_id(id), true <- Visibility.visible_for_user?(activity, user) do conn |> put_view(StatusView) @@ -316,7 +316,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def get_context(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %Activity{} = activity <- Repo.get(Activity, id), + with %Activity{} = activity <- Activity.get_by_id(id), activities <- ActivityPub.fetch_activities_for_context(activity.data["context"], %{ "blocking_user" => user, @@ -448,7 +448,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def bookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %Activity{} = activity <- Repo.get(Activity, id), + with %Activity{} = activity <- Activity.get_by_id(id), %User{} = user <- User.get_by_nickname(user.nickname), true <- Visibility.visible_for_user?(activity, user), {:ok, user} <- User.bookmark(user, activity.data["object"]["id"]) do @@ -459,7 +459,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def unbookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %Activity{} = activity <- Repo.get(Activity, id), + with %Activity{} = activity <- Activity.get_by_id(id), %User{} = user <- User.get_by_nickname(user.nickname), true <- Visibility.visible_for_user?(activity, user), {:ok, user} <- User.unbookmark(user, activity.data["object"]["id"]) do @@ -583,7 +583,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def favourited_by(conn, %{"id" => id}) do - with %Activity{data: %{"object" => %{"likes" => likes}}} <- Repo.get(Activity, id) do + with %Activity{data: %{"object" => %{"likes" => likes}}} <- Activity.get_by_id(id) do q = from(u in User, where: u.ap_id in ^likes) users = Repo.all(q) @@ -596,7 +596,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def reblogged_by(conn, %{"id" => id}) do - with %Activity{data: %{"object" => %{"announcements" => announces}}} <- Repo.get(Activity, id) do + with %Activity{data: %{"object" => %{"announcements" => announces}}} <- Activity.get_by_id(id) do q = from(u in User, where: u.ap_id in ^announces) users = Repo.all(q) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 6fcb46878..5033b5446 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -143,6 +143,7 @@ defmodule Pleroma.Web.Router do get("/users/search", AdminAPIController, :search_users) delete("/user", AdminAPIController, :user_delete) patch("/users/:nickname/toggle_activation", AdminAPIController, :user_toggle_activation) + patch("/users/:nickname/toggle_disabled", AdminAPIController, :user_toggle_disabled) post("/user", AdminAPIController, :user_create) put("/users/tag", AdminAPIController, :tag_users) delete("/users/tag", AdminAPIController, :untag_users) @@ -183,6 +184,7 @@ defmodule Pleroma.Web.Router do post("/change_password", UtilController, :change_password) post("/delete_account", UtilController, :delete_account) + post("/disable_account", UtilController, :disable_account) end scope [] do diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index e2fdedb25..0006d53e8 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -311,6 +311,17 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do end end + def disable_account(%{assigns: %{user: user}} = conn, params) do + case CommonAPI.Utils.confirm_current_password(user, params["password"]) do + {:ok, user} -> + User.disable_async(user) + json(conn, %{status: "success"}) + + {:error, msg} -> + json(conn, %{error: msg}) + end + end + def captcha(conn, _params) do json(conn, Pleroma.Captcha.new()) end diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index ab6470d78..615a34be9 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -21,7 +21,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do end def delete(%User{} = user, id) do - with %Activity{data: %{"type" => _type}} <- Repo.get(Activity, id), + with %Activity{data: %{"type" => _type}} <- Activity.get_by_id(id), {:ok, activity} <- CommonAPI.delete(id, user) do {:ok, activity} end @@ -232,21 +232,27 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do def get_user(user \\ nil, params) do case params do %{"user_id" => user_id} -> - case target = User.get_cached_by_nickname_or_id(user_id) do + case User.get_cached_by_nickname_or_id(user_id) do nil -> {:error, "No user with such user_id"} - _ -> - {:ok, target} + %User{info: %{disabled: true}} -> + {:error, "User has been disabled"} + + user -> + {:ok, user} end %{"screen_name" => nickname} -> - case target = Repo.get_by(User, nickname: nickname) do + case User.get_by_nickname(nickname) do nil -> {:error, "No user with such screen_name"} - _ -> - {:ok, target} + %User{info: %{disabled: true}} -> + {:error, "User has been disabled"} + + user -> + {:ok, user} end _ -> diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index de7b9f24c..0769f8698 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -269,7 +269,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do end def fetch_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do - with %Activity{} = activity <- Repo.get(Activity, id), + with %Activity{} = activity <- Activity.get_by_id(id), true <- Visibility.visible_for_user?(activity, user) do conn |> put_view(ActivityView) @@ -341,7 +341,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do end def get_by_id_or_ap_id(id) do - activity = Repo.get(Activity, id) || Activity.get_create_by_object_ap_id(id) + activity = Activity.get_by_id(id) || Activity.get_create_by_object_ap_id(id) if activity.data["type"] == "Create" do activity -- cgit v1.2.3 From f6fab01ba7a08fe0e5147f82d9e3dd294922dc93 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Sun, 17 Mar 2019 17:06:28 +0100 Subject: Web.Router: Add routes for Conversation mastoAPI --- lib/pleroma/web/router.ex | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index befd382ba..6d000b7f5 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -243,6 +243,9 @@ defmodule Pleroma.Web.Router do get("/suggestions", MastodonAPIController, :suggestions) + get("/conversations", MastodonAPIController, :conversations) + get("/conversations/:id/read", MastodonAPIController, :get_conversation) + get("/endorsements", MastodonAPIController, :empty_array) get("/pleroma/flavour", MastodonAPIController, :get_flavour) -- cgit v1.2.3 From a2e03d4f3cfc7ccae98ae19db253aec8f1d3e9d0 Mon Sep 17 00:00:00 2001 From: Zachary Dunn Date: Mon, 18 Mar 2019 13:56:59 +0000 Subject: Initial attempt at updating return type --- lib/pleroma/user.ex | 33 ++++++++++++++-------- lib/pleroma/web/activity_pub/relay.ex | 4 +-- lib/pleroma/web/activity_pub/transmogrifier.ex | 24 ++++++++-------- .../web/mastodon_api/mastodon_api_controller.ex | 2 +- lib/pleroma/web/twitter_api/twitter_api.ex | 2 +- 5 files changed, 37 insertions(+), 28 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 1ce9882f6..6e8103c1c 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -411,7 +411,7 @@ defmodule Pleroma.User do Enum.map( followed_identifiers, fn followed_identifier -> - with %User{} = followed <- get_or_fetch(followed_identifier), + with {:ok, %User{} = followed} <- get_or_fetch(followed_identifier), {:ok, follower} <- maybe_direct_follow(follower, followed), {:ok, _} <- ActivityPub.follow(follower, followed) do followed @@ -492,7 +492,14 @@ defmodule Pleroma.User do def get_cached_by_nickname(nickname) do key = "nickname:#{nickname}" - Cachex.fetch!(:user_cache, key, fn _ -> get_or_fetch_by_nickname(nickname) end) + Cachex.fetch!(:user_cache, key, fn -> + user_result = get_or_fetch_by_nickname(nickname) + + case user_result do + {:ok, user} -> {:commit, user} + {:error, error} -> {:ignore, error} + end + end) end def get_cached_by_nickname_or_id(nickname_or_id) do @@ -529,7 +536,7 @@ defmodule Pleroma.User do def get_or_fetch_by_nickname(nickname) do with %User{} = user <- get_by_nickname(nickname) do - user + {:ok, user} else _e -> with [_nick, _domain] <- String.split(nickname, "@"), @@ -538,9 +545,9 @@ defmodule Pleroma.User do {:ok, _} = Task.start(__MODULE__, :fetch_initial_posts, [user]) end - user + {:ok, user} else - _e -> nil + _e -> {:error, "Error"} end end end @@ -939,7 +946,7 @@ defmodule Pleroma.User do Enum.map( blocked_identifiers, fn blocked_identifier -> - with %User{} = blocked <- get_or_fetch(blocked_identifier), + with {:ok, %User{} = blocked} <- get_or_fetch(blocked_identifier), {:ok, blocker} <- block(blocker, blocked), {:ok, _} <- ActivityPub.block(blocker, blocked) do blocked @@ -1157,17 +1164,19 @@ defmodule Pleroma.User do user = get_by_ap_id(ap_id) if !is_nil(user) and !User.needs_update?(user) do - user + {:ok, user} else user = fetch_by_ap_id(ap_id) - if Pleroma.Config.get([:fetch_initial_posts, :enabled]) do - with %User{} = user do + with %User{} = user do + if Pleroma.Config.get([:fetch_initial_posts, :enabled]) do {:ok, _} = Task.start(__MODULE__, :fetch_initial_posts, [user]) end - end - user + {:ok, user} + else + _ -> {:error, "Could not fetch by AP id"} + end end end @@ -1209,7 +1218,7 @@ defmodule Pleroma.User do end def get_public_key_for_ap_id(ap_id) do - with %User{} = user <- get_or_fetch_by_ap_id(ap_id), + with {:ok, %User{} = user} <- get_or_fetch_by_ap_id(ap_id), {:ok, public_key} <- public_key_from_info(user.info) do {:ok, public_key} else diff --git a/lib/pleroma/web/activity_pub/relay.ex b/lib/pleroma/web/activity_pub/relay.ex index 01fef71b9..2bab9b03c 100644 --- a/lib/pleroma/web/activity_pub/relay.ex +++ b/lib/pleroma/web/activity_pub/relay.ex @@ -15,7 +15,7 @@ defmodule Pleroma.Web.ActivityPub.Relay do def follow(target_instance) do with %User{} = local_user <- get_actor(), - %User{} = target_user <- User.get_or_fetch_by_ap_id(target_instance), + {:ok, %User{} = target_user} <- User.get_or_fetch_by_ap_id(target_instance), {:ok, activity} <- ActivityPub.follow(local_user, target_user) do Logger.info("relay: followed instance: #{target_instance}; id=#{activity.data["id"]}") {:ok, activity} @@ -28,7 +28,7 @@ defmodule Pleroma.Web.ActivityPub.Relay do def unfollow(target_instance) do with %User{} = local_user <- get_actor(), - %User{} = target_user <- User.get_or_fetch_by_ap_id(target_instance), + {:ok, %User{} = target_user} <- User.get_or_fetch_by_ap_id(target_instance), {:ok, activity} <- ActivityPub.unfollow(local_user, target_user) do Logger.info("relay: unfollowed instance: #{target_instance}: id=#{activity.data["id"]}") {:ok, activity} diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 1247e4b61..a90b934e5 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -373,7 +373,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do |> fix_addressing with nil <- Activity.get_create_by_object_ap_id(object["id"]), - %User{} = user <- User.get_or_fetch_by_ap_id(data["actor"]) do + {:ok, %User{} = user} <- User.get_or_fetch_by_ap_id(data["actor"]) do object = fix_object(data["object"]) params = %{ @@ -402,7 +402,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do %{"type" => "Follow", "object" => followed, "actor" => follower, "id" => id} = data ) do with %User{local: true} = followed <- User.get_cached_by_ap_id(followed), - %User{} = follower <- User.get_or_fetch_by_ap_id(follower), + {:ok, %User{} = follower} <- User.get_or_fetch_by_ap_id(follower), {:ok, activity} <- ActivityPub.follow(follower, followed, id, false) do if not User.locked?(followed) do ActivityPub.accept(%{ @@ -425,7 +425,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do %{"type" => "Accept", "object" => follow_object, "actor" => _actor, "id" => _id} = data ) do with actor <- get_actor(data), - %User{} = followed <- User.get_or_fetch_by_ap_id(actor), + {:ok, %User{} = followed} <- User.get_or_fetch_by_ap_id(actor), {:ok, follow_activity} <- get_follow_activity(follow_object, followed), {:ok, follow_activity} <- Utils.update_follow_state(follow_activity, "accept"), %User{local: true} = follower <- User.get_cached_by_ap_id(follow_activity.data["actor"]), @@ -451,7 +451,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do %{"type" => "Reject", "object" => follow_object, "actor" => _actor, "id" => _id} = data ) do with actor <- get_actor(data), - %User{} = followed <- User.get_or_fetch_by_ap_id(actor), + {:ok, %User{} = followed} <- User.get_or_fetch_by_ap_id(actor), {:ok, follow_activity} <- get_follow_activity(follow_object, followed), {:ok, follow_activity} <- Utils.update_follow_state(follow_activity, "reject"), %User{local: true} = follower <- User.get_cached_by_ap_id(follow_activity.data["actor"]), @@ -475,7 +475,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do %{"type" => "Like", "object" => object_id, "actor" => _actor, "id" => id} = data ) do with actor <- get_actor(data), - %User{} = actor <- User.get_or_fetch_by_ap_id(actor), + {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(actor), {:ok, object} <- get_obj_helper(object_id) || fetch_obj_helper(object_id), {:ok, activity, _object} <- ActivityPub.like(actor, object, id, false) do {:ok, activity} @@ -488,7 +488,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do %{"type" => "Announce", "object" => object_id, "actor" => _actor, "id" => id} = data ) do with actor <- get_actor(data), - %User{} = actor <- User.get_or_fetch_by_ap_id(actor), + {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(actor), {:ok, object} <- get_obj_helper(object_id) || fetch_obj_helper(object_id), public <- Visibility.is_public?(data), {:ok, activity, _object} <- ActivityPub.announce(actor, object, id, false, public) do @@ -543,7 +543,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do object_id = Utils.get_ap_id(object_id) with actor <- get_actor(data), - %User{} = actor <- User.get_or_fetch_by_ap_id(actor), + {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(actor), {:ok, object} <- get_obj_helper(object_id) || fetch_obj_helper(object_id), :ok <- contain_origin(actor.ap_id, object.data), {:ok, activity} <- ActivityPub.delete(object, false) do @@ -562,7 +562,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do } = data ) do with actor <- get_actor(data), - %User{} = actor <- User.get_or_fetch_by_ap_id(actor), + {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(actor), {:ok, object} <- get_obj_helper(object_id) || fetch_obj_helper(object_id), {:ok, activity, _} <- ActivityPub.unannounce(actor, object, id, false) do {:ok, activity} @@ -580,7 +580,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do } = _data ) do with %User{local: true} = followed <- User.get_cached_by_ap_id(followed), - %User{} = follower <- User.get_or_fetch_by_ap_id(follower), + {:ok, %User{} = follower} <- User.get_or_fetch_by_ap_id(follower), {:ok, activity} <- ActivityPub.unfollow(follower, followed, id, false) do User.unfollow(follower, followed) {:ok, activity} @@ -599,7 +599,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do ) do with true <- Pleroma.Config.get([:activitypub, :accept_blocks]), %User{local: true} = blocked <- User.get_cached_by_ap_id(blocked), - %User{} = blocker <- User.get_or_fetch_by_ap_id(blocker), + {:ok, %User{} = blocker} <- User.get_or_fetch_by_ap_id(blocker), {:ok, activity} <- ActivityPub.unblock(blocker, blocked, id, false) do User.unblock(blocker, blocked) {:ok, activity} @@ -613,7 +613,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do ) do with true <- Pleroma.Config.get([:activitypub, :accept_blocks]), %User{local: true} = blocked = User.get_cached_by_ap_id(blocked), - %User{} = blocker = User.get_or_fetch_by_ap_id(blocker), + {:ok, %User{} = blocker = User.get_or_fetch_by_ap_id(blocker), {:ok, activity} <- ActivityPub.block(blocker, blocked, id, false) do User.unfollow(blocker, blocked) User.block(blocker, blocked) @@ -632,7 +632,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do } = data ) do with actor <- get_actor(data), - %User{} = actor <- User.get_or_fetch_by_ap_id(actor), + {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(actor), {:ok, object} <- get_obj_helper(object_id) || fetch_obj_helper(object_id), {:ok, activity, _, _} <- ActivityPub.unlike(actor, object, id, false) do {:ok, activity} diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index e578f707e..cbf2a7ce1 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -1450,7 +1450,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do x, "id", case User.get_or_fetch(x["acct"]) do - %{id: id} -> id + {:ok, %User{} = %{id: id}} -> id _ -> 0 end ) diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index d57100491..feadf8670 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -312,7 +312,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do end def get_external_profile(for_user, uri) do - with %User{} = user <- User.get_or_fetch(uri) do + with {:ok, %User{} = user} <- User.get_or_fetch(uri) do {:ok, UserView.render("show.json", %{user: user, for: for_user})} else _e -> -- cgit v1.2.3 From 5ba14c664b46faf633692cafa4290c0e6521d03c Mon Sep 17 00:00:00 2001 From: Zachary Dunn Date: Mon, 18 Mar 2019 14:05:10 +0000 Subject: Fix missing end brace --- lib/pleroma/web/activity_pub/transmogrifier.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index a90b934e5..546134f46 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -613,7 +613,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do ) do with true <- Pleroma.Config.get([:activitypub, :accept_blocks]), %User{local: true} = blocked = User.get_cached_by_ap_id(blocked), - {:ok, %User{} = blocker = User.get_or_fetch_by_ap_id(blocker), + {:ok, %User{} = blocker} = User.get_or_fetch_by_ap_id(blocker), {:ok, activity} <- ActivityPub.block(blocker, blocked, id, false) do User.unfollow(blocker, blocked) User.block(blocker, blocked) -- cgit v1.2.3 From af4338da0c26d992a5189fe940aa08ba69222e3b Mon Sep 17 00:00:00 2001 From: Zachary Dunn Date: Mon, 18 Mar 2019 14:52:24 +0000 Subject: Use better error message --- lib/pleroma/user.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 6e8103c1c..dcc03ae95 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -547,7 +547,7 @@ defmodule Pleroma.User do {:ok, user} else - _e -> {:error, "Error"} + e -> {:error, e} end end end -- cgit v1.2.3 From e572786dad231a954c87ce54bb63e9be7fb396e9 Mon Sep 17 00:00:00 2001 From: Zachary Dunn Date: Mon, 18 Mar 2019 14:53:30 +0000 Subject: Run --- lib/pleroma/user.ex | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index dcc03ae95..a29f836be 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -492,6 +492,7 @@ defmodule Pleroma.User do def get_cached_by_nickname(nickname) do key = "nickname:#{nickname}" + Cachex.fetch!(:user_cache, key, fn -> user_result = get_or_fetch_by_nickname(nickname) -- cgit v1.2.3 From 97b35e00b049c8f908484163b5ffdbcb55db7867 Mon Sep 17 00:00:00 2001 From: Zachary Dunn Date: Mon, 18 Mar 2019 14:59:52 +0000 Subject: Fix with expression always matching --- lib/pleroma/user.ex | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index a29f836be..5e8dfc669 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1167,9 +1167,7 @@ defmodule Pleroma.User do if !is_nil(user) and !User.needs_update?(user) do {:ok, user} else - user = fetch_by_ap_id(ap_id) - - with %User{} = user do + with %User{} = user <- fetch_by_ap_id(ap_id) do if Pleroma.Config.get([:fetch_initial_posts, :enabled]) do {:ok, _} = Task.start(__MODULE__, :fetch_initial_posts, [user]) end -- cgit v1.2.3 From c810fb81a489dc3faeb1f21092c89a3131188ac1 Mon Sep 17 00:00:00 2001 From: lain Date: Sun, 31 Mar 2019 14:55:09 +0200 Subject: Basic SSH daemon. --- lib/pleroma/bbs/bbs.ex | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 lib/pleroma/bbs/bbs.ex (limited to 'lib') diff --git a/lib/pleroma/bbs/bbs.ex b/lib/pleroma/bbs/bbs.ex new file mode 100644 index 000000000..486ab9183 --- /dev/null +++ b/lib/pleroma/bbs/bbs.ex @@ -0,0 +1,34 @@ +defmodule Pleroma.BBS do + def start_daemon do + :ok = :ssh.start() + + options = [ + system_dir: 'ssh_keys', + auth_method_kb_interactive_data: fn (_, user, _) -> { + 'Welcome to Pleroma BBS', + 'Hello #{user}', + 'Password: ', + false } + end, + auth_methods: 'keyboard-interactive,password', + pwdfun: fn(user, password) -> true end, + shell: &start_prompt/1 + ] + :ssh.daemon(13121, options) + end + + def start_prompt(user) do + spawn(__MODULE__, :prompt, [user]) + end + + def prompt(user) do + IO.puts("Hey #{user}.\n") + IO.puts("Here's your timeline:\n") + + user = Pleroma.User.get_cached_by_nickname(to_string(user)) + Pleroma.Web.TwitterAPI.TwitterAPI.fetch_friend_statuses(user) + |> Enum.each(fn (status) -> + IO.puts("#{status["user"]["name"]} (#{status["user"]["screen_name"]}): #{status["text"]}") + end) + end +end -- cgit v1.2.3 From 17ab9fa45bf8a359746d30f4a91cb57a9c94f206 Mon Sep 17 00:00:00 2001 From: lain Date: Sun, 31 Mar 2019 18:01:16 +0200 Subject: BBS: Some more functionality. --- lib/pleroma/bbs/authenticator.ex | 16 +++++ lib/pleroma/bbs/bbs.ex | 34 ---------- lib/pleroma/bbs/handler.ex | 130 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+), 34 deletions(-) create mode 100644 lib/pleroma/bbs/authenticator.ex delete mode 100644 lib/pleroma/bbs/bbs.ex create mode 100644 lib/pleroma/bbs/handler.ex (limited to 'lib') diff --git a/lib/pleroma/bbs/authenticator.ex b/lib/pleroma/bbs/authenticator.ex new file mode 100644 index 000000000..a2c153720 --- /dev/null +++ b/lib/pleroma/bbs/authenticator.ex @@ -0,0 +1,16 @@ +defmodule Pleroma.BBS.Authenticator do + use Sshd.PasswordAuthenticator + alias Comeonin.Pbkdf2 + alias Pleroma.User + + def authenticate(username, password) do + username = to_string(username) + password = to_string(password) + + with %User{} = user <- User.get_by_nickname(username) do + Pbkdf2.checkpw(password, user.password_hash) + else + _e -> false + end + end +end diff --git a/lib/pleroma/bbs/bbs.ex b/lib/pleroma/bbs/bbs.ex deleted file mode 100644 index 486ab9183..000000000 --- a/lib/pleroma/bbs/bbs.ex +++ /dev/null @@ -1,34 +0,0 @@ -defmodule Pleroma.BBS do - def start_daemon do - :ok = :ssh.start() - - options = [ - system_dir: 'ssh_keys', - auth_method_kb_interactive_data: fn (_, user, _) -> { - 'Welcome to Pleroma BBS', - 'Hello #{user}', - 'Password: ', - false } - end, - auth_methods: 'keyboard-interactive,password', - pwdfun: fn(user, password) -> true end, - shell: &start_prompt/1 - ] - :ssh.daemon(13121, options) - end - - def start_prompt(user) do - spawn(__MODULE__, :prompt, [user]) - end - - def prompt(user) do - IO.puts("Hey #{user}.\n") - IO.puts("Here's your timeline:\n") - - user = Pleroma.User.get_cached_by_nickname(to_string(user)) - Pleroma.Web.TwitterAPI.TwitterAPI.fetch_friend_statuses(user) - |> Enum.each(fn (status) -> - IO.puts("#{status["user"]["name"]} (#{status["user"]["screen_name"]}): #{status["text"]}") - end) - end -end diff --git a/lib/pleroma/bbs/handler.ex b/lib/pleroma/bbs/handler.ex new file mode 100644 index 000000000..010929ed2 --- /dev/null +++ b/lib/pleroma/bbs/handler.ex @@ -0,0 +1,130 @@ +defmodule Pleroma.BBS.Handler do + @moduledoc """ + An example implementation of `Sshd.ShellHandler`, implementing a very simple + Read-Eval-Loop, that does nothing. + """ + use Sshd.ShellHandler + alias Pleroma.Web.CommonAPI + alias Pleroma.Web.ActivityPub.ActivityPub + + def on_shell(username, _pubkey, _ip, _port) do + :ok = IO.puts "Welcome to #{Pleroma.Config.get([:instance, :name])}!" + user = Pleroma.User.get_by_nickname(to_string(username)) + Logger.debug("#{inspect user}") + loop(run_state([user: user])) + end + + def on_connect(username, ip, port, method) do + Logger.debug fn -> + """ + Incoming SSH shell #{inspect self()} requested for #{username} from #{inspect ip}:#{inspect port} using #{inspect method} + """ + end + end + + def on_disconnect(username, ip, port) do + Logger.debug fn -> + "Disconnecting SSH shell for #{username} from #{inspect ip}:#{inspect port}" + end + end + + defp loop(state) do + self_pid = self() + counter = state.counter + prefix = state.prefix + user = state.user + + input = spawn(fn -> io_get(self_pid, prefix, counter, user.nickname) end) + wait_input state, input + end + + def puts_activity(activity) do + status = Pleroma.Web.MastodonAPI.StatusView.render("status.json", %{activity: activity}) + IO.puts("#{status.id} by #{status.account.display_name} (#{status.account.acct}):") + IO.puts(HtmlSanitizeEx.strip_tags(status.content)) + IO.puts("") + end + + def handle_command(state, "help") do + IO.puts("Available commands:") + IO.puts("help - This help") + IO.puts("home - Show the home timeline") + IO.puts("p - Post the given text") + IO.puts("quit - Quit") + + state + end + + def handle_command(%{user: user} = state, "p " <> text) do + text = String.trim(text) + + with {:ok, _activity} <- CommonAPI.post(user, %{"status" => text}) do + IO.puts("Posted!") + else + _e -> IO.puts("Could not post...") + end + state + end + + def handle_command(state, "home") do + user = state.user + params = + %{} + |> Map.put("type", ["Create", "Announce"]) + |> Map.put("blocking_user", user) + |> Map.put("muting_user", user) + |> Map.put("user", user) + + activities = + [user.ap_id | user.following] + |> ActivityPub.fetch_activities(params) + |> ActivityPub.contain_timeline(user) + |> Enum.reverse() + + Enum.each(activities, fn (activity) -> + puts_activity(activity) + end) + + state + end + + def handle_command(_state, command) do + IO.puts("Unknown command '#{command}'") + end + + defp wait_input(state, input) do + receive do + {:input, ^input, "quit\n"} -> + IO.puts "Exiting..." + + {:input, ^input, code} when is_binary(code) -> + code = String.trim(code) + + handle_command(state, code) + + loop(%{state | counter: state.counter + 1}) + + {:error, :interrupted} -> + IO.puts "Caught Ctrl+C..." + loop(%{state | counter: state.counter + 1}) + + {:input, ^input, msg} -> + :ok = Logger.warn "received unknown message: #{inspect msg}" + loop(%{state | counter: state.counter + 1}) + end + end + + defp run_state(opts) do + %{prefix: "pleroma", counter: 1, user: opts[:user]} + end + + defp io_get(pid, prefix, counter, username) do + prompt = prompt(prefix, counter, username) + send pid, {:input, self(), IO.gets(:stdio, prompt)} + end + + defp prompt(prefix, counter, username) do + prompt = "#{username}@#{prefix}:#{counter}>" + prompt <> " " + end +end -- cgit v1.2.3 From 10fdc080a0048a4776abb4bd1b5aa22d8c65e2da Mon Sep 17 00:00:00 2001 From: lain Date: Sun, 31 Mar 2019 20:35:10 +0200 Subject: BBS: Tests and formatting. --- lib/pleroma/bbs/handler.ex | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/bbs/handler.ex b/lib/pleroma/bbs/handler.ex index 010929ed2..d999dcf76 100644 --- a/lib/pleroma/bbs/handler.ex +++ b/lib/pleroma/bbs/handler.ex @@ -8,34 +8,36 @@ defmodule Pleroma.BBS.Handler do alias Pleroma.Web.ActivityPub.ActivityPub def on_shell(username, _pubkey, _ip, _port) do - :ok = IO.puts "Welcome to #{Pleroma.Config.get([:instance, :name])}!" + :ok = IO.puts("Welcome to #{Pleroma.Config.get([:instance, :name])}!") user = Pleroma.User.get_by_nickname(to_string(username)) - Logger.debug("#{inspect user}") - loop(run_state([user: user])) + Logger.debug("#{inspect(user)}") + loop(run_state(user: user)) end def on_connect(username, ip, port, method) do - Logger.debug fn -> + Logger.debug(fn -> """ - Incoming SSH shell #{inspect self()} requested for #{username} from #{inspect ip}:#{inspect port} using #{inspect method} + Incoming SSH shell #{inspect(self())} requested for #{username} from #{inspect(ip)}:#{ + inspect(port) + } using #{inspect(method)} """ - end + end) end def on_disconnect(username, ip, port) do - Logger.debug fn -> - "Disconnecting SSH shell for #{username} from #{inspect ip}:#{inspect port}" - end + Logger.debug(fn -> + "Disconnecting SSH shell for #{username} from #{inspect(ip)}:#{inspect(port)}" + end) end defp loop(state) do self_pid = self() - counter = state.counter - prefix = state.prefix - user = state.user + counter = state.counter + prefix = state.prefix + user = state.user input = spawn(fn -> io_get(self_pid, prefix, counter, user.nickname) end) - wait_input state, input + wait_input(state, input) end def puts_activity(activity) do @@ -63,11 +65,13 @@ defmodule Pleroma.BBS.Handler do else _e -> IO.puts("Could not post...") end + state end def handle_command(state, "home") do user = state.user + params = %{} |> Map.put("type", ["Create", "Announce"]) @@ -81,7 +85,7 @@ defmodule Pleroma.BBS.Handler do |> ActivityPub.contain_timeline(user) |> Enum.reverse() - Enum.each(activities, fn (activity) -> + Enum.each(activities, fn activity -> puts_activity(activity) end) @@ -95,7 +99,7 @@ defmodule Pleroma.BBS.Handler do defp wait_input(state, input) do receive do {:input, ^input, "quit\n"} -> - IO.puts "Exiting..." + IO.puts("Exiting...") {:input, ^input, code} when is_binary(code) -> code = String.trim(code) @@ -105,11 +109,11 @@ defmodule Pleroma.BBS.Handler do loop(%{state | counter: state.counter + 1}) {:error, :interrupted} -> - IO.puts "Caught Ctrl+C..." + IO.puts("Caught Ctrl+C...") loop(%{state | counter: state.counter + 1}) {:input, ^input, msg} -> - :ok = Logger.warn "received unknown message: #{inspect msg}" + :ok = Logger.warn("received unknown message: #{inspect(msg)}") loop(%{state | counter: state.counter + 1}) end end @@ -120,7 +124,7 @@ defmodule Pleroma.BBS.Handler do defp io_get(pid, prefix, counter, username) do prompt = prompt(prefix, counter, username) - send pid, {:input, self(), IO.gets(:stdio, prompt)} + send(pid, {:input, self(), IO.gets(:stdio, prompt)}) end defp prompt(prefix, counter, username) do -- cgit v1.2.3 From e3bf6655ba412268e4f5fee645609c9738e453ef Mon Sep 17 00:00:00 2001 From: lain Date: Sun, 31 Mar 2019 21:14:21 +0200 Subject: Add replying. --- lib/pleroma/bbs/handler.ex | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/bbs/handler.ex b/lib/pleroma/bbs/handler.ex index d999dcf76..7749eb3af 100644 --- a/lib/pleroma/bbs/handler.ex +++ b/lib/pleroma/bbs/handler.ex @@ -6,6 +6,7 @@ defmodule Pleroma.BBS.Handler do use Sshd.ShellHandler alias Pleroma.Web.CommonAPI alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Activity def on_shell(username, _pubkey, _ip, _port) do :ok = IO.puts("Welcome to #{Pleroma.Config.get([:instance, :name])}!") @@ -42,7 +43,7 @@ defmodule Pleroma.BBS.Handler do def puts_activity(activity) do status = Pleroma.Web.MastodonAPI.StatusView.render("status.json", %{activity: activity}) - IO.puts("#{status.id} by #{status.account.display_name} (#{status.account.acct}):") + IO.puts("-- #{status.id} by #{status.account.display_name} (#{status.account.acct})") IO.puts(HtmlSanitizeEx.strip_tags(status.content)) IO.puts("") end @@ -52,11 +53,27 @@ defmodule Pleroma.BBS.Handler do IO.puts("help - This help") IO.puts("home - Show the home timeline") IO.puts("p - Post the given text") + IO.puts("r - Reply to the post with the given id") IO.puts("quit - Quit") state end + def handle_command(%{user: user} = state, "r " <> text) do + text = String.trim(text) + [activity_id, rest] = String.split(text, " ", parts: 2) + + with %Activity{} <- Activity.get_by_id(activity_id), + {:ok, _activity} <- + CommonAPI.post(user, %{"status" => rest, "in_reply_to_status_id" => activity_id}) do + IO.puts("Replied!") + else + _e -> IO.puts("Could not reply...") + end + + state + end + def handle_command(%{user: user} = state, "p " <> text) do text = String.trim(text) @@ -104,7 +121,7 @@ defmodule Pleroma.BBS.Handler do {:input, ^input, code} when is_binary(code) -> code = String.trim(code) - handle_command(state, code) + state = handle_command(state, code) loop(%{state | counter: state.counter + 1}) -- cgit v1.2.3 From 629ad1766ce5da434bf095f6baa81a460334e1b2 Mon Sep 17 00:00:00 2001 From: lain Date: Sun, 31 Mar 2019 21:53:17 +0200 Subject: BBS: Some fixes. --- lib/pleroma/bbs/handler.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/bbs/handler.ex b/lib/pleroma/bbs/handler.ex index 7749eb3af..1ebba77d2 100644 --- a/lib/pleroma/bbs/handler.ex +++ b/lib/pleroma/bbs/handler.ex @@ -91,7 +91,7 @@ defmodule Pleroma.BBS.Handler do params = %{} - |> Map.put("type", ["Create", "Announce"]) + |> Map.put("type", ["Create"]) |> Map.put("blocking_user", user) |> Map.put("muting_user", user) |> Map.put("user", user) @@ -100,7 +100,6 @@ defmodule Pleroma.BBS.Handler do [user.ap_id | user.following] |> ActivityPub.fetch_activities(params) |> ActivityPub.contain_timeline(user) - |> Enum.reverse() Enum.each(activities, fn activity -> puts_activity(activity) @@ -109,8 +108,9 @@ defmodule Pleroma.BBS.Handler do state end - def handle_command(_state, command) do + def handle_command(state, command) do IO.puts("Unknown command '#{command}'") + state end defp wait_input(state, input) do -- cgit v1.2.3 From d1da6b155ab758ae4eb8fa154997a0a2a179897c Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 10 Apr 2019 09:34:53 +0200 Subject: Conversation: Add Conversations and Participations. --- lib/conversation.ex | 30 ++++++++++++++++++++++++++++++ lib/conversation/participation.ex | 31 +++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 lib/conversation.ex create mode 100644 lib/conversation/participation.ex (limited to 'lib') diff --git a/lib/conversation.ex b/lib/conversation.ex new file mode 100644 index 000000000..cfb78d925 --- /dev/null +++ b/lib/conversation.ex @@ -0,0 +1,30 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Conversation do + alias Pleroma.Repo + alias Pleroma.Conversation.Participation + use Ecto.Schema + import Ecto.Changeset + + schema "conversations" do + field(:ap_id, :string) + has_many(:participations, Participation) + + timestamps() + end + + def creation_cng(struct, params) do + struct + |> cast(params, [:ap_id]) + |> validate_required([:ap_id]) + |> unique_constraint(:ap_id) + end + + def create_for_ap_id(ap_id) do + %__MODULE__{} + |> creation_cng(%{ap_id: ap_id}) + |> Repo.insert() + end +end diff --git a/lib/conversation/participation.ex b/lib/conversation/participation.ex new file mode 100644 index 000000000..244d37c46 --- /dev/null +++ b/lib/conversation/participation.ex @@ -0,0 +1,31 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Conversation.Participation do + use Ecto.Schema + alias Pleroma.User + alias Pleroma.Conversation + alias Pleroma.Repo + import Ecto.Changeset + + schema "conversation_participations" do + belongs_to(:user, User, type: Pleroma.FlakeId) + belongs_to(:conversation, Conversation) + field(:read, :boolean, default: false) + + timestamps() + end + + def creation_cng(struct, params) do + struct + |> cast(params, [:user_id, :conversation_id]) + |> validate_required([:user_id, :conversation_id]) + end + + def create_for_user_and_conversation(user, conversation) do + %__MODULE__{} + |> creation_cng(%{user_id: user.id, conversation_id: conversation.id}) + |> Repo.insert() + end +end -- cgit v1.2.3 From 64c1c3a4071f3f99a59f38e2dcde499bda3969cf Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 10 Apr 2019 15:12:01 +0200 Subject: Participations: Add marking as read and unread. --- lib/conversation/participation.ex | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'lib') diff --git a/lib/conversation/participation.ex b/lib/conversation/participation.ex index 244d37c46..ab59a529e 100644 --- a/lib/conversation/participation.ex +++ b/lib/conversation/participation.ex @@ -28,4 +28,22 @@ defmodule Pleroma.Conversation.Participation do |> creation_cng(%{user_id: user.id, conversation_id: conversation.id}) |> Repo.insert() end + + def read_cng(struct, params) do + struct + |> cast(params, [:read]) + |> validate_required([:read]) + end + + def mark_as_read(participation) do + participation + |> read_cng(%{read: true}) + |> Repo.update() + end + + def mark_as_unread(participation) do + participation + |> read_cng(%{read: false}) + |> Repo.update() + end end -- cgit v1.2.3 From 280172f6f6d74872349e3b4e6f1feaa9c95b3900 Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 10 Apr 2019 16:33:45 +0200 Subject: Conversations: Create or bump on inserting a dm. --- lib/conversation.ex | 42 +++++++++++++++++++++++++++- lib/conversation/participation.ex | 6 +++- lib/pleroma/web/activity_pub/activity_pub.ex | 2 ++ 3 files changed, 48 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/conversation.ex b/lib/conversation.ex index cfb78d925..3d53e91b7 100644 --- a/lib/conversation.ex +++ b/lib/conversation.ex @@ -5,10 +5,12 @@ defmodule Pleroma.Conversation do alias Pleroma.Repo alias Pleroma.Conversation.Participation + alias Pleroma.User use Ecto.Schema import Ecto.Changeset schema "conversations" do + # This is the context ap id. field(:ap_id, :string) has_many(:participations, Participation) @@ -25,6 +27,44 @@ defmodule Pleroma.Conversation do def create_for_ap_id(ap_id) do %__MODULE__{} |> creation_cng(%{ap_id: ap_id}) - |> Repo.insert() + |> Repo.insert( + on_conflict: [set: [updated_at: NaiveDateTime.utc_now()]], + returning: true, + conflict_target: :ap_id + ) + end + + def get_for_ap_id(ap_id) do + Repo.get_by(__MODULE__, ap_id: ap_id) + end + + @doc """ + This will + 1. Create a conversation if there isn't one already + 2. Create a participation for all the people involved who don't have one already + 3. Bump all relevant participations to 'unread' + """ + def create_or_bump_for(activity) do + with true <- Pleroma.Web.ActivityPub.Visibility.is_direct?(activity), + "Create" <- activity.data["type"], + "Note" <- activity.data["object"]["type"], + ap_id when is_binary(ap_id) <- activity.data["object"]["context"] do + {:ok, conversation} = create_for_ap_id(ap_id) + + local_users = User.get_users_from_set(activity.recipients, true) + + participations = + Enum.map(local_users, fn user -> + {:ok, participation} = + Participation.create_for_user_and_conversation(user, conversation) + + participation + end) + + %{ + conversation + | participations: participations + } + end end end diff --git a/lib/conversation/participation.ex b/lib/conversation/participation.ex index ab59a529e..a58d0ca0d 100644 --- a/lib/conversation/participation.ex +++ b/lib/conversation/participation.ex @@ -26,7 +26,11 @@ defmodule Pleroma.Conversation.Participation do def create_for_user_and_conversation(user, conversation) do %__MODULE__{} |> creation_cng(%{user_id: user.id, conversation_id: conversation.id}) - |> Repo.insert() + |> Repo.insert( + on_conflict: [set: [read: false, updated_at: NaiveDateTime.utc_now()]], + returning: true, + conflict_target: [:user_id, :conversation_id] + ) end def read_cng(struct, params) do diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index f217e7bac..880d19a5e 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -4,6 +4,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do alias Pleroma.Activity + alias Pleroma.Conversation alias Pleroma.Instances alias Pleroma.Notification alias Pleroma.Object @@ -143,6 +144,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end) Notification.create_notifications(activity) + Conversation.create_or_bump_for(activity) stream_out(activity) {:ok, activity} else -- cgit v1.2.3 From 20d9b9076051d2dea60919ad85aaf88154629dc4 Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 10 Apr 2019 17:05:33 +0200 Subject: Participation: Get for a user. --- lib/conversation.ex | 4 ++-- lib/conversation/participation.ex | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/conversation.ex b/lib/conversation.ex index 3d53e91b7..6eedc72b6 100644 --- a/lib/conversation.ex +++ b/lib/conversation.ex @@ -51,10 +51,10 @@ defmodule Pleroma.Conversation do ap_id when is_binary(ap_id) <- activity.data["object"]["context"] do {:ok, conversation} = create_for_ap_id(ap_id) - local_users = User.get_users_from_set(activity.recipients, true) + users = User.get_users_from_set(activity.recipients) participations = - Enum.map(local_users, fn user -> + Enum.map(users, fn user -> {:ok, participation} = Participation.create_for_user_and_conversation(user, conversation) diff --git a/lib/conversation/participation.ex b/lib/conversation/participation.ex index a58d0ca0d..23e6409f1 100644 --- a/lib/conversation/participation.ex +++ b/lib/conversation/participation.ex @@ -8,6 +8,7 @@ defmodule Pleroma.Conversation.Participation do alias Pleroma.Conversation alias Pleroma.Repo import Ecto.Changeset + import Ecto.Query schema "conversation_participations" do belongs_to(:user, User, type: Pleroma.FlakeId) @@ -50,4 +51,12 @@ defmodule Pleroma.Conversation.Participation do |> read_cng(%{read: false}) |> Repo.update() end + + def for_user(user, params \\ %{}) do + from(p in __MODULE__, + where: p.user_id == ^user.id, + order_by: [desc: p.updated_at] + ) + |> Pleroma.Pagination.fetch_paginated(params) + end end -- cgit v1.2.3 From cf353514feff50c2ccb9a8079ce5e695eb7f8cb6 Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 10 Apr 2019 17:28:02 +0200 Subject: Participations: Add last activity. --- lib/conversation/participation.ex | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'lib') diff --git a/lib/conversation/participation.ex b/lib/conversation/participation.ex index 23e6409f1..4183af8a7 100644 --- a/lib/conversation/participation.ex +++ b/lib/conversation/participation.ex @@ -7,6 +7,7 @@ defmodule Pleroma.Conversation.Participation do alias Pleroma.User alias Pleroma.Conversation alias Pleroma.Repo + alias Pleroma.Web.ActivityPub.ActivityPub import Ecto.Changeset import Ecto.Query @@ -14,6 +15,7 @@ defmodule Pleroma.Conversation.Participation do belongs_to(:user, User, type: Pleroma.FlakeId) belongs_to(:conversation, Conversation) field(:read, :boolean, default: false) + field(:last_activity_id, Pleroma.FlakeId, virtual: true) timestamps() end @@ -59,4 +61,29 @@ defmodule Pleroma.Conversation.Participation do ) |> Pleroma.Pagination.fetch_paginated(params) end + + def for_user_with_last_activity_id(user, params \\ %{}) do + for_user(user, params) + |> Repo.preload(:conversation) + |> Enum.map(fn participation -> + # TODO: Don't load all those activities, just get the most recent + # Involves splitting up the query. + activities = + ActivityPub.fetch_activities_for_context(participation.conversation.ap_id, %{ + "user" => user, + "blocking_user" => user + }) + + activity_id = + case activities do + [activity | _] -> activity.id + _ -> nil + end + + %{ + participation + | last_activity_id: activity_id + } + end) + end end -- cgit v1.2.3 From c352a0aba601ae444bf5b479ab3c643728a8b35e Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 10 Apr 2019 17:48:31 +0200 Subject: Conversations: Make tests run. --- .../web/mastodon_api/mastodon_api_controller.ex | 36 ++++++++++++++++++++++ lib/pleroma/web/router.ex | 2 +- 2 files changed, 37 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 5462ce8be..57f73dacd 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -8,6 +8,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Ecto.Changeset alias Pleroma.Activity alias Pleroma.Config + alias Pleroma.Conversation.Participation alias Pleroma.Filter alias Pleroma.Notification alias Pleroma.Object @@ -1584,6 +1585,41 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end end + def conversations(%{assigns: %{user: user}} = conn, params) do + participations = Participation.for_user_with_last_activity_id(user, params) + + conversations = + Enum.map(participations, fn participation -> + %{ + id: participation.id, + # TODO: Add this. + accounts: [], + unread: !participation.read, + last_status: participation.last_activity_id + } + end) + + conn + |> add_link_headers(:conversations, participations) + |> json(conversations) + end + + def conversation_read(%{assigns: %{user: user}} = conn, %{"id" => participation_id}) do + with %Participation{} = participation <- + Repo.get_by(Participation, id: participation_id, user_id: user.id), + {:ok, participation} <- Participation.mark_as_read(participation) do + conn + |> json(%{ + id: participation.id, + # TODO: Add this. + accounts: [], + unread: !participation.read, + # TODO: Add this. + last_status: nil + }) + end + end + def try_render(conn, target, params) when is_binary(target) do res = render(conn, target, params) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 0af743b80..dc5119c50 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -273,7 +273,7 @@ defmodule Pleroma.Web.Router do get("/suggestions", MastodonAPIController, :suggestions) get("/conversations", MastodonAPIController, :conversations) - get("/conversations/:id/read", MastodonAPIController, :get_conversation) + post("/conversations/:id/read", MastodonAPIController, :conversation_read) get("/endorsements", MastodonAPIController, :empty_array) -- cgit v1.2.3 From d115d2a27e2e7a9df466fc4393416f804cb7e8e2 Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 10 Apr 2019 18:17:22 +0200 Subject: Conversations: Tidying up. --- lib/conversation.ex | 70 ------------------------ lib/conversation/participation.ex | 89 ------------------------------- lib/pleroma/conversation.ex | 70 ++++++++++++++++++++++++ lib/pleroma/conversation/participation.ex | 89 +++++++++++++++++++++++++++++++ 4 files changed, 159 insertions(+), 159 deletions(-) delete mode 100644 lib/conversation.ex delete mode 100644 lib/conversation/participation.ex create mode 100644 lib/pleroma/conversation.ex create mode 100644 lib/pleroma/conversation/participation.ex (limited to 'lib') diff --git a/lib/conversation.ex b/lib/conversation.ex deleted file mode 100644 index 6eedc72b6..000000000 --- a/lib/conversation.ex +++ /dev/null @@ -1,70 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Conversation do - alias Pleroma.Repo - alias Pleroma.Conversation.Participation - alias Pleroma.User - use Ecto.Schema - import Ecto.Changeset - - schema "conversations" do - # This is the context ap id. - field(:ap_id, :string) - has_many(:participations, Participation) - - timestamps() - end - - def creation_cng(struct, params) do - struct - |> cast(params, [:ap_id]) - |> validate_required([:ap_id]) - |> unique_constraint(:ap_id) - end - - def create_for_ap_id(ap_id) do - %__MODULE__{} - |> creation_cng(%{ap_id: ap_id}) - |> Repo.insert( - on_conflict: [set: [updated_at: NaiveDateTime.utc_now()]], - returning: true, - conflict_target: :ap_id - ) - end - - def get_for_ap_id(ap_id) do - Repo.get_by(__MODULE__, ap_id: ap_id) - end - - @doc """ - This will - 1. Create a conversation if there isn't one already - 2. Create a participation for all the people involved who don't have one already - 3. Bump all relevant participations to 'unread' - """ - def create_or_bump_for(activity) do - with true <- Pleroma.Web.ActivityPub.Visibility.is_direct?(activity), - "Create" <- activity.data["type"], - "Note" <- activity.data["object"]["type"], - ap_id when is_binary(ap_id) <- activity.data["object"]["context"] do - {:ok, conversation} = create_for_ap_id(ap_id) - - users = User.get_users_from_set(activity.recipients) - - participations = - Enum.map(users, fn user -> - {:ok, participation} = - Participation.create_for_user_and_conversation(user, conversation) - - participation - end) - - %{ - conversation - | participations: participations - } - end - end -end diff --git a/lib/conversation/participation.ex b/lib/conversation/participation.ex deleted file mode 100644 index 4183af8a7..000000000 --- a/lib/conversation/participation.ex +++ /dev/null @@ -1,89 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Conversation.Participation do - use Ecto.Schema - alias Pleroma.User - alias Pleroma.Conversation - alias Pleroma.Repo - alias Pleroma.Web.ActivityPub.ActivityPub - import Ecto.Changeset - import Ecto.Query - - schema "conversation_participations" do - belongs_to(:user, User, type: Pleroma.FlakeId) - belongs_to(:conversation, Conversation) - field(:read, :boolean, default: false) - field(:last_activity_id, Pleroma.FlakeId, virtual: true) - - timestamps() - end - - def creation_cng(struct, params) do - struct - |> cast(params, [:user_id, :conversation_id]) - |> validate_required([:user_id, :conversation_id]) - end - - def create_for_user_and_conversation(user, conversation) do - %__MODULE__{} - |> creation_cng(%{user_id: user.id, conversation_id: conversation.id}) - |> Repo.insert( - on_conflict: [set: [read: false, updated_at: NaiveDateTime.utc_now()]], - returning: true, - conflict_target: [:user_id, :conversation_id] - ) - end - - def read_cng(struct, params) do - struct - |> cast(params, [:read]) - |> validate_required([:read]) - end - - def mark_as_read(participation) do - participation - |> read_cng(%{read: true}) - |> Repo.update() - end - - def mark_as_unread(participation) do - participation - |> read_cng(%{read: false}) - |> Repo.update() - end - - def for_user(user, params \\ %{}) do - from(p in __MODULE__, - where: p.user_id == ^user.id, - order_by: [desc: p.updated_at] - ) - |> Pleroma.Pagination.fetch_paginated(params) - end - - def for_user_with_last_activity_id(user, params \\ %{}) do - for_user(user, params) - |> Repo.preload(:conversation) - |> Enum.map(fn participation -> - # TODO: Don't load all those activities, just get the most recent - # Involves splitting up the query. - activities = - ActivityPub.fetch_activities_for_context(participation.conversation.ap_id, %{ - "user" => user, - "blocking_user" => user - }) - - activity_id = - case activities do - [activity | _] -> activity.id - _ -> nil - end - - %{ - participation - | last_activity_id: activity_id - } - end) - end -end diff --git a/lib/pleroma/conversation.ex b/lib/pleroma/conversation.ex new file mode 100644 index 000000000..a77a7cd6e --- /dev/null +++ b/lib/pleroma/conversation.ex @@ -0,0 +1,70 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Conversation do + alias Pleroma.Conversation.Participation + alias Pleroma.Repo + alias Pleroma.User + use Ecto.Schema + import Ecto.Changeset + + schema "conversations" do + # This is the context ap id. + field(:ap_id, :string) + has_many(:participations, Participation) + + timestamps() + end + + def creation_cng(struct, params) do + struct + |> cast(params, [:ap_id]) + |> validate_required([:ap_id]) + |> unique_constraint(:ap_id) + end + + def create_for_ap_id(ap_id) do + %__MODULE__{} + |> creation_cng(%{ap_id: ap_id}) + |> Repo.insert( + on_conflict: [set: [updated_at: NaiveDateTime.utc_now()]], + returning: true, + conflict_target: :ap_id + ) + end + + def get_for_ap_id(ap_id) do + Repo.get_by(__MODULE__, ap_id: ap_id) + end + + @doc """ + This will + 1. Create a conversation if there isn't one already + 2. Create a participation for all the people involved who don't have one already + 3. Bump all relevant participations to 'unread' + """ + def create_or_bump_for(activity) do + with true <- Pleroma.Web.ActivityPub.Visibility.is_direct?(activity), + "Create" <- activity.data["type"], + "Note" <- activity.data["object"]["type"], + ap_id when is_binary(ap_id) <- activity.data["object"]["context"] do + {:ok, conversation} = create_for_ap_id(ap_id) + + users = User.get_users_from_set(activity.recipients) + + participations = + Enum.map(users, fn user -> + {:ok, participation} = + Participation.create_for_user_and_conversation(user, conversation) + + participation + end) + + %{ + conversation + | participations: participations + } + end + end +end diff --git a/lib/pleroma/conversation/participation.ex b/lib/pleroma/conversation/participation.ex new file mode 100644 index 000000000..1a2ceafeb --- /dev/null +++ b/lib/pleroma/conversation/participation.ex @@ -0,0 +1,89 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Conversation.Participation do + use Ecto.Schema + alias Pleroma.Conversation + alias Pleroma.Repo + alias Pleroma.User + alias Pleroma.Web.ActivityPub.ActivityPub + import Ecto.Changeset + import Ecto.Query + + schema "conversation_participations" do + belongs_to(:user, User, type: Pleroma.FlakeId) + belongs_to(:conversation, Conversation) + field(:read, :boolean, default: false) + field(:last_activity_id, Pleroma.FlakeId, virtual: true) + + timestamps() + end + + def creation_cng(struct, params) do + struct + |> cast(params, [:user_id, :conversation_id]) + |> validate_required([:user_id, :conversation_id]) + end + + def create_for_user_and_conversation(user, conversation) do + %__MODULE__{} + |> creation_cng(%{user_id: user.id, conversation_id: conversation.id}) + |> Repo.insert( + on_conflict: [set: [read: false, updated_at: NaiveDateTime.utc_now()]], + returning: true, + conflict_target: [:user_id, :conversation_id] + ) + end + + def read_cng(struct, params) do + struct + |> cast(params, [:read]) + |> validate_required([:read]) + end + + def mark_as_read(participation) do + participation + |> read_cng(%{read: true}) + |> Repo.update() + end + + def mark_as_unread(participation) do + participation + |> read_cng(%{read: false}) + |> Repo.update() + end + + def for_user(user, params \\ %{}) do + from(p in __MODULE__, + where: p.user_id == ^user.id, + order_by: [desc: p.updated_at] + ) + |> Pleroma.Pagination.fetch_paginated(params) + end + + def for_user_with_last_activity_id(user, params \\ %{}) do + for_user(user, params) + |> Repo.preload(:conversation) + |> Enum.map(fn participation -> + # TODO: Don't load all those activities, just get the most recent + # Involves splitting up the query. + activities = + ActivityPub.fetch_activities_for_context(participation.conversation.ap_id, %{ + "user" => user, + "blocking_user" => user + }) + + activity_id = + case activities do + [activity | _] -> activity.id + _ -> nil + end + + %{ + participation + | last_activity_id: activity_id + } + end) + end +end -- cgit v1.2.3 From db4badc6aa71df4cb9372ef4aff699399516ffb2 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Thu, 11 Apr 2019 17:22:42 +0700 Subject: move user disable into deactivation --- lib/mix/tasks/pleroma/user.ex | 18 -------- lib/pleroma/activity.ex | 8 ++-- lib/pleroma/notification.ex | 2 +- lib/pleroma/user.ex | 51 +++++++++------------- lib/pleroma/user/info.ex | 9 ---- lib/pleroma/web/activity_pub/activity_pub.ex | 2 +- lib/pleroma/web/admin_api/admin_api_controller.ex | 10 ----- lib/pleroma/web/router.ex | 1 - .../web/twitter_api/controllers/util_controller.ex | 2 +- lib/pleroma/web/twitter_api/twitter_api.ex | 2 +- 10 files changed, 29 insertions(+), 76 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 78493231c..441168df2 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -53,10 +53,6 @@ defmodule Mix.Tasks.Pleroma.User do mix pleroma.user toggle_activated NICKNAME - ## Disable or enable the user's account. - - mix pleroma.user toggle_disabled NICKNAME - ## Unsubscribe local users from user's account and deactivate it mix pleroma.user unsubscribe NICKNAME @@ -190,20 +186,6 @@ defmodule Mix.Tasks.Pleroma.User do end end - def run(["toggle_disabled", nickname]) do - Common.start_pleroma() - - case User.get_by_nickname(nickname) do - %User{} = user -> - {:ok, user} = User.disable(user, !user.info.disabled) - status = if(user.info.disabled, do: "ON", else: "OFF") - Mix.shell().info("Disabled status of #{nickname}: #{status}") - - _ -> - Mix.shell().error("No user #{nickname}") - end - end - def run(["reset_password", nickname]) do Common.start_pleroma() diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index c8c7f0d04..d06fd917d 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -100,7 +100,7 @@ defmodule Pleroma.Activity do def get_by_id(id) do Activity |> where([a], a.id == ^id) - |> restrict_disabled_users() + |> restrict_deactivated_users() |> Repo.one() end @@ -169,7 +169,7 @@ defmodule Pleroma.Activity do def get_create_by_object_ap_id(ap_id) when is_binary(ap_id) do create_by_object_ap_id(ap_id) - |> restrict_disabled_users() + |> restrict_deactivated_users() |> Repo.one() end @@ -296,11 +296,11 @@ defmodule Pleroma.Activity do end end - def restrict_disabled_users(query) do + def restrict_deactivated_users(query) do from(activity in query, where: fragment( - "? not in (SELECT ap_id FROM users WHERE info->'disabled' @> 'true')", + "? not in (SELECT ap_id FROM users WHERE info->'deactivated' @> 'true')", activity.actor ) ) diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 7de2d4c18..941218eea 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -36,7 +36,7 @@ defmodule Pleroma.Notification do |> where( [n, a], fragment( - "? not in (SELECT ap_id FROM users WHERE info->'disabled' @> 'true')", + "? not in (SELECT ap_id FROM users WHERE info->'deactivated' @> 'true')", a.actor ) ) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 1f2aca235..c08d3a171 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -117,9 +117,9 @@ defmodule Pleroma.User do } end - defp restrict_disabled(query) do + defp restrict_deactivated(query) do from(u in query, - where: not fragment("? \\? 'disabled' AND ?->'disabled' @> 'true'", u.info, u.info) + where: not fragment("? \\? 'deactivated' AND ?->'deactivated' @> 'true'", u.info, u.info) ) end @@ -130,7 +130,7 @@ defmodule Pleroma.User do where: u.follower_address in ^following, where: u.id != ^id ) - |> restrict_disabled() + |> restrict_deactivated() |> Repo.aggregate(:count, :id) end @@ -584,7 +584,7 @@ defmodule Pleroma.User do where: fragment("? <@ ?", ^[follower_address], u.following), where: u.id != ^id ) - |> restrict_disabled() + |> restrict_deactivated() end def get_followers_query(user, page) do @@ -612,7 +612,7 @@ defmodule Pleroma.User do where: u.follower_address in ^following, where: u.id != ^id ) - |> restrict_disabled() + |> restrict_deactivated() end def get_friends_query(user, page) do @@ -736,7 +736,7 @@ defmodule Pleroma.User do |> where([u], ^user.follower_address in u.following) |> where([u], u.id != ^user.id) |> select([u], %{count: count(u.id)}) - |> restrict_disabled() + |> restrict_deactivated() User |> where(id: ^user.id) @@ -887,7 +887,7 @@ defmodule Pleroma.User do ^processed_query ) ) - |> restrict_disabled() + |> restrict_deactivated() end defp trigram_search_subquery(term) do @@ -906,7 +906,7 @@ defmodule Pleroma.User do }, where: fragment("trim(? || ' ' || coalesce(?, '')) % ?", u.nickname, u.name, ^term) ) - |> restrict_disabled() + |> restrict_deactivated() end def blocks_import(%User{} = blocker, blocked_identifiers) when is_list(blocked_identifiers) do @@ -1150,13 +1150,24 @@ defmodule Pleroma.User do ) end + + def deactivate_async(user, status \\ true) do + PleromaJobQueue.enqueue(:user, __MODULE__, [:deactivate_async, user, status]) + end + + def perform(:deactivate_async, user, status), do: deactivate(user, status) + def deactivate(%User{} = user, status \\ true) do info_cng = User.Info.set_activation_status(user.info, status) - user + with {:ok, user} <- user |> change() |> put_embed(:info, info_cng) - |> update_and_set_cache() + |> update_and_set_cache(), + {:ok, friends} <- User.get_friends(user) do + Enum.each(friends, &update_follower_count(&1)) + {:ok, user} + end end def update_notification_settings(%User{} = user, settings \\ %{}) do @@ -1199,26 +1210,6 @@ defmodule Pleroma.User do {:ok, user} end - def disable_async(user, status \\ true) do - PleromaJobQueue.enqueue(:user, __MODULE__, [:disable_async, user, status]) - end - - def disable(%User{} = user, status \\ true) do - with {:ok, user} <- User.deactivate(user, status), - info_cng <- User.Info.set_disabled_status(user.info, status), - {:ok, user} <- - user - |> change() - |> put_embed(:info, info_cng) - |> update_and_set_cache(), - {:ok, friends} <- User.get_friends(user) do - Enum.each(friends, &update_follower_count(&1)) - {:ok, user} - end - end - - def perform(:disable_async, user, status), do: disable(user, status) - def html_filter_policy(%User{info: %{no_rich_text: true}}) do Pleroma.HTML.Scrubber.TwitterText end diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 07825a1c4..5afa7988c 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -40,7 +40,6 @@ defmodule Pleroma.User.Info do field(:hide_follows, :boolean, default: false) field(:pinned_activities, {:array, :string}, default: []) field(:flavour, :string, default: nil) - field(:disabled, :boolean, default: false) field(:notification_settings, :map, default: %{"remote" => true, "local" => true, "followers" => true, "follows" => true} @@ -76,14 +75,6 @@ defmodule Pleroma.User.Info do |> validate_required([:notification_settings]) end - def set_disabled_status(info, disabled) do - params = %{disabled: disabled} - - info - |> cast(params, [:disabled]) - |> validate_required([:disabled]) - end - def add_to_note_count(info, number) do set_note_count(info, info.note_count + number) end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index dd51d63c8..e749a80aa 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -804,7 +804,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> restrict_reblogs(opts) |> restrict_pinned(opts) |> restrict_muted_reblogs(opts) - |> Activity.restrict_disabled_users() + |> Activity.restrict_deactivated_users() end def fetch_activities(recipients, opts \\ %{}) do diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index fb43d0b01..70a5b5c5d 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -75,16 +75,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do end end - def user_toggle_disabled(conn, %{"nickname" => nickname}) do - user = User.get_by_nickname(nickname) - - {:ok, updated_user} = User.disable(user, !user.info.disabled) - - conn - |> put_view(AccountView) - |> render("show.json", %{user: updated_user}) - end - def user_toggle_activation(conn, %{"nickname" => nickname}) do user = User.get_by_nickname(nickname) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index dd23d7fd5..c331098b4 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -153,7 +153,6 @@ defmodule Pleroma.Web.Router do delete("/user", AdminAPIController, :user_delete) patch("/users/:nickname/toggle_activation", AdminAPIController, :user_toggle_activation) - patch("/users/:nickname/toggle_disabled", AdminAPIController, :user_toggle_disabled) post("/user", AdminAPIController, :user_create) put("/users/tag", AdminAPIController, :tag_users) delete("/users/tag", AdminAPIController, :untag_users) diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 317f2b0ff..44f4b183b 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -358,7 +358,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do def disable_account(%{assigns: %{user: user}} = conn, params) do case CommonAPI.Utils.confirm_current_password(user, params["password"]) do {:ok, user} -> - User.disable_async(user) + User.deactivate_async(user) json(conn, %{status: "success"}) {:error, msg} -> diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index 156f5d40f..bf1051afd 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -235,7 +235,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do nil -> {:error, "No user with such user_id"} - %User{info: %{disabled: true}} -> + %User{info: %{deactivated: true}} -> {:error, "User has been disabled"} user -> -- cgit v1.2.3 From 46bd5c1d875934370621375957fa33a10e2d3507 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Thu, 11 Apr 2019 17:28:12 +0700 Subject: fix format --- lib/pleroma/user.ex | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index c08d3a171..a8e902bf3 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1150,7 +1150,6 @@ defmodule Pleroma.User do ) end - def deactivate_async(user, status \\ true) do PleromaJobQueue.enqueue(:user, __MODULE__, [:deactivate_async, user, status]) end @@ -1160,11 +1159,12 @@ defmodule Pleroma.User do def deactivate(%User{} = user, status \\ true) do info_cng = User.Info.set_activation_status(user.info, status) - with {:ok, user} <- user - |> change() - |> put_embed(:info, info_cng) - |> update_and_set_cache(), - {:ok, friends} <- User.get_friends(user) do + with {:ok, user} <- + user + |> change() + |> put_embed(:info, info_cng) + |> update_and_set_cache(), + {:ok, friends} <- User.get_friends(user) do Enum.each(friends, &update_follower_count(&1)) {:ok, user} end -- cgit v1.2.3 From dd097a406baf15e983454ab8f13635b4af2a8de4 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Fri, 12 Apr 2019 16:38:32 +0700 Subject: add tests --- lib/pleroma/user.ex | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index a8e902bf3..95f5c6d21 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1159,13 +1159,16 @@ defmodule Pleroma.User do def deactivate(%User{} = user, status \\ true) do info_cng = User.Info.set_activation_status(user.info, status) - with {:ok, user} <- + with {:ok, friends} <- User.get_friends(user), + {:ok, followers} <- User.get_followers(user), + {:ok, user} <- user |> change() |> put_embed(:info, info_cng) - |> update_and_set_cache(), - {:ok, friends} <- User.get_friends(user) do + |> update_and_set_cache() do + Enum.each(followers, &invalidate_cache(&1)) Enum.each(friends, &update_follower_count(&1)) + {:ok, user} end end -- cgit v1.2.3 From c1ebb38d3adc1d222be832405ec0d7497b61f94a Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 15 Apr 2019 21:45:25 +0200 Subject: Conversation: Also create participations for remote users. Needed to get the participating user list. --- lib/pleroma/conversation.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/conversation.ex b/lib/pleroma/conversation.ex index a77a7cd6e..5a2a3fc6d 100644 --- a/lib/pleroma/conversation.ex +++ b/lib/pleroma/conversation.ex @@ -51,7 +51,7 @@ defmodule Pleroma.Conversation do ap_id when is_binary(ap_id) <- activity.data["object"]["context"] do {:ok, conversation} = create_for_ap_id(ap_id) - users = User.get_users_from_set(activity.recipients) + users = User.get_users_from_set(activity.recipients, false) participations = Enum.map(users, fn user -> -- cgit v1.2.3 From 0da985182f26927de0d2d9733816600afb89e79e Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 15 Apr 2019 21:58:58 +0200 Subject: Conversation: Return full status object, id is a string. --- lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 57f73dacd..3ffb767b9 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -1590,12 +1590,16 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do conversations = Enum.map(participations, fn participation -> + activity = Activity.get_by_id_with_object(participation.last_activity_id) + + last_status = StatusView.render("status.json", %{activity: activity, for: user}) + %{ - id: participation.id, + id: participation.id |> to_string(), # TODO: Add this. accounts: [], unread: !participation.read, - last_status: participation.last_activity_id + last_status: last_status } end) -- cgit v1.2.3 From 76999c73a790232ff0c30fff7a51589fb44651a3 Mon Sep 17 00:00:00 2001 From: lain Date: Mon, 15 Apr 2019 22:28:42 +0200 Subject: Conversation: Add accounts to output. --- lib/pleroma/conversation.ex | 1 + lib/pleroma/conversation/participation.ex | 1 + lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 9 +++++++-- 3 files changed, 9 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/conversation.ex b/lib/pleroma/conversation.ex index 5a2a3fc6d..d9c84cb1b 100644 --- a/lib/pleroma/conversation.ex +++ b/lib/pleroma/conversation.ex @@ -13,6 +13,7 @@ defmodule Pleroma.Conversation do # This is the context ap id. field(:ap_id, :string) has_many(:participations, Participation) + has_many(:users, through: [:participations, :user]) timestamps() end diff --git a/lib/pleroma/conversation/participation.ex b/lib/pleroma/conversation/participation.ex index 1a2ceafeb..f200c1df5 100644 --- a/lib/pleroma/conversation/participation.ex +++ b/lib/pleroma/conversation/participation.ex @@ -60,6 +60,7 @@ defmodule Pleroma.Conversation.Participation do order_by: [desc: p.updated_at] ) |> Pleroma.Pagination.fetch_paginated(params) + |> Repo.preload(conversation: [:users]) end def for_user_with_last_activity_id(user, params \\ %{}) do diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 3ffb767b9..c7166ff28 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -1594,10 +1594,15 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do last_status = StatusView.render("status.json", %{activity: activity, for: user}) + accounts = + AccountView.render("accounts.json", %{ + users: participation.conversation.users, + as: :user + }) + %{ id: participation.id |> to_string(), - # TODO: Add this. - accounts: [], + accounts: accounts, unread: !participation.read, last_status: last_status } -- cgit v1.2.3 From 24073f829f18d1ebd2cb23dd815c775b39145e42 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Sun, 21 Apr 2019 00:40:41 +0700 Subject: Refactor query to return only 1 message instead of 20 --- lib/pleroma/conversation/participation.ex | 13 ++----- lib/pleroma/web/activity_pub/activity_pub.ex | 53 ++++++++++++++++------------ 2 files changed, 33 insertions(+), 33 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/conversation/participation.ex b/lib/pleroma/conversation/participation.ex index f200c1df5..61021fb18 100644 --- a/lib/pleroma/conversation/participation.ex +++ b/lib/pleroma/conversation/participation.ex @@ -65,22 +65,13 @@ defmodule Pleroma.Conversation.Participation do def for_user_with_last_activity_id(user, params \\ %{}) do for_user(user, params) - |> Repo.preload(:conversation) |> Enum.map(fn participation -> - # TODO: Don't load all those activities, just get the most recent - # Involves splitting up the query. - activities = - ActivityPub.fetch_activities_for_context(participation.conversation.ap_id, %{ + activity_id = + ActivityPub.fetch_latest_activity_id_for_context(participation.conversation.ap_id, %{ "user" => user, "blocking_user" => user }) - activity_id = - case activities do - [activity | _] -> activity.id - _ -> nil - end - %{ participation | last_activity_id: activity_id diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 880d19a5e..577e6a59e 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -459,35 +459,44 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end end - def fetch_activities_for_context(context, opts \\ %{}) do + defp fetch_activities_for_context_query(context, opts) do public = ["https://www.w3.org/ns/activitystreams#Public"] recipients = if opts["user"], do: [opts["user"].ap_id | opts["user"].following] ++ public, else: public - query = from(activity in Activity) - - query = - query - |> restrict_blocked(opts) - |> restrict_recipients(recipients, opts["user"]) - - query = - from( - activity in query, - where: - fragment( - "?->>'type' = ? and ?->>'context' = ?", - activity.data, - "Create", - activity.data, - ^context - ), - order_by: [desc: :id] + from(activity in Activity) + |> restrict_blocked(opts) + |> restrict_recipients(recipients, opts["user"]) + |> where( + [activity], + fragment( + "?->>'type' = ? and ?->>'context' = ?", + activity.data, + "Create", + activity.data, + ^context ) - |> Activity.with_preloaded_object() + ) + |> order_by([activity], desc: activity.id) + end + + @spec fetch_activities_for_context(String.t(), keyword() | map()) :: [Activity.t()] + def fetch_activities_for_context(context, opts \\ %{}) do + context + |> fetch_activities_for_context_query(opts) + |> Activity.with_preloaded_object() + |> Repo.all() + end - Repo.all(query) + @spec fetch_latest_activity_id_for_context(String.t(), keyword() | map()) :: + Pleroma.FlakeId.t() | nil + def fetch_latest_activity_id_for_context(context, opts \\ %{}) do + context + |> fetch_activities_for_context_query(opts) + |> limit(1) + |> select([a], a.id) + |> Repo.one() end def fetch_public_activities(opts \\ %{}) do -- cgit v1.2.3 From 2662bea4e0d945edf7a24a44edf3ed39b2e64de9 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Sun, 21 Apr 2019 20:26:13 +0700 Subject: Add accounts and last_status to conversation read response --- .../web/mastodon_api/mastodon_api_controller.ex | 24 ++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index c7166ff28..86cacb0b0 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -1617,14 +1617,30 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do with %Participation{} = participation <- Repo.get_by(Participation, id: participation_id, user_id: user.id), {:ok, participation} <- Participation.mark_as_read(participation) do + participation = Repo.preload(participation, conversation: :users) + + accounts = + AccountView.render("accounts.json", %{ + users: participation.conversation.users, + as: :user + }) + + last_activity_id = + ActivityPub.fetch_latest_activity_id_for_context(participation.conversation.ap_id, %{ + "user" => user, + "blocking_user" => user + }) + + activity = Activity.get_by_id_with_object(last_activity_id) + + last_status = StatusView.render("status.json", %{activity: activity, for: user}) + conn |> json(%{ id: participation.id, - # TODO: Add this. - accounts: [], + accounts: accounts, unread: !participation.read, - # TODO: Add this. - last_status: nil + last_status: last_status }) end end -- cgit v1.2.3 From e56afefef9c0f256561c6ecab79e5520fdeb6d5e Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Sun, 21 Apr 2019 23:14:27 +0700 Subject: Refactor conversation function in MastodonAPIController to use a View --- .../web/mastodon_api/mastodon_api_controller.ex | 44 +++------------------- .../web/mastodon_api/views/conversation_view.ex | 38 +++++++++++++++++++ 2 files changed, 43 insertions(+), 39 deletions(-) create mode 100644 lib/pleroma/web/mastodon_api/views/conversation_view.ex (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 86cacb0b0..d5b6a943f 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -22,6 +22,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Web.CommonAPI alias Pleroma.Web.MastodonAPI.AccountView alias Pleroma.Web.MastodonAPI.AppView + alias Pleroma.Web.MastodonAPI.ConversationView alias Pleroma.Web.MastodonAPI.FilterView alias Pleroma.Web.MastodonAPI.ListView alias Pleroma.Web.MastodonAPI.MastodonAPI @@ -1590,22 +1591,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do conversations = Enum.map(participations, fn participation -> - activity = Activity.get_by_id_with_object(participation.last_activity_id) - - last_status = StatusView.render("status.json", %{activity: activity, for: user}) - - accounts = - AccountView.render("accounts.json", %{ - users: participation.conversation.users, - as: :user - }) - - %{ - id: participation.id |> to_string(), - accounts: accounts, - unread: !participation.read, - last_status: last_status - } + ConversationView.render("participation.json", %{participation: participation, user: user}) end) conn @@ -1617,31 +1603,11 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do with %Participation{} = participation <- Repo.get_by(Participation, id: participation_id, user_id: user.id), {:ok, participation} <- Participation.mark_as_read(participation) do - participation = Repo.preload(participation, conversation: :users) - - accounts = - AccountView.render("accounts.json", %{ - users: participation.conversation.users, - as: :user - }) - - last_activity_id = - ActivityPub.fetch_latest_activity_id_for_context(participation.conversation.ap_id, %{ - "user" => user, - "blocking_user" => user - }) - - activity = Activity.get_by_id_with_object(last_activity_id) - - last_status = StatusView.render("status.json", %{activity: activity, for: user}) + participation_view = + ConversationView.render("participation.json", %{participation: participation, user: user}) conn - |> json(%{ - id: participation.id, - accounts: accounts, - unread: !participation.read, - last_status: last_status - }) + |> json(participation_view) end end diff --git a/lib/pleroma/web/mastodon_api/views/conversation_view.ex b/lib/pleroma/web/mastodon_api/views/conversation_view.ex new file mode 100644 index 000000000..d841a840c --- /dev/null +++ b/lib/pleroma/web/mastodon_api/views/conversation_view.ex @@ -0,0 +1,38 @@ +defmodule Pleroma.Web.MastodonAPI.ConversationView do + use Pleroma.Web, :view + + alias Pleroma.Activity + alias Pleroma.Repo + alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.MastodonAPI.StatusView + alias Pleroma.Web.MastodonAPI.AccountView + + def render("participation.json", %{participation: participation, user: user}) do + participation = Repo.preload(participation, conversation: :users) + + last_activity_id = + with nil <- participation.last_activity_id do + ActivityPub.fetch_latest_activity_id_for_context(participation.conversation.ap_id, %{ + "user" => user, + "blocking_user" => user + }) + end + + activity = Activity.get_by_id_with_object(last_activity_id) + + last_status = StatusView.render("status.json", %{activity: activity, for: user}) + + accounts = + AccountView.render("accounts.json", %{ + users: participation.conversation.users, + as: :user + }) + + %{ + id: participation.id |> to_string(), + accounts: accounts, + unread: !participation.read, + last_status: last_status + } + end +end -- cgit v1.2.3 From eeb093631cd50583feb4864a016d0dc1e4c58f5e Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Sun, 21 Apr 2019 23:19:36 +0700 Subject: Fix Credo warning --- lib/pleroma/web/mastodon_api/views/conversation_view.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/views/conversation_view.ex b/lib/pleroma/web/mastodon_api/views/conversation_view.ex index d841a840c..eb61baa03 100644 --- a/lib/pleroma/web/mastodon_api/views/conversation_view.ex +++ b/lib/pleroma/web/mastodon_api/views/conversation_view.ex @@ -3,9 +3,9 @@ defmodule Pleroma.Web.MastodonAPI.ConversationView do alias Pleroma.Activity alias Pleroma.Repo + alias Pleroma.Web.MastodonAPI.AccountView alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.MastodonAPI.StatusView - alias Pleroma.Web.MastodonAPI.AccountView def render("participation.json", %{participation: participation, user: user}) do participation = Repo.preload(participation, conversation: :users) -- cgit v1.2.3 From 4908e0eeee2ecb58b204198c20720d52548b6f4a Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Sun, 21 Apr 2019 23:24:33 +0700 Subject: Fix Credo warning --- lib/pleroma/web/mastodon_api/views/conversation_view.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/views/conversation_view.ex b/lib/pleroma/web/mastodon_api/views/conversation_view.ex index eb61baa03..8e8f7cf31 100644 --- a/lib/pleroma/web/mastodon_api/views/conversation_view.ex +++ b/lib/pleroma/web/mastodon_api/views/conversation_view.ex @@ -3,8 +3,8 @@ defmodule Pleroma.Web.MastodonAPI.ConversationView do alias Pleroma.Activity alias Pleroma.Repo - alias Pleroma.Web.MastodonAPI.AccountView alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.MastodonAPI.AccountView alias Pleroma.Web.MastodonAPI.StatusView def render("participation.json", %{participation: participation, user: user}) do -- cgit v1.2.3 From 963d5774af7efb57fa306b3ac164049f8958a72c Mon Sep 17 00:00:00 2001 From: Sachin Joshi Date: Wed, 24 Apr 2019 07:06:17 +0545 Subject: fix the status notification with special char --- lib/pleroma/web/twitter_api/views/activity_view.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex index c64152da8..1007a2a48 100644 --- a/lib/pleroma/web/twitter_api/views/activity_view.ex +++ b/lib/pleroma/web/twitter_api/views/activity_view.ex @@ -289,7 +289,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do "uri" => object.data["id"], "user" => UserView.render("show.json", %{user: user, for: opts[:for]}), "statusnet_html" => html, - "text" => text, + "text" => HtmlEntities.decode(text), "is_local" => activity.local, "is_post_verb" => true, "created_at" => created_at, -- cgit v1.2.3 From ce4825c1dc8a2b7ec2712170f45cde0ae14b46cf Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 30 Apr 2019 20:21:28 +0300 Subject: Do not normalize objects in stream_out unless the activity type is Create Saves quite a bit of time with delete activities because they would always query the db --- lib/pleroma/web/activity_pub/activity_pub.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 604ffae7b..483a2153f 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -168,7 +168,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do public = "https://www.w3.org/ns/activitystreams#Public" if activity.data["type"] in ["Create", "Announce", "Delete"] do - object = Object.normalize(activity) Pleroma.Web.Streamer.stream("user", activity) Pleroma.Web.Streamer.stream("list", activity) @@ -180,6 +179,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end if activity.data["type"] in ["Create"] do + object = Object.normalize(activity) + object.data |> Map.get("tag", []) |> Enum.filter(fn tag -> is_bitstring(tag) end) -- cgit v1.2.3 From 85fa2fbce4ee315a15b517fae4bc9b5474d1db5a Mon Sep 17 00:00:00 2001 From: Sachin Joshi Date: Wed, 1 May 2019 01:37:17 +0545 Subject: add scrubber for html special char --- lib/pleroma/html.ex | 27 ++++++++++++++++++---- lib/pleroma/web/twitter_api/views/activity_view.ex | 2 +- 2 files changed, 23 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex index cf6c0ee0a..eb33d12d9 100644 --- a/lib/pleroma/html.ex +++ b/lib/pleroma/html.ex @@ -28,12 +28,18 @@ defmodule Pleroma.HTML do def filter_tags(html), do: filter_tags(html, nil) def strip_tags(html), do: Scrubber.scrub(html, Scrubber.StripTags) - def get_cached_scrubbed_html_for_activity(content, scrubbers, activity, key \\ "") do + def get_cached_scrubbed_html_for_activity( + content, + scrubbers, + activity, + key \\ "", + callback \\ fn x -> x end + ) do key = "#{key}#{generate_scrubber_signature(scrubbers)}|#{activity.id}" Cachex.fetch!(:scrubber_cache, key, fn _key -> object = Pleroma.Object.normalize(activity) - ensure_scrubbed_html(content, scrubbers, object.data["fake"] || false) + ensure_scrubbed_html(content, scrubbers, object.data["fake"] || false, callback) end) end @@ -42,16 +48,27 @@ defmodule Pleroma.HTML do content, HtmlSanitizeEx.Scrubber.StripTags, activity, - key + key, + &HtmlEntities.decode/1 ) end def ensure_scrubbed_html( content, scrubbers, - false = _fake + fake, + callback ) do - {:commit, filter_tags(content, scrubbers)} + content = + content + |> filter_tags(scrubbers) + |> callback.() + + if fake do + {:ignore, content} + else + {:commit, content} + end end def ensure_scrubbed_html( diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex index 1007a2a48..c64152da8 100644 --- a/lib/pleroma/web/twitter_api/views/activity_view.ex +++ b/lib/pleroma/web/twitter_api/views/activity_view.ex @@ -289,7 +289,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do "uri" => object.data["id"], "user" => UserView.render("show.json", %{user: user, for: opts[:for]}), "statusnet_html" => html, - "text" => HtmlEntities.decode(text), + "text" => text, "is_local" => activity.local, "is_post_verb" => true, "created_at" => created_at, -- cgit v1.2.3 From f11e7037c21d611cddd7f2eab64ebfc39630a078 Mon Sep 17 00:00:00 2001 From: Alex S Date: Wed, 1 May 2019 16:09:53 +0700 Subject: test fixes --- lib/mix/tasks/pleroma/user.ex | 2 +- lib/pleroma/user.ex | 18 +++++++++--------- .../web/activity_pub/activity_pub_controller.ex | 2 +- lib/pleroma/web/activity_pub/transmogrifier.ex | 2 +- .../web/mastodon_api/mastodon_api_controller.ex | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index b396ff0de..9e2523b18 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -126,7 +126,7 @@ defmodule Mix.Tasks.Pleroma.User do proceed? = assume_yes? or Mix.shell().yes?("Continue?") - unless not proceed? do + if proceed? do Common.start_pleroma() params = %{ diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 755d8f773..1c62f238e 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -513,7 +513,7 @@ defmodule Pleroma.User do case user_result do {:ok, user} -> {:commit, user} - {:error, error} -> {:ignore, error} + {:error, _error} -> {:ignore, nil} end end) end @@ -563,7 +563,7 @@ defmodule Pleroma.User do {:ok, user} else - e -> {:error, e} + _e -> {:error, "not found " <> nickname} end end end @@ -1210,11 +1210,11 @@ defmodule Pleroma.User do case ap_try do {:ok, user} -> - user + {:ok, user} _ -> case OStatus.make_user(ap_id) do - {:ok, user} -> user + {:ok, user} -> {:ok, user} _ -> {:error, "Could not fetch by AP id"} end end @@ -1229,15 +1229,15 @@ defmodule Pleroma.User do # Whether to fetch initial posts for the user (if it's a new user & the fetching is enabled) should_fetch_initial = is_nil(user) and Pleroma.Config.get([:fetch_initial_posts, :enabled]) + resp = fetch_by_ap_id(ap_id) + if should_fetch_initial do - with {:ok, %User{} = user} = fetch_by_ap_id(ap_id) do + with {:ok, %User{} = user} = resp do {:ok, _} = Task.start(__MODULE__, :fetch_initial_posts, [user]) end - - {:ok, user} - else - _ -> {:error, "Could not fetch by AP id"} end + + resp end end diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index 0b80566bf..c967ab7a9 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -155,7 +155,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do def inbox(%{assigns: %{valid_signature: true}} = conn, %{"nickname" => nickname} = params) do with %User{} = recipient <- User.get_cached_by_nickname(nickname), - %User{} = actor <- User.get_or_fetch_by_ap_id(params["actor"]), + {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(params["actor"]), true <- Utils.recipient_in_message(recipient, actor, params), params <- Utils.maybe_splice_recipient(recipient.ap_id, params) do Federator.incoming_ap_doc(params) diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 80317171d..b774c2afa 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -126,7 +126,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do def fix_implicit_addressing(object, _), do: object def fix_addressing(object) do - %User{} = user = User.get_or_fetch_by_ap_id(object["actor"]) + {:ok, %User{} = user} = User.get_or_fetch_by_ap_id(object["actor"]) followers_collection = User.ap_followers(user) object diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 727e1c310..ed585098a 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -1653,7 +1653,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do x, "id", case User.get_or_fetch(x["acct"]) do - {:ok, %User{} = %{id: id}} -> id + {:ok, %User{id: id}} -> id _ -> 0 end ) -- cgit v1.2.3 From 51e26f14f7fc342c23fe1fe643a1cf444ef9392b Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 1 May 2019 13:52:44 +0300 Subject: Remove redundant ensure_scrubbed_html It is never used as handling for fake and non-fake activities was merged into one function above it --- lib/pleroma/html.ex | 8 -------- 1 file changed, 8 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex index eb33d12d9..726c370ad 100644 --- a/lib/pleroma/html.ex +++ b/lib/pleroma/html.ex @@ -71,14 +71,6 @@ defmodule Pleroma.HTML do end end - def ensure_scrubbed_html( - content, - scrubbers, - true = _fake - ) do - {:ignore, filter_tags(content, scrubbers)} - end - defp generate_scrubber_signature(scrubber) when is_atom(scrubber) do generate_scrubber_signature([scrubber]) end -- cgit v1.2.3 From c854bff8f528b4f1560707ac3aa74f4a37044f52 Mon Sep 17 00:00:00 2001 From: Maksim Date: Wed, 1 May 2019 13:28:04 +0000 Subject: Refactored Pleroma.Web.Auth.Authenticator --- lib/pleroma/web/auth/authenticator.ex | 26 ++++++++++++++++++ lib/pleroma/web/auth/ldap_authenticator.ex | 39 +++++++++++---------------- lib/pleroma/web/auth/pleroma_authenticator.ex | 15 ++++------- 3 files changed, 47 insertions(+), 33 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/auth/authenticator.ex b/lib/pleroma/web/auth/authenticator.ex index b02f595dc..d4e0ffa80 100644 --- a/lib/pleroma/web/auth/authenticator.ex +++ b/lib/pleroma/web/auth/authenticator.ex @@ -42,4 +42,30 @@ defmodule Pleroma.Web.Auth.Authenticator do implementation().oauth_consumer_template() || Pleroma.Config.get([:auth, :oauth_consumer_template], "consumer.html") end + + @doc "Gets user by nickname or email for auth." + @spec fetch_user(String.t()) :: User.t() | nil + def fetch_user(name) do + User.get_by_nickname_or_email(name) + end + + # Gets name and password from conn + # + @spec fetch_credentials(Plug.Conn.t() | map()) :: + {:ok, {name :: any, password :: any}} | {:error, :invalid_credentials} + def fetch_credentials(%Plug.Conn{params: params} = _), + do: fetch_credentials(params) + + def fetch_credentials(params) do + case params do + %{"authorization" => %{"name" => name, "password" => password}} -> + {:ok, {name, password}} + + %{"grant_type" => "password", "username" => name, "password" => password} -> + {:ok, {name, password}} + + _ -> + {:error, :invalid_credentials} + end + end end diff --git a/lib/pleroma/web/auth/ldap_authenticator.ex b/lib/pleroma/web/auth/ldap_authenticator.ex index 363c99597..177c05636 100644 --- a/lib/pleroma/web/auth/ldap_authenticator.ex +++ b/lib/pleroma/web/auth/ldap_authenticator.ex @@ -7,6 +7,9 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do require Logger + import Pleroma.Web.Auth.Authenticator, + only: [fetch_credentials: 1, fetch_user: 1] + @behaviour Pleroma.Web.Auth.Authenticator @base Pleroma.Web.Auth.PleromaAuthenticator @@ -20,30 +23,20 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do defdelegate oauth_consumer_template, to: @base def get_user(%Plug.Conn{} = conn) do - if Pleroma.Config.get([:ldap, :enabled]) do - {name, password} = - case conn.params do - %{"authorization" => %{"name" => name, "password" => password}} -> - {name, password} - - %{"grant_type" => "password", "username" => name, "password" => password} -> - {name, password} - end - - case ldap_user(name, password) do - %User{} = user -> - {:ok, user} + with {:ldap, true} <- {:ldap, Pleroma.Config.get([:ldap, :enabled])}, + {:ok, {name, password}} <- fetch_credentials(conn), + %User{} = user <- ldap_user(name, password) do + {:ok, user} + else + {:error, {:ldap_connection_error, _}} -> + # When LDAP is unavailable, try default authenticator + @base.get_user(conn) - {:error, {:ldap_connection_error, _}} -> - # When LDAP is unavailable, try default authenticator - @base.get_user(conn) + {:ldap, _} -> + @base.get_user(conn) - error -> - error - end - else - # Fall back to default authenticator - @base.get_user(conn) + error -> + error end end @@ -94,7 +87,7 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do case :eldap.simple_bind(connection, "#{uid}=#{name},#{base}", password) do :ok -> - case User.get_by_nickname_or_email(name) do + case fetch_user(name) do %User{} = user -> user diff --git a/lib/pleroma/web/auth/pleroma_authenticator.ex b/lib/pleroma/web/auth/pleroma_authenticator.ex index d647f1e05..dd79cdcf7 100644 --- a/lib/pleroma/web/auth/pleroma_authenticator.ex +++ b/lib/pleroma/web/auth/pleroma_authenticator.ex @@ -8,19 +8,14 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do alias Pleroma.Repo alias Pleroma.User + import Pleroma.Web.Auth.Authenticator, + only: [fetch_credentials: 1, fetch_user: 1] + @behaviour Pleroma.Web.Auth.Authenticator def get_user(%Plug.Conn{} = conn) do - {name, password} = - case conn.params do - %{"authorization" => %{"name" => name, "password" => password}} -> - {name, password} - - %{"grant_type" => "password", "username" => name, "password" => password} -> - {name, password} - end - - with {_, %User{} = user} <- {:user, User.get_by_nickname_or_email(name)}, + with {:ok, {name, password}} <- fetch_credentials(conn), + {_, %User{} = user} <- {:user, fetch_user(name)}, {_, true} <- {:checkpw, Pbkdf2.checkpw(password, user.password_hash)} do {:ok, user} else -- cgit v1.2.3 From 8af55728e47f9f62d237704cd5a33fba5f946fa2 Mon Sep 17 00:00:00 2001 From: Roman Chvanikov Date: Mon, 29 Apr 2019 03:44:04 +0700 Subject: Fix tests --- lib/pleroma/conversation.ex | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/conversation.ex b/lib/pleroma/conversation.ex index d9c84cb1b..e6a4ccc85 100644 --- a/lib/pleroma/conversation.ex +++ b/lib/pleroma/conversation.ex @@ -47,9 +47,10 @@ defmodule Pleroma.Conversation do """ def create_or_bump_for(activity) do with true <- Pleroma.Web.ActivityPub.Visibility.is_direct?(activity), + object <- Pleroma.Object.normalize(activity), "Create" <- activity.data["type"], - "Note" <- activity.data["object"]["type"], - ap_id when is_binary(ap_id) <- activity.data["object"]["context"] do + "Note" <- object.data["type"], + ap_id when is_binary(ap_id) and byte_size(ap_id) > 0 <- object.data["context"] do {:ok, conversation} = create_for_ap_id(ap_id) users = User.get_users_from_set(activity.recipients, false) -- cgit v1.2.3 From 533d8cd5816343ccfb6e26495124416e9808554c Mon Sep 17 00:00:00 2001 From: AkiraFukushima Date: Thu, 2 May 2019 21:04:00 +0900 Subject: Parse access_token from body parameters and URL parameters --- lib/pleroma/plugs/oauth_plug.ex | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/plugs/oauth_plug.ex b/lib/pleroma/plugs/oauth_plug.ex index 5888d596a..9d43732eb 100644 --- a/lib/pleroma/plugs/oauth_plug.ex +++ b/lib/pleroma/plugs/oauth_plug.ex @@ -16,6 +16,16 @@ defmodule Pleroma.Plugs.OAuthPlug do def call(%{assigns: %{user: %User{}}} = conn, _), do: conn + def call(%{params: %{"access_token" => access_token}} = conn, _) do + with {:ok, user, token_record} <- fetch_user_and_token(access_token) do + conn + |> assign(:token, token_record) + |> assign(:user, user) + else + _ -> conn + end + end + def call(conn, _) do with {:ok, token_str} <- fetch_token_str(conn), {:ok, user, token_record} <- fetch_user_and_token(token_str) do -- cgit v1.2.3 From 38b79461dfe6d14eb95799013b2fdd502e73245c Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 2 May 2019 22:19:14 +0300 Subject: Fix embeded relationships in Mastodon API Currently some endpoints render accounts without for user resulting in embedded relationship being empty. It causes bugs in followers/following tab in pleroma-fe but I fixed it for other endpoints as well just in case --- lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index ed585098a..78dae1c64 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -704,7 +704,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end end - def favourited_by(conn, %{"id" => id}) do + def favourited_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do with %Activity{data: %{"object" => object}} <- Repo.get(Activity, id), %Object{data: %{"likes" => likes}} <- Object.normalize(object) do q = from(u in User, where: u.ap_id in ^likes) @@ -712,13 +712,13 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do conn |> put_view(AccountView) - |> render(AccountView, "accounts.json", %{users: users, as: :user}) + |> render(AccountView, "accounts.json", %{for: user, users: users, as: :user}) else _ -> json(conn, []) end end - def reblogged_by(conn, %{"id" => id}) do + def reblogged_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do with %Activity{data: %{"object" => object}} <- Repo.get(Activity, id), %Object{data: %{"announcements" => announces}} <- Object.normalize(object) do q = from(u in User, where: u.ap_id in ^announces) @@ -726,7 +726,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do conn |> put_view(AccountView) - |> render("accounts.json", %{users: users, as: :user}) + |> render("accounts.json", %{for: user, users: users, as: :user}) else _ -> json(conn, []) end @@ -783,7 +783,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do conn |> add_link_headers(:followers, followers, user) |> put_view(AccountView) - |> render("accounts.json", %{users: followers, as: :user}) + |> render("accounts.json", %{for: for_user, users: followers, as: :user}) end end @@ -800,7 +800,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do conn |> add_link_headers(:following, followers, user) |> put_view(AccountView) - |> render("accounts.json", %{users: followers, as: :user}) + |> render("accounts.json", %{for: for_user, users: followers, as: :user}) end end @@ -808,7 +808,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do with {:ok, follow_requests} <- User.get_follow_requests(followed) do conn |> put_view(AccountView) - |> render("accounts.json", %{users: follow_requests, as: :user}) + |> render("accounts.json", %{for: followed, users: follow_requests, as: :user}) end end @@ -1235,7 +1235,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do {:ok, users} = Pleroma.List.get_following(list) do conn |> put_view(AccountView) - |> render("accounts.json", %{users: users, as: :user}) + |> render("accounts.json", %{for: user, users: users, as: :user}) end end -- cgit v1.2.3 From 81d1aa424d65b364ec8f2aee45247e7d95e3f255 Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 3 May 2019 13:39:14 +0200 Subject: Streamer: Stream out Conversations/Participations. --- lib/pleroma/conversation.ex | 11 +++++++---- lib/pleroma/web/activity_pub/activity_pub.ex | 22 ++++++++++++++++++++- lib/pleroma/web/streamer.ex | 29 ++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/conversation.ex b/lib/pleroma/conversation.ex index e6a4ccc85..6e26c5fd4 100644 --- a/lib/pleroma/conversation.ex +++ b/lib/pleroma/conversation.ex @@ -63,10 +63,13 @@ defmodule Pleroma.Conversation do participation end) - %{ - conversation - | participations: participations - } + {:ok, + %{ + conversation + | participations: participations + }} + else + e -> {:error, e} end end end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 28754e864..6c737d0a4 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -142,8 +142,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end) Notification.create_notifications(activity) - Conversation.create_or_bump_for(activity) + + participations = + activity + |> Conversation.create_or_bump_for() + |> get_participations() + stream_out(activity) + stream_out_participations(participations) {:ok, activity} else %Activity{} = activity -> @@ -166,6 +172,19 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end end + defp get_participations({:ok, %{participations: participations}}), do: participations + defp get_participations(_), do: [] + + def stream_out_participations(participations) do + participations = + participations + |> Repo.preload(:user) + + Enum.each(participations, fn participation -> + Pleroma.Web.Streamer.stream("participation", participation) + end) + end + def stream_out(activity) do public = "https://www.w3.org/ns/activitystreams#Public" @@ -197,6 +216,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end end else + # TODO: Write test, replace with visibility test if !Enum.member?(activity.data["cc"] || [], public) && !Enum.member?( activity.data["to"], diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex index 72eaf2084..b8f6663a1 100644 --- a/lib/pleroma/web/streamer.ex +++ b/lib/pleroma/web/streamer.ex @@ -5,6 +5,7 @@ defmodule Pleroma.Web.Streamer do use GenServer require Logger + alias Pleroma.Conversation.Participation alias Pleroma.Activity alias Pleroma.Notification alias Pleroma.Object @@ -71,6 +72,15 @@ defmodule Pleroma.Web.Streamer do {:noreply, topics} end + def handle_cast(%{action: :stream, topic: "participation", item: participation}, topics) do + user_topic = "direct:#{participation.user_id}" + Logger.debug("Trying to push a conversation participation to #{user_topic}\n\n") + + push_to_socket(topics, user_topic, participation) + + {:noreply, topics} + end + def handle_cast(%{action: :stream, topic: "list", item: item}, topics) do # filter the recipient list if the activity is not public, see #270. recipient_lists = @@ -192,6 +202,19 @@ defmodule Pleroma.Web.Streamer do |> Jason.encode!() end + def represent_conversation(%Participation{} = participation) do + %{ + event: "conversation", + payload: + Pleroma.Web.MastodonAPI.ConversationView.render("participation.json", %{ + participation: participation, + user: participation.user + }) + |> Jason.encode!() + } + |> Jason.encode!() + end + def push_to_socket(topics, topic, %Activity{data: %{"type" => "Announce"}} = item) do Enum.each(topics[topic] || [], fn socket -> # Get the current user so we have up-to-date blocks etc. @@ -214,6 +237,12 @@ defmodule Pleroma.Web.Streamer do end) end + def push_to_socket(topics, topic, %Participation{} = participation) do + Enum.each(topics[topic] || [], fn socket -> + send(socket.transport_pid, {:text, represent_conversation(participation)}) + end) + end + def push_to_socket(topics, topic, %Activity{ data: %{"type" => "Delete", "deleted_activity_id" => deleted_activity_id} }) do -- cgit v1.2.3 From a0c755cc4ac3af7ddb7e8fe91fcfc1bae9750e9b Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 3 May 2019 13:40:43 +0200 Subject: MastodonApi: Bump api level. --- lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index aa3f46482..754946624 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -159,7 +159,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end end - @mastodon_api_level "2.5.0" + @mastodon_api_level "2.6.5" def masto_instance(conn, _params) do instance = Config.get(:instance) -- cgit v1.2.3 From acb04306b6954aac8d66a74438d0e213d93a9046 Mon Sep 17 00:00:00 2001 From: feld Date: Fri, 3 May 2019 11:45:04 +0000 Subject: Standardize construction of websocket URL This follows up on the change made in d747bd98 --- lib/pleroma/plugs/http_security_plug.ex | 2 +- lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/plugs/http_security_plug.ex b/lib/pleroma/plugs/http_security_plug.ex index f701aaaa5..a476f1d49 100644 --- a/lib/pleroma/plugs/http_security_plug.ex +++ b/lib/pleroma/plugs/http_security_plug.ex @@ -35,7 +35,7 @@ defmodule Pleroma.Plugs.HTTPSecurityPlug do defp csp_string do scheme = Config.get([Pleroma.Web.Endpoint, :url])[:scheme] static_url = Pleroma.Web.Endpoint.static_url() - websocket_url = String.replace(static_url, "http", "ws") + websocket_url = Pleroma.Web.Endpoint.websocket_url() connect_src = "connect-src 'self' #{static_url} #{websocket_url}" diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index ed585098a..201a21f50 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -1295,8 +1295,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do initial_state = %{ meta: %{ - streaming_api_base_url: - String.replace(Pleroma.Web.Endpoint.static_url(), "http", "ws"), + streaming_api_base_url: Pleroma.Web.Endpoint.websocket_url(), access_token: token, locale: "en", domain: Pleroma.Web.Endpoint.host(), -- cgit v1.2.3 From c42ded13a2caa02f3f5aa00accce69b183546f9e Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 3 May 2019 13:53:17 +0200 Subject: Credo fixes. --- lib/pleroma/web/streamer.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex index b8f6663a1..133decfc4 100644 --- a/lib/pleroma/web/streamer.ex +++ b/lib/pleroma/web/streamer.ex @@ -5,8 +5,8 @@ defmodule Pleroma.Web.Streamer do use GenServer require Logger - alias Pleroma.Conversation.Participation alias Pleroma.Activity + alias Pleroma.Conversation.Participation alias Pleroma.Notification alias Pleroma.Object alias Pleroma.User -- cgit v1.2.3 From 85b5c60694e07d3bfb1f885d5fda14be6b7bade9 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Thu, 7 Feb 2019 16:41:20 +0100 Subject: Pleroma.Formatter: width/height to class=emoji --- lib/pleroma/formatter.ex | 4 +--- lib/pleroma/html.ex | 2 ++ 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex index dab8910c1..0ec6bcee0 100644 --- a/lib/pleroma/formatter.ex +++ b/lib/pleroma/formatter.ex @@ -113,9 +113,7 @@ defmodule Pleroma.Formatter do html = if not strip do - "#{emoji}" + "#{emoji}" else "" end diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex index 726c370ad..d1da746de 100644 --- a/lib/pleroma/html.ex +++ b/lib/pleroma/html.ex @@ -151,6 +151,7 @@ defmodule Pleroma.HTML.Scrubber.TwitterText do Meta.allow_tag_with_these_attributes("img", [ "width", "height", + "class", "title", "alt" ]) @@ -221,6 +222,7 @@ defmodule Pleroma.HTML.Scrubber.Default do Meta.allow_tag_with_these_attributes("img", [ "width", "height", + "class", "title", "alt" ]) -- cgit v1.2.3 From d70af32127bda1431bacad58e7c6516a2e652fcd Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Mon, 11 Feb 2019 23:47:32 +0100 Subject: Pleroma.User: remove emojify on parse_bio --- lib/pleroma/user.ex | 21 +++++++++------------ .../web/mastodon_api/mastodon_api_controller.ex | 2 +- 2 files changed, 10 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 1c62f238e..1741ce684 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -11,7 +11,6 @@ defmodule Pleroma.User do alias Comeonin.Pbkdf2 alias Pleroma.Activity alias Pleroma.Bookmark - alias Pleroma.Formatter alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Registration @@ -1331,18 +1330,15 @@ defmodule Pleroma.User do end end - def parse_bio(bio, user \\ %User{info: %{source_data: %{}}}) - def parse_bio(nil, _user), do: "" - def parse_bio(bio, _user) when bio == "", do: bio + def parse_bio(bio) when is_binary(bio) and bio != "" do + bio + |> CommonUtils.format_input("text/plain", mentions_format: :full) + |> elem(0) + end - def parse_bio(bio, user) do - emoji = - (user.info.source_data["tag"] || []) - |> Enum.filter(fn %{"type" => t} -> t == "Emoji" end) - |> Enum.map(fn %{"icon" => %{"url" => url}, "name" => name} -> - {String.trim(name, ":"), url} - end) + def parse_bio(_), do: "" + def parse_bio(bio, user) when is_binary(bio) and bio != "" do # TODO: get profile URLs other than user.ap_id profile_urls = [user.ap_id] @@ -1352,9 +1348,10 @@ defmodule Pleroma.User do rel: &RelMe.maybe_put_rel_me(&1, profile_urls) ) |> elem(0) - |> Formatter.emojify(emoji) end + def parse_bio(_, _), do: "" + def tag(user_identifiers, tags) when is_list(user_identifiers) do Repo.transaction(fn -> for user_identifier <- user_identifiers, do: tag(user_identifier, tags) diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 201a21f50..564dbb829 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -86,7 +86,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do user_params = %{} |> add_if_present(params, "display_name", :name) - |> add_if_present(params, "note", :bio, fn value -> {:ok, User.parse_bio(value)} end) + |> add_if_present(params, "note", :bio, fn value -> {:ok, User.parse_bio(value, user)} end) |> add_if_present(params, "avatar", :avatar, fn value -> with %Plug.Upload{} <- value, {:ok, object} <- ActivityPub.upload(value, type: :avatar) do -- cgit v1.2.3 From 2f76a40d028c45e99425b061298a1b05e4b59923 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Tue, 12 Feb 2019 14:59:34 +0100 Subject: formatter.ex: Add get_emoji_map/1 --- lib/pleroma/formatter.ex | 11 +++++++++++ lib/pleroma/user/info.ex | 1 + lib/pleroma/web/activity_pub/transmogrifier.ex | 14 ++++++++++++-- lib/pleroma/web/activity_pub/views/user_view.ex | 7 ++++++- lib/pleroma/web/common_api/common_api.ex | 9 +++------ lib/pleroma/web/twitter_api/twitter_api_controller.ex | 12 +++++++++++- 6 files changed, 44 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex index 0ec6bcee0..3d7c36d21 100644 --- a/lib/pleroma/formatter.ex +++ b/lib/pleroma/formatter.ex @@ -128,12 +128,23 @@ defmodule Pleroma.Formatter do def demojify(text, nil), do: text + @doc "Outputs a list of the emoji-shortcodes in a text" def get_emoji(text) when is_binary(text) do Enum.filter(Emoji.get_all(), fn {emoji, _, _} -> String.contains?(text, ":#{emoji}:") end) end def get_emoji(_), do: [] + @doc "Outputs a list of the emoji-Maps in a text" + def get_emoji_map(text) when is_binary(text) do + get_emoji(text) + |> Enum.reduce(%{}, fn {name, file, _group}, acc -> + Map.put(acc, name, "#{Pleroma.Web.Endpoint.static_url()}#{file}") + end) + end + + def get_emoji_map(_), do: [] + def html_escape({text, mentions, hashtags}, type) do {html_escape(text, type), mentions, hashtags} end diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index a3658d57f..1b81619ce 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -41,6 +41,7 @@ defmodule Pleroma.User.Info do field(:hide_favorites, :boolean, default: true) field(:pinned_activities, {:array, :string}, default: []) field(:flavour, :string, default: nil) + field(:emoji, {:array, :map}, default: []) field(:notification_settings, :map, default: %{"remote" => true, "local" => true, "followers" => true, "follows" => true} diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index b774c2afa..508f3532f 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -856,10 +856,16 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do |> Map.put("tag", tags ++ mentions) end + def add_emoji_tags(%User{info: %{"emoji" => _emoji} = user_info} = object) do + user_info = add_emoji_tags(user_info) + + object + |> Map.put(:info, user_info) + end + # TODO: we should probably send mtime instead of unix epoch time for updated - def add_emoji_tags(object) do + def add_emoji_tags(%{"emoji" => emoji} = object) do tags = object["tag"] || [] - emoji = object["emoji"] || [] out = emoji @@ -877,6 +883,10 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do |> Map.put("tag", tags ++ out) end + def add_emoji_tags(object) do + object + end + def set_conversation(object) do Map.put(object, "conversation", object["context"]) end diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 5926a3294..1254fdf6c 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -69,6 +69,11 @@ defmodule Pleroma.Web.ActivityPub.UserView do endpoints = render("endpoints.json", %{user: user}) + user_tags = + user + |> Transmogrifier.add_emoji_tags() + |> Map.get("tag", []) + %{ "id" => user.ap_id, "type" => "Person", @@ -87,7 +92,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do "publicKeyPem" => public_key }, "endpoints" => endpoints, - "tag" => user.info.source_data["tag"] || [] + "tag" => (user.info.source_data["tag"] || []) ++ user_tags } |> Map.merge(maybe_make_image(&User.avatar_url/2, "icon", user)) |> Map.merge(maybe_make_image(&User.banner_url/2, "image", user)) diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index ecd183110..b53869c75 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -151,8 +151,8 @@ defmodule Pleroma.Web.CommonAPI do ), {to, cc} <- to_for_user_and_mentions(user, mentions, in_reply_to, visibility), context <- make_context(in_reply_to), - cw <- data["spoiler_text"], - full_payload <- String.trim(status <> (data["spoiler_text"] || "")), + cw <- data["spoiler_text"] || "", + full_payload <- String.trim(status <> cw), length when length in 1..limit <- String.length(full_payload), object <- make_note_data( @@ -170,10 +170,7 @@ defmodule Pleroma.Web.CommonAPI do Map.put( object, "emoji", - (Formatter.get_emoji(status) ++ Formatter.get_emoji(data["spoiler_text"])) - |> Enum.reduce(%{}, fn {name, file, _}, acc -> - Map.put(acc, name, "#{Pleroma.Web.Endpoint.static_url()}#{file}") - end) + Formatter.get_emoji_map(full_payload) ) do res = ActivityPub.create( diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index 79ed9dad2..261cc4462 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -9,6 +9,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do alias Ecto.Changeset alias Pleroma.Activity + alias Pleroma.Formatter alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Repo @@ -653,7 +654,16 @@ defmodule Pleroma.Web.TwitterAPI.Controller do defp parse_profile_bio(user, params) do if bio = params["description"] do - Map.put(params, "bio", User.parse_bio(bio, user)) + user_info = + user.info + |> Map.put( + "emojis", + Formatter.get_emoji_map(params["description"]) + ) + + params + |> Map.put("bio", User.parse_bio(bio, user)) + |> Map.put("info", user_info) else params end -- cgit v1.2.3 From 85434669bb0d363528b738a6d32dd9ce18401065 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Fri, 22 Feb 2019 22:35:47 +0100 Subject: Web.TwitterAPI.UserView: Also view local user emojis --- lib/pleroma/web/twitter_api/views/user_view.ex | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex index ea015b8f0..6857055c9 100644 --- a/lib/pleroma/web/twitter_api/views/user_view.ex +++ b/lib/pleroma/web/twitter_api/views/user_view.ex @@ -67,6 +67,8 @@ defmodule Pleroma.Web.TwitterAPI.UserView do {String.trim(name, ":"), url} end) + emoji = Enum.dedup(emoji ++ user.info.emoji) + # ``fields`` is an array of mastodon profile field, containing ``{"name": "…", "value": "…"}``. # For example: [{"name": "Pronoun", "value": "she/her"}, …] fields = -- cgit v1.2.3 From 46bbf9e1cff4e00f2fbd95dcc21c038d7d686b86 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Sat, 23 Feb 2019 00:09:11 +0100 Subject: TwitterAPI: profile update with emoji_map --- lib/pleroma/web/twitter_api/twitter_api_controller.ex | 10 ++++++++-- lib/pleroma/web/twitter_api/views/user_view.ex | 7 ++++++- 2 files changed, 14 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index 261cc4462..ef7b6fe65 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -654,11 +654,17 @@ defmodule Pleroma.Web.TwitterAPI.Controller do defp parse_profile_bio(user, params) do if bio = params["description"] do + emojis_text = (params["description"] || "") <> " " <> (params["name"] || "") + + emojis = + ((user.info.emoji || []) ++ Formatter.get_emoji_map(emojis_text)) + |> Enum.dedup() + user_info = user.info |> Map.put( - "emojis", - Formatter.get_emoji_map(params["description"]) + "emoji", + emojis ) params diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex index 6857055c9..f0a4ddbd3 100644 --- a/lib/pleroma/web/twitter_api/views/user_view.ex +++ b/lib/pleroma/web/twitter_api/views/user_view.ex @@ -69,6 +69,11 @@ defmodule Pleroma.Web.TwitterAPI.UserView do emoji = Enum.dedup(emoji ++ user.info.emoji) + description_html = + (user.bio || "") + |> HTML.filter_tags(User.html_filter_policy(for_user)) + |> Formatter.emojify(emoji) + # ``fields`` is an array of mastodon profile field, containing ``{"name": "…", "value": "…"}``. # For example: [{"name": "Pronoun", "value": "she/her"}, …] fields = @@ -80,7 +85,7 @@ defmodule Pleroma.Web.TwitterAPI.UserView do %{ "created_at" => user.inserted_at |> Utils.format_naive_asctime(), "description" => HTML.strip_tags((user.bio || "") |> String.replace("
", "\n")), - "description_html" => HTML.filter_tags(user.bio, User.html_filter_policy(for_user)), + "description_html" => description_html, "favourites_count" => 0, "followers_count" => user_info[:follower_count], "following" => following, -- cgit v1.2.3 From b5ad1715b2d4a2a5bdaefa2d56bde71120d23acb Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Sat, 23 Feb 2019 00:57:42 +0100 Subject: MastoAPI: profile update with emoji_map --- lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 564dbb829..0840c2c5a 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -9,6 +9,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Bookmark alias Pleroma.Config alias Pleroma.Filter + alias Pleroma.Formatter alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Object.Fetcher @@ -96,6 +97,12 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end end) + emojis_text = (user_params["display_name"] || "") <> (user_params["note"] || "") + + user_info_emojis = + ((user.info.emoji || []) ++ Formatter.get_emoji_map(emojis_text)) + |> Enum.dedup() + info_params = [:no_rich_text, :locked, :hide_followers, :hide_follows, :hide_favorites, :show_role] |> Enum.reduce(%{}, fn key, acc -> @@ -112,6 +119,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do _ -> :error end end) + |> Map.put(:emoji, user_info_emojis) info_cng = User.Info.profile_update(user.info, info_params) -- cgit v1.2.3 From 0e37fddd5abad5db0378c8186513fbba0fbd6586 Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 3 May 2019 19:15:55 +0200 Subject: Search: Add fts index on objects table. --- lib/mix/tasks/benchmark.ex | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 lib/mix/tasks/benchmark.ex (limited to 'lib') diff --git a/lib/mix/tasks/benchmark.ex b/lib/mix/tasks/benchmark.ex new file mode 100644 index 000000000..0fbb4dbb1 --- /dev/null +++ b/lib/mix/tasks/benchmark.ex @@ -0,0 +1,25 @@ +defmodule Mix.Tasks.Pleroma.Benchmark do + use Mix.Task + alias Mix.Tasks.Pleroma.Common + + def run(["search"]) do + Common.start_pleroma() + + Benchee.run(%{ + "search" => fn -> + Pleroma.Web.MastodonAPI.MastodonAPIController.status_search(nil, "cofe") + end + }) + end + + def run(["tag"]) do + Common.start_pleroma() + + Benchee.run(%{ + "tag" => fn -> + %{"type" => "Create", "tag" => "cofe"} + |> Pleroma.Web.ActivityPub.ActivityPub.fetch_public_activities() + end + }) + end +end -- cgit v1.2.3 From 4c76f49e60287e6618f87a2bae3e0d4e8c444895 Mon Sep 17 00:00:00 2001 From: lain Date: Sat, 4 May 2019 15:06:18 +0200 Subject: BBS: small fixes. --- lib/pleroma/bbs/handler.ex | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/bbs/handler.ex b/lib/pleroma/bbs/handler.ex index 1ebba77d2..75ba35dc2 100644 --- a/lib/pleroma/bbs/handler.ex +++ b/lib/pleroma/bbs/handler.ex @@ -1,12 +1,8 @@ defmodule Pleroma.BBS.Handler do - @moduledoc """ - An example implementation of `Sshd.ShellHandler`, implementing a very simple - Read-Eval-Loop, that does nothing. - """ use Sshd.ShellHandler + alias Pleroma.Activity alias Pleroma.Web.CommonAPI alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Activity def on_shell(username, _pubkey, _ip, _port) do :ok = IO.puts("Welcome to #{Pleroma.Config.get([:instance, :name])}!") -- cgit v1.2.3 From c9d1cb2dcefb850357b953a7a2d308de39b35e07 Mon Sep 17 00:00:00 2001 From: lain Date: Sat, 4 May 2019 15:08:07 +0200 Subject: BBS: Use cached user fetcher. --- lib/pleroma/bbs/handler.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/bbs/handler.ex b/lib/pleroma/bbs/handler.ex index 75ba35dc2..14e6a6807 100644 --- a/lib/pleroma/bbs/handler.ex +++ b/lib/pleroma/bbs/handler.ex @@ -6,7 +6,7 @@ defmodule Pleroma.BBS.Handler do def on_shell(username, _pubkey, _ip, _port) do :ok = IO.puts("Welcome to #{Pleroma.Config.get([:instance, :name])}!") - user = Pleroma.User.get_by_nickname(to_string(username)) + user = Pleroma.User.get_cached_by_nickname(to_string(username)) Logger.debug("#{inspect(user)}") loop(run_state(user: user)) end -- cgit v1.2.3 From eb0fb73ddbed109ca4dcd758b60a25ff0dafc883 Mon Sep 17 00:00:00 2001 From: lain Date: Sat, 4 May 2019 15:47:50 +0200 Subject: BBS: Credo fixes. --- lib/pleroma/bbs/handler.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/bbs/handler.ex b/lib/pleroma/bbs/handler.ex index 14e6a6807..106fe5d18 100644 --- a/lib/pleroma/bbs/handler.ex +++ b/lib/pleroma/bbs/handler.ex @@ -1,8 +1,8 @@ defmodule Pleroma.BBS.Handler do use Sshd.ShellHandler alias Pleroma.Activity - alias Pleroma.Web.CommonAPI alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.CommonAPI def on_shell(username, _pubkey, _ip, _port) do :ok = IO.puts("Welcome to #{Pleroma.Config.get([:instance, :name])}!") -- cgit v1.2.3 From af62ace9545e60a0c93498ec3054697e781e058a Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Mon, 6 May 2019 04:28:04 +0200 Subject: Add short documentation on every MRF Policy --- lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex | 2 ++ lib/pleroma/web/activity_pub/mrf/drop_policy.ex | 1 + lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex | 1 + lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex | 2 ++ lib/pleroma/web/activity_pub/mrf/keyword_policy.ex | 2 ++ lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex | 1 + lib/pleroma/web/activity_pub/mrf/noop_policy.ex | 1 + lib/pleroma/web/activity_pub/mrf/normalize_markup.ex | 1 + lib/pleroma/web/activity_pub/mrf/reject_non_public.ex | 1 + lib/pleroma/web/activity_pub/mrf/simple_policy.ex | 1 + lib/pleroma/web/activity_pub/mrf/tag_policy.ex | 1 + lib/pleroma/web/activity_pub/mrf/user_allowlist.ex | 1 + 12 files changed, 15 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex b/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex index 34665a3a6..87fa514c3 100644 --- a/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex @@ -5,6 +5,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy do alias Pleroma.User + @moduledoc "Prevent followbots from following with a bit of heuristic" + @behaviour Pleroma.Web.ActivityPub.MRF # XXX: this should become User.normalize_by_ap_id() or similar, really. diff --git a/lib/pleroma/web/activity_pub/mrf/drop_policy.ex b/lib/pleroma/web/activity_pub/mrf/drop_policy.ex index a93ccf386..b8d38aae6 100644 --- a/lib/pleroma/web/activity_pub/mrf/drop_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/drop_policy.ex @@ -4,6 +4,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.DropPolicy do require Logger + @moduledoc "Drop and log everything received" @behaviour Pleroma.Web.ActivityPub.MRF @impl true diff --git a/lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex b/lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex index 895376c9d..15d8514be 100644 --- a/lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex +++ b/lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex @@ -5,6 +5,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.EnsureRePrepended do alias Pleroma.Object + @moduledoc "Ensure a re: is prepended on replies to a post with a Subject" @behaviour Pleroma.Web.ActivityPub.MRF @reply_prefix Regex.compile!("^re:[[:space:]]*", [:caseless]) diff --git a/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex b/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex index 6736f3cb9..a699f6a7e 100644 --- a/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex @@ -4,6 +4,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicy do alias Pleroma.User + @moduledoc "Block messages with too much mentions (configurable)" + @behaviour Pleroma.Web.ActivityPub.MRF defp delist_message(message, threshold) when threshold > 0 do diff --git a/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex b/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex index e8dfba672..d5c341433 100644 --- a/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex @@ -3,6 +3,8 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do + @moduledoc "Reject or Word-Replace messages with a keyword or regex" + @behaviour Pleroma.Web.ActivityPub.MRF defp string_matches?(string, _) when not is_binary(string) do false diff --git a/lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex b/lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex index 081456046..f30fee0d5 100644 --- a/lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex @@ -3,6 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.MRF.NoPlaceholderTextPolicy do + @moduledoc "Ensure no content placeholder is present (such as the dot from mastodon)" @behaviour Pleroma.Web.ActivityPub.MRF @impl true diff --git a/lib/pleroma/web/activity_pub/mrf/noop_policy.ex b/lib/pleroma/web/activity_pub/mrf/noop_policy.ex index 40f37bdb1..c47cb3298 100644 --- a/lib/pleroma/web/activity_pub/mrf/noop_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/noop_policy.ex @@ -3,6 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.MRF.NoOpPolicy do + @moduledoc "Does nothing (lets the messages go through unmodified)" @behaviour Pleroma.Web.ActivityPub.MRF @impl true diff --git a/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex b/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex index 3d13cdb32..9c87c6963 100644 --- a/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex +++ b/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex @@ -3,6 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.MRF.NormalizeMarkup do + @moduledoc "Scrub configured hypertext markup" alias Pleroma.HTML @behaviour Pleroma.Web.ActivityPub.MRF diff --git a/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex b/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex index 4197be847..ea3df1b4d 100644 --- a/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex +++ b/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex @@ -4,6 +4,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublic do alias Pleroma.User + @moduledoc "Rejects non-public (followers-only, direct) activities" @behaviour Pleroma.Web.ActivityPub.MRF @impl true diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex index 798ba9687..2f105700b 100644 --- a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex @@ -4,6 +4,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do alias Pleroma.User + @moduledoc "Filter activities depending on their origin instance" @behaviour Pleroma.Web.ActivityPub.MRF defp check_accept(%{host: actor_host} = _actor_info, object) do diff --git a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex index b242e44e6..5ed1ee77c 100644 --- a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex @@ -5,6 +5,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do alias Pleroma.User @behaviour Pleroma.Web.ActivityPub.MRF + @moduledoc "Apply policies based on user tags" defp get_tags(%User{tags: tags}) when is_list(tags), do: tags defp get_tags(_), do: [] diff --git a/lib/pleroma/web/activity_pub/mrf/user_allowlist.ex b/lib/pleroma/web/activity_pub/mrf/user_allowlist.ex index a3b1f8aa0..f5078d818 100644 --- a/lib/pleroma/web/activity_pub/mrf/user_allowlist.ex +++ b/lib/pleroma/web/activity_pub/mrf/user_allowlist.ex @@ -5,6 +5,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.UserAllowListPolicy do alias Pleroma.Config + @moduledoc "Accept-list of users from specified instances" @behaviour Pleroma.Web.ActivityPub.MRF defp filter_by_list(object, []), do: {:ok, object} -- cgit v1.2.3 From e41a2f98d5f061d263cf731b76a20851931e6e33 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Mon, 6 May 2019 03:43:11 +0200 Subject: mrf/tag_policy.ex: Add some documentation mrf_tag:disable-remote-subscription exact way of working is quite unclear to me. Is it the requester that is denied if they have a tag, or is it the requestee if they have one? --- lib/pleroma/web/activity_pub/mrf/tag_policy.ex | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex index 5ed1ee77c..b52be30e7 100644 --- a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex @@ -5,7 +5,19 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do alias Pleroma.User @behaviour Pleroma.Web.ActivityPub.MRF - @moduledoc "Apply policies based on user tags" + @moduledoc """ + Apply policies based on user tags + + This policy applies policies on a user activities depending on their tags + on your instance. + + - `mrf_tag:media-force-nsfw`: Mark as sensitive on presence of attachments + - `mrf_tag:media-strip`: Remove attachments + - `mrf_tag:force-unlisted`: Mark as unlisted (removes from the federated timeline) + - `mrf_tag:sandbox`: Remove from public (local and federated) timelines + - `mrf_tag:disable-remote-subscription`: Reject non-local follow requests + - `mrf_tag:disable-any-subscription`: Reject any follow requests + """ defp get_tags(%User{tags: tags}) when is_list(tags), do: tags defp get_tags(_), do: [] -- cgit v1.2.3 From 69a5074893d050a9a3ce6d245f1aa05c385ea4fb Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Mon, 6 May 2019 04:47:04 +0200 Subject: Remove H1 in @moduledoc --- lib/pleroma/object/containment.ex | 2 +- lib/pleroma/upload.ex | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/object/containment.ex b/lib/pleroma/object/containment.ex index 25bd911fb..70325d6be 100644 --- a/lib/pleroma/object/containment.ex +++ b/lib/pleroma/object/containment.ex @@ -1,6 +1,6 @@ defmodule Pleroma.Object.Containment do @moduledoc """ - # Object Containment + help on getting the origin of contained objects This module contains some useful functions for containing objects to specific origins and determining those origins. They previously lived in the diff --git a/lib/pleroma/upload.ex b/lib/pleroma/upload.ex index f72334930..c47d65241 100644 --- a/lib/pleroma/upload.ex +++ b/lib/pleroma/upload.ex @@ -4,7 +4,7 @@ defmodule Pleroma.Upload do @moduledoc """ - # Upload + Manage user uploads Options: * `:type`: presets for activity type (defaults to Document) and size limits from app configuration -- cgit v1.2.3 From ce6ca0fefe7feb1c31447287aec117d40233652a Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Mon, 6 May 2019 16:45:22 +0000 Subject: Merge branch 'develop' of https://git.pleroma.social/pleroma/pleroma into feature/845-improve-status-deletion --- lib/mix/tasks/pleroma/user.ex | 4 +-- lib/pleroma/activity.ex | 7 +++++ lib/pleroma/user.ex | 30 +++++++++++++--------- lib/pleroma/user_invite_token.ex | 2 +- .../web/twitter_api/controllers/util_controller.ex | 2 +- 5 files changed, 29 insertions(+), 16 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 9e2523b18..6a83a8c0d 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -163,7 +163,7 @@ defmodule Mix.Tasks.Pleroma.User do Common.start_pleroma() with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do - User.delete(user) + User.perform(:delete, user) Mix.shell().info("User #{nickname} deleted.") else _ -> @@ -380,7 +380,7 @@ defmodule Mix.Tasks.Pleroma.User do Common.start_pleroma() with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do - User.delete_user_activities(user) + {:ok, _} = User.delete_user_activities(user) Mix.shell().info("User #{nickname} statuses deleted.") else _ -> diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index 4a2ded518..73e63bb14 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -14,6 +14,8 @@ defmodule Pleroma.Activity do import Ecto.Query @type t :: %__MODULE__{} + @type actor :: String.t() + @primary_key {:id, Pleroma.FlakeId, autogenerate: true} # https://github.com/tootsuite/mastodon/blob/master/app/models/notification.rb#L19 @@ -260,4 +262,9 @@ defmodule Pleroma.Activity do |> where([s], s.actor == ^actor) |> Repo.all() end + + @spec query_by_actor(actor()) :: Ecto.Query.t() + def query_by_actor(actor) do + from(a in Activity, where: a.actor == ^actor) + end end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 1741ce684..fd2ce81ad 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1164,7 +1164,12 @@ defmodule Pleroma.User do |> update_and_set_cache() end - def delete(%User{} = user) do + @spec delete(User.t()) :: :ok + def delete(%User{} = user), + do: PleromaJobQueue.enqueue(:background, __MODULE__, [:delete, user]) + + @spec perform(atom(), User.t()) :: {:ok, User.t()} + def perform(:delete, %User{} = user) do {:ok, user} = User.deactivate(user) # Remove all relationships @@ -1180,22 +1185,23 @@ defmodule Pleroma.User do end def delete_user_activities(%User{ap_id: ap_id} = user) do - Activity - |> where(actor: ^ap_id) - |> Activity.with_preloaded_object() - |> Repo.all() - |> Enum.each(fn - %{data: %{"type" => "Create"}} = activity -> - activity |> Object.normalize() |> ActivityPub.delete() + stream = + ap_id + |> Activity.query_by_actor() + |> Activity.with_preloaded_object() + |> Repo.stream() - # TODO: Do something with likes, follows, repeats. - _ -> - "Doing nothing" - end) + Repo.transaction(fn -> Enum.each(stream, &delete_activity(&1)) end, timeout: :infinity) {:ok, user} end + defp delete_activity(%{data: %{"type" => "Create"}} = activity) do + Object.normalize(activity) |> ActivityPub.delete() + end + + defp delete_activity(_activity), do: "Doing nothing" + def html_filter_policy(%User{info: %{no_rich_text: true}}) do Pleroma.HTML.Scrubber.TwitterText end diff --git a/lib/pleroma/user_invite_token.ex b/lib/pleroma/user_invite_token.ex index 86f0a5486..fadc89891 100644 --- a/lib/pleroma/user_invite_token.ex +++ b/lib/pleroma/user_invite_token.ex @@ -24,7 +24,7 @@ defmodule Pleroma.UserInviteToken do timestamps() end - @spec create_invite(map()) :: UserInviteToken.t() + @spec create_invite(map()) :: {:ok, UserInviteToken.t()} def create_invite(params \\ %{}) do %UserInviteToken{} |> cast(params, [:max_use, :expires_at]) diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 1122e6c5d..c03f8ab3a 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -352,7 +352,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do def delete_account(%{assigns: %{user: user}} = conn, params) do case CommonAPI.Utils.confirm_current_password(user, params["password"]) do {:ok, user} -> - Task.start(fn -> User.delete(user) end) + User.delete(user) json(conn, %{status: "success"}) {:error, msg} -> -- cgit v1.2.3 From 1040caf096347b638b9fda5b23fcccde87b32ede Mon Sep 17 00:00:00 2001 From: Maksim Date: Mon, 6 May 2019 17:51:03 +0000 Subject: fix format Modified-by: Maksim Pechnikov --- lib/pleroma/repo.ex | 28 ++++ lib/pleroma/web/oauth/app.ex | 1 + lib/pleroma/web/oauth/authorization.ex | 8 ++ lib/pleroma/web/oauth/oauth_controller.ex | 159 ++++++++++++--------- lib/pleroma/web/oauth/token.ex | 81 ++++++++--- .../web/oauth/token/strategy/refresh_token.ex | 54 +++++++ lib/pleroma/web/oauth/token/strategy/revoke.ex | 22 +++ lib/pleroma/web/oauth/token/utils.ex | 30 ++++ 8 files changed, 296 insertions(+), 87 deletions(-) create mode 100644 lib/pleroma/web/oauth/token/strategy/refresh_token.ex create mode 100644 lib/pleroma/web/oauth/token/strategy/revoke.ex create mode 100644 lib/pleroma/web/oauth/token/utils.ex (limited to 'lib') diff --git a/lib/pleroma/repo.ex b/lib/pleroma/repo.ex index aa5d427ae..f57e088bc 100644 --- a/lib/pleroma/repo.ex +++ b/lib/pleroma/repo.ex @@ -19,4 +19,32 @@ defmodule Pleroma.Repo do def init(_, opts) do {:ok, Keyword.put(opts, :url, System.get_env("DATABASE_URL"))} end + + @doc "find resource based on prepared query" + @spec find_resource(Ecto.Query.t()) :: {:ok, struct()} | {:error, :not_found} + def find_resource(%Ecto.Query{} = query) do + case __MODULE__.one(query) do + nil -> {:error, :not_found} + resource -> {:ok, resource} + end + end + + def find_resource(_query), do: {:error, :not_found} + + @doc """ + Gets association from cache or loads if need + + ## Examples + + iex> Repo.get_assoc(token, :user) + %User{} + + """ + @spec get_assoc(struct(), atom()) :: {:ok, struct()} | {:error, :not_found} + def get_assoc(resource, association) do + case __MODULE__.preload(resource, association) do + %{^association => assoc} when not is_nil(assoc) -> {:ok, assoc} + _ -> {:error, :not_found} + end + end end diff --git a/lib/pleroma/web/oauth/app.ex b/lib/pleroma/web/oauth/app.ex index 3476da484..bccc2ac96 100644 --- a/lib/pleroma/web/oauth/app.ex +++ b/lib/pleroma/web/oauth/app.ex @@ -6,6 +6,7 @@ defmodule Pleroma.Web.OAuth.App do use Ecto.Schema import Ecto.Changeset + @type t :: %__MODULE__{} schema "apps" do field(:client_name, :string) field(:redirect_uris, :string) diff --git a/lib/pleroma/web/oauth/authorization.ex b/lib/pleroma/web/oauth/authorization.ex index 3461f9983..ca3901cc4 100644 --- a/lib/pleroma/web/oauth/authorization.ex +++ b/lib/pleroma/web/oauth/authorization.ex @@ -13,6 +13,7 @@ defmodule Pleroma.Web.OAuth.Authorization do import Ecto.Changeset import Ecto.Query + @type t :: %__MODULE__{} schema "oauth_authorizations" do field(:token, :string) field(:scopes, {:array, :string}, default: []) @@ -63,4 +64,11 @@ defmodule Pleroma.Web.OAuth.Authorization do ) |> Repo.delete_all() end + + @doc "gets auth for app by token" + @spec get_by_token(App.t(), String.t()) :: {:ok, t()} | {:error, :not_found} + def get_by_token(%App{id: app_id} = _app, token) do + from(t in __MODULE__, where: t.app_id == ^app_id and t.token == ^token) + |> Repo.find_resource() + end end diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index 688eaca11..e3c01217d 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -13,11 +13,15 @@ defmodule Pleroma.Web.OAuth.OAuthController do alias Pleroma.Web.OAuth.App alias Pleroma.Web.OAuth.Authorization alias Pleroma.Web.OAuth.Token + alias Pleroma.Web.OAuth.Token.Strategy.RefreshToken + alias Pleroma.Web.OAuth.Token.Strategy.Revoke, as: RevokeToken import Pleroma.Web.ControllerHelper, only: [oauth_scopes: 2] if Pleroma.Config.oauth_consumer_enabled?(), do: plug(Ueberauth) + @expires_in Pleroma.Config.get([:oauth2, :token_expires_in], 600) + plug(:fetch_session) plug(:fetch_flash) @@ -138,25 +142,33 @@ defmodule Pleroma.Web.OAuth.OAuthController do Authenticator.handle_error(conn, error) end + @doc "Renew access_token with refresh_token" + def token_exchange( + conn, + %{"grant_type" => "refresh_token", "refresh_token" => token} = params + ) do + with %App{} = app <- get_app_from_request(conn, params), + {:ok, %{user: user} = token} <- Token.get_by_refresh_token(app, token), + {:ok, token} <- RefreshToken.grant(token) do + response_attrs = %{created_at: Token.Utils.format_created_at(token)} + + json(conn, response_token(user, token, response_attrs)) + else + _error -> + put_status(conn, 400) + |> json(%{error: "Invalid credentials"}) + end + end + def token_exchange(conn, %{"grant_type" => "authorization_code"} = params) do with %App{} = app <- get_app_from_request(conn, params), - fixed_token = fix_padding(params["code"]), - %Authorization{} = auth <- - Repo.get_by(Authorization, token: fixed_token, app_id: app.id), + fixed_token = Token.Utils.fix_padding(params["code"]), + {:ok, auth} <- Authorization.get_by_token(app, fixed_token), %User{} = user <- User.get_cached_by_id(auth.user_id), - {:ok, token} <- Token.exchange_token(app, auth), - {:ok, inserted_at} <- DateTime.from_naive(token.inserted_at, "Etc/UTC") do - response = %{ - token_type: "Bearer", - access_token: token.token, - refresh_token: token.refresh_token, - created_at: DateTime.to_unix(inserted_at), - expires_in: 60 * 10, - scope: Enum.join(token.scopes, " "), - me: user.ap_id - } - - json(conn, response) + {:ok, token} <- Token.exchange_token(app, auth) do + response_attrs = %{created_at: Token.Utils.format_created_at(token)} + + json(conn, response_token(user, token, response_attrs)) else _error -> put_status(conn, 400) @@ -177,16 +189,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do true <- Enum.any?(scopes), {:ok, auth} <- Authorization.create_authorization(app, user, scopes), {:ok, token} <- Token.exchange_token(app, auth) do - response = %{ - token_type: "Bearer", - access_token: token.token, - refresh_token: token.refresh_token, - expires_in: 60 * 10, - scope: Enum.join(token.scopes, " "), - me: user.ap_id - } - - json(conn, response) + json(conn, response_token(user, token)) else {:auth_active, false} -> # Per https://github.com/tootsuite/mastodon/blob/ @@ -218,10 +221,12 @@ defmodule Pleroma.Web.OAuth.OAuthController do token_exchange(conn, params) end - def token_revoke(conn, %{"token" => token} = params) do + # Bad request + def token_exchange(conn, params), do: bad_request(conn, params) + + def token_revoke(conn, %{"token" => _token} = params) do with %App{} = app <- get_app_from_request(conn, params), - %Token{} = token <- Repo.get_by(Token, token: token, app_id: app.id), - {:ok, %Token{}} <- Repo.delete(token) do + {:ok, _token} <- RevokeToken.revoke(app, params) do json(conn, %{}) else _error -> @@ -230,6 +235,15 @@ defmodule Pleroma.Web.OAuth.OAuthController do end end + def token_revoke(conn, params), do: bad_request(conn, params) + + # Response for bad request + defp bad_request(conn, _) do + conn + |> put_status(500) + |> json(%{error: "Bad request"}) + end + @doc "Prepares OAuth request to provider for Ueberauth" def prepare_request(conn, %{"provider" => provider, "authorization" => auth_attrs}) do scope = @@ -278,25 +292,22 @@ defmodule Pleroma.Web.OAuth.OAuthController do params = callback_params(params) with {:ok, registration} <- Authenticator.get_registration(conn) do - user = Repo.preload(registration, :user).user auth_attrs = Map.take(params, ~w(client_id redirect_uri scope scopes state)) - if user do - create_authorization( - conn, - %{"authorization" => auth_attrs}, - user: user - ) - else - registration_params = - Map.merge(auth_attrs, %{ - "nickname" => Registration.nickname(registration), - "email" => Registration.email(registration) - }) + case Repo.get_assoc(registration, :user) do + {:ok, user} -> + create_authorization(conn, %{"authorization" => auth_attrs}, user: user) - conn - |> put_session(:registration_id, registration.id) - |> registration_details(%{"authorization" => registration_params}) + _ -> + registration_params = + Map.merge(auth_attrs, %{ + "nickname" => Registration.nickname(registration), + "email" => Registration.email(registration) + }) + + conn + |> put_session(:registration_id, registration.id) + |> registration_details(%{"authorization" => registration_params}) end else _ -> @@ -399,36 +410,30 @@ defmodule Pleroma.Web.OAuth.OAuthController do end end - # XXX - for whatever reason our token arrives urlencoded, but Plug.Conn should be - # decoding it. Investigate sometime. - defp fix_padding(token) do - token - |> URI.decode() - |> Base.url_decode64!(padding: false) - |> Base.url_encode64(padding: false) + defp get_app_from_request(conn, params) do + conn + |> fetch_client_credentials(params) + |> fetch_client end - defp get_app_from_request(conn, params) do - # Per RFC 6749, HTTP Basic is preferred to body params - {client_id, client_secret} = - with ["Basic " <> encoded] <- get_req_header(conn, "authorization"), - {:ok, decoded} <- Base.decode64(encoded), - [id, secret] <- - String.split(decoded, ":") - |> Enum.map(fn s -> URI.decode_www_form(s) end) do - {id, secret} - else - _ -> {params["client_id"], params["client_secret"]} - end + defp fetch_client({id, secret}) when is_binary(id) and is_binary(secret) do + Repo.get_by(App, client_id: id, client_secret: secret) + end - if client_id && client_secret do - Repo.get_by( - App, - client_id: client_id, - client_secret: client_secret - ) + defp fetch_client({_id, _secret}), do: nil + + defp fetch_client_credentials(conn, params) do + # Per RFC 6749, HTTP Basic is preferred to body params + with ["Basic " <> encoded] <- get_req_header(conn, "authorization"), + {:ok, decoded} <- Base.decode64(encoded), + [id, secret] <- + Enum.map( + String.split(decoded, ":"), + fn s -> URI.decode_www_form(s) end + ) do + {id, secret} else - nil + _ -> {params["client_id"], params["client_secret"]} end end @@ -441,4 +446,16 @@ defmodule Pleroma.Web.OAuth.OAuthController do defp put_session_registration_id(conn, registration_id), do: put_session(conn, :registration_id, registration_id) + + defp response_token(%User{} = user, token, opts \\ %{}) do + %{ + token_type: "Bearer", + access_token: token.token, + refresh_token: token.refresh_token, + expires_in: @expires_in, + scope: Enum.join(token.scopes, " "), + me: user.ap_id + } + |> Map.merge(opts) + end end diff --git a/lib/pleroma/web/oauth/token.ex b/lib/pleroma/web/oauth/token.ex index 399140003..4e5d1d118 100644 --- a/lib/pleroma/web/oauth/token.ex +++ b/lib/pleroma/web/oauth/token.ex @@ -6,6 +6,7 @@ defmodule Pleroma.Web.OAuth.Token do use Ecto.Schema import Ecto.Query + import Ecto.Changeset alias Pleroma.Repo alias Pleroma.User @@ -13,6 +14,9 @@ defmodule Pleroma.Web.OAuth.Token do alias Pleroma.Web.OAuth.Authorization alias Pleroma.Web.OAuth.Token + @expires_in Pleroma.Config.get([:oauth2, :token_expires_in], 600) + @type t :: %__MODULE__{} + schema "oauth_tokens" do field(:token, :string) field(:refresh_token, :string) @@ -24,28 +28,67 @@ defmodule Pleroma.Web.OAuth.Token do timestamps() end + @doc "Gets token for app by access token" + @spec get_by_token(App.t(), String.t()) :: {:ok, t()} | {:error, :not_found} + def get_by_token(%App{id: app_id} = _app, token) do + from(t in __MODULE__, where: t.app_id == ^app_id and t.token == ^token) + |> Repo.find_resource() + end + + @doc "Gets token for app by refresh token" + @spec get_by_refresh_token(App.t(), String.t()) :: {:ok, t()} | {:error, :not_found} + def get_by_refresh_token(%App{id: app_id} = _app, token) do + from(t in __MODULE__, + where: t.app_id == ^app_id and t.refresh_token == ^token, + preload: [:user] + ) + |> Repo.find_resource() + end + def exchange_token(app, auth) do with {:ok, auth} <- Authorization.use_token(auth), true <- auth.app_id == app.id do - create_token(app, User.get_cached_by_id(auth.user_id), auth.scopes) + create_token( + app, + User.get_cached_by_id(auth.user_id), + %{scopes: auth.scopes} + ) end end - def create_token(%App{} = app, %User{} = user, scopes \\ nil) do - scopes = scopes || app.scopes - token = :crypto.strong_rand_bytes(32) |> Base.url_encode64(padding: false) - refresh_token = :crypto.strong_rand_bytes(32) |> Base.url_encode64(padding: false) - - token = %Token{ - token: token, - refresh_token: refresh_token, - scopes: scopes, - user_id: user.id, - app_id: app.id, - valid_until: NaiveDateTime.add(NaiveDateTime.utc_now(), 60 * 10) - } - - Repo.insert(token) + defp put_token(changeset) do + changeset + |> change(%{token: Token.Utils.generate_token()}) + |> validate_required([:token]) + |> unique_constraint(:token) + end + + defp put_refresh_token(changeset, attrs) do + refresh_token = Map.get(attrs, :refresh_token, Token.Utils.generate_token()) + + changeset + |> change(%{refresh_token: refresh_token}) + |> validate_required([:refresh_token]) + |> unique_constraint(:refresh_token) + end + + defp put_valid_until(changeset, attrs) do + expires_in = + Map.get(attrs, :valid_until, NaiveDateTime.add(NaiveDateTime.utc_now(), @expires_in)) + + changeset + |> change(%{valid_until: expires_in}) + |> validate_required([:valid_until]) + end + + def create_token(%App{} = app, %User{} = user, attrs \\ %{}) do + %__MODULE__{user_id: user.id, app_id: app.id} + |> cast(%{scopes: attrs[:scopes] || app.scopes}, [:scopes]) + |> validate_required([:scopes, :user_id, :app_id]) + |> put_valid_until(attrs) + |> put_token + |> put_refresh_token(attrs) + |> Repo.insert() end def delete_user_tokens(%User{id: user_id}) do @@ -73,4 +116,10 @@ defmodule Pleroma.Web.OAuth.Token do |> Repo.all() |> Repo.preload(:app) end + + def is_expired?(%__MODULE__{valid_until: valid_until}) do + NaiveDateTime.diff(NaiveDateTime.utc_now(), valid_until) > 0 + end + + def is_expired?(_), do: false end diff --git a/lib/pleroma/web/oauth/token/strategy/refresh_token.ex b/lib/pleroma/web/oauth/token/strategy/refresh_token.ex new file mode 100644 index 000000000..7df0be14e --- /dev/null +++ b/lib/pleroma/web/oauth/token/strategy/refresh_token.ex @@ -0,0 +1,54 @@ +defmodule Pleroma.Web.OAuth.Token.Strategy.RefreshToken do + @moduledoc """ + Functions for dealing with refresh token strategy. + """ + + alias Pleroma.Config + alias Pleroma.Repo + alias Pleroma.Web.OAuth.Token + alias Pleroma.Web.OAuth.Token.Strategy.Revoke + + @doc """ + Will grant access token by refresh token. + """ + @spec grant(Token.t()) :: {:ok, Token.t()} | {:error, any()} + def grant(token) do + access_token = Repo.preload(token, [:user, :app]) + + result = + Repo.transaction(fn -> + token_params = %{ + app: access_token.app, + user: access_token.user, + scopes: access_token.scopes + } + + access_token + |> revoke_access_token() + |> create_access_token(token_params) + end) + + case result do + {:ok, {:error, reason}} -> {:error, reason} + {:ok, {:ok, token}} -> {:ok, token} + {:error, reason} -> {:error, reason} + end + end + + defp revoke_access_token(token) do + Revoke.revoke(token) + end + + defp create_access_token({:error, error}, _), do: {:error, error} + + defp create_access_token({:ok, token}, %{app: app, user: user} = token_params) do + Token.create_token(app, user, add_refresh_token(token_params, token.refresh_token)) + end + + defp add_refresh_token(params, token) do + case Config.get([:oauth2, :issue_new_refresh_token], false) do + true -> Map.put(params, :refresh_token, token) + false -> params + end + end +end diff --git a/lib/pleroma/web/oauth/token/strategy/revoke.ex b/lib/pleroma/web/oauth/token/strategy/revoke.ex new file mode 100644 index 000000000..dea63ca54 --- /dev/null +++ b/lib/pleroma/web/oauth/token/strategy/revoke.ex @@ -0,0 +1,22 @@ +defmodule Pleroma.Web.OAuth.Token.Strategy.Revoke do + @moduledoc """ + Functions for dealing with revocation. + """ + + alias Pleroma.Repo + alias Pleroma.Web.OAuth.App + alias Pleroma.Web.OAuth.Token + + @doc "Finds and revokes access token for app and by token" + @spec revoke(App.t(), map()) :: {:ok, Token.t()} | {:error, :not_found | Ecto.Changeset.t()} + def revoke(%App{} = app, %{"token" => token} = _attrs) do + with {:ok, token} <- Token.get_by_token(app, token), + do: revoke(token) + end + + @doc "Revokes access token" + @spec revoke(Token.t()) :: {:ok, Token.t()} | {:error, Ecto.Changeset.t()} + def revoke(%Token{} = token) do + Repo.delete(token) + end +end diff --git a/lib/pleroma/web/oauth/token/utils.ex b/lib/pleroma/web/oauth/token/utils.ex new file mode 100644 index 000000000..a81560a1c --- /dev/null +++ b/lib/pleroma/web/oauth/token/utils.ex @@ -0,0 +1,30 @@ +defmodule Pleroma.Web.OAuth.Token.Utils do + @moduledoc """ + Auxiliary functions for dealing with tokens. + """ + + @doc "convert token inserted_at to unix timestamp" + def format_created_at(%{inserted_at: inserted_at} = _token) do + inserted_at + |> DateTime.from_naive!("Etc/UTC") + |> DateTime.to_unix() + end + + @doc false + @spec generate_token(keyword()) :: binary() + def generate_token(opts \\ []) do + opts + |> Keyword.get(:size, 32) + |> :crypto.strong_rand_bytes() + |> Base.url_encode64(padding: false) + end + + # XXX - for whatever reason our token arrives urlencoded, but Plug.Conn should be + # decoding it. Investigate sometime. + def fix_padding(token) do + token + |> URI.decode() + |> Base.url_decode64!(padding: false) + |> Base.url_encode64(padding: false) + end +end -- cgit v1.2.3 From e71ddf23bac6e9b92f2158ac647e6fb68677b1b0 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Tue, 7 May 2019 16:11:10 +0000 Subject: containment: remove pointless moduledoc line --- lib/pleroma/object/containment.ex | 2 -- 1 file changed, 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/object/containment.ex b/lib/pleroma/object/containment.ex index 70325d6be..2f4687fa2 100644 --- a/lib/pleroma/object/containment.ex +++ b/lib/pleroma/object/containment.ex @@ -1,7 +1,5 @@ defmodule Pleroma.Object.Containment do @moduledoc """ - help on getting the origin of contained objects - This module contains some useful functions for containing objects to specific origins and determining those origins. They previously lived in the ActivityPub `Transmogrifier` module. -- cgit v1.2.3 From 06947c91471fda6e774c5b6fc04720b87db2b1e6 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 3 May 2019 22:15:47 +0300 Subject: Remove bookmarks assoc --- lib/pleroma/user.ex | 2 -- .../web/mastodon_api/mastodon_api_controller.ex | 24 +--------------------- 2 files changed, 1 insertion(+), 25 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index fd2ce81ad..b1adaad2f 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -10,7 +10,6 @@ defmodule Pleroma.User do alias Comeonin.Pbkdf2 alias Pleroma.Activity - alias Pleroma.Bookmark alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Registration @@ -54,7 +53,6 @@ defmodule Pleroma.User do field(:search_type, :integer, virtual: true) field(:tags, {:array, :string}, default: []) field(:last_refreshed_at, :naive_datetime_usec) - has_many(:bookmarks, Bookmark) has_many(:notifications, Notification) has_many(:registrations, Registration) embeds_one(:info, Pleroma.User.Info) diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index be60e5e3c..2a3d58592 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -295,8 +295,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do |> ActivityPub.contain_timeline(user) |> Enum.reverse() - user = Repo.preload(user, bookmarks: :activity) - conn |> add_link_headers(:home_timeline, activities) |> put_view(StatusView) @@ -315,8 +313,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do |> ActivityPub.fetch_public_activities() |> Enum.reverse() - user = Repo.preload(user, bookmarks: :activity) - conn |> add_link_headers(:public_timeline, activities, false, %{"local" => local_only}) |> put_view(StatusView) @@ -324,8 +320,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def user_statuses(%{assigns: %{user: reading_user}} = conn, params) do - with %User{} = user <- User.get_cached_by_id(params["id"]), - reading_user <- Repo.preload(reading_user, :bookmarks) do + with %User{} = user <- User.get_cached_by_id(params["id"]) do activities = ActivityPub.fetch_user_activities(user, reading_user, params) conn @@ -352,8 +347,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do |> ActivityPub.fetch_activities_query(params) |> Pagination.fetch_paginated(params) - user = Repo.preload(user, bookmarks: :activity) - conn |> add_link_headers(:dm_timeline, activities) |> put_view(StatusView) @@ -363,8 +356,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do def get_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do with %Activity{} = activity <- Activity.get_by_id_with_object(id), true <- Visibility.visible_for_user?(activity, user) do - user = Repo.preload(user, bookmarks: :activity) - conn |> put_view(StatusView) |> try_render("status.json", %{activity: activity, for: user}) @@ -514,8 +505,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do def reblog_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do with {:ok, announce, _activity} <- CommonAPI.repeat(ap_id_or_id, user), %Activity{} = announce <- Activity.normalize(announce.data) do - user = Repo.preload(user, bookmarks: :activity) - conn |> put_view(StatusView) |> try_render("status.json", %{activity: announce, for: user, as: :activity}) @@ -525,8 +514,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do def unreblog_status(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do with {:ok, _unannounce, %{data: %{"id" => id}}} <- CommonAPI.unrepeat(ap_id_or_id, user), %Activity{} = activity <- Activity.get_create_by_object_ap_id_with_object(id) do - user = Repo.preload(user, bookmarks: :activity) - conn |> put_view(StatusView) |> try_render("status.json", %{activity: activity, for: user, as: :activity}) @@ -577,8 +564,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do %User{} = user <- User.get_cached_by_nickname(user.nickname), true <- Visibility.visible_for_user?(activity, user), {:ok, _bookmark} <- Bookmark.create(user.id, activity.id) do - user = Repo.preload(user, bookmarks: :activity) - conn |> put_view(StatusView) |> try_render("status.json", %{activity: activity, for: user, as: :activity}) @@ -590,8 +575,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do %User{} = user <- User.get_cached_by_nickname(user.nickname), true <- Visibility.visible_for_user?(activity, user), {:ok, _bookmark} <- Bookmark.destroy(user.id, activity.id) do - user = Repo.preload(user, bookmarks: :activity) - conn |> put_view(StatusView) |> try_render("status.json", %{activity: activity, for: user, as: :activity}) @@ -1112,8 +1095,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do ActivityPub.fetch_activities([], params) |> Enum.reverse() - user = Repo.preload(user, bookmarks: :activity) - conn |> add_link_headers(:favourites, activities) |> put_view(StatusView) @@ -1159,7 +1140,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do def bookmarks(%{assigns: %{user: user}} = conn, params) do user = User.get_cached_by_id(user.id) - user = Repo.preload(user, bookmarks: :activity) bookmarks = Bookmark.for_user_query(user.id) @@ -1276,8 +1256,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do |> ActivityPub.fetch_activities_bounded(following, params) |> Enum.reverse() - user = Repo.preload(user, bookmarks: :activity) - conn |> put_view(StatusView) |> render("index.json", %{activities: activities, for: user, as: :activity}) -- cgit v1.2.3 From f841eb7cdb83afc444dfe260581b6be6e690a717 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 4 May 2019 12:46:42 +0300 Subject: Preload bookmarks wherever the object is preloaded --- lib/pleroma/activity.ex | 12 +++++++++--- lib/pleroma/web/activity_pub/activity_pub.ex | 7 +++++++ 2 files changed, 16 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index 73e63bb14..7845c264a 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -6,6 +6,7 @@ defmodule Pleroma.Activity do use Ecto.Schema alias Pleroma.Activity + alias Pleroma.Bookmark alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Repo @@ -36,6 +37,7 @@ defmodule Pleroma.Activity do field(:actor, :string) field(:recipients, {:array, :string}, default: []) has_many(:notifications, Notification, on_delete: :delete_all) + has_many(:bookmarks, Bookmark, on_delete: :delete_all) # Attention: this is a fake relation, don't try to preload it blindly and expect it to work! # The foreign key is embedded in a jsonb field. @@ -71,6 +73,7 @@ defmodule Pleroma.Activity do ) ) |> preload([activity, object], object: object) + |> preload(:bookmarks) end def get_by_ap_id(ap_id) do @@ -102,7 +105,8 @@ defmodule Pleroma.Activity do activity.data, activity.data ), - preload: [object: o] + preload: [object: o], + preload: :bookmarks ) ) end @@ -122,7 +126,8 @@ defmodule Pleroma.Activity do activity.data, activity.data ), - preload: [object: o] + preload: [object: o], + preload: :bookmarks ) |> Repo.one() end @@ -200,7 +205,8 @@ defmodule Pleroma.Activity do activity.data, activity.data ), - preload: [object: o] + preload: [object: o], + preload: :bookmarks ) end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 6c737d0a4..bd2544470 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -137,6 +137,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do activity end + activity = + if activity.data["type"] in ["Create", "Announce"] do + Repo.preload(activity, :bookmarks) + else + activity + end + Task.start(fn -> Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) end) -- cgit v1.2.3 From 3a7c14645ed726bd6b7deb6489ec0578c4d8cd79 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 4 May 2019 13:42:54 +0300 Subject: - Actually use preloaded bookmarks in views - Preload bookmarks in bookmark timeline - Rework bookmark preload tests --- lib/pleroma/activity.ex | 13 +++++++++---- lib/pleroma/bookmark.ex | 3 ++- .../web/mastodon_api/mastodon_api_controller.ex | 9 ++++++++- lib/pleroma/web/mastodon_api/views/status_view.ex | 18 +++++++++++++++--- 4 files changed, 34 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index 7845c264a..e432fcb07 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -73,6 +73,11 @@ defmodule Pleroma.Activity do ) ) |> preload([activity, object], object: object) + |> with_preloaded_bookmarks() + end + + def with_preloaded_bookmarks(query) do + query |> preload(:bookmarks) end @@ -105,9 +110,9 @@ defmodule Pleroma.Activity do activity.data, activity.data ), - preload: [object: o], - preload: :bookmarks + preload: [object: o] ) + |> with_preloaded_bookmarks() ) end @@ -126,9 +131,9 @@ defmodule Pleroma.Activity do activity.data, activity.data ), - preload: [object: o], - preload: :bookmarks + preload: [object: o] ) + |> with_preloaded_bookmarks() |> Repo.one() end diff --git a/lib/pleroma/bookmark.ex b/lib/pleroma/bookmark.ex index 7f8fd43b6..bbb51c22c 100644 --- a/lib/pleroma/bookmark.ex +++ b/lib/pleroma/bookmark.ex @@ -38,7 +38,8 @@ defmodule Pleroma.Bookmark do Bookmark |> where(user_id: ^user_id) |> join(:inner, [b], activity in assoc(b, :activity)) - |> preload([b, a], activity: a) + |> join(:inner, [_b, a], bookmarks in assoc(a, :bookmarks)) + |> preload([b, a, b2], activity: {a, bookmarks: b2}) end def get(user_id, activity_id) do diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 2a3d58592..451fc85ce 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -563,7 +563,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do with %Activity{} = activity <- Activity.get_by_id_with_object(id), %User{} = user <- User.get_cached_by_nickname(user.nickname), true <- Visibility.visible_for_user?(activity, user), - {:ok, _bookmark} <- Bookmark.create(user.id, activity.id) do + {:ok, bookmark} <- Bookmark.create(user.id, activity.id) do + activity = %{activity | bookmarks: [bookmark | activity.bookmarks]} + conn |> put_view(StatusView) |> try_render("status.json", %{activity: activity, for: user, as: :activity}) @@ -575,6 +577,11 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do %User{} = user <- User.get_cached_by_nickname(user.nickname), true <- Visibility.visible_for_user?(activity, user), {:ok, _bookmark} <- Bookmark.destroy(user.id, activity.id) do + bookmarks = + Enum.filter(activity.bookmarks, fn %{user_id: user_id} -> user_id != user.id end) + + activity = %{activity | bookmarks: bookmarks} + conn |> put_view(StatusView) |> try_render("status.json", %{activity: activity, for: user, as: :activity}) diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 62d064d71..c5a7bcbab 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -80,13 +80,21 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do user = get_user(activity.data["actor"]) created_at = Utils.to_masto_date(activity.data["published"]) - reblogged_activity = Activity.get_create_by_object_ap_id(object) + reblogged_activity = + Activity.create_by_object_ap_id(object) + |> Activity.with_preloaded_bookmarks() + |> Repo.one() + reblogged = render("status.json", Map.put(opts, :activity, reblogged_activity)) activity_object = Object.normalize(activity) favorited = opts[:for] && opts[:for].ap_id in (activity_object.data["likes"] || []) - bookmarked = opts[:for] && CommonAPI.bookmarked?(opts[:for], reblogged_activity) + bookmarked = + opts[:for] && Ecto.assoc_loaded?(reblogged_activity.bookmarks) && + Enum.any?(reblogged_activity.bookmarks, fn %{user_id: user_id} -> + user_id == opts[:for].id + end) mentions = activity.recipients @@ -149,7 +157,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do favorited = opts[:for] && opts[:for].ap_id in (object.data["likes"] || []) - bookmarked = opts[:for] && CommonAPI.bookmarked?(opts[:for], activity) + bookmarked = + opts[:for] && Ecto.assoc_loaded?(activity.bookmarks) && + Enum.any?(activity.bookmarks, fn %{user_id: user_id} -> + user_id == opts[:for].id + end) attachment_data = object.data["attachment"] || [] attachments = render_many(attachment_data, StatusView, "attachment.json", as: :attachment) -- cgit v1.2.3 From be067ec2ab7d3ebcbad7b1306ab19b266dcda664 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 4 May 2019 13:50:39 +0300 Subject: Use with_preloaded_bookmark in create_by_object_ap_id_with_object --- lib/pleroma/activity.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index e432fcb07..ab41364dc 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -210,9 +210,9 @@ defmodule Pleroma.Activity do activity.data, activity.data ), - preload: [object: o], - preload: :bookmarks + preload: [object: o] ) + |> with_preloaded_bookmarks() end def create_by_object_ap_id_with_object(_), do: nil -- cgit v1.2.3 From 4c5125dedc429ac021c861c11eb2e41c856ae4e8 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 7 May 2019 18:00:50 +0300 Subject: Remove `bookmarks` assoc and add a fake `bookmark` assoc instead --- lib/pleroma/activity.ex | 29 ++++++++++++++++------ lib/pleroma/bookmark.ex | 3 +-- lib/pleroma/web/activity_pub/activity_pub.ex | 15 +++++------ .../web/mastodon_api/mastodon_api_controller.ex | 11 ++------ lib/pleroma/web/mastodon_api/views/status_view.ex | 24 ++++++------------ 5 files changed, 40 insertions(+), 42 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index ab41364dc..2b661edc1 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -10,6 +10,7 @@ defmodule Pleroma.Activity do alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Repo + alias Pleroma.User import Ecto.Changeset import Ecto.Query @@ -36,8 +37,9 @@ defmodule Pleroma.Activity do field(:local, :boolean, default: true) field(:actor, :string) field(:recipients, {:array, :string}, default: []) + # This is a fake relation, do not use outside of with_preloaded_bookmark/get_bookmark + has_one(:bookmark, Bookmark) has_many(:notifications, Notification, on_delete: :delete_all) - has_many(:bookmarks, Bookmark, on_delete: :delete_all) # Attention: this is a fake relation, don't try to preload it blindly and expect it to work! # The foreign key is embedded in a jsonb field. @@ -73,14 +75,18 @@ defmodule Pleroma.Activity do ) ) |> preload([activity, object], object: object) - |> with_preloaded_bookmarks() end - def with_preloaded_bookmarks(query) do - query - |> preload(:bookmarks) + def with_preloaded_bookmark(query, %User{} = user) do + from([a] in query, + left_join: b in Bookmark, + on: b.user_id == ^user.id and b.activity_id == a.id, + preload: [bookmark: b] + ) end + def with_preloaded_bookmark(query, _), do: query + def get_by_ap_id(ap_id) do Repo.one( from( @@ -90,6 +96,16 @@ defmodule Pleroma.Activity do ) end + def get_bookmark(%Activity{} = activity, %User{} = user) do + if Ecto.assoc_loaded?(activity.bookmark) do + activity.bookmark + else + Bookmark.get(user.id, activity.id) + end + end + + def get_bookmark(_, _), do: nil + def change(struct, params \\ %{}) do struct |> cast(params, [:data]) @@ -112,7 +128,6 @@ defmodule Pleroma.Activity do ), preload: [object: o] ) - |> with_preloaded_bookmarks() ) end @@ -133,7 +148,6 @@ defmodule Pleroma.Activity do ), preload: [object: o] ) - |> with_preloaded_bookmarks() |> Repo.one() end @@ -212,7 +226,6 @@ defmodule Pleroma.Activity do ), preload: [object: o] ) - |> with_preloaded_bookmarks() end def create_by_object_ap_id_with_object(_), do: nil diff --git a/lib/pleroma/bookmark.ex b/lib/pleroma/bookmark.ex index bbb51c22c..7f8fd43b6 100644 --- a/lib/pleroma/bookmark.ex +++ b/lib/pleroma/bookmark.ex @@ -38,8 +38,7 @@ defmodule Pleroma.Bookmark do Bookmark |> where(user_id: ^user_id) |> join(:inner, [b], activity in assoc(b, :activity)) - |> join(:inner, [_b, a], bookmarks in assoc(a, :bookmarks)) - |> preload([b, a, b2], activity: {a, bookmarks: b2}) + |> preload([b, a], activity: a) end def get(user_id, activity_id) do diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index bd2544470..a4053986f 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -137,13 +137,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do activity end - activity = - if activity.data["type"] in ["Create", "Announce"] do - Repo.preload(activity, :bookmarks) - else - activity - end - Task.start(fn -> Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) end) @@ -822,11 +815,19 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> Activity.with_preloaded_object() end + defp maybe_preload_bookmarks(query, %{"skip_preload" => true}), do: query + + defp maybe_preload_bookmarks(query, opts) do + query + |> Activity.with_preloaded_bookmark(opts["user"]) + end + def fetch_activities_query(recipients, opts \\ %{}) do base_query = from(activity in Activity) base_query |> maybe_preload_objects(opts) + |> maybe_preload_bookmarks(opts) |> restrict_recipients(recipients, opts["user"]) |> restrict_tag(opts) |> restrict_tag_reject(opts) diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 451fc85ce..83ad90989 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -563,9 +563,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do with %Activity{} = activity <- Activity.get_by_id_with_object(id), %User{} = user <- User.get_cached_by_nickname(user.nickname), true <- Visibility.visible_for_user?(activity, user), - {:ok, bookmark} <- Bookmark.create(user.id, activity.id) do - activity = %{activity | bookmarks: [bookmark | activity.bookmarks]} - + {:ok, _bookmark} <- Bookmark.create(user.id, activity.id) do conn |> put_view(StatusView) |> try_render("status.json", %{activity: activity, for: user, as: :activity}) @@ -577,11 +575,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do %User{} = user <- User.get_cached_by_nickname(user.nickname), true <- Visibility.visible_for_user?(activity, user), {:ok, _bookmark} <- Bookmark.destroy(user.id, activity.id) do - bookmarks = - Enum.filter(activity.bookmarks, fn %{user_id: user_id} -> user_id != user.id end) - - activity = %{activity | bookmarks: bookmarks} - conn |> put_view(StatusView) |> try_render("status.json", %{activity: activity, for: user, as: :activity}) @@ -1154,7 +1147,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do activities = bookmarks - |> Enum.map(fn b -> b.activity end) + |> Enum.map(fn b -> Map.put(b.activity, :bookmark, Map.delete(b, :activity)) end) conn |> add_link_headers(:bookmarks, bookmarks) diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index c5a7bcbab..bd2372944 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -75,26 +75,22 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do def render( "status.json", - %{activity: %{data: %{"type" => "Announce", "object" => object}} = activity} = opts + %{activity: %{data: %{"type" => "Announce", "object" => _object}} = activity} = opts ) do user = get_user(activity.data["actor"]) created_at = Utils.to_masto_date(activity.data["published"]) + activity_object = Object.normalize(activity) reblogged_activity = - Activity.create_by_object_ap_id(object) - |> Activity.with_preloaded_bookmarks() + Activity.create_by_object_ap_id(activity_object.data["id"]) + |> Activity.with_preloaded_bookmark(opts[:for]) |> Repo.one() reblogged = render("status.json", Map.put(opts, :activity, reblogged_activity)) - activity_object = Object.normalize(activity) favorited = opts[:for] && opts[:for].ap_id in (activity_object.data["likes"] || []) - bookmarked = - opts[:for] && Ecto.assoc_loaded?(reblogged_activity.bookmarks) && - Enum.any?(reblogged_activity.bookmarks, fn %{user_id: user_id} -> - user_id == opts[:for].id - end) + bookmarked = Activity.get_bookmark(reblogged_activity, opts[:for]) != nil mentions = activity.recipients @@ -104,8 +100,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do %{ id: to_string(activity.id), - uri: object, - url: object, + uri: activity_object.data["id"], + url: activity_object.data["id"], account: AccountView.render("account.json", %{user: user}), in_reply_to_id: nil, in_reply_to_account_id: nil, @@ -157,11 +153,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do favorited = opts[:for] && opts[:for].ap_id in (object.data["likes"] || []) - bookmarked = - opts[:for] && Ecto.assoc_loaded?(activity.bookmarks) && - Enum.any?(activity.bookmarks, fn %{user_id: user_id} -> - user_id == opts[:for].id - end) + bookmarked = Activity.get_bookmark(activity, opts[:for]) != nil attachment_data = object.data["attachment"] || [] attachments = render_many(attachment_data, StatusView, "attachment.json", as: :attachment) -- cgit v1.2.3 From 6020ff3fb696c6b46e948d69a8687182c701a743 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Tue, 7 May 2019 19:30:27 +0000 Subject: activitypub: add optional order constraint to timeline query builder --- lib/pleroma/web/activity_pub/activity_pub.ex | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index a4053986f..8f8c23a9b 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -822,12 +822,25 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> Activity.with_preloaded_bookmark(opts["user"]) end + defp maybe_order(query, %{order: :desc}) do + query + |> order_by(desc: :id) + end + + defp maybe_order(query, %{order: :asc}) do + query + |> order_by(asc: :id) + end + + defp maybe_order(query, _), do: query + def fetch_activities_query(recipients, opts \\ %{}) do base_query = from(activity in Activity) base_query |> maybe_preload_objects(opts) |> maybe_preload_bookmarks(opts) + |> maybe_order(opts) |> restrict_recipients(recipients, opts["user"]) |> restrict_tag(opts) |> restrict_tag_reject(opts) -- cgit v1.2.3 From d64c3b604e4eb5e8dd3f51aff7d1f15024d5fa33 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Tue, 7 May 2019 19:30:51 +0000 Subject: twitterapi: use order constraint to force descending order --- lib/pleroma/web/twitter_api/twitter_api_controller.ex | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index ef7b6fe65..21e6c555a 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -182,6 +182,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do |> Map.put("blocking_user", user) |> Map.put("user", user) |> Map.put(:visibility, "direct") + |> Map.put(:order, :desc) activities = ActivityPub.fetch_activities_query([user.ap_id], params) -- cgit v1.2.3 From 799e1f48b52762f21f577269938bc037eba9e20f Mon Sep 17 00:00:00 2001 From: Maksim Date: Wed, 8 May 2019 10:52:13 +0000 Subject: Refactoring functions for dealing with oauth scopes. --- lib/pleroma/web/controller_helper.ex | 6 -- .../web/mastodon_api/mastodon_api_controller.ex | 3 +- lib/pleroma/web/oauth.ex | 14 ----- lib/pleroma/web/oauth/oauth_controller.ex | 31 +++++----- lib/pleroma/web/oauth/scopes.ex | 67 ++++++++++++++++++++++ 5 files changed, 86 insertions(+), 35 deletions(-) create mode 100644 lib/pleroma/web/oauth/scopes.ex (limited to 'lib') diff --git a/lib/pleroma/web/controller_helper.ex b/lib/pleroma/web/controller_helper.ex index 181483664..55706eeb8 100644 --- a/lib/pleroma/web/controller_helper.ex +++ b/lib/pleroma/web/controller_helper.ex @@ -10,12 +10,6 @@ defmodule Pleroma.Web.ControllerHelper do def truthy_param?(blank_value) when blank_value in [nil, ""], do: nil def truthy_param?(value), do: value not in @falsy_param_values - def oauth_scopes(params, default) do - # Note: `scopes` is used by Mastodon — supporting it but sticking to - # OAuth's standard `scope` wherever we control it - Pleroma.Web.OAuth.parse_scopes(params["scope"] || params["scopes"], default) - end - def json_response(conn, status, json) do conn |> put_status(status) diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 83ad90989..956736780 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -37,6 +37,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Web.MediaProxy alias Pleroma.Web.OAuth.App alias Pleroma.Web.OAuth.Authorization + alias Pleroma.Web.OAuth.Scopes alias Pleroma.Web.OAuth.Token alias Pleroma.Web.ControllerHelper @@ -50,7 +51,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do action_fallback(:errors) def create_app(conn, params) do - scopes = ControllerHelper.oauth_scopes(params, ["read"]) + scopes = Scopes.fetch_scopes(params, ["read"]) app_attrs = params diff --git a/lib/pleroma/web/oauth.ex b/lib/pleroma/web/oauth.ex index d2835a0ba..280cf28c0 100644 --- a/lib/pleroma/web/oauth.ex +++ b/lib/pleroma/web/oauth.ex @@ -3,18 +3,4 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.OAuth do - def parse_scopes(scopes, _default) when is_list(scopes) do - Enum.filter(scopes, &(&1 not in [nil, ""])) - end - - def parse_scopes(scopes, default) when is_binary(scopes) do - scopes - |> String.trim() - |> String.split(~r/[\s,]+/) - |> parse_scopes(default) - end - - def parse_scopes(_, default) do - default - end end diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index e3c01217d..8ee0da667 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -15,8 +15,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do alias Pleroma.Web.OAuth.Token alias Pleroma.Web.OAuth.Token.Strategy.RefreshToken alias Pleroma.Web.OAuth.Token.Strategy.Revoke, as: RevokeToken - - import Pleroma.Web.ControllerHelper, only: [oauth_scopes: 2] + alias Pleroma.Web.OAuth.Scopes if Pleroma.Config.oauth_consumer_enabled?(), do: plug(Ueberauth) @@ -57,7 +56,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do defp do_authorize(conn, params) do app = Repo.get_by(App, client_id: params["client_id"]) available_scopes = (app && app.scopes) || [] - scopes = oauth_scopes(params, nil) || available_scopes + scopes = Scopes.fetch_scopes(params, available_scopes) # Note: `params` might differ from `conn.params`; use `@params` not `@conn.params` in template render(conn, Authenticator.auth_template(), %{ @@ -113,7 +112,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do defp handle_create_authorization_error( conn, - {scopes_issue, _}, + {:error, scopes_issue}, %{"authorization" => _} = params ) when scopes_issue in [:unsupported_scopes, :missing_scopes] do @@ -184,9 +183,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do %App{} = app <- get_app_from_request(conn, params), {:auth_active, true} <- {:auth_active, User.auth_active?(user)}, {:user_active, true} <- {:user_active, !user.info.deactivated}, - scopes <- oauth_scopes(params, app.scopes), - [] <- scopes -- app.scopes, - true <- Enum.any?(scopes), + {:ok, scopes} <- validate_scopes(app, params), {:ok, auth} <- Authorization.create_authorization(app, user, scopes), {:ok, token} <- Token.exchange_token(app, auth) do json(conn, response_token(user, token)) @@ -247,8 +244,9 @@ defmodule Pleroma.Web.OAuth.OAuthController do @doc "Prepares OAuth request to provider for Ueberauth" def prepare_request(conn, %{"provider" => provider, "authorization" => auth_attrs}) do scope = - oauth_scopes(auth_attrs, []) - |> Enum.join(" ") + auth_attrs + |> Scopes.fetch_scopes([]) + |> Scopes.to_string() state = auth_attrs @@ -326,7 +324,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do client_id: auth_attrs["client_id"], redirect_uri: auth_attrs["redirect_uri"], state: auth_attrs["state"], - scopes: oauth_scopes(auth_attrs, []), + scopes: Scopes.fetch_scopes(auth_attrs, []), nickname: auth_attrs["nickname"], email: auth_attrs["email"] }) @@ -401,10 +399,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do {:get_user, (user && {:ok, user}) || Authenticator.get_user(conn)}, %App{} = app <- Repo.get_by(App, client_id: client_id), true <- redirect_uri in String.split(app.redirect_uris), - scopes <- oauth_scopes(auth_attrs, []), - {:unsupported_scopes, []} <- {:unsupported_scopes, scopes -- app.scopes}, - # Note: `scope` param is intentionally not optional in this context - {:missing_scopes, false} <- {:missing_scopes, scopes == []}, + {:ok, scopes} <- validate_scopes(app, auth_attrs), {:auth_active, true} <- {:auth_active, User.auth_active?(user)} do Authorization.create_authorization(app, user, scopes) end @@ -458,4 +453,12 @@ defmodule Pleroma.Web.OAuth.OAuthController do } |> Map.merge(opts) end + + @spec validate_scopes(App.t(), map()) :: + {:ok, list()} | {:error, :missing_scopes | :unsupported_scopes} + defp validate_scopes(app, params) do + params + |> Scopes.fetch_scopes(app.scopes) + |> Scopes.validates(app.scopes) + end end diff --git a/lib/pleroma/web/oauth/scopes.ex b/lib/pleroma/web/oauth/scopes.ex new file mode 100644 index 000000000..ad9dfb260 --- /dev/null +++ b/lib/pleroma/web/oauth/scopes.ex @@ -0,0 +1,67 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.OAuth.Scopes do + @moduledoc """ + Functions for dealing with scopes. + """ + + @doc """ + Fetch scopes from requiest params. + + Note: `scopes` is used by Mastodon — supporting it but sticking to + OAuth's standard `scope` wherever we control it + """ + @spec fetch_scopes(map(), list()) :: list() + def fetch_scopes(params, default) do + parse_scopes(params["scope"] || params["scopes"], default) + end + + def parse_scopes(scopes, _default) when is_list(scopes) do + Enum.filter(scopes, &(&1 not in [nil, ""])) + end + + def parse_scopes(scopes, default) when is_binary(scopes) do + scopes + |> to_list + |> parse_scopes(default) + end + + def parse_scopes(_, default) do + default + end + + @doc """ + Convert scopes string to list + """ + @spec to_list(binary()) :: [binary()] + def to_list(nil), do: [] + + def to_list(str) do + str + |> String.trim() + |> String.split(~r/[\s,]+/) + end + + @doc """ + Convert scopes list to string + """ + @spec to_string(list()) :: binary() + def to_string(scopes), do: Enum.join(scopes, " ") + + @doc """ + Validates scopes. + """ + @spec validates(list() | nil, list()) :: + {:ok, list()} | {:error, :missing_scopes | :unsupported_scopes} + def validates([], _app_scopes), do: {:error, :missing_scopes} + def validates(nil, _app_scopes), do: {:error, :missing_scopes} + + def validates(scopes, app_scopes) do + case scopes -- app_scopes do + [] -> {:ok, scopes} + _ -> {:error, :unsupported_scopes} + end + end +end -- cgit v1.2.3 From a76e2622ca0201dfd78616cbad58c9fb14111796 Mon Sep 17 00:00:00 2001 From: Alex S Date: Wed, 8 May 2019 19:05:25 +0700 Subject: emoji dowload follow redirects --- lib/mix/tasks/pleroma/emoji.ex | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/emoji.ex b/lib/mix/tasks/pleroma/emoji.ex index cced73226..5cb54c3ca 100644 --- a/lib/mix/tasks/pleroma/emoji.ex +++ b/lib/mix/tasks/pleroma/emoji.ex @@ -109,7 +109,7 @@ defmodule Mix.Tasks.Pleroma.Emoji do ]) ) - binary_archive = Tesla.get!(src_url).body + binary_archive = Tesla.get!(client(), src_url).body archive_sha = :crypto.hash(:sha256, binary_archive) |> Base.encode16() sha_status_text = ["SHA256 of ", :bright, pack_name, :normal, " source file is ", :bright] @@ -137,7 +137,7 @@ defmodule Mix.Tasks.Pleroma.Emoji do ]) ) - files = Tesla.get!(files_url).body |> Poison.decode!() + files = Tesla.get!(client(), files_url).body |> Poison.decode!() IO.puts(IO.ANSI.format(["Unpacking ", :bright, pack_name])) @@ -213,7 +213,7 @@ defmodule Mix.Tasks.Pleroma.Emoji do IO.puts("Downloading the pack and generating SHA256") - binary_archive = Tesla.get!(src).body + binary_archive = Tesla.get!(client(), src).body archive_sha = :crypto.hash(:sha256, binary_archive) |> Base.encode16() IO.puts("SHA256 is #{archive_sha}") @@ -272,7 +272,7 @@ defmodule Mix.Tasks.Pleroma.Emoji do defp fetch_manifest(from) do Poison.decode!( if String.starts_with?(from, "http") do - Tesla.get!(from).body + Tesla.get!(client(), from).body else File.read!(from) end @@ -290,4 +290,12 @@ defmodule Mix.Tasks.Pleroma.Emoji do ] ) end + + defp client do + middleware = [ + {Tesla.Middleware.FollowRedirects, [max_redirects: 3]} + ] + + Tesla.client(middleware) + end end -- cgit v1.2.3 From bfeb33e951c8997f33a0242fe69b8e669e3afe07 Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Wed, 8 May 2019 14:34:36 +0000 Subject: Merge develop Merge conflict in lib/pleroma/activity.ex --- lib/pleroma/activity.ex | 23 +++ lib/pleroma/stats.ex | 9 +- lib/pleroma/user.ex | 196 +++++----------------- lib/pleroma/user/query.ex | 150 +++++++++++++++++ lib/pleroma/web/admin_api/admin_api_controller.ex | 9 +- lib/pleroma/web/admin_api/search.ex | 44 ++--- 6 files changed, 236 insertions(+), 195 deletions(-) create mode 100644 lib/pleroma/user/query.ex (limited to 'lib') diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index 2b661edc1..c121e800f 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -287,6 +287,29 @@ defmodule Pleroma.Activity do |> Repo.all() end + def follow_requests_for_actor(%Pleroma.User{ap_id: ap_id}) do + from( + a in Activity, + where: + fragment( + "? ->> 'type' = 'Follow'", + a.data + ), + where: + fragment( + "? ->> 'state' = 'pending'", + a.data + ), + where: + fragment( + "coalesce((?)->'object'->>'id', (?)->>'object') = ?", + a.data, + a.data, + ^ap_id + ) + ) + end + @spec query_by_actor(actor()) :: Ecto.Query.t() def query_by_actor(actor) do from(a in Activity, where: a.actor == ^actor) diff --git a/lib/pleroma/stats.ex b/lib/pleroma/stats.ex index 2e7d747df..5b242927b 100644 --- a/lib/pleroma/stats.ex +++ b/lib/pleroma/stats.ex @@ -34,7 +34,7 @@ defmodule Pleroma.Stats do def update_stats do peers = from( - u in Pleroma.User, + u in User, select: fragment("distinct split_part(?, '@', 2)", u.nickname), where: u.local != ^true ) @@ -44,10 +44,13 @@ defmodule Pleroma.Stats do domain_count = Enum.count(peers) status_query = - from(u in User.local_user_query(), select: fragment("sum((?->>'note_count')::int)", u.info)) + from(u in User.Query.build(%{local: true}), + select: fragment("sum((?->>'note_count')::int)", u.info) + ) status_count = Repo.one(status_query) - user_count = Repo.aggregate(User.active_local_user_query(), :count, :id) + + user_count = Repo.aggregate(User.Query.build(%{local: true, active: true}), :count, :id) Agent.update(__MODULE__, fn _ -> {peers, %{domain_count: domain_count, status_count: status_count, user_count: user_count}} diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index b1adaad2f..427400aa1 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -254,10 +254,7 @@ defmodule Pleroma.User do candidates = Pleroma.Config.get([:instance, :autofollowed_nicknames]) autofollowed_users = - from(u in User, - where: u.local == true, - where: u.nickname in ^candidates - ) + User.Query.build(%{nickname: candidates, local: true}) |> Repo.all() follow_all(user, autofollowed_users) @@ -576,19 +573,17 @@ defmodule Pleroma.User do ) end - def get_followers_query(%User{id: id, follower_address: follower_address}, nil) do - from( - u in User, - where: fragment("? <@ ?", ^[follower_address], u.following), - where: u.id != ^id - ) + @spec get_followers_query(User.t(), pos_integer() | nil) :: Ecto.Query.t() + def get_followers_query(%User{} = user, nil) do + User.Query.build(%{followers: user}) end def get_followers_query(user, page) do from(u in get_followers_query(user, nil)) - |> paginate(page, 20) + |> User.Query.paginate(page, 20) end + @spec get_followers_query(User.t()) :: Ecto.Query.t() def get_followers_query(user), do: get_followers_query(user, nil) def get_followers(user, page \\ nil) do @@ -603,19 +598,17 @@ defmodule Pleroma.User do Repo.all(from(u in q, select: u.id)) end - def get_friends_query(%User{id: id, following: following}, nil) do - from( - u in User, - where: u.follower_address in ^following, - where: u.id != ^id - ) + @spec get_friends_query(User.t(), pos_integer() | nil) :: Ecto.Query.t() + def get_friends_query(%User{} = user, nil) do + User.Query.build(%{friends: user}) end def get_friends_query(user, page) do from(u in get_friends_query(user, nil)) - |> paginate(page, 20) + |> User.Query.paginate(page, 20) end + @spec get_friends_query(User.t()) :: Ecto.Query.t() def get_friends_query(user), do: get_friends_query(user, nil) def get_friends(user, page \\ nil) do @@ -630,33 +623,10 @@ defmodule Pleroma.User do Repo.all(from(u in q, select: u.id)) end - def get_follow_requests_query(%User{} = user) do - from( - a in Activity, - where: - fragment( - "? ->> 'type' = 'Follow'", - a.data - ), - where: - fragment( - "? ->> 'state' = 'pending'", - a.data - ), - where: - fragment( - "coalesce((?)->'object'->>'id', (?)->>'object') = ?", - a.data, - a.data, - ^user.ap_id - ) - ) - end - + @spec get_follow_requests(User.t()) :: {:ok, [User.t()]} def get_follow_requests(%User{} = user) do users = - user - |> User.get_follow_requests_query() + Activity.follow_requests_for_actor(user) |> join(:inner, [a], u in User, on: a.actor == u.ap_id) |> where([a, u], not fragment("? @> ?", u.following, ^[user.follower_address])) |> group_by([a, u], u.id) @@ -729,10 +699,7 @@ defmodule Pleroma.User do def update_follower_count(%User{} = user) do follower_count_query = - User - |> where([u], ^user.follower_address in u.following) - |> where([u], u.id != ^user.id) - |> select([u], %{count: count(u.id)}) + User.Query.build(%{followers: user}) |> select([u], %{count: count(u.id)}) User |> where(id: ^user.id) @@ -755,38 +722,19 @@ defmodule Pleroma.User do end end - def get_users_from_set_query(ap_ids, false) do - from( - u in User, - where: u.ap_id in ^ap_ids - ) - end - - def get_users_from_set_query(ap_ids, true) do - query = get_users_from_set_query(ap_ids, false) - - from( - u in query, - where: u.local == true - ) - end - + @spec get_users_from_set([String.t()], boolean()) :: [User.t()] def get_users_from_set(ap_ids, local_only \\ true) do - get_users_from_set_query(ap_ids, local_only) + criteria = %{ap_id: ap_ids} + criteria = if local_only, do: Map.put(criteria, :local, true), else: criteria + + User.Query.build(criteria) |> Repo.all() end + @spec get_recipients_from_activity(Activity.t()) :: [User.t()] def get_recipients_from_activity(%Activity{recipients: to}) do - query = - from( - u in User, - where: u.ap_id in ^to, - or_where: fragment("? && ?", u.following, ^to) - ) - - query = from(u in query, where: u.local == true) - - Repo.all(query) + User.Query.build(%{recipients_from_activity: to, local: true}) + |> Repo.all() end def search(query, resolve \\ false, for_user \\ nil) do @@ -1048,14 +996,23 @@ defmodule Pleroma.User do end end - def muted_users(user), - do: Repo.all(from(u in User, where: u.ap_id in ^user.info.mutes)) + @spec muted_users(User.t()) :: [User.t()] + def muted_users(user) do + User.Query.build(%{ap_id: user.info.mutes}) + |> Repo.all() + end - def blocked_users(user), - do: Repo.all(from(u in User, where: u.ap_id in ^user.info.blocks)) + @spec blocked_users(User.t()) :: [User.t()] + def blocked_users(user) do + User.Query.build(%{ap_id: user.info.blocks}) + |> Repo.all() + end - def subscribers(user), - do: Repo.all(from(u in User, where: u.ap_id in ^user.info.subscribers)) + @spec subscribers(User.t()) :: [User.t()] + def subscribers(user) do + User.Query.build(%{ap_id: user.info.subscribers}) + |> Repo.all() + end def block_domain(user, domain) do info_cng = @@ -1081,69 +1038,6 @@ defmodule Pleroma.User do update_and_set_cache(cng) end - def maybe_local_user_query(query, local) do - if local, do: local_user_query(query), else: query - end - - def local_user_query(query \\ User) do - from( - u in query, - where: u.local == true, - where: not is_nil(u.nickname) - ) - end - - def maybe_external_user_query(query, external) do - if external, do: external_user_query(query), else: query - end - - def external_user_query(query \\ User) do - from( - u in query, - where: u.local == false, - where: not is_nil(u.nickname) - ) - end - - def maybe_active_user_query(query, active) do - if active, do: active_user_query(query), else: query - end - - def active_user_query(query \\ User) do - from( - u in query, - where: fragment("not (?->'deactivated' @> 'true')", u.info), - where: not is_nil(u.nickname) - ) - end - - def maybe_deactivated_user_query(query, deactivated) do - if deactivated, do: deactivated_user_query(query), else: query - end - - def deactivated_user_query(query \\ User) do - from( - u in query, - where: fragment("(?->'deactivated' @> 'true')", u.info), - where: not is_nil(u.nickname) - ) - end - - def active_local_user_query do - from( - u in local_user_query(), - where: fragment("not (?->'deactivated' @> 'true')", u.info) - ) - end - - def moderator_user_query do - from( - u in User, - where: u.local == true, - where: fragment("?->'is_moderator' @> 'true'", u.info) - ) - end - def deactivate(%User{} = user, status \\ true) do info_cng = User.Info.set_activation_status(user.info, status) @@ -1306,7 +1200,7 @@ defmodule Pleroma.User do def ap_enabled?(_), do: false @doc "Gets or fetch a user by uri or nickname." - @spec get_or_fetch(String.t()) :: User.t() + @spec get_or_fetch(String.t()) :: {:ok, User.t()} | {:error, String.t()} def get_or_fetch("http" <> _host = uri), do: get_or_fetch_by_ap_id(uri) def get_or_fetch(nickname), do: get_or_fetch_by_nickname(nickname) @@ -1423,22 +1317,12 @@ defmodule Pleroma.User do } end + @spec all_superusers() :: [User.t()] def all_superusers do - from( - u in User, - where: u.local == true, - where: fragment("?->'is_admin' @> 'true' OR ?->'is_moderator' @> 'true'", u.info, u.info) - ) + User.Query.build(%{super_users: true, local: true}) |> Repo.all() end - defp paginate(query, page, page_size) do - from(u in query, - limit: ^page_size, - offset: ^((page - 1) * page_size) - ) - end - def showing_reblogs?(%User{} = user, %User{} = target) do target.ap_id not in user.info.muted_reblogs end diff --git a/lib/pleroma/user/query.ex b/lib/pleroma/user/query.ex new file mode 100644 index 000000000..2dfe5ce92 --- /dev/null +++ b/lib/pleroma/user/query.ex @@ -0,0 +1,150 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2018 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.User.Query do + @moduledoc """ + User query builder module. Builds query from new query or another user query. + + ## Example: + query = Pleroma.User.Query(%{nickname: "nickname"}) + another_query = Pleroma.User.Query.build(query, %{email: "email@example.com"}) + Pleroma.Repo.all(query) + Pleroma.Repo.all(another_query) + + Adding new rules: + - *ilike criteria* + - add field to @ilike_criteria list + - pass non empty string + - e.g. Pleroma.User.Query.build(%{nickname: "nickname"}) + - *equal criteria* + - add field to @equal_criteria list + - pass non empty string + - e.g. Pleroma.User.Query.build(%{email: "email@example.com"}) + - *contains criteria* + - add field to @containns_criteria list + - pass values list + - e.g. Pleroma.User.Query.build(%{ap_id: ["http://ap_id1", "http://ap_id2"]}) + """ + import Ecto.Query + import Pleroma.Web.AdminAPI.Search, only: [not_empty_string: 1] + alias Pleroma.User + + @type criteria :: + %{ + query: String.t(), + tags: [String.t()], + name: String.t(), + email: String.t(), + local: boolean(), + external: boolean(), + active: boolean(), + deactivated: boolean(), + is_admin: boolean(), + is_moderator: boolean(), + super_users: boolean(), + followers: User.t(), + friends: User.t(), + recipients_from_activity: [String.t()], + nickname: [String.t()], + ap_id: [String.t()] + } + | %{} + + @ilike_criteria [:nickname, :name, :query] + @equal_criteria [:email] + @role_criteria [:is_admin, :is_moderator] + @contains_criteria [:ap_id, :nickname] + + @spec build(criteria()) :: Query.t() + def build(query \\ base_query(), criteria) do + prepare_query(query, criteria) + end + + @spec paginate(Ecto.Query.t(), pos_integer(), pos_integer()) :: Ecto.Query.t() + def paginate(query, page, page_size) do + from(u in query, + limit: ^page_size, + offset: ^((page - 1) * page_size) + ) + end + + defp base_query do + from(u in User) + end + + defp prepare_query(query, criteria) do + Enum.reduce(criteria, query, &compose_query/2) + end + + defp compose_query({key, value}, query) + when key in @ilike_criteria and not_empty_string(value) do + # hack for :query key + key = if key == :query, do: :nickname, else: key + where(query, [u], ilike(field(u, ^key), ^"%#{value}%")) + end + + defp compose_query({key, value}, query) + when key in @equal_criteria and not_empty_string(value) do + where(query, [u], ^[{key, value}]) + end + + defp compose_query({key, values}, query) when key in @contains_criteria and is_list(values) do + where(query, [u], field(u, ^key) in ^values) + end + + defp compose_query({:tags, tags}, query) when is_list(tags) and length(tags) > 0 do + Enum.reduce(tags, query, &prepare_tag_criteria/2) + end + + defp compose_query({key, _}, query) when key in @role_criteria do + where(query, [u], fragment("(?->? @> 'true')", u.info, ^to_string(key))) + end + + defp compose_query({:super_users, _}, query) do + where( + query, + [u], + fragment("?->'is_admin' @> 'true' OR ?->'is_moderator' @> 'true'", u.info, u.info) + ) + end + + defp compose_query({:local, _}, query), do: location_query(query, true) + + defp compose_query({:external, _}, query), do: location_query(query, false) + + defp compose_query({:active, _}, query) do + where(query, [u], fragment("not (?->'deactivated' @> 'true')", u.info)) + |> where([u], not is_nil(u.nickname)) + end + + defp compose_query({:deactivated, _}, query) do + where(query, [u], fragment("?->'deactivated' @> 'true'", u.info)) + |> where([u], not is_nil(u.nickname)) + end + + defp compose_query({:followers, %User{id: id, follower_address: follower_address}}, query) do + where(query, [u], fragment("? <@ ?", ^[follower_address], u.following)) + |> where([u], u.id != ^id) + end + + defp compose_query({:friends, %User{id: id, following: following}}, query) do + where(query, [u], u.follower_address in ^following) + |> where([u], u.id != ^id) + end + + defp compose_query({:recipients_from_activity, to}, query) do + where(query, [u], u.ap_id in ^to or fragment("? && ?", u.following, ^to)) + end + + defp compose_query(_unsupported_param, query), do: query + + defp prepare_tag_criteria(tag, query) do + or_where(query, [u], fragment("? = any(?)", ^tag, u.tags)) + end + + defp location_query(query, local) do + where(query, [u], u.local == ^local) + |> where([u], not is_nil(u.nickname)) + end +end diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 711f233a6..b553d96a8 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -101,7 +101,10 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do search_params = %{ query: params["query"], page: page, - page_size: page_size + page_size: page_size, + tags: params["tags"], + name: params["name"], + email: params["email"] } with {:ok, users, count} <- Search.user(Map.merge(search_params, filters)), @@ -116,11 +119,11 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do ) end - @filters ~w(local external active deactivated) + @filters ~w(local external active deactivated is_admin is_moderator) + @spec maybe_parse_filters(String.t()) :: %{required(String.t()) => true} | %{} defp maybe_parse_filters(filters) when is_nil(filters) or filters == "", do: %{} - @spec maybe_parse_filters(String.t()) :: %{required(String.t()) => true} | %{} defp maybe_parse_filters(filters) do filters |> String.split(",") diff --git a/lib/pleroma/web/admin_api/search.ex b/lib/pleroma/web/admin_api/search.ex index 9a8e41c2a..ed919833e 100644 --- a/lib/pleroma/web/admin_api/search.ex +++ b/lib/pleroma/web/admin_api/search.ex @@ -10,45 +10,23 @@ defmodule Pleroma.Web.AdminAPI.Search do @page_size 50 - def user(%{query: term} = params) when is_nil(term) or term == "" do - query = maybe_filtered_query(params) + defmacro not_empty_string(string) do + quote do + is_binary(unquote(string)) and unquote(string) != "" + end + end + + @spec user(map()) :: {:ok, [User.t()], pos_integer()} + def user(params \\ %{}) do + query = User.Query.build(params) |> order_by([u], u.nickname) paginated_query = - maybe_filtered_query(params) - |> paginate(params[:page] || 1, params[:page_size] || @page_size) + User.Query.paginate(query, params[:page] || 1, params[:page_size] || @page_size) - count = query |> Repo.aggregate(:count, :id) + count = Repo.aggregate(query, :count, :id) results = Repo.all(paginated_query) {:ok, results, count} end - - def user(%{query: term} = params) when is_binary(term) do - search_query = from(u in maybe_filtered_query(params), where: ilike(u.nickname, ^"%#{term}%")) - - count = search_query |> Repo.aggregate(:count, :id) - - results = - search_query - |> paginate(params[:page] || 1, params[:page_size] || @page_size) - |> Repo.all() - - {:ok, results, count} - end - - defp maybe_filtered_query(params) do - from(u in User, order_by: u.nickname) - |> User.maybe_local_user_query(params[:local]) - |> User.maybe_external_user_query(params[:external]) - |> User.maybe_active_user_query(params[:active]) - |> User.maybe_deactivated_user_query(params[:deactivated]) - end - - defp paginate(query, page, page_size) do - from(u in query, - limit: ^page_size, - offset: ^((page - 1) * page_size) - ) - end end -- cgit v1.2.3 From fcf2f38d20eed40a53b03374467d9e52b013da07 Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 8 May 2019 17:37:00 +0200 Subject: Conversations: Add a function to 'import' old DMs. --- lib/pleroma/conversation.ex | 14 ++++++++++++++ lib/pleroma/web/activity_pub/activity_pub.ex | 6 ++++++ 2 files changed, 20 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/conversation.ex b/lib/pleroma/conversation.ex index 6e26c5fd4..aa73edd75 100644 --- a/lib/pleroma/conversation.ex +++ b/lib/pleroma/conversation.ex @@ -72,4 +72,18 @@ defmodule Pleroma.Conversation do e -> {:error, e} end end + + @doc """ + This is only meant to be run by a mix task. It creates conversations/participations for all direct messages in the database. + """ + def bump_for_all_activities() do + stream = + Pleroma.Web.ActivityPub.ActivityPub.fetch_direct_messages_query() + |> Repo.stream() + + Repo.transaction(fn -> + stream + |> Enum.each(&create_or_bump_for/1) + end) + end end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 8f8c23a9b..23cf4e9c4 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1061,4 +1061,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do contain_activity(activity, user) end) end + + def fetch_direct_messages_query() do + Activity + |> restrict_type(%{"type" => "Create"}) + |> restrict_visibility(%{visibility: "direct"}) + end end -- cgit v1.2.3 From 920bd4705526d8dfa8ada516853bbb4e5438cbf1 Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 8 May 2019 17:40:24 +0200 Subject: ActivityPub: Remove leftover printf debugging. --- lib/pleroma/web/activity_pub/activity_pub.ex | 42 +++++++++++----------------- 1 file changed, 16 insertions(+), 26 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 23cf4e9c4..cd8495035 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -533,22 +533,17 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do defp restrict_visibility(query, %{visibility: visibility}) when is_list(visibility) do if Enum.all?(visibility, &(&1 in @valid_visibilities)) do - query = - from( - a in query, - where: - fragment( - "activity_visibility(?, ?, ?) = ANY (?)", - a.actor, - a.recipients, - a.data, - ^visibility - ) - ) - - Ecto.Adapters.SQL.to_sql(:all, Repo, query) - - query + from( + a in query, + where: + fragment( + "activity_visibility(?, ?, ?) = ANY (?)", + a.actor, + a.recipients, + a.data, + ^visibility + ) + ) else Logger.error("Could not restrict visibility to #{visibility}") end @@ -556,16 +551,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do defp restrict_visibility(query, %{visibility: visibility}) when visibility in @valid_visibilities do - query = - from( - a in query, - where: - fragment("activity_visibility(?, ?, ?) = ?", a.actor, a.recipients, a.data, ^visibility) - ) - - Ecto.Adapters.SQL.to_sql(:all, Repo, query) - - query + from( + a in query, + where: + fragment("activity_visibility(?, ?, ?) = ?", a.actor, a.recipients, a.data, ^visibility) + ) end defp restrict_visibility(_query, %{visibility: visibility}) -- cgit v1.2.3 From a4598b5e8bc640ffc1a052438e21f3573ff837ee Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 8 May 2019 18:08:50 +0200 Subject: Visibility: Make it more resilient. --- lib/pleroma/web/activity_pub/visibility.ex | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/visibility.ex b/lib/pleroma/web/activity_pub/visibility.ex index 6dee61dd6..e7613a5c8 100644 --- a/lib/pleroma/web/activity_pub/visibility.ex +++ b/lib/pleroma/web/activity_pub/visibility.ex @@ -13,11 +13,12 @@ defmodule Pleroma.Web.ActivityPub.Visibility do end def is_private?(activity) do - unless is_public?(activity) do - follower_address = User.get_cached_by_ap_id(activity.data["actor"]).follower_address - Enum.any?(activity.data["to"], &(&1 == follower_address)) + with false <- is_public?(activity), + %User{follower_address: follower_address} <- + User.get_cached_by_ap_id(activity.data["actor"]) do + follower_address in activity.data["to"] else - false + _ -> false end end -- cgit v1.2.3 From 6d19bb4eae43270099a68f749519ba0f323da01a Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 8 May 2019 18:09:07 +0200 Subject: Conversations: Add mix task to 'import' old DMs. --- lib/mix/tasks/pleroma/conversations.ex | 23 +++++++++++++++++++++++ lib/pleroma/conversation.ex | 11 +++++++---- 2 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 lib/mix/tasks/pleroma/conversations.ex (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/conversations.ex b/lib/mix/tasks/pleroma/conversations.ex new file mode 100644 index 000000000..125d8851a --- /dev/null +++ b/lib/mix/tasks/pleroma/conversations.ex @@ -0,0 +1,23 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2018 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Mix.Tasks.Pleroma.Conversations do + use Mix.Task + alias Mix.Tasks.Pleroma.Common + alias Pleroma.Conversation + + @shortdoc "Manages Pleroma users" + @moduledoc """ + Manages Pleroma conversations. + + ## Create a conversation for all existing DMs. Can be safely re-run. + + mix pleroma.conversations bump_all + + """ + def run(["bump_all"]) do + Common.start_pleroma() + Conversation.bump_for_all_activities() + end +end diff --git a/lib/pleroma/conversation.ex b/lib/pleroma/conversation.ex index aa73edd75..10c2403e8 100644 --- a/lib/pleroma/conversation.ex +++ b/lib/pleroma/conversation.ex @@ -81,9 +81,12 @@ defmodule Pleroma.Conversation do Pleroma.Web.ActivityPub.ActivityPub.fetch_direct_messages_query() |> Repo.stream() - Repo.transaction(fn -> - stream - |> Enum.each(&create_or_bump_for/1) - end) + Repo.transaction( + fn -> + stream + |> Enum.each(&create_or_bump_for/1) + end, + timeout: :infinity + ) end end -- cgit v1.2.3 From e6d7f8d223b2604df38f8efa8baf09e2c607c487 Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 8 May 2019 18:19:20 +0200 Subject: Credo fixes. --- lib/pleroma/conversation.ex | 2 +- lib/pleroma/web/activity_pub/activity_pub.ex | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/conversation.ex b/lib/pleroma/conversation.ex index 10c2403e8..0c6ca9f72 100644 --- a/lib/pleroma/conversation.ex +++ b/lib/pleroma/conversation.ex @@ -76,7 +76,7 @@ defmodule Pleroma.Conversation do @doc """ This is only meant to be run by a mix task. It creates conversations/participations for all direct messages in the database. """ - def bump_for_all_activities() do + def bump_for_all_activities do stream = Pleroma.Web.ActivityPub.ActivityPub.fetch_direct_messages_query() |> Repo.stream() diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index cd8495035..8137ac83b 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1052,7 +1052,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end) end - def fetch_direct_messages_query() do + def fetch_direct_messages_query do Activity |> restrict_type(%{"type" => "Create"}) |> restrict_visibility(%{visibility: "direct"}) -- cgit v1.2.3 From a33bec7d58091059d578f6b7537513de11eb0679 Mon Sep 17 00:00:00 2001 From: lain Date: Thu, 9 May 2019 16:39:28 +0200 Subject: Conversations: Import order, import as read. --- lib/pleroma/conversation.ex | 6 +++--- lib/pleroma/conversation/participation.ex | 10 ++++++---- lib/pleroma/web/activity_pub/activity_pub.ex | 1 + 3 files changed, 10 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/conversation.ex b/lib/pleroma/conversation.ex index 0c6ca9f72..5f6ab902c 100644 --- a/lib/pleroma/conversation.ex +++ b/lib/pleroma/conversation.ex @@ -45,7 +45,7 @@ defmodule Pleroma.Conversation do 2. Create a participation for all the people involved who don't have one already 3. Bump all relevant participations to 'unread' """ - def create_or_bump_for(activity) do + def create_or_bump_for(activity, opts \\ []) do with true <- Pleroma.Web.ActivityPub.Visibility.is_direct?(activity), object <- Pleroma.Object.normalize(activity), "Create" <- activity.data["type"], @@ -58,7 +58,7 @@ defmodule Pleroma.Conversation do participations = Enum.map(users, fn user -> {:ok, participation} = - Participation.create_for_user_and_conversation(user, conversation) + Participation.create_for_user_and_conversation(user, conversation, opts) participation end) @@ -84,7 +84,7 @@ defmodule Pleroma.Conversation do Repo.transaction( fn -> stream - |> Enum.each(&create_or_bump_for/1) + |> Enum.each(fn a -> create_or_bump_for(a, read: true) end) end, timeout: :infinity ) diff --git a/lib/pleroma/conversation/participation.ex b/lib/pleroma/conversation/participation.ex index 61021fb18..2a11f9069 100644 --- a/lib/pleroma/conversation/participation.ex +++ b/lib/pleroma/conversation/participation.ex @@ -22,15 +22,17 @@ defmodule Pleroma.Conversation.Participation do def creation_cng(struct, params) do struct - |> cast(params, [:user_id, :conversation_id]) + |> cast(params, [:user_id, :conversation_id, :read]) |> validate_required([:user_id, :conversation_id]) end - def create_for_user_and_conversation(user, conversation) do + def create_for_user_and_conversation(user, conversation, opts \\ []) do + read = !!opts[:read] + %__MODULE__{} - |> creation_cng(%{user_id: user.id, conversation_id: conversation.id}) + |> creation_cng(%{user_id: user.id, conversation_id: conversation.id, read: read}) |> Repo.insert( - on_conflict: [set: [read: false, updated_at: NaiveDateTime.utc_now()]], + on_conflict: [set: [read: read, updated_at: NaiveDateTime.utc_now()]], returning: true, conflict_target: [:user_id, :conversation_id] ) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 8137ac83b..728761ebd 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1056,5 +1056,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do Activity |> restrict_type(%{"type" => "Create"}) |> restrict_visibility(%{visibility: "direct"}) + |> order_by([activity], asc: activity.id) end end -- cgit v1.2.3 From e4523c301023de0d4cff5ca0168094fea25955a2 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 9 May 2019 22:27:00 +0300 Subject: Fix get_in_reply_to in OStatus' activity representer depending on embedded objects --- lib/pleroma/web/ostatus/activity_representer.ex | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/activity_representer.ex b/lib/pleroma/web/ostatus/activity_representer.ex index 166691a09..a7832a3d9 100644 --- a/lib/pleroma/web/ostatus/activity_representer.ex +++ b/lib/pleroma/web/ostatus/activity_representer.ex @@ -18,15 +18,18 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do end end - defp get_in_reply_to(%{"object" => %{"inReplyTo" => in_reply_to}}) do - [ - {:"thr:in-reply-to", - [ref: to_charlist(in_reply_to), href: to_charlist(get_href(in_reply_to))], []} - ] + defp get_in_reply_to(activity) do + with %Object{data: %{"inReplyTo" => in_reply_to}} <- Object.normalize(activity) do + [ + {:"thr:in-reply-to", + [ref: to_charlist(in_reply_to), href: to_charlist(get_href(in_reply_to))], []} + ] + else + _ -> + [] + end end - defp get_in_reply_to(_), do: [] - defp get_mentions(to) do Enum.map(to, fn id -> cond do @@ -98,7 +101,7 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do []} end) - in_reply_to = get_in_reply_to(activity.data) + in_reply_to = get_in_reply_to(activity) author = if with_author, do: [{:author, UserRepresenter.to_simple_form(user)}], else: [] mentions = activity.recipients |> get_mentions -- cgit v1.2.3 From 2a54e8c1f51cb681cefc5ba08ad0f1c7ed1fdc6d Mon Sep 17 00:00:00 2001 From: Francis Dinh Date: Thu, 9 May 2019 19:48:41 -0400 Subject: Use "repeated" instead of "retweeted" for repeated statuses in Twitter API This makes it consistent with the language used in Pleroma FE (at least in English). Resolves https://git.pleroma.social/pleroma/pleroma-fe/issues/533 --- lib/pleroma/web/twitter_api/views/activity_view.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex index c64152da8..d084ad734 100644 --- a/lib/pleroma/web/twitter_api/views/activity_view.ex +++ b/lib/pleroma/web/twitter_api/views/activity_view.ex @@ -170,7 +170,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do created_at = activity.data["published"] |> Utils.date_to_asctime() announced_activity = Activity.get_create_by_object_ap_id(activity.data["object"]) - text = "#{user.nickname} retweeted a status." + text = "#{user.nickname} repeated a status." retweeted_status = render("activity.json", Map.merge(opts, %{activity: announced_activity})) -- cgit v1.2.3 From 1d78e42fd4ca73402c4101ac01b9abb44f4f8cf6 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 10 May 2019 13:49:34 +0300 Subject: Remove get_in_reply_to calls in some functions because the result is unused and it does not have any side-effects --- lib/pleroma/web/ostatus/activity_representer.ex | 2 -- 1 file changed, 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/activity_representer.ex b/lib/pleroma/web/ostatus/activity_representer.ex index a7832a3d9..95037125d 100644 --- a/lib/pleroma/web/ostatus/activity_representer.ex +++ b/lib/pleroma/web/ostatus/activity_representer.ex @@ -149,7 +149,6 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do updated_at = activity.data["published"] inserted_at = activity.data["published"] - _in_reply_to = get_in_reply_to(activity.data) author = if with_author, do: [{:author, UserRepresenter.to_simple_form(user)}], else: [] mentions = activity.recipients |> get_mentions @@ -180,7 +179,6 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do updated_at = activity.data["published"] inserted_at = activity.data["published"] - _in_reply_to = get_in_reply_to(activity.data) author = if with_author, do: [{:author, UserRepresenter.to_simple_form(user)}], else: [] retweeted_activity = Activity.get_create_by_object_ap_id(activity.data["object"]) -- cgit v1.2.3 From c953ae8c3d75beb55ba02b3bada864d019470b05 Mon Sep 17 00:00:00 2001 From: feld Date: Sat, 11 May 2019 01:34:17 +0000 Subject: Initial bundle of basic AdminFE Due to CSP headers we only allow connecting to self. If you want to host AdminFE on a separate domain without CSP headers you will be able to connect to any public Pleroma host. --- lib/pleroma/web/endpoint.ex | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex index 7f939991d..9ef30e885 100644 --- a/lib/pleroma/web/endpoint.ex +++ b/lib/pleroma/web/endpoint.ex @@ -29,6 +29,13 @@ defmodule Pleroma.Web.Endpoint do # credo:disable-for-previous-line Credo.Check.Readability.MaxLineLength ) + plug(Plug.Static.IndexHtml, at: "/pleroma/admin/") + + plug(Plug.Static, + at: "/pleroma/admin/", + from: {:pleroma, "priv/static/adminfe/"} + ) + # Code reloading can be explicitly enabled under the # :code_reloader configuration of your endpoint. if code_reloading? do -- cgit v1.2.3 From f01f995816d86999d5cbf261605887b3a3b313ac Mon Sep 17 00:00:00 2001 From: Sachin Joshi Date: Sat, 11 May 2019 14:17:04 +0545 Subject: make url uniform in admin api --- lib/pleroma/web/router.ex | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 6d9c77c1a..8b84fbbad 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -146,34 +146,52 @@ defmodule Pleroma.Web.Router do scope "/api/pleroma/admin", Pleroma.Web.AdminAPI do pipe_through([:admin_api, :oauth_write]) - post("/user/follow", AdminAPIController, :user_follow) - post("/user/unfollow", AdminAPIController, :user_unfollow) - - get("/users", AdminAPIController, :list_users) - get("/users/:nickname", AdminAPIController, :user_show) + post("/users/follow", AdminAPIController, :user_follow) + post("/users/unfollow", AdminAPIController, :user_unfollow) + # TODO: to be removed at version 1.0 delete("/user", AdminAPIController, :user_delete) - patch("/users/:nickname/toggle_activation", AdminAPIController, :user_toggle_activation) post("/user", AdminAPIController, :user_create) + + delete("/users", AdminAPIController, :user_delete) + post("/users", AdminAPIController, :user_create) + patch("/users/:nickname/toggle_activation", AdminAPIController, :user_toggle_activation) put("/users/tag", AdminAPIController, :tag_users) delete("/users/tag", AdminAPIController, :untag_users) + # TODO: to be removed at version 1.0 get("/permission_group/:nickname", AdminAPIController, :right_get) get("/permission_group/:nickname/:permission_group", AdminAPIController, :right_get) post("/permission_group/:nickname/:permission_group", AdminAPIController, :right_add) delete("/permission_group/:nickname/:permission_group", AdminAPIController, :right_delete) - put("/activation_status/:nickname", AdminAPIController, :set_activation_status) + 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 + ) + + put("/users/:nickname/activation_status", AdminAPIController, :set_activation_status) post("/relay", AdminAPIController, :relay_follow) delete("/relay", AdminAPIController, :relay_unfollow) - get("/invite_token", AdminAPIController, :get_invite_token) - get("/invites", AdminAPIController, :invites) - post("/revoke_invite", AdminAPIController, :revoke_invite) - post("/email_invite", AdminAPIController, :email_invite) + get("/users/invite_token", AdminAPIController, :get_invite_token) + get("/users/invites", AdminAPIController, :invites) + post("/users/revoke_invite", AdminAPIController, :revoke_invite) + post("/users/email_invite", AdminAPIController, :email_invite) + # TODO: to be removed at version 1.0 get("/password_reset", AdminAPIController, :get_password_reset) + + get("/users/:nickname/password_reset", AdminAPIController, :get_password_reset) + + get("/users", AdminAPIController, :list_users) + get("/users/:nickname", AdminAPIController, :user_show) end scope "/", Pleroma.Web.TwitterAPI do -- cgit v1.2.3 From 01c45ddc9ead715131b3c583caa14fcf20845354 Mon Sep 17 00:00:00 2001 From: lain Date: Sat, 11 May 2019 11:26:46 +0200 Subject: Search: Use RUM index. --- lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 956736780..32677df95 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -1019,12 +1019,12 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do where: "https://www.w3.org/ns/activitystreams#Public" in a.recipients, where: fragment( - "to_tsvector('english', ?->>'content') @@ plainto_tsquery('english', ?)", - o.data, + "? @@ plainto_tsquery('english', ?)", + o.fts_content, ^query ), limit: 20, - order_by: [desc: :id] + order_by: [fragment("? <=> now()::date", o.inserted_at)] ) Repo.all(q) ++ fetched -- cgit v1.2.3 From b9f84a382a0e4bbee09e21346f9293962b80917c Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sun, 12 May 2019 03:01:42 +0300 Subject: Normalize the object only after ensuring the activity type is Create --- lib/pleroma/conversation.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/conversation.ex b/lib/pleroma/conversation.ex index 6e26c5fd4..0db195988 100644 --- a/lib/pleroma/conversation.ex +++ b/lib/pleroma/conversation.ex @@ -47,8 +47,8 @@ defmodule Pleroma.Conversation do """ def create_or_bump_for(activity) do with true <- Pleroma.Web.ActivityPub.Visibility.is_direct?(activity), - object <- Pleroma.Object.normalize(activity), "Create" <- activity.data["type"], + object <- Pleroma.Object.normalize(activity), "Note" <- object.data["type"], ap_id when is_binary(ap_id) and byte_size(ap_id) > 0 <- object.data["context"] do {:ok, conversation} = create_for_ap_id(ap_id) -- cgit v1.2.3 From e7d292f80ee03d6eabf30792640a7a40e041a796 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 12 May 2019 02:41:34 +0000 Subject: federator: add publisher module defining a contract for publishing behaviours --- lib/pleroma/web/federator/publisher.ex | 38 ++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 lib/pleroma/web/federator/publisher.ex (limited to 'lib') diff --git a/lib/pleroma/web/federator/publisher.ex b/lib/pleroma/web/federator/publisher.ex new file mode 100644 index 000000000..36277fd7e --- /dev/null +++ b/lib/pleroma/web/federator/publisher.ex @@ -0,0 +1,38 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.Federator.Publisher do + @moduledoc """ + Defines the contract used by federation implementations to publish messages to + their peers. + """ + + @doc """ + Determine whether an activity can be relayed using the federation module. + """ + @callback is_representable?(Pleroma.Activity.t()) :: boolean() + + @doc """ + Relays an activity to a specified peer, determined by the parameters. The + parameters used are controlled by the federation module. + """ + @callback publish_one(Map.t()) :: {:ok, Map.t()} | {:error, any()} + + @doc """ + Relays an activity to all specified peers. + """ + @callback publish(Pleroma.User.t(), Pleroma.Activity.t()) :: :ok | {:error, any()} + + @doc """ + Enqueues work generated by the federation module. + """ + @spec enqueue(module(), keyword()) :: :ok + def enqueue(module, args), do: PleromaJobQueue.enqueue(:federation_outgoing, module, args) + + @doc """ + Enqueue publishing a single activity. + """ + @spec enqueue_one(module(), Map.t()) :: :ok + def enqueue_one(module, %{} = args), do: enqueue(module, [:publish_one, args]) +end -- cgit v1.2.3 From ef1f9e8d4e4bd2bae0483523c7d31a20c086207e Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 12 May 2019 03:09:05 +0000 Subject: activitypub: split out outgoing federation into a federation module --- lib/pleroma/web/activity_pub/activity_pub.ex | 87 ------------------ lib/pleroma/web/activity_pub/publisher.ex | 131 +++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 87 deletions(-) create mode 100644 lib/pleroma/web/activity_pub/publisher.ex (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 8f8c23a9b..11777c220 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -5,7 +5,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do alias Pleroma.Activity alias Pleroma.Conversation - alias Pleroma.Instances alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Object.Fetcher @@ -15,7 +14,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do alias Pleroma.User alias Pleroma.Web.ActivityPub.MRF alias Pleroma.Web.ActivityPub.Transmogrifier - alias Pleroma.Web.Federator alias Pleroma.Web.WebFinger import Ecto.Query @@ -24,8 +22,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do require Logger - @httpoison Application.get_env(:pleroma, :httpoison) - # For Announce activities, we filter the recipients based on following status for any actors # that match actual users. See issue #164 for more information about why this is necessary. defp get_recipients(%{"type" => "Announce"} = data) do @@ -961,89 +957,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end end - def should_federate?(inbox, public) do - if public do - true - else - inbox_info = URI.parse(inbox) - !Enum.member?(Pleroma.Config.get([:instance, :quarantined_instances], []), inbox_info.host) - end - end - - def publish(actor, activity) do - remote_followers = - if actor.follower_address in activity.recipients do - {:ok, followers} = User.get_followers(actor) - followers |> Enum.filter(&(!&1.local)) - else - [] - end - - public = is_public?(activity) - - {:ok, data} = Transmogrifier.prepare_outgoing(activity.data) - json = Jason.encode!(data) - - (Pleroma.Web.Salmon.remote_users(activity) ++ remote_followers) - |> Enum.filter(fn user -> User.ap_enabled?(user) end) - |> Enum.map(fn %{info: %{source_data: data}} -> - (is_map(data["endpoints"]) && Map.get(data["endpoints"], "sharedInbox")) || data["inbox"] - end) - |> Enum.uniq() - |> Enum.filter(fn inbox -> should_federate?(inbox, public) end) - |> Instances.filter_reachable() - |> Enum.each(fn {inbox, unreachable_since} -> - Federator.publish_single_ap(%{ - inbox: inbox, - json: json, - actor: actor, - id: activity.data["id"], - unreachable_since: unreachable_since - }) - end) - end - - def publish_one(%{inbox: inbox, json: json, actor: actor, id: id} = params) do - Logger.info("Federating #{id} to #{inbox}") - host = URI.parse(inbox).host - - digest = "SHA-256=" <> (:crypto.hash(:sha256, json) |> Base.encode64()) - - date = - NaiveDateTime.utc_now() - |> Timex.format!("{WDshort}, {0D} {Mshort} {YYYY} {h24}:{m}:{s} GMT") - - signature = - Pleroma.Web.HTTPSignatures.sign(actor, %{ - host: host, - "content-length": byte_size(json), - digest: digest, - date: date - }) - - with {:ok, %{status: code}} when code in 200..299 <- - result = - @httpoison.post( - inbox, - json, - [ - {"Content-Type", "application/activity+json"}, - {"Date", date}, - {"signature", signature}, - {"digest", digest} - ] - ) do - if !Map.has_key?(params, :unreachable_since) || params[:unreachable_since], - do: Instances.set_reachable(inbox) - - result - else - {_post_result, response} -> - unless params[:unreachable_since], do: Instances.set_unreachable(inbox) - {:error, response} - end - end - # filter out broken threads def contain_broken_threads(%Activity{} = activity, %User{} = user) do entire_thread_visible_for_user?(activity, user) diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex new file mode 100644 index 000000000..ee9f0fdd3 --- /dev/null +++ b/lib/pleroma/web/activity_pub/publisher.ex @@ -0,0 +1,131 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.Publisher do + alias Pleroma.Activity + alias Pleroma.Instances + alias Pleroma.User + alias Pleroma.Web.ActivityPub.Transmogrifier + + import Pleroma.Web.ActivityPub.Visibility + + @behaviour Pleroma.Web.Federator.Publisher + + require Logger + + @httpoison Application.get_env(:pleroma, :httpoison) + + @moduledoc """ + ActivityPub outgoing federation module. + """ + + @doc """ + Determine if an activity can be represented by running it through Transmogrifier. + """ + def is_representable?(%Activity{} = activity) do + with %{} = _data <- Transmogrifier.prepare_outgoing(activity.data) do + true + else + _e -> false + end + end + + @doc """ + Publish a single message to a peer. Takes a struct with the following + parameters set: + + * `inbox`: the inbox to publish to + * `json`: the JSON message body representing the ActivityPub message + * `actor`: the actor which is signing the message + * `id`: the ActivityStreams URI of the message + """ + def publish_one(%{inbox: inbox, json: json, actor: %User{} = actor, id: id} = params) do + Logger.info("Federating #{id} to #{inbox}") + host = URI.parse(inbox).host + + digest = "SHA-256=" <> (:crypto.hash(:sha256, json) |> Base.encode64()) + + date = + NaiveDateTime.utc_now() + |> Timex.format!("{WDshort}, {0D} {Mshort} {YYYY} {h24}:{m}:{s} GMT") + + signature = + Pleroma.Web.HTTPSignatures.sign(actor, %{ + host: host, + "content-length": byte_size(json), + digest: digest, + date: date + }) + + with {:ok, %{status: code}} when code in 200..299 <- + result = + @httpoison.post( + inbox, + json, + [ + {"Content-Type", "application/activity+json"}, + {"Date", date}, + {"signature", signature}, + {"digest", digest} + ] + ) do + if !Map.has_key?(params, :unreachable_since) || params[:unreachable_since], + do: Instances.set_reachable(inbox) + + result + else + {_post_result, response} -> + unless params[:unreachable_since], do: Instances.set_unreachable(inbox) + {:error, response} + end + end + + defp should_federate?(inbox, public) do + if public do + true + else + inbox_info = URI.parse(inbox) + !Enum.member?(Pleroma.Config.get([:instance, :quarantined_instances], []), inbox_info.host) + end + end + + @doc """ + Publishes an activity to all relevant peers. + """ + def publish(%User{} = actor, %Activity{} = activity) do + remote_followers = + if actor.follower_address in activity.recipients do + {:ok, followers} = User.get_followers(actor) + followers |> Enum.filter(&(!&1.local)) + else + [] + end + + public = is_public?(activity) + + {:ok, data} = Transmogrifier.prepare_outgoing(activity.data) + json = Jason.encode!(data) + + (Pleroma.Web.Salmon.remote_users(activity) ++ remote_followers) + |> Enum.filter(fn user -> User.ap_enabled?(user) end) + |> Enum.map(fn %{info: %{source_data: data}} -> + (is_map(data["endpoints"]) && Map.get(data["endpoints"], "sharedInbox")) || data["inbox"] + end) + |> Enum.uniq() + |> Enum.filter(fn inbox -> should_federate?(inbox, public) end) + |> Instances.filter_reachable() + |> Enum.each(fn {inbox, unreachable_since} -> + Pleroma.Web.Federator.Publisher.enqueue_one( + __MODULE__, + %{ + inbox: inbox, + json: json, + actor: actor, + id: activity.data["id"], + unreachable_since: unreachable_since + } + ) + end) + end +end -- cgit v1.2.3 From 0afc8d7856c9fe37de338d1e9365563d986c9319 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 12 May 2019 03:43:53 +0000 Subject: federator: publisher: integrate job queue, simplify publish_one logic --- lib/pleroma/web/federator/publisher.ex | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/federator/publisher.ex b/lib/pleroma/web/federator/publisher.ex index 36277fd7e..2e533ae94 100644 --- a/lib/pleroma/web/federator/publisher.ex +++ b/lib/pleroma/web/federator/publisher.ex @@ -3,6 +3,10 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Federator.Publisher do + alias Pleroma.Web.Federator.RetryQueue + + require Logger + @moduledoc """ Defines the contract used by federation implementations to publish messages to their peers. @@ -24,15 +28,26 @@ defmodule Pleroma.Web.Federator.Publisher do """ @callback publish(Pleroma.User.t(), Pleroma.Activity.t()) :: :ok | {:error, any()} - @doc """ - Enqueues work generated by the federation module. - """ - @spec enqueue(module(), keyword()) :: :ok - def enqueue(module, args), do: PleromaJobQueue.enqueue(:federation_outgoing, module, args) - @doc """ Enqueue publishing a single activity. """ @spec enqueue_one(module(), Map.t()) :: :ok - def enqueue_one(module, %{} = args), do: enqueue(module, [:publish_one, args]) + def enqueue_one(module, %{} = params), + do: PleromaJobQueue.enqueue(:federation_outgoing, __MODULE__, [:publish_one, module, params]) + + @spec perform(atom(), module(), any()) :: {:ok, any()} | {:error, any()} + def perform(:publish_one, module, params) do + case apply(module, :publish_one, [params]) do + {:ok, _} -> + :ok + + {:error, _} -> + RetryQueue.enqueue(params, module) + end + end + + def perform(type, _, _) do + Logger.debug("Unknown task: #{type}") + {:error, "Don't know what to do with this"} + end end -- cgit v1.2.3 From 10695a28d28d74f4b6b9bba20af66b506b662c07 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 12 May 2019 03:55:17 +0000 Subject: federator: publisher: add publish() wrapper --- lib/pleroma/web/federator/publisher.ex | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/federator/publisher.ex b/lib/pleroma/web/federator/publisher.ex index 2e533ae94..8777a3deb 100644 --- a/lib/pleroma/web/federator/publisher.ex +++ b/lib/pleroma/web/federator/publisher.ex @@ -3,6 +3,9 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Federator.Publisher do + alias Pleroma.Activity + alias Pleroma.Config + alias Pleroma.User alias Pleroma.Web.Federator.RetryQueue require Logger @@ -23,11 +26,6 @@ defmodule Pleroma.Web.Federator.Publisher do """ @callback publish_one(Map.t()) :: {:ok, Map.t()} | {:error, any()} - @doc """ - Relays an activity to all specified peers. - """ - @callback publish(Pleroma.User.t(), Pleroma.Activity.t()) :: :ok | {:error, any()} - @doc """ Enqueue publishing a single activity. """ @@ -50,4 +48,20 @@ defmodule Pleroma.Web.Federator.Publisher do Logger.debug("Unknown task: #{type}") {:error, "Don't know what to do with this"} end + + @doc """ + Relays an activity to all specified peers. + """ + @callback publish(Pleroma.User.t(), Pleroma.Activity.t()) :: :ok | {:error, any()} + + @spec publish(Pleroma.User.t(), Pleroma.Activity.t()) :: :ok + def publish(%User{} = user, %Activity{} = activity) do + Config.get([:instance, :federation_publisher_modules]) + |> Enum.each(fn module -> + Logger.info("Publishing #{activity.data["id"]} using #{inspect(module)}") + module.publish(user, activity) + end) + + :ok + end end -- cgit v1.2.3 From f7a6a37c4eb98e354fbcd98ea19c9207d891e993 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 12 May 2019 03:56:49 +0000 Subject: federator: remove no longer used :publish_single_ap --- lib/pleroma/web/federator/federator.ex | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex index 29e178ba9..d8534b365 100644 --- a/lib/pleroma/web/federator/federator.ex +++ b/lib/pleroma/web/federator/federator.ex @@ -42,10 +42,6 @@ defmodule Pleroma.Web.Federator do PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:publish, activity], priority) end - def publish_single_ap(params) do - PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:publish_single_ap, params]) - end - def publish_single_websub(websub) do PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:publish_single_websub, websub]) end @@ -157,16 +153,6 @@ defmodule Pleroma.Web.Federator do Salmon.send_to_user(params) end - def perform(:publish_single_ap, params) do - case ActivityPub.publish_one(params) do - {:ok, _} -> - :ok - - {:error, _} -> - RetryQueue.enqueue(params, ActivityPub) - end - end - def perform( :publish_single_websub, %{xml: _xml, topic: _topic, callback: _callback, secret: _secret} = params -- cgit v1.2.3 From 676752bb8367ec6b5831c7dbd2aad993b1fe45aa Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 12 May 2019 03:57:10 +0000 Subject: federator: hook up Publisher.publish() --- lib/pleroma/web/federator/federator.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex index d8534b365..ef2708c07 100644 --- a/lib/pleroma/web/federator/federator.ex +++ b/lib/pleroma/web/federator/federator.ex @@ -11,6 +11,7 @@ defmodule Pleroma.Web.Federator do alias Pleroma.Web.ActivityPub.Transmogrifier alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Visibility + alias Pleroma.Web.Federator.Publisher alias Pleroma.Web.Federator.RetryQueue alias Pleroma.Web.OStatus alias Pleroma.Web.Salmon @@ -106,8 +107,7 @@ defmodule Pleroma.Web.Federator do end end - Logger.info(fn -> "Sending #{activity.data["id"]} out via AP" end) - Pleroma.Web.ActivityPub.ActivityPub.publish(actor, activity) + Publisher.publish(actor, activity) end end -- cgit v1.2.3 From 85377c0b67cf82fdf7e49608b94aec80ace74c4d Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 12 May 2019 04:00:55 +0000 Subject: federator: move activitypub relaying to the AP publisher module --- lib/pleroma/web/activity_pub/publisher.ex | 7 +++++++ lib/pleroma/web/federator/federator.ex | 6 ------ 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex index ee9f0fdd3..11e54b77d 100644 --- a/lib/pleroma/web/activity_pub/publisher.ex +++ b/lib/pleroma/web/activity_pub/publisher.ex @@ -4,8 +4,10 @@ defmodule Pleroma.Web.ActivityPub.Publisher do alias Pleroma.Activity + alias Pleroma.Config alias Pleroma.Instances alias Pleroma.User + alias Pleroma.Web.ActivityPub.Relay alias Pleroma.Web.ActivityPub.Transmogrifier import Pleroma.Web.ActivityPub.Visibility @@ -104,6 +106,11 @@ defmodule Pleroma.Web.ActivityPub.Publisher do public = is_public?(activity) + if public && Config.get([:instance, :allow_relay]) do + Logger.info(fn -> "Relaying #{activity.data["id"]} out" end) + Relay.publish(activity) + end + {:ok, data} = Transmogrifier.prepare_outgoing(activity.data) json = Jason.encode!(data) diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex index ef2708c07..252d3b009 100644 --- a/lib/pleroma/web/federator/federator.ex +++ b/lib/pleroma/web/federator/federator.ex @@ -7,7 +7,6 @@ defmodule Pleroma.Web.Federator do alias Pleroma.Object.Containment alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.ActivityPub.Relay alias Pleroma.Web.ActivityPub.Transmogrifier alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Visibility @@ -100,11 +99,6 @@ defmodule Pleroma.Web.Federator do Logger.info(fn -> "Sending #{activity.data["id"]} out via Salmon" end) Pleroma.Web.Salmon.publish(actor, activity) end - - if Keyword.get(Application.get_env(:pleroma, :instance), :allow_relay) do - Logger.info(fn -> "Relaying #{activity.data["id"]} out" end) - Relay.publish(activity) - end end Publisher.publish(actor, activity) -- cgit v1.2.3 From 69158f10652e735e3300335dba3856a0233da89f Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 12 May 2019 04:04:50 +0000 Subject: ostatus: only as:Public activities are representable --- lib/pleroma/web/ostatus/ostatus.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index 4744c6d83..61515b31e 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -16,6 +16,7 @@ defmodule Pleroma.Web.OStatus do alias Pleroma.Web alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Transmogrifier + alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.OStatus.DeleteHandler alias Pleroma.Web.OStatus.FollowHandler alias Pleroma.Web.OStatus.NoteHandler @@ -30,7 +31,7 @@ defmodule Pleroma.Web.OStatus do is_nil(object) -> false - object.data["type"] == "Note" -> + Visibility.is_public?(activity) && object.data["type"] == "Note" -> true true -> -- cgit v1.2.3 From 2aee62a4565d36983484ead9dda187e9e8188971 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 12 May 2019 04:17:17 +0000 Subject: federator: publisher: only attempt publishing if we know the activity is representable --- lib/pleroma/web/federator/publisher.ex | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/federator/publisher.ex b/lib/pleroma/web/federator/publisher.ex index 8777a3deb..67f4b7ba7 100644 --- a/lib/pleroma/web/federator/publisher.ex +++ b/lib/pleroma/web/federator/publisher.ex @@ -39,7 +39,7 @@ defmodule Pleroma.Web.Federator.Publisher do {:ok, _} -> :ok - {:error, _} -> + {:error, _e} -> RetryQueue.enqueue(params, module) end end @@ -58,8 +58,10 @@ defmodule Pleroma.Web.Federator.Publisher do def publish(%User{} = user, %Activity{} = activity) do Config.get([:instance, :federation_publisher_modules]) |> Enum.each(fn module -> - Logger.info("Publishing #{activity.data["id"]} using #{inspect(module)}") - module.publish(user, activity) + if module.is_representable?(activity) do + Logger.info("Publishing #{activity.data["id"]} using #{inspect(module)}") + module.publish(user, activity) + end end) :ok -- cgit v1.2.3 From 179293e51c2e381fdc15c0a291b735750f9cd656 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 12 May 2019 04:27:01 +0000 Subject: salmon: refactor to work as a federator publishing module --- lib/pleroma/web/federator/federator.ex | 12 ------------ lib/pleroma/web/salmon/salmon.ex | 34 ++++++++++++++++++++++------------ 2 files changed, 22 insertions(+), 24 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex index 252d3b009..c9b245933 100644 --- a/lib/pleroma/web/federator/federator.ex +++ b/lib/pleroma/web/federator/federator.ex @@ -13,7 +13,6 @@ defmodule Pleroma.Web.Federator do alias Pleroma.Web.Federator.Publisher alias Pleroma.Web.Federator.RetryQueue alias Pleroma.Web.OStatus - alias Pleroma.Web.Salmon alias Pleroma.Web.WebFinger alias Pleroma.Web.Websub @@ -58,10 +57,6 @@ defmodule Pleroma.Web.Federator do PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:refresh_subscriptions]) end - def publish_single_salmon(params) do - PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:publish_single_salmon, params]) - end - # Job Worker Callbacks def perform(:refresh_subscriptions) do @@ -95,9 +90,6 @@ defmodule Pleroma.Web.Federator do if OStatus.is_representable?(activity) do Logger.info(fn -> "Sending #{activity.data["id"]} out via WebSub" end) Websub.publish(Pleroma.Web.OStatus.feed_path(actor), actor, activity) - - Logger.info(fn -> "Sending #{activity.data["id"]} out via Salmon" end) - Pleroma.Web.Salmon.publish(actor, activity) end end @@ -143,10 +135,6 @@ defmodule Pleroma.Web.Federator do end end - def perform(:publish_single_salmon, params) do - Salmon.send_to_user(params) - end - def perform( :publish_single_websub, %{xml: _xml, topic: _topic, callback: _callback, secret: _secret} = params diff --git a/lib/pleroma/web/salmon/salmon.ex b/lib/pleroma/web/salmon/salmon.ex index 0a9e51656..7b59609c0 100644 --- a/lib/pleroma/web/salmon/salmon.ex +++ b/lib/pleroma/web/salmon/salmon.ex @@ -3,12 +3,17 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.Salmon do + @behaviour Pleroma.Web.Federator.Publisher + @httpoison Application.get_env(:pleroma, :httpoison) use Bitwise + alias Pleroma.Activity alias Pleroma.Instances alias Pleroma.User + alias Pleroma.Web.ActivityPub.Visibility + alias Pleroma.Web.Federator.Publisher alias Pleroma.Web.OStatus.ActivityRepresenter alias Pleroma.Web.XML @@ -165,12 +170,12 @@ defmodule Pleroma.Web.Salmon do end @doc "Pushes an activity to remote account." - def send_to_user(%{recipient: %{info: %{salmon: salmon}}} = params), - do: send_to_user(Map.put(params, :recipient, salmon)) + def publish_one(%{recipient: %{info: %{salmon: salmon}}} = params), + do: publish_one(Map.put(params, :recipient, salmon)) - def send_to_user(%{recipient: url, feed: feed, poster: poster} = params) when is_binary(url) do + def publish_one(%{recipient: url, feed: feed} = params) when is_binary(url) do with {:ok, %{status: code}} when code in 200..299 <- - poster.( + @httpoison.post( url, feed, [{"Content-Type", "application/magic-envelope+xml"}] @@ -184,11 +189,11 @@ defmodule Pleroma.Web.Salmon do e -> unless params[:unreachable_since], do: Instances.set_reachable(url) Logger.debug(fn -> "Pushing Salmon to #{url} failed, #{inspect(e)}" end) - :error + {:error, "Unreachable instance"} end end - def send_to_user(_), do: :noop + def publish_one(_), do: :noop @supported_activities [ "Create", @@ -199,13 +204,19 @@ defmodule Pleroma.Web.Salmon do "Delete" ] + def is_representable?(%Activity{data: %{"type" => type}} = activity) + when type in @supported_activities, + do: Visibility.is_public?(activity) + + def is_representable?(_), do: false + @doc """ Publishes an activity to remote accounts """ - @spec publish(User.t(), Pleroma.Activity.t(), Pleroma.HTTP.t()) :: none - def publish(user, activity, poster \\ &@httpoison.post/3) + @spec publish(User.t(), Pleroma.Activity.t()) :: none + def publish(user, activity) - def publish(%{info: %{keys: keys}} = user, %{data: %{"type" => type}} = activity, poster) + def publish(%{info: %{keys: keys}} = user, %{data: %{"type" => type}} = activity) when type in @supported_activities do feed = ActivityRepresenter.to_simple_form(activity, user, true) @@ -229,15 +240,14 @@ defmodule Pleroma.Web.Salmon do |> Enum.each(fn remote_user -> Logger.debug(fn -> "Sending Salmon to #{remote_user.ap_id}" end) - Pleroma.Web.Federator.publish_single_salmon(%{ + Publisher.enqueue_one(__MODULE__, %{ recipient: remote_user, feed: feed, - poster: poster, unreachable_since: reachable_urls_metadata[remote_user.info.salmon] }) end) end end - def publish(%{id: id}, _, _), do: Logger.debug(fn -> "Keys missing for user #{id}" end) + def publish(%{id: id}, _), do: Logger.debug(fn -> "Keys missing for user #{id}" end) end -- cgit v1.2.3 From fedaca15a3932897d86f73d836b6b6c2f7860f59 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 12 May 2019 04:34:55 +0000 Subject: websub: adapt to work as a federator publishing module --- lib/pleroma/web/federator/federator.ex | 4 ---- lib/pleroma/web/websub/websub.ex | 16 +++++++++++++++- 2 files changed, 15 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex index c9b245933..9a377da68 100644 --- a/lib/pleroma/web/federator/federator.ex +++ b/lib/pleroma/web/federator/federator.ex @@ -41,10 +41,6 @@ defmodule Pleroma.Web.Federator do PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:publish, activity], priority) end - def publish_single_websub(websub) do - PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:publish_single_websub, websub]) - end - def verify_websub(websub) do PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:verify_websub, websub]) end diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex index 3ffa6b416..1fb993282 100644 --- a/lib/pleroma/web/websub/websub.ex +++ b/lib/pleroma/web/websub/websub.ex @@ -4,10 +4,13 @@ defmodule Pleroma.Web.Websub do alias Ecto.Changeset + alias Pleroma.Activity alias Pleroma.Instances alias Pleroma.Repo + alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.Endpoint alias Pleroma.Web.Federator + alias Pleroma.Web.Federator.Publisher alias Pleroma.Web.OStatus alias Pleroma.Web.OStatus.FeedRepresenter alias Pleroma.Web.Router.Helpers @@ -18,6 +21,8 @@ defmodule Pleroma.Web.Websub do import Ecto.Query + @behaviour Pleroma.Web.Federator.Publisher + @httpoison Application.get_env(:pleroma, :httpoison) def verify(subscription, getter \\ &@httpoison.get/3) do @@ -56,6 +61,13 @@ defmodule Pleroma.Web.Websub do "Undo", "Delete" ] + + def is_representable?(%Activity{data: %{"type" => type}} = activity) + when type in @supported_activities, + do: Visibility.is_public?(activity) + + def is_representable?(_), do: false + def publish(topic, user, %{data: %{"type" => type}} = activity) when type in @supported_activities do response = @@ -88,12 +100,14 @@ defmodule Pleroma.Web.Websub do unreachable_since: reachable_callbacks_metadata[sub.callback] } - Federator.publish_single_websub(data) + Publisher.enqueue_one(__MODULE__, data) end) end def publish(_, _, _), do: "" + def publish(actor, activity), do: publish(Pleroma.Web.OStatus.feed_path(actor), actor, activity) + def sign(secret, doc) do :crypto.hmac(:sha, secret, to_string(doc)) |> Base.encode16() |> String.downcase() end -- cgit v1.2.3 From c23276a59aa57a89e27c2e2f46d701392917b9a0 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 12 May 2019 05:01:00 +0000 Subject: activitypub: publisher: fixups --- lib/pleroma/web/activity_pub/publisher.ex | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex index 11e54b77d..5d72299a5 100644 --- a/lib/pleroma/web/activity_pub/publisher.ex +++ b/lib/pleroma/web/activity_pub/publisher.ex @@ -26,10 +26,11 @@ defmodule Pleroma.Web.ActivityPub.Publisher do Determine if an activity can be represented by running it through Transmogrifier. """ def is_representable?(%Activity{} = activity) do - with %{} = _data <- Transmogrifier.prepare_outgoing(activity.data) do + with {:ok, _data} <- Transmogrifier.prepare_outgoing(activity.data) do true else - _e -> false + _e -> + false end end -- cgit v1.2.3 From 55fa4b812a30feddc0c60d7ade03d50193871d22 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 12 May 2019 05:01:15 +0000 Subject: federator: websub removal --- lib/pleroma/web/federator/federator.ex | 9 --------- 1 file changed, 9 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex index 9a377da68..8621eda95 100644 --- a/lib/pleroma/web/federator/federator.ex +++ b/lib/pleroma/web/federator/federator.ex @@ -9,10 +9,8 @@ defmodule Pleroma.Web.Federator do alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Transmogrifier alias Pleroma.Web.ActivityPub.Utils - alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.Federator.Publisher alias Pleroma.Web.Federator.RetryQueue - alias Pleroma.Web.OStatus alias Pleroma.Web.WebFinger alias Pleroma.Web.Websub @@ -82,13 +80,6 @@ defmodule Pleroma.Web.Federator do with actor when not is_nil(actor) <- User.get_cached_by_ap_id(activity.data["actor"]) do {:ok, actor} = WebFinger.ensure_keys_present(actor) - if Visibility.is_public?(activity) do - if OStatus.is_representable?(activity) do - Logger.info(fn -> "Sending #{activity.data["id"]} out via WebSub" end) - Websub.publish(Pleroma.Web.OStatus.feed_path(actor), actor, activity) - end - end - Publisher.publish(actor, activity) end end -- cgit v1.2.3 From 80759f012eb2183bc24f84c4a1f2a5dbe94762ce Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 12 May 2019 19:04:37 +0000 Subject: xml builder: properly escape quotes --- lib/xml_builder.ex | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/xml_builder.ex b/lib/xml_builder.ex index 88f8ce2a3..b58602c7b 100644 --- a/lib/xml_builder.ex +++ b/lib/xml_builder.ex @@ -35,6 +35,7 @@ defmodule Pleroma.XmlBuilder do defp make_open_tag(tag, attributes) do attributes_string = for {attribute, value} <- attributes do + value = String.replace(value, "\"", """) "#{attribute}=\"#{value}\"" end |> Enum.join(" ") -- cgit v1.2.3 From 28f7f4c6dec681ae292767623cbad553b2a0f5b5 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 12 May 2019 19:05:03 +0000 Subject: webfinger: build the response based on enabled federation modules --- lib/pleroma/web/activity_pub/publisher.ex | 11 ++++++ lib/pleroma/web/federator/publisher.ex | 13 ++++++ lib/pleroma/web/salmon/salmon.ex | 14 +++++++ lib/pleroma/web/web_finger/web_finger.ex | 66 +++++++++---------------------- lib/pleroma/web/websub/websub.ex | 15 +++++++ 5 files changed, 71 insertions(+), 48 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex index 5d72299a5..5c97485c8 100644 --- a/lib/pleroma/web/activity_pub/publisher.ex +++ b/lib/pleroma/web/activity_pub/publisher.ex @@ -136,4 +136,15 @@ defmodule Pleroma.Web.ActivityPub.Publisher do ) end) end + + def gather_webfinger_links(%User{} = user) 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 + } + ] + end end diff --git a/lib/pleroma/web/federator/publisher.ex b/lib/pleroma/web/federator/publisher.ex index 67f4b7ba7..112a0574f 100644 --- a/lib/pleroma/web/federator/publisher.ex +++ b/lib/pleroma/web/federator/publisher.ex @@ -66,4 +66,17 @@ defmodule Pleroma.Web.Federator.Publisher do :ok end + + @doc """ + Gathers links used by an outgoing federation module for WebFinger output. + """ + @callback gather_webfinger_links(Pleroma.User.t()) :: list() + + @spec gather_webfinger_links(Pleroma.User.t()) :: list() + def gather_webfinger_links(%User{} = user) do + Config.get([:instance, :federation_publisher_modules]) + |> Enum.reduce([], fn module, links -> + links ++ module.gather_webfinger_links(user) + end) + end end diff --git a/lib/pleroma/web/salmon/salmon.ex b/lib/pleroma/web/salmon/salmon.ex index 7b59609c0..92e85b5e9 100644 --- a/lib/pleroma/web/salmon/salmon.ex +++ b/lib/pleroma/web/salmon/salmon.ex @@ -14,6 +14,7 @@ defmodule Pleroma.Web.Salmon do alias Pleroma.User alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.Federator.Publisher + alias Pleroma.Web.OStatus alias Pleroma.Web.OStatus.ActivityRepresenter alias Pleroma.Web.XML @@ -250,4 +251,17 @@ defmodule Pleroma.Web.Salmon do end def publish(%{id: id}, _), do: Logger.debug(fn -> "Keys missing for user #{id}" end) + + def gather_webfinger_links(%User{} = user) do + {:ok, _private, public} = keys_from_pem(user.info.keys) + magic_key = encode_key(public) + + [ + %{"rel" => "salmon", "href" => OStatus.salmon_path(user)}, + %{ + "rel" => "magic-public-key", + "href" => "data:application/magic-public-key,#{magic_key}" + } + ] + end end diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex index a3b0bf999..3a3b98a10 100644 --- a/lib/pleroma/web/web_finger/web_finger.ex +++ b/lib/pleroma/web/web_finger/web_finger.ex @@ -7,7 +7,7 @@ defmodule Pleroma.Web.WebFinger do alias Pleroma.User alias Pleroma.Web - alias Pleroma.Web.OStatus + alias Pleroma.Web.Federator.Publisher alias Pleroma.Web.Salmon alias Pleroma.Web.XML alias Pleroma.XmlBuilder @@ -50,70 +50,40 @@ defmodule Pleroma.Web.WebFinger do end end + defp gather_links(%User{} = user) do + [ + %{ + "rel" => "http://webfinger.net/rel/profile-page", + "type" => "text/html", + "href" => user.ap_id + } + ] ++ Publisher.gather_webfinger_links(user) + end + def represent_user(user, "JSON") do {:ok, user} = ensure_keys_present(user) - {:ok, _private, public} = Salmon.keys_from_pem(user.info.keys) - magic_key = Salmon.encode_key(public) %{ "subject" => "acct:#{user.nickname}@#{Pleroma.Web.Endpoint.host()}", "aliases" => [user.ap_id], - "links" => [ - %{ - "rel" => "http://schemas.google.com/g/2010#updates-from", - "type" => "application/atom+xml", - "href" => OStatus.feed_path(user) - }, - %{ - "rel" => "http://webfinger.net/rel/profile-page", - "type" => "text/html", - "href" => user.ap_id - }, - %{"rel" => "salmon", "href" => OStatus.salmon_path(user)}, - %{ - "rel" => "magic-public-key", - "href" => "data:application/magic-public-key,#{magic_key}" - }, - %{"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() - } - ] + "links" => gather_links(user) } end def represent_user(user, "XML") do {:ok, user} = ensure_keys_present(user) - {:ok, _private, public} = Salmon.keys_from_pem(user.info.keys) - magic_key = Salmon.encode_key(public) + + links = + gather_links(user) + |> Enum.map(fn link -> {:Link, link} end) { :XRD, %{xmlns: "http://docs.oasis-open.org/ns/xri/xrd-1.0"}, [ {:Subject, "acct:#{user.nickname}@#{Pleroma.Web.Endpoint.host()}"}, - {:Alias, user.ap_id}, - {:Link, - %{ - rel: "http://schemas.google.com/g/2010#updates-from", - type: "application/atom+xml", - href: OStatus.feed_path(user) - }}, - {:Link, - %{rel: "http://webfinger.net/rel/profile-page", type: "text/html", href: user.ap_id}}, - {:Link, %{rel: "salmon", href: OStatus.salmon_path(user)}}, - {:Link, - %{rel: "magic-public-key", href: "data:application/magic-public-key,#{magic_key}"}}, - {:Link, %{rel: "self", type: "application/activity+json", href: user.ap_id}}, - {:Link, - %{rel: "http://ostatus.org/schema/1.0/subscribe", template: OStatus.remote_follow_path()}} - ] + {:Alias, user.ap_id} + ] ++ links } |> XmlBuilder.to_doc() end diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex index 1fb993282..2ce6dcc19 100644 --- a/lib/pleroma/web/websub/websub.ex +++ b/lib/pleroma/web/websub/websub.ex @@ -7,6 +7,7 @@ defmodule Pleroma.Web.Websub do alias Pleroma.Activity alias Pleroma.Instances alias Pleroma.Repo + alias Pleroma.User alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.Endpoint alias Pleroma.Web.Federator @@ -313,4 +314,18 @@ defmodule Pleroma.Web.Websub do {:error, response} end end + + def gather_webfinger_links(%User{} = user) do + [ + %{ + "rel" => "http://schemas.google.com/g/2010#updates-from", + "type" => "application/atom+xml", + "href" => OStatus.feed_path(user) + }, + %{ + "rel" => "http://ostatus.org/schema/1.0/subscribe", + "template" => OStatus.remote_follow_path() + } + ] + end end -- cgit v1.2.3 From 44b182732efe2d8571aa54e6062637e7e42021ce Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 12 May 2019 19:15:29 +0000 Subject: nodeinfo: gather supported protocol names from federation modules --- lib/pleroma/web/activity_pub/publisher.ex | 2 ++ lib/pleroma/web/federator/publisher.ex | 13 +++++++++++++ lib/pleroma/web/nodeinfo/nodeinfo_controller.ex | 3 ++- lib/pleroma/web/salmon/salmon.ex | 2 ++ lib/pleroma/web/websub/websub.ex | 2 ++ 5 files changed, 21 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex index 5c97485c8..8e3af0a81 100644 --- a/lib/pleroma/web/activity_pub/publisher.ex +++ b/lib/pleroma/web/activity_pub/publisher.ex @@ -147,4 +147,6 @@ defmodule Pleroma.Web.ActivityPub.Publisher do } ] end + + def gather_nodeinfo_protocol_names, do: ["activitypub"] end diff --git a/lib/pleroma/web/federator/publisher.ex b/lib/pleroma/web/federator/publisher.ex index 112a0574f..916bcdcba 100644 --- a/lib/pleroma/web/federator/publisher.ex +++ b/lib/pleroma/web/federator/publisher.ex @@ -79,4 +79,17 @@ defmodule Pleroma.Web.Federator.Publisher do links ++ module.gather_webfinger_links(user) end) end + + @doc """ + Gathers nodeinfo protocol names supported by the federation module. + """ + @callback gather_nodeinfo_protocol_names() :: list() + + @spec gather_nodeinfo_protocol_names() :: list() + def gather_nodeinfo_protocol_names do + Config.get([:instance, :federation_publisher_modules]) + |> Enum.reduce([], fn module, links -> + links ++ module.gather_nodeinfo_protocol_names() + end) + end end diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex index 216a962bd..3bf2a0fbc 100644 --- a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex +++ b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex @@ -10,6 +10,7 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do alias Pleroma.User alias Pleroma.Web alias Pleroma.Web.ActivityPub.MRF + alias Pleroma.Web.Federator.Publisher plug(Pleroma.Web.FederatingPlug) @@ -137,7 +138,7 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do name: Pleroma.Application.name() |> String.downcase(), version: Pleroma.Application.version() }, - protocols: ["ostatus", "activitypub"], + protocols: Publisher.gather_nodeinfo_protocol_names(), services: %{ inbound: [], outbound: [] diff --git a/lib/pleroma/web/salmon/salmon.ex b/lib/pleroma/web/salmon/salmon.ex index 92e85b5e9..42709ab47 100644 --- a/lib/pleroma/web/salmon/salmon.ex +++ b/lib/pleroma/web/salmon/salmon.ex @@ -264,4 +264,6 @@ defmodule Pleroma.Web.Salmon do } ] end + + def gather_nodeinfo_protocol_names, do: [] end diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex index 2ce6dcc19..7ad0414ab 100644 --- a/lib/pleroma/web/websub/websub.ex +++ b/lib/pleroma/web/websub/websub.ex @@ -328,4 +328,6 @@ defmodule Pleroma.Web.Websub do } ] end + + def gather_nodeinfo_protocol_names, do: ["ostatus"] end -- cgit v1.2.3 From 786f2c7a849bc4fa2bd4aac18de59ef6b2ed18c5 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Mon, 13 May 2019 11:16:54 -0500 Subject: Update shortdoc description --- lib/mix/tasks/pleroma/conversations.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/conversations.ex b/lib/mix/tasks/pleroma/conversations.ex index 125d8851a..b52b9921a 100644 --- a/lib/mix/tasks/pleroma/conversations.ex +++ b/lib/mix/tasks/pleroma/conversations.ex @@ -7,7 +7,7 @@ defmodule Mix.Tasks.Pleroma.Conversations do alias Mix.Tasks.Pleroma.Common alias Pleroma.Conversation - @shortdoc "Manages Pleroma users" + @shortdoc "Manages Pleroma conversations." @moduledoc """ Manages Pleroma conversations. -- cgit v1.2.3 From 7701a4c84191a445e0b62e8a241e8af86f86e16a Mon Sep 17 00:00:00 2001 From: Sachin Joshi Date: Mon, 13 May 2019 23:50:33 +0545 Subject: Make irreversible field default to false in filters --- lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 956736780..fd595031d 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -1536,7 +1536,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do user_id: user.id, phrase: phrase, context: context, - hide: Map.get(params, "irreversible", nil), + hide: Map.get(params, "irreversible", false), whole_word: Map.get(params, "boolean", true) # expires_at } -- cgit v1.2.3 From a2be420f940fb8f181feeb9b0fb9759d433dcae1 Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Mon, 13 May 2019 18:35:45 +0000 Subject: differences_in_mastoapi_responses.md: fullname & bio are optionnal [ci skip] --- lib/mix/tasks/pleroma/user.ex | 2 +- lib/pleroma/plugs/oauth_plug.ex | 48 +++++++++++++++--- lib/pleroma/plugs/rate_limit_plug.ex | 36 ++++++++++++++ lib/pleroma/user.ex | 11 +++-- lib/pleroma/user/info.ex | 30 +++++++----- lib/pleroma/web/admin_api/admin_api_controller.ex | 2 +- lib/pleroma/web/auth/pleroma_authenticator.ex | 2 +- .../web/mastodon_api/mastodon_api_controller.ex | 57 ++++++++++++++++++++++ lib/pleroma/web/oauth/app.ex | 1 + lib/pleroma/web/oauth/authorization.ex | 39 +++++++++++---- lib/pleroma/web/oauth/oauth_controller.ex | 22 +++++++++ lib/pleroma/web/oauth/token.ex | 11 +++-- lib/pleroma/web/router.ex | 2 + lib/pleroma/web/twitter_api/twitter_api.ex | 29 ++++++----- .../web/twitter_api/twitter_api_controller.ex | 2 +- 15 files changed, 239 insertions(+), 55 deletions(-) create mode 100644 lib/pleroma/plugs/rate_limit_plug.ex (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 6a83a8c0d..d130ff8c9 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -138,7 +138,7 @@ defmodule Mix.Tasks.Pleroma.User do bio: bio } - changeset = User.register_changeset(%User{}, params, confirmed: true) + changeset = User.register_changeset(%User{}, params, need_confirmation: false) {:ok, _user} = User.register(changeset) Mix.shell().info("User #{nickname} created") diff --git a/lib/pleroma/plugs/oauth_plug.ex b/lib/pleroma/plugs/oauth_plug.ex index 9d43732eb..86bc4aa3a 100644 --- a/lib/pleroma/plugs/oauth_plug.ex +++ b/lib/pleroma/plugs/oauth_plug.ex @@ -8,6 +8,7 @@ defmodule Pleroma.Plugs.OAuthPlug do alias Pleroma.Repo alias Pleroma.User + alias Pleroma.Web.OAuth.App alias Pleroma.Web.OAuth.Token @realm_reg Regex.compile!("Bearer\:?\s+(.*)$", "i") @@ -22,18 +23,39 @@ defmodule Pleroma.Plugs.OAuthPlug do |> assign(:token, token_record) |> assign(:user, user) else - _ -> conn + _ -> + # token found, but maybe only with app + with {:ok, app, token_record} <- fetch_app_and_token(access_token) do + conn + |> assign(:token, token_record) + |> assign(:app, app) + else + _ -> conn + end end end def call(conn, _) do - with {:ok, token_str} <- fetch_token_str(conn), - {:ok, user, token_record} <- fetch_user_and_token(token_str) do - conn - |> assign(:token, token_record) - |> assign(:user, user) - else - _ -> conn + case fetch_token_str(conn) do + {:ok, token} -> + with {:ok, user, token_record} <- fetch_user_and_token(token) do + conn + |> assign(:token, token_record) + |> assign(:user, user) + else + _ -> + # token found, but maybe only with app + with {:ok, app, token_record} <- fetch_app_and_token(token) do + conn + |> assign(:token, token_record) + |> assign(:app, app) + else + _ -> conn + end + end + + _ -> + conn end end @@ -54,6 +76,16 @@ defmodule Pleroma.Plugs.OAuthPlug do end end + @spec fetch_app_and_token(String.t()) :: {:ok, App.t(), Token.t()} | nil + defp fetch_app_and_token(token) do + query = + from(t in Token, where: t.token == ^token, join: app in assoc(t, :app), preload: [app: app]) + + with %Token{app: app} = token_record <- Repo.one(query) do + {:ok, app, token_record} + end + end + # Gets token from session by :oauth_token key # @spec fetch_token_from_session(Plug.Conn.t()) :: :no_token_found | {:ok, String.t()} diff --git a/lib/pleroma/plugs/rate_limit_plug.ex b/lib/pleroma/plugs/rate_limit_plug.ex new file mode 100644 index 000000000..466f64a79 --- /dev/null +++ b/lib/pleroma/plugs/rate_limit_plug.ex @@ -0,0 +1,36 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Plugs.RateLimitPlug do + import Phoenix.Controller, only: [json: 2] + import Plug.Conn + + def init(opts), do: opts + + def call(conn, opts) do + enabled? = Pleroma.Config.get([:app_account_creation, :enabled]) + + case check_rate(conn, Map.put(opts, :enabled, enabled?)) do + {:ok, _count} -> conn + {:error, _count} -> render_error(conn) + %Plug.Conn{} = conn -> conn + end + end + + defp check_rate(conn, %{enabled: true} = opts) do + max_requests = opts[:max_requests] + bucket_name = conn.remote_ip |> Tuple.to_list() |> Enum.join(".") + + ExRated.check_rate(bucket_name, opts[:interval] * 1000, max_requests) + end + + defp check_rate(conn, _), do: conn + + defp render_error(conn) do + conn + |> put_status(:forbidden) + |> json(%{error: "Rate limit exceeded."}) + |> halt() + end +end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 427400aa1..474de9ba5 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -204,14 +204,15 @@ defmodule Pleroma.User do end def register_changeset(struct, params \\ %{}, opts \\ []) do - confirmation_status = - if opts[:confirmed] || !Pleroma.Config.get([:instance, :account_activation_required]) do - :confirmed + need_confirmation? = + if is_nil(opts[:need_confirmation]) do + Pleroma.Config.get([:instance, :account_activation_required]) else - :unconfirmed + opts[:need_confirmation] end - info_change = User.Info.confirmation_changeset(%User.Info{}, confirmation_status) + info_change = + User.Info.confirmation_changeset(%User.Info{}, need_confirmation: need_confirmation?) changeset = struct diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 1b81619ce..5a50ee639 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -8,6 +8,8 @@ defmodule Pleroma.User.Info do alias Pleroma.User.Info + @type t :: %__MODULE__{} + embedded_schema do field(:banner, :map, default: %{}) field(:background, :map, default: %{}) @@ -210,21 +212,23 @@ defmodule Pleroma.User.Info do ]) end - def confirmation_changeset(info, :confirmed) do - confirmation_changeset(info, %{ - confirmation_pending: false, - confirmation_token: nil - }) - end + @spec confirmation_changeset(Info.t(), keyword()) :: Ecto.Changerset.t() + def confirmation_changeset(info, opts) do + need_confirmation? = Keyword.get(opts, :need_confirmation) - def confirmation_changeset(info, :unconfirmed) do - confirmation_changeset(info, %{ - confirmation_pending: true, - confirmation_token: :crypto.strong_rand_bytes(32) |> Base.url_encode64() - }) - end + params = + if need_confirmation? do + %{ + confirmation_pending: true, + confirmation_token: :crypto.strong_rand_bytes(32) |> Base.url_encode64() + } + else + %{ + confirmation_pending: false, + confirmation_token: nil + } + end - def confirmation_changeset(info, params) do cast(info, params, [:confirmation_pending, :confirmation_token]) end diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index b553d96a8..e00b33aba 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -59,7 +59,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do bio: "." } - changeset = User.register_changeset(%User{}, user_data, confirmed: true) + changeset = User.register_changeset(%User{}, user_data, need_confirmation: false) {:ok, user} = User.register(changeset) conn diff --git a/lib/pleroma/web/auth/pleroma_authenticator.ex b/lib/pleroma/web/auth/pleroma_authenticator.ex index dd79cdcf7..c4a6fce08 100644 --- a/lib/pleroma/web/auth/pleroma_authenticator.ex +++ b/lib/pleroma/web/auth/pleroma_authenticator.ex @@ -74,7 +74,7 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticator do password_confirmation: random_password }, external: true, - confirmed: true + need_confirmation: false ) |> Repo.insert(), {:ok, _} <- diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index fd595031d..defd88a44 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -39,12 +39,22 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Web.OAuth.Authorization alias Pleroma.Web.OAuth.Scopes alias Pleroma.Web.OAuth.Token + alias Pleroma.Web.TwitterAPI.TwitterAPI alias Pleroma.Web.ControllerHelper import Ecto.Query require Logger + plug( + Pleroma.Plugs.RateLimitPlug, + %{ + max_requests: Config.get([:app_account_creation, :max_requests]), + interval: Config.get([:app_account_creation, :interval]) + } + when action in [:account_register] + ) + @httpoison Application.get_env(:pleroma, :httpoison) @local_mastodon_name "Mastodon-Local" @@ -1693,6 +1703,53 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end end + def account_register( + %{assigns: %{app: app}} = conn, + %{"username" => nickname, "email" => _, "password" => _, "agreement" => true} = params + ) do + params = + params + |> Map.take([ + "email", + "captcha_solution", + "captcha_token", + "captcha_answer_data", + "token", + "password" + ]) + |> Map.put("nickname", nickname) + |> Map.put("fullname", params["fullname"] || nickname) + |> Map.put("bio", params["bio"] || "") + |> Map.put("confirm", params["password"]) + + with {:ok, user} <- TwitterAPI.register_user(params, need_confirmation: true), + {:ok, token} <- Token.create_token(app, user, %{scopes: app.scopes}) do + json(conn, %{ + token_type: "Bearer", + access_token: token.token, + scope: app.scopes, + created_at: Token.Utils.format_created_at(token) + }) + else + {:error, errors} -> + conn + |> put_status(400) + |> json(Jason.encode!(errors)) + end + end + + def account_register(%{assigns: %{app: _app}} = conn, _params) do + conn + |> put_status(400) + |> json(%{error: "Missing parameters"}) + end + + def account_register(conn, _) do + conn + |> put_status(403) + |> json(%{error: "Invalid credentials"}) + end + def conversations(%{assigns: %{user: user}} = conn, params) do participations = Participation.for_user_with_last_activity_id(user, params) diff --git a/lib/pleroma/web/oauth/app.ex b/lib/pleroma/web/oauth/app.ex index bccc2ac96..ddcdb1871 100644 --- a/lib/pleroma/web/oauth/app.ex +++ b/lib/pleroma/web/oauth/app.ex @@ -7,6 +7,7 @@ defmodule Pleroma.Web.OAuth.App do import Ecto.Changeset @type t :: %__MODULE__{} + schema "apps" do field(:client_name, :string) field(:redirect_uris, :string) diff --git a/lib/pleroma/web/oauth/authorization.ex b/lib/pleroma/web/oauth/authorization.ex index ca3901cc4..b47688de1 100644 --- a/lib/pleroma/web/oauth/authorization.ex +++ b/lib/pleroma/web/oauth/authorization.ex @@ -14,6 +14,7 @@ defmodule Pleroma.Web.OAuth.Authorization do import Ecto.Query @type t :: %__MODULE__{} + schema "oauth_authorizations" do field(:token, :string) field(:scopes, {:array, :string}, default: []) @@ -25,28 +26,45 @@ defmodule Pleroma.Web.OAuth.Authorization do timestamps() end + @spec create_authorization(App.t(), User.t() | %{}, [String.t()] | nil) :: + {:ok, Authorization.t()} | {:error, Changeset.t()} def create_authorization(%App{} = app, %User{} = user, scopes \\ nil) do - scopes = scopes || app.scopes - token = :crypto.strong_rand_bytes(32) |> Base.url_encode64(padding: false) - - authorization = %Authorization{ - token: token, - used: false, + %{ + scopes: scopes || app.scopes, user_id: user.id, - app_id: app.id, - scopes: scopes, - valid_until: NaiveDateTime.add(NaiveDateTime.utc_now(), 60 * 10) + app_id: app.id } + |> create_changeset() + |> Repo.insert() + end + + @spec create_changeset(map()) :: Changeset.t() + def create_changeset(attrs \\ %{}) do + %Authorization{} + |> cast(attrs, [:user_id, :app_id, :scopes, :valid_until]) + |> validate_required([:app_id, :scopes]) + |> add_token() + |> add_lifetime() + end + + defp add_token(changeset) do + token = :crypto.strong_rand_bytes(32) |> Base.url_encode64(padding: false) + put_change(changeset, :token, token) + end - Repo.insert(authorization) + defp add_lifetime(changeset) do + put_change(changeset, :valid_until, NaiveDateTime.add(NaiveDateTime.utc_now(), 60 * 10)) end + @spec use_changeset(Authtorizatiton.t(), map()) :: Changeset.t() def use_changeset(%Authorization{} = auth, params) do auth |> cast(params, [:used]) |> validate_required([:used]) end + @spec use_token(Authorization.t()) :: + {:ok, Authorization.t()} | {:error, Changeset.t()} | {:error, String.t()} def use_token(%Authorization{used: false, valid_until: valid_until} = auth) do if NaiveDateTime.diff(NaiveDateTime.utc_now(), valid_until) < 0 do Repo.update(use_changeset(auth, %{used: true})) @@ -57,6 +75,7 @@ defmodule Pleroma.Web.OAuth.Authorization do def use_token(%Authorization{used: true}), do: {:error, "already used"} + @spec delete_user_authorizations(User.t()) :: {integer(), any()} def delete_user_authorizations(%User{id: user_id}) do from( a in Pleroma.Web.OAuth.Authorization, diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index 8ee0da667..862b8f8c9 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -218,6 +218,28 @@ defmodule Pleroma.Web.OAuth.OAuthController do token_exchange(conn, params) end + def token_exchange(conn, %{"grant_type" => "client_credentials"} = params) do + with %App{} = app <- get_app_from_request(conn, params), + {:ok, auth} <- Authorization.create_authorization(app, %User{}), + {:ok, token} <- Token.exchange_token(app, auth), + {:ok, inserted_at} <- DateTime.from_naive(token.inserted_at, "Etc/UTC") do + response = %{ + token_type: "Bearer", + access_token: token.token, + refresh_token: token.refresh_token, + created_at: DateTime.to_unix(inserted_at), + expires_in: 60 * 10, + scope: Enum.join(token.scopes, " ") + } + + json(conn, response) + else + _error -> + put_status(conn, 400) + |> json(%{error: "Invalid credentials"}) + end + end + # Bad request def token_exchange(conn, params), do: bad_request(conn, params) diff --git a/lib/pleroma/web/oauth/token.ex b/lib/pleroma/web/oauth/token.ex index 4e5d1d118..ef047d565 100644 --- a/lib/pleroma/web/oauth/token.ex +++ b/lib/pleroma/web/oauth/token.ex @@ -45,12 +45,16 @@ defmodule Pleroma.Web.OAuth.Token do |> Repo.find_resource() end + @spec exchange_token(App.t(), Authorization.t()) :: + {:ok, Token.t()} | {:error, Changeset.t()} def exchange_token(app, auth) do with {:ok, auth} <- Authorization.use_token(auth), true <- auth.app_id == app.id do + user = if auth.user_id, do: User.get_cached_by_id(auth.user_id), else: %User{} + create_token( app, - User.get_cached_by_id(auth.user_id), + user, %{scopes: auth.scopes} ) end @@ -81,12 +85,13 @@ defmodule Pleroma.Web.OAuth.Token do |> validate_required([:valid_until]) end + @spec create_token(App.t(), User.t(), map()) :: {:ok, Token} | {:error, Changeset.t()} def create_token(%App{} = app, %User{} = user, attrs \\ %{}) do %__MODULE__{user_id: user.id, app_id: app.id} |> cast(%{scopes: attrs[:scopes] || app.scopes}, [:scopes]) - |> validate_required([:scopes, :user_id, :app_id]) + |> validate_required([:scopes, :app_id]) |> put_valid_until(attrs) - |> put_token + |> put_token() |> put_refresh_token(attrs) |> Repo.insert() end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 8b84fbbad..51146d010 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -385,6 +385,8 @@ defmodule Pleroma.Web.Router do scope "/api/v1", Pleroma.Web.MastodonAPI do pipe_through(:api) + post("/accounts", MastodonAPIController, :account_register) + get("/instance", MastodonAPIController, :masto_instance) get("/instance/peers", MastodonAPIController, :peers) post("/apps", MastodonAPIController, :create_app) diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index 3a7774647..1362ef57c 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -128,7 +128,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do end end - def register_user(params) do + def register_user(params, opts \\ []) do token = params["token"] params = %{ @@ -162,13 +162,22 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do # I have no idea how this error handling works {:error, %{error: Jason.encode!(%{captcha: [error]})}} else - registrations_open = Pleroma.Config.get([:instance, :registrations_open]) - registration_process(registrations_open, params, token) + registration_process( + params, + %{ + registrations_open: Pleroma.Config.get([:instance, :registrations_open]), + token: token + }, + opts + ) end end - defp registration_process(registration_open, params, token) - when registration_open == false or is_nil(registration_open) do + defp registration_process(params, %{registrations_open: true}, opts) do + create_user(params, opts) + end + + defp registration_process(params, %{token: token}, opts) do invite = unless is_nil(token) do Repo.get_by(UserInviteToken, %{token: token}) @@ -182,19 +191,15 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do invite when valid_invite? -> UserInviteToken.update_usage!(invite) - create_user(params) + create_user(params, opts) _ -> {:error, "Expired token"} end end - defp registration_process(true, params, _token) do - create_user(params) - end - - defp create_user(params) do - changeset = User.register_changeset(%User{}, params) + defp create_user(params, opts) do + changeset = User.register_changeset(%User{}, params, opts) case User.register(changeset) do {:ok, user} -> diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index 21e6c555a..3c5a70be9 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -440,7 +440,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do true <- user.local, true <- user.info.confirmation_pending, true <- user.info.confirmation_token == token, - info_change <- User.Info.confirmation_changeset(user.info, :confirmed), + info_change <- User.Info.confirmation_changeset(user.info, need_confirmation: false), changeset <- Changeset.change(user) |> Changeset.put_embed(:info, info_change), {:ok, _} <- User.update_and_set_cache(changeset) do conn -- cgit v1.2.3 From 32d4630c9ca1c89e655b37b3b939d728f569dc9f Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 13 May 2019 01:58:30 +0000 Subject: user: move initial post fetching to job queue --- lib/pleroma/user.ex | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 474de9ba5..a79da4dd8 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -552,8 +552,7 @@ defmodule Pleroma.User do with [_nick, _domain] <- String.split(nickname, "@"), {:ok, user} <- fetch_by_nickname(nickname) do if Pleroma.Config.get([:fetch_initial_posts, :enabled]) do - # TODO turn into job - {:ok, _} = Task.start(__MODULE__, :fetch_initial_posts, [user]) + fetch_initial_posts(user) end {:ok, user} @@ -564,15 +563,8 @@ defmodule Pleroma.User do end @doc "Fetch some posts when the user has just been federated with" - def fetch_initial_posts(user) do - pages = Pleroma.Config.get!([:fetch_initial_posts, :pages]) - - Enum.each( - # Insert all the posts in reverse order, so they're in the right order on the timeline - Enum.reverse(Utils.fetch_ordered_collection(user.info.source_data["outbox"], pages)), - &Pleroma.Web.Federator.incoming_ap_doc/1 - ) - end + def fetch_initial_posts(user), + do: PleromaJobQueue.enqueue(:background, __MODULE__, [:fetch_initial_posts, user]) @spec get_followers_query(User.t(), pos_integer() | nil) :: Ecto.Query.t() def get_followers_query(%User{} = user, nil) do @@ -1077,6 +1069,19 @@ defmodule Pleroma.User do delete_user_activities(user) end + @spec perform(atom(), User.t()) :: {:ok, User.t()} + def perform(:fetch_initial_posts, %User{} = user) do + pages = Pleroma.Config.get!([:fetch_initial_posts, :pages]) + + Enum.each( + # Insert all the posts in reverse order, so they're in the right order on the timeline + Enum.reverse(Utils.fetch_ordered_collection(user.info.source_data["outbox"], pages)), + &Pleroma.Web.Federator.incoming_ap_doc/1 + ) + + {:ok, user} + end + def delete_user_activities(%User{ap_id: ap_id} = user) do stream = ap_id @@ -1130,8 +1135,8 @@ defmodule Pleroma.User do resp = fetch_by_ap_id(ap_id) if should_fetch_initial do - with {:ok, %User{} = user} = resp do - {:ok, _} = Task.start(__MODULE__, :fetch_initial_posts, [user]) + with {:ok, %User{} = user} <- resp do + fetch_initial_posts(user) end end -- cgit v1.2.3 From 57d11ac9dbe4f3befd288cb0f59f368968474f93 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 13 May 2019 02:02:00 +0000 Subject: activitypub: move post rich media fetching to job queue --- lib/pleroma/web/activity_pub/activity_pub.ex | 4 +--- lib/pleroma/web/rich_media/helpers.ex | 2 ++ 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 11777c220..d7c0ab4d3 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -133,9 +133,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do activity end - Task.start(fn -> - Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) - end) + PleromaJobQueue.enqueue(:background, Pleroma.Web.RichMedia.Helpers, [:fetch, activity]) Notification.create_notifications(activity) diff --git a/lib/pleroma/web/rich_media/helpers.ex b/lib/pleroma/web/rich_media/helpers.ex index f67aaf58b..0162a5be9 100644 --- a/lib/pleroma/web/rich_media/helpers.ex +++ b/lib/pleroma/web/rich_media/helpers.ex @@ -34,4 +34,6 @@ defmodule Pleroma.Web.RichMedia.Helpers do end def fetch_data_for_activity(_), do: %{} + + def perform(:fetch, %Activity{} = activity), do: fetch_data_for_activity(activity) end -- cgit v1.2.3 From 69a9e0563cc441a772c4884d747bb755ddf58c45 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 13 May 2019 02:09:28 +0000 Subject: user: migrate follow/blocks import to job queue --- lib/pleroma/user.ex | 73 +++++++++++----------- .../web/twitter_api/controllers/util_controller.ex | 14 ++++- 2 files changed, 50 insertions(+), 37 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index a79da4dd8..c94660de4 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -413,24 +413,6 @@ defmodule Pleroma.User do Enum.member?(follower.following, followed.follower_address) end - def follow_import(%User{} = follower, followed_identifiers) - when is_list(followed_identifiers) do - Enum.map( - followed_identifiers, - fn followed_identifier -> - with {:ok, %User{} = followed} <- get_or_fetch(followed_identifier), - {:ok, follower} <- maybe_direct_follow(follower, followed), - {:ok, _} <- ActivityPub.follow(follower, followed) do - followed - else - err -> - Logger.debug("follow_import failed for #{followed_identifier} with: #{inspect(err)}") - err - end - end - ) - end - def locked?(%User{} = user) do user.info.locked || false end @@ -844,23 +826,6 @@ defmodule Pleroma.User do ) end - def blocks_import(%User{} = blocker, blocked_identifiers) when is_list(blocked_identifiers) do - Enum.map( - blocked_identifiers, - fn blocked_identifier -> - with {:ok, %User{} = blocked} <- get_or_fetch(blocked_identifier), - {:ok, blocker} <- block(blocker, blocked), - {:ok, _} <- ActivityPub.block(blocker, blocked) do - blocked - else - err -> - Logger.debug("blocks_import failed for #{blocked_identifier} with: #{inspect(err)}") - err - end - end - ) - end - def mute(muter, %User{ap_id: ap_id}) do info_cng = muter.info @@ -1082,6 +1047,44 @@ defmodule Pleroma.User do {:ok, user} end + @spec perform(atom(), User.t(), list()) :: list() | {:error, any()} + def perform(:blocks_import, %User{} = blocker, blocked_identifiers) + when is_list(blocked_identifiers) do + Enum.map( + blocked_identifiers, + fn blocked_identifier -> + with {:ok, %User{} = blocked} <- get_or_fetch(blocked_identifier), + {:ok, blocker} <- block(blocker, blocked), + {:ok, _} <- ActivityPub.block(blocker, blocked) do + blocked + else + err -> + Logger.debug("blocks_import failed for #{blocked_identifier} with: #{inspect(err)}") + err + end + end + ) + end + + @spec perform(atom(), User.t(), list()) :: list() | {:error, any()} + def perform(:follow_import, %User{} = follower, followed_identifiers) + when is_list(followed_identifiers) do + Enum.map( + followed_identifiers, + fn followed_identifier -> + with {:ok, %User{} = followed} <- get_or_fetch(followed_identifier), + {:ok, follower} <- maybe_direct_follow(follower, followed), + {:ok, _} <- ActivityPub.follow(follower, followed) do + followed + else + err -> + Logger.debug("follow_import failed for #{followed_identifier} with: #{inspect(err)}") + err + end + end + ) + end + def delete_user_activities(%User{ap_id: ap_id} = user) do stream = ap_id diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index c03f8ab3a..143960206 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -310,7 +310,12 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do String.split(line, ",") |> List.first() end) |> List.delete("Account address"), - {:ok, _} = Task.start(fn -> User.follow_import(follower, followed_identifiers) end) do + :ok <- + PleromaJobQueue.enqueue(:background, User, [ + :follow_import, + follower, + followed_identifiers + ]) do json(conn, "job started") end end @@ -321,7 +326,12 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do def blocks_import(%{assigns: %{user: blocker}} = conn, %{"list" => list}) do with blocked_identifiers <- String.split(list), - {:ok, _} = Task.start(fn -> User.blocks_import(blocker, blocked_identifiers) end) do + :ok <- + PleromaJobQueue.enqueue(:background, User, [ + :blocks_import, + blocker, + blocked_identifiers + ]) do json(conn, "job started") end end -- cgit v1.2.3 From 498bfdf403b6d20f92363a4b650dd0b926351e17 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Mon, 13 May 2019 15:37:38 -0500 Subject: Switch to Jason over Poison --- lib/mix/tasks/pleroma/emoji.ex | 12 ++++++------ lib/pleroma/captcha/kocaptcha.ex | 2 +- lib/pleroma/uploaders/swift/keystone.ex | 4 ++-- lib/pleroma/web/activity_pub/utils.ex | 2 +- lib/pleroma/web/federator/federator.ex | 2 +- lib/pleroma/web/oauth/oauth_controller.ex | 4 ++-- 6 files changed, 13 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/emoji.ex b/lib/mix/tasks/pleroma/emoji.ex index 5cb54c3ca..d2ddf450a 100644 --- a/lib/mix/tasks/pleroma/emoji.ex +++ b/lib/mix/tasks/pleroma/emoji.ex @@ -137,7 +137,7 @@ defmodule Mix.Tasks.Pleroma.Emoji do ]) ) - files = Tesla.get!(client(), files_url).body |> Poison.decode!() + files = Tesla.get!(client(), files_url).body |> Jason.decode!() IO.puts(IO.ANSI.format(["Unpacking ", :bright, pack_name])) @@ -239,7 +239,7 @@ defmodule Mix.Tasks.Pleroma.Emoji do emoji_map = Pleroma.Emoji.make_shortcode_to_file_map(tmp_pack_dir, exts) - File.write!(files_name, Poison.encode!(emoji_map, pretty: true)) + File.write!(files_name, Jason.encode!(emoji_map, pretty: true)) IO.puts(""" @@ -248,11 +248,11 @@ defmodule Mix.Tasks.Pleroma.Emoji do """) if File.exists?("index.json") do - existing_data = File.read!("index.json") |> Poison.decode!() + existing_data = File.read!("index.json") |> Jason.decode!() File.write!( "index.json", - Poison.encode!( + Jason.encode!( Map.merge( existing_data, pack_json @@ -263,14 +263,14 @@ defmodule Mix.Tasks.Pleroma.Emoji do IO.puts("index.json file has been update with the #{name} pack") else - File.write!("index.json", Poison.encode!(pack_json, pretty: true)) + File.write!("index.json", Jason.encode!(pack_json, pretty: true)) IO.puts("index.json has been created with the #{name} pack") end end defp fetch_manifest(from) do - Poison.decode!( + Jason.decode!( if String.starts_with?(from, "http") do Tesla.get!(client(), from).body else diff --git a/lib/pleroma/captcha/kocaptcha.ex b/lib/pleroma/captcha/kocaptcha.ex index 61688e778..18931d5a0 100644 --- a/lib/pleroma/captcha/kocaptcha.ex +++ b/lib/pleroma/captcha/kocaptcha.ex @@ -15,7 +15,7 @@ defmodule Pleroma.Captcha.Kocaptcha do %{error: "Kocaptcha service unavailable"} {:ok, res} -> - json_resp = Poison.decode!(res.body) + json_resp = Jason.decode!(res.body) %{ type: :kocaptcha, diff --git a/lib/pleroma/uploaders/swift/keystone.ex b/lib/pleroma/uploaders/swift/keystone.ex index 3046cdbd2..dd44c7561 100644 --- a/lib/pleroma/uploaders/swift/keystone.ex +++ b/lib/pleroma/uploaders/swift/keystone.ex @@ -14,7 +14,7 @@ defmodule Pleroma.Uploaders.Swift.Keystone do def process_response_body(body) do body - |> Poison.decode!() + |> Jason.decode!() end def get_token do @@ -38,7 +38,7 @@ defmodule Pleroma.Uploaders.Swift.Keystone do end def make_auth_body(username, password, tenant) do - Poison.encode!(%{ + Jason.encode!(%{ :auth => %{ :passwordCredentials => %{ :username => username, diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 581b9d1ab..236d1b4ac 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -682,7 +682,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do """ def fetch_ordered_collection(from, pages_left, acc \\ []) do with {:ok, response} <- Tesla.get(from), - {:ok, collection} <- Poison.decode(response.body) do + {:ok, collection} <- Jason.decode(response.body) do case collection["type"] do "OrderedCollection" -> # If we've encountered the OrderedCollection and not the page, diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex index 8621eda95..169fdf4dc 100644 --- a/lib/pleroma/web/federator/federator.ex +++ b/lib/pleroma/web/federator/federator.ex @@ -117,7 +117,7 @@ defmodule Pleroma.Web.Federator do _e -> # Just drop those for now Logger.info("Unhandled activity") - Logger.info(Poison.encode!(params, pretty: 2)) + Logger.info(Jason.encode!(params, pretty: true)) :error end end diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index 862b8f8c9..4ee8339e2 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -274,7 +274,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do auth_attrs |> Map.delete("scopes") |> Map.put("scope", scope) - |> Poison.encode!() + |> Jason.encode!() params = auth_attrs @@ -338,7 +338,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do end defp callback_params(%{"state" => state} = params) do - Map.merge(params, Poison.decode!(state)) + Map.merge(params, Jason.decode!(state)) end def registration_details(conn, %{"authorization" => auth_attrs}) do -- cgit v1.2.3 From bbacdf235299e0c26c61f9b4784d4638093be343 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Mon, 13 May 2019 15:52:16 -0500 Subject: Bump Mastodon API level --- lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index defd88a44..87e597074 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -178,7 +178,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end end - @mastodon_api_level "2.6.5" + @mastodon_api_level "2.7.2" def masto_instance(conn, _params) do instance = Config.get(:instance) -- cgit v1.2.3 From a18b2c0b12b413c9a8d0aa0d4fd3b15e0e843cdf Mon Sep 17 00:00:00 2001 From: Aaron Tinio Date: Tue, 14 May 2019 06:40:59 +0800 Subject: Fix Pleroma.Config.get!/1 raising an error when value is false --- lib/pleroma/config.ex | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/config.ex b/lib/pleroma/config.ex index 189faa15f..71a47b9fb 100644 --- a/lib/pleroma/config.ex +++ b/lib/pleroma/config.ex @@ -12,8 +12,12 @@ defmodule Pleroma.Config do def get([key], default), do: get(key, default) def get([parent_key | keys], default) do - Application.get_env(:pleroma, parent_key) - |> get_in(keys) || default + case :pleroma + |> Application.get_env(parent_key) + |> get_in(keys) do + nil -> default + any -> any + end end def get(key, default) do -- cgit v1.2.3 From b92c004ea8a9ecd066b8eddf755a07a175338416 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 14 May 2019 18:29:10 +0700 Subject: Reuse query from User.restrict_deactivated/1 --- lib/pleroma/user.ex | 2 +- lib/pleroma/user/query.ex | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index cf378d467..3eb684c3a 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -115,7 +115,7 @@ defmodule Pleroma.User do } end - defp restrict_deactivated(query) do + def restrict_deactivated(query) do from(u in query, where: not fragment("? \\? 'deactivated' AND ?->'deactivated' @> 'true'", u.info, u.info) ) diff --git a/lib/pleroma/user/query.ex b/lib/pleroma/user/query.ex index 3873ef80c..ace9c05f2 100644 --- a/lib/pleroma/user/query.ex +++ b/lib/pleroma/user/query.ex @@ -119,9 +119,7 @@ defmodule Pleroma.User.Query do end defp compose_query({:deactivated, false}, query) do - from(u in query, - where: not fragment("? \\? 'deactivated' AND ?->'deactivated' @> 'true'", u.info, u.info) - ) + User.restrict_deactivated(query) end defp compose_query({:deactivated, true}, query) do -- cgit v1.2.3 From 52297920e74ad7f51bcd3b118522e5e3a8e1c794 Mon Sep 17 00:00:00 2001 From: Maksim Date: Tue, 14 May 2019 14:49:45 +0000 Subject: Refactoring oauth response. --- lib/pleroma/web/oauth/oauth_controller.ex | 77 ++++++------------------------- lib/pleroma/web/oauth/token/response.ex | 32 +++++++++++++ lib/pleroma/web/oauth/token/utils.ex | 38 +++++++++++++++ 3 files changed, 83 insertions(+), 64 deletions(-) create mode 100644 lib/pleroma/web/oauth/token/response.ex (limited to 'lib') diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index 4ee8339e2..ae2b80d95 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -19,8 +19,6 @@ defmodule Pleroma.Web.OAuth.OAuthController do if Pleroma.Config.oauth_consumer_enabled?(), do: plug(Ueberauth) - @expires_in Pleroma.Config.get([:oauth2, :token_expires_in], 600) - plug(:fetch_session) plug(:fetch_flash) @@ -144,14 +142,14 @@ defmodule Pleroma.Web.OAuth.OAuthController do @doc "Renew access_token with refresh_token" def token_exchange( conn, - %{"grant_type" => "refresh_token", "refresh_token" => token} = params + %{"grant_type" => "refresh_token", "refresh_token" => token} = _params ) do - with %App{} = app <- get_app_from_request(conn, params), + with {:ok, app} <- Token.Utils.fetch_app(conn), {:ok, %{user: user} = token} <- Token.get_by_refresh_token(app, token), {:ok, token} <- RefreshToken.grant(token) do response_attrs = %{created_at: Token.Utils.format_created_at(token)} - json(conn, response_token(user, token, response_attrs)) + json(conn, Token.Response.build(user, token, response_attrs)) else _error -> put_status(conn, 400) @@ -160,14 +158,14 @@ defmodule Pleroma.Web.OAuth.OAuthController do end def token_exchange(conn, %{"grant_type" => "authorization_code"} = params) do - with %App{} = app <- get_app_from_request(conn, params), + with {:ok, app} <- Token.Utils.fetch_app(conn), fixed_token = Token.Utils.fix_padding(params["code"]), {:ok, auth} <- Authorization.get_by_token(app, fixed_token), %User{} = user <- User.get_cached_by_id(auth.user_id), {:ok, token} <- Token.exchange_token(app, auth) do response_attrs = %{created_at: Token.Utils.format_created_at(token)} - json(conn, response_token(user, token, response_attrs)) + json(conn, Token.Response.build(user, token, response_attrs)) else _error -> put_status(conn, 400) @@ -179,14 +177,14 @@ defmodule Pleroma.Web.OAuth.OAuthController do conn, %{"grant_type" => "password"} = params ) do - with {_, {:ok, %User{} = user}} <- {:get_user, Authenticator.get_user(conn)}, - %App{} = app <- get_app_from_request(conn, params), + with {:ok, %User{} = user} <- Authenticator.get_user(conn), + {:ok, app} <- Token.Utils.fetch_app(conn), {:auth_active, true} <- {:auth_active, User.auth_active?(user)}, {:user_active, true} <- {:user_active, !user.info.deactivated}, {:ok, scopes} <- validate_scopes(app, params), {:ok, auth} <- Authorization.create_authorization(app, user, scopes), {:ok, token} <- Token.exchange_token(app, auth) do - json(conn, response_token(user, token)) + json(conn, Token.Response.build(user, token)) else {:auth_active, false} -> # Per https://github.com/tootsuite/mastodon/blob/ @@ -218,21 +216,11 @@ defmodule Pleroma.Web.OAuth.OAuthController do token_exchange(conn, params) end - def token_exchange(conn, %{"grant_type" => "client_credentials"} = params) do - with %App{} = app <- get_app_from_request(conn, params), + def token_exchange(conn, %{"grant_type" => "client_credentials"} = _params) do + with {:ok, app} <- Token.Utils.fetch_app(conn), {:ok, auth} <- Authorization.create_authorization(app, %User{}), - {:ok, token} <- Token.exchange_token(app, auth), - {:ok, inserted_at} <- DateTime.from_naive(token.inserted_at, "Etc/UTC") do - response = %{ - token_type: "Bearer", - access_token: token.token, - refresh_token: token.refresh_token, - created_at: DateTime.to_unix(inserted_at), - expires_in: 60 * 10, - scope: Enum.join(token.scopes, " ") - } - - json(conn, response) + {:ok, token} <- Token.exchange_token(app, auth) do + json(conn, Token.Response.build_for_client_credentials(token)) else _error -> put_status(conn, 400) @@ -244,7 +232,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do def token_exchange(conn, params), do: bad_request(conn, params) def token_revoke(conn, %{"token" => _token} = params) do - with %App{} = app <- get_app_from_request(conn, params), + with {:ok, app} <- Token.Utils.fetch_app(conn), {:ok, _token} <- RevokeToken.revoke(app, params) do json(conn, %{}) else @@ -427,33 +415,6 @@ defmodule Pleroma.Web.OAuth.OAuthController do end end - defp get_app_from_request(conn, params) do - conn - |> fetch_client_credentials(params) - |> fetch_client - end - - defp fetch_client({id, secret}) when is_binary(id) and is_binary(secret) do - Repo.get_by(App, client_id: id, client_secret: secret) - end - - defp fetch_client({_id, _secret}), do: nil - - defp fetch_client_credentials(conn, params) do - # Per RFC 6749, HTTP Basic is preferred to body params - with ["Basic " <> encoded] <- get_req_header(conn, "authorization"), - {:ok, decoded} <- Base.decode64(encoded), - [id, secret] <- - Enum.map( - String.split(decoded, ":"), - fn s -> URI.decode_www_form(s) end - ) do - {id, secret} - else - _ -> {params["client_id"], params["client_secret"]} - end - end - # Special case: Local MastodonFE defp redirect_uri(conn, "."), do: mastodon_api_url(conn, :login) @@ -464,18 +425,6 @@ defmodule Pleroma.Web.OAuth.OAuthController do defp put_session_registration_id(conn, registration_id), do: put_session(conn, :registration_id, registration_id) - defp response_token(%User{} = user, token, opts \\ %{}) do - %{ - token_type: "Bearer", - access_token: token.token, - refresh_token: token.refresh_token, - expires_in: @expires_in, - scope: Enum.join(token.scopes, " "), - me: user.ap_id - } - |> Map.merge(opts) - end - @spec validate_scopes(App.t(), map()) :: {:ok, list()} | {:error, :missing_scopes | :unsupported_scopes} defp validate_scopes(app, params) do diff --git a/lib/pleroma/web/oauth/token/response.ex b/lib/pleroma/web/oauth/token/response.ex new file mode 100644 index 000000000..64e78b183 --- /dev/null +++ b/lib/pleroma/web/oauth/token/response.ex @@ -0,0 +1,32 @@ +defmodule Pleroma.Web.OAuth.Token.Response do + @moduledoc false + + alias Pleroma.User + alias Pleroma.Web.OAuth.Token.Utils + + @expires_in Pleroma.Config.get([:oauth2, :token_expires_in], 600) + + @doc false + def build(%User{} = user, token, opts \\ %{}) do + %{ + token_type: "Bearer", + access_token: token.token, + refresh_token: token.refresh_token, + expires_in: @expires_in, + scope: Enum.join(token.scopes, " "), + me: user.ap_id + } + |> Map.merge(opts) + end + + def build_for_client_credentials(token) do + %{ + token_type: "Bearer", + access_token: token.token, + refresh_token: token.refresh_token, + created_at: Utils.format_created_at(token), + expires_in: @expires_in, + scope: Enum.join(token.scopes, " ") + } + end +end diff --git a/lib/pleroma/web/oauth/token/utils.ex b/lib/pleroma/web/oauth/token/utils.ex index a81560a1c..7a4fddafd 100644 --- a/lib/pleroma/web/oauth/token/utils.ex +++ b/lib/pleroma/web/oauth/token/utils.ex @@ -3,6 +3,44 @@ defmodule Pleroma.Web.OAuth.Token.Utils do Auxiliary functions for dealing with tokens. """ + alias Pleroma.Repo + alias Pleroma.Web.OAuth.App + + @doc "Fetch app by client credentials from request" + @spec fetch_app(Plug.Conn.t()) :: {:ok, App.t()} | {:error, :not_found} + def fetch_app(conn) do + res = + conn + |> fetch_client_credentials() + |> fetch_client + + case res do + %App{} = app -> {:ok, app} + _ -> {:error, :not_found} + end + end + + defp fetch_client({id, secret}) when is_binary(id) and is_binary(secret) do + Repo.get_by(App, client_id: id, client_secret: secret) + end + + defp fetch_client({_id, _secret}), do: nil + + defp fetch_client_credentials(conn) do + # Per RFC 6749, HTTP Basic is preferred to body params + with ["Basic " <> encoded] <- Plug.Conn.get_req_header(conn, "authorization"), + {:ok, decoded} <- Base.decode64(encoded), + [id, secret] <- + Enum.map( + String.split(decoded, ":"), + fn s -> URI.decode_www_form(s) end + ) do + {id, secret} + else + _ -> {conn.params["client_id"], conn.params["client_secret"]} + end + end + @doc "convert token inserted_at to unix timestamp" def format_created_at(%{inserted_at: inserted_at} = _token) do inserted_at -- cgit v1.2.3 From ac3a3abf6bfae5a6217e0a212abd6be0b4a17309 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Tue, 14 May 2019 15:07:38 +0000 Subject: clean up follow/block imports a little --- lib/pleroma/user.ex | 16 +++++++++++++ .../web/twitter_api/controllers/util_controller.ex | 28 +++++++++++----------- 2 files changed, 30 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index c94660de4..417d57d72 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1085,6 +1085,22 @@ defmodule Pleroma.User do ) end + def blocks_import(%User{} = blocker, blocked_identifiers) when is_list(blocked_identifiers), + do: + PleromaJobQueue.enqueue(:background, __MODULE__, [ + :blocks_import, + blocker, + blocked_identifiers + ]) + + def follow_import(%User{} = follower, followed_identifiers) when is_list(followed_identifiers), + do: + PleromaJobQueue.enqueue(:background, __MODULE__, [ + :follow_import, + follower, + followed_identifiers + ]) + def delete_user_activities(%User{ap_id: ap_id} = user) do stream = ap_id diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 143960206..deaacd946 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -309,13 +309,13 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do Enum.map(lines, fn line -> String.split(line, ",") |> List.first() end) - |> List.delete("Account address"), - :ok <- - PleromaJobQueue.enqueue(:background, User, [ - :follow_import, - follower, - followed_identifiers - ]) do + |> List.delete("Account address") do + PleromaJobQueue.enqueue(:background, User, [ + :follow_import, + follower, + followed_identifiers + ]) + json(conn, "job started") end end @@ -325,13 +325,13 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do end def blocks_import(%{assigns: %{user: blocker}} = conn, %{"list" => list}) do - with blocked_identifiers <- String.split(list), - :ok <- - PleromaJobQueue.enqueue(:background, User, [ - :blocks_import, - blocker, - blocked_identifiers - ]) do + with blocked_identifiers <- String.split(list) do + PleromaJobQueue.enqueue(:background, User, [ + :blocks_import, + blocker, + blocked_identifiers + ]) + json(conn, "job started") end end -- cgit v1.2.3 From 51325fd60cf96e2ae99e09f53264f2ca1e69781b Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Tue, 14 May 2019 15:35:06 +0000 Subject: gopher: fix rendering of post content (closes #895) --- lib/pleroma/gopher/server.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/gopher/server.ex b/lib/pleroma/gopher/server.ex index 1d2e0785c..b3319e137 100644 --- a/lib/pleroma/gopher/server.ex +++ b/lib/pleroma/gopher/server.ex @@ -77,13 +77,13 @@ defmodule Pleroma.Gopher.Server.ProtocolHandler do user = User.get_cached_by_ap_id(activity.data["actor"]) object = Object.normalize(activity) - like_count = object["like_count"] || 0 - announcement_count = object["announcement_count"] || 0 + like_count = object.data["like_count"] || 0 + announcement_count = object.data["announcement_count"] || 0 link("Post ##{activity.id} by #{user.nickname}", "/notices/#{activity.id}") <> info("#{like_count} likes, #{announcement_count} repeats") <> "i\tfake\t(NULL)\t0\r\n" <> - info(HTML.strip_tags(String.replace(object["content"], "
", "\r"))) + info(HTML.strip_tags(String.replace(object.data["content"], "
", "\r"))) end) |> Enum.join("i\tfake\t(NULL)\t0\r\n") end -- cgit v1.2.3 From 1caa6331eaba71db5a04b2097ef06fd6e4a54739 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Tue, 14 May 2019 12:33:03 -0500 Subject: Group def perform() together to fix the build --- lib/pleroma/user.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 19f91d63c..c6a562a61 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1014,8 +1014,6 @@ defmodule Pleroma.User do PleromaJobQueue.enqueue(:background, __MODULE__, [:deactivate_async, user, status]) end - def perform(:deactivate_async, user, status), do: deactivate(user, status) - def deactivate(%User{} = user, status \\ true) do info_cng = User.Info.set_activation_status(user.info, status) @@ -1074,6 +1072,8 @@ defmodule Pleroma.User do {:ok, user} end + def perform(:deactivate_async, user, status), do: deactivate(user, status) + @spec perform(atom(), User.t(), list()) :: list() | {:error, any()} def perform(:blocks_import, %User{} = blocker, blocked_identifiers) when is_list(blocked_identifiers) do -- cgit v1.2.3 From 071f78733aaa8a6546c9267d14381be9c0af0333 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Tue, 14 May 2019 20:03:13 +0000 Subject: switch to pleroma/http_signatures library --- lib/pleroma/plugs/http_signature.ex | 1 - lib/pleroma/signature.ex | 41 ++++++++++ lib/pleroma/web/activity_pub/publisher.ex | 2 +- lib/pleroma/web/http_signatures/http_signatures.ex | 91 ---------------------- 4 files changed, 42 insertions(+), 93 deletions(-) create mode 100644 lib/pleroma/signature.ex delete mode 100644 lib/pleroma/web/http_signatures/http_signatures.ex (limited to 'lib') diff --git a/lib/pleroma/plugs/http_signature.ex b/lib/pleroma/plugs/http_signature.ex index 21c195713..e2874c469 100644 --- a/lib/pleroma/plugs/http_signature.ex +++ b/lib/pleroma/plugs/http_signature.ex @@ -4,7 +4,6 @@ defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do alias Pleroma.Web.ActivityPub.Utils - alias Pleroma.Web.HTTPSignatures import Plug.Conn require Logger diff --git a/lib/pleroma/signature.ex b/lib/pleroma/signature.ex new file mode 100644 index 000000000..b7ecf00a0 --- /dev/null +++ b/lib/pleroma/signature.ex @@ -0,0 +1,41 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Signature do + @behaviour HTTPSignatures.Adapter + + alias Pleroma.User + alias Pleroma.Web.ActivityPub.ActivityPub + alias Pleroma.Web.ActivityPub.Utils + alias Pleroma.Web.Salmon + alias Pleroma.Web.WebFinger + + def fetch_public_key(conn) do + with actor_id <- Utils.get_ap_id(conn.params["actor"]), + {:ok, public_key} <- User.get_public_key_for_ap_id(actor_id) do + {:ok, public_key} + else + e -> + {:error, e} + end + end + + def refetch_public_key(conn) do + with actor_id <- Utils.get_ap_id(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 + {:ok, public_key} + else + e -> + {:error, e} + end + end + + def sign(%User{} = user, headers) do + with {:ok, %{info: %{keys: keys}}} <- WebFinger.ensure_keys_present(user), + {:ok, private_key, _} <- Salmon.keys_from_pem(keys) do + HTTPSignatures.sign(private_key, user.ap_id <> "#main-key", headers) + end + end +end diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex index 8e3af0a81..11dba87de 100644 --- a/lib/pleroma/web/activity_pub/publisher.ex +++ b/lib/pleroma/web/activity_pub/publisher.ex @@ -54,7 +54,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do |> Timex.format!("{WDshort}, {0D} {Mshort} {YYYY} {h24}:{m}:{s} GMT") signature = - Pleroma.Web.HTTPSignatures.sign(actor, %{ + Pleroma.Signature.sign(actor, %{ host: host, "content-length": byte_size(json), digest: digest, diff --git a/lib/pleroma/web/http_signatures/http_signatures.ex b/lib/pleroma/web/http_signatures/http_signatures.ex deleted file mode 100644 index 8e2e2a44b..000000000 --- a/lib/pleroma/web/http_signatures/http_signatures.ex +++ /dev/null @@ -1,91 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -# https://tools.ietf.org/html/draft-cavage-http-signatures-08 -defmodule Pleroma.Web.HTTPSignatures do - alias Pleroma.User - alias Pleroma.Web.ActivityPub.ActivityPub - alias Pleroma.Web.ActivityPub.Utils - - require Logger - - def split_signature(sig) do - default = %{"headers" => "date"} - - sig = - sig - |> String.trim() - |> String.split(",") - |> Enum.reduce(default, fn part, acc -> - [key | rest] = String.split(part, "=") - value = Enum.join(rest, "=") - Map.put(acc, key, String.trim(value, "\"")) - end) - - Map.put(sig, "headers", String.split(sig["headers"], ~r/\s/)) - end - - def validate(headers, signature, public_key) do - sigstring = build_signing_string(headers, signature["headers"]) - Logger.debug("Signature: #{signature["signature"]}") - Logger.debug("Sigstring: #{sigstring}") - {:ok, sig} = Base.decode64(signature["signature"]) - :public_key.verify(sigstring, :sha256, sig, public_key) - end - - 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 <- Utils.get_ap_id(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 <- Utils.get_ap_id(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) - end - end - else - _e -> - Logger.debug("Could not public key!") - false - end - end - - def validate_conn(conn, public_key) do - headers = Enum.into(conn.req_headers, %{}) - signature = split_signature(headers["signature"]) - validate(headers, signature, public_key) - end - - def build_signing_string(headers, used_headers) do - used_headers - |> Enum.map(fn header -> "#{header}: #{headers[header]}" end) - |> Enum.join("\n") - end - - def sign(user, headers) do - with {:ok, %{info: %{keys: keys}}} <- Pleroma.Web.WebFinger.ensure_keys_present(user), - {:ok, private_key, _} = Pleroma.Web.Salmon.keys_from_pem(keys) do - sigstring = build_signing_string(headers, Map.keys(headers)) - - signature = - :public_key.sign(sigstring, :sha256, private_key) - |> Base.encode64() - - [ - keyId: user.ap_id <> "#main-key", - algorithm: "rsa-sha256", - headers: Map.keys(headers) |> Enum.join(" "), - signature: signature - ] - |> Enum.map(fn {k, v} -> "#{k}=\"#{v}\"" end) - |> Enum.join(",") - end - end -end -- cgit v1.2.3 From 7b8dc99ef106314f1418ff1c314b47cf58a3c2d2 Mon Sep 17 00:00:00 2001 From: Aaron Tinio Date: Tue, 14 May 2019 08:21:44 +0800 Subject: Implement Pleroma.Plugs.EnsurePublicOrAuthenticated --- .../plugs/ensure_public_or_authenticated_plug.ex | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 lib/pleroma/plugs/ensure_public_or_authenticated_plug.ex (limited to 'lib') diff --git a/lib/pleroma/plugs/ensure_public_or_authenticated_plug.ex b/lib/pleroma/plugs/ensure_public_or_authenticated_plug.ex new file mode 100644 index 000000000..317fd5445 --- /dev/null +++ b/lib/pleroma/plugs/ensure_public_or_authenticated_plug.ex @@ -0,0 +1,31 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug do + import Plug.Conn + alias Pleroma.Config + alias Pleroma.User + + def init(options) do + options + end + + def call(conn, _) do + public? = Config.get!([:instance, :public]) + + case {public?, conn} do + {true, _} -> + conn + + {false, %{assigns: %{user: %User{}}}} -> + conn + + {false, _} -> + conn + |> put_resp_content_type("application/json") + |> send_resp(403, Jason.encode!(%{error: "This resource requires authentication."})) + |> halt + end + end +end -- cgit v1.2.3 From 70c81b95d095a7148085201cfa3a07283ef296d9 Mon Sep 17 00:00:00 2001 From: Aaron Tinio Date: Mon, 13 May 2019 23:07:11 +0800 Subject: Pipe requests to public endpoints through EnsurePublicOrAuthenticatedPlug --- lib/pleroma/web/router.ex | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 80af0afe1..7fef82f82 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -84,11 +84,13 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Plugs.EnsureUserKeyPlug) end - pipeline :oauth_read_or_unauthenticated do + pipeline :oauth_read_or_public do plug(Pleroma.Plugs.OAuthScopesPlug, %{ scopes: ["read"], fallback: :proceed_unauthenticated }) + + plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug) end pipeline :oauth_read do @@ -404,7 +406,7 @@ defmodule Pleroma.Web.Router do get("/accounts/search", MastodonAPIController, :account_search) scope [] do - pipe_through(:oauth_read_or_unauthenticated) + pipe_through(:oauth_read_or_public) get("/timelines/public", MastodonAPIController, :public_timeline) get("/timelines/tag/:tag", MastodonAPIController, :hashtag_timeline) @@ -425,7 +427,7 @@ defmodule Pleroma.Web.Router do end scope "/api/v2", Pleroma.Web.MastodonAPI do - pipe_through([:api, :oauth_read_or_unauthenticated]) + pipe_through([:api, :oauth_read_or_public]) get("/search", MastodonAPIController, :search2) end @@ -455,7 +457,7 @@ defmodule Pleroma.Web.Router do ) scope [] do - pipe_through(:oauth_read_or_unauthenticated) + pipe_through(:oauth_read_or_public) get("/statuses/user_timeline", TwitterAPI.Controller, :user_timeline) get("/qvitter/statuses/user_timeline", TwitterAPI.Controller, :user_timeline) @@ -473,7 +475,7 @@ defmodule Pleroma.Web.Router do end scope "/api", Pleroma.Web do - pipe_through([:api, :oauth_read_or_unauthenticated]) + pipe_through([:api, :oauth_read_or_public]) get("/statuses/public_timeline", TwitterAPI.Controller, :public_timeline) @@ -487,7 +489,7 @@ defmodule Pleroma.Web.Router do end scope "/api", Pleroma.Web, as: :twitter_api_search do - pipe_through([:api, :oauth_read_or_unauthenticated]) + pipe_through([:api, :oauth_read_or_public]) get("/pleroma/search_user", TwitterAPI.Controller, :search_user) end @@ -671,7 +673,7 @@ defmodule Pleroma.Web.Router do delete("/auth/sign_out", MastodonAPIController, :logout) scope [] do - pipe_through(:oauth_read_or_unauthenticated) + pipe_through(:oauth_read_or_public) get("/web/*path", MastodonAPIController, :index) end end -- cgit v1.2.3 From ee22fff5ac4631edc6035e349c787d29a13adeaf Mon Sep 17 00:00:00 2001 From: Sachin Joshi Date: Tue, 14 May 2019 23:37:08 +0545 Subject: remove deprecated PleromaFE configuration --- lib/pleroma/config/deprecation_warnings.ex | 10 -------- .../web/twitter_api/controllers/util_controller.ex | 28 +--------------------- 2 files changed, 1 insertion(+), 37 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/config/deprecation_warnings.ex b/lib/pleroma/config/deprecation_warnings.ex index 0345ac19c..240fb1c37 100644 --- a/lib/pleroma/config/deprecation_warnings.ex +++ b/lib/pleroma/config/deprecation_warnings.ex @@ -5,15 +5,6 @@ defmodule Pleroma.Config.DeprecationWarnings do require Logger - def check_frontend_config_mechanism do - if Pleroma.Config.get(:fe) do - Logger.warn(""" - !!!DEPRECATION WARNING!!! - You are using the old configuration mechanism for the frontend. Please check config.md. - """) - end - end - def check_hellthread_threshold do if Pleroma.Config.get([:mrf_hellthread, :threshold]) do Logger.warn(""" @@ -24,7 +15,6 @@ defmodule Pleroma.Config.DeprecationWarnings do end def warn do - check_frontend_config_mechanism() check_hellthread_threshold() end end diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 89c55ef0e..489170d80 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -173,8 +173,6 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do def config(conn, _params) do instance = Pleroma.Config.get(:instance) - instance_fe = Pleroma.Config.get(:fe) - instance_chat = Pleroma.Config.get(:chat) case get_format(conn) do "xml" -> @@ -219,31 +217,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do if(Pleroma.Config.get([:instance, :safe_dm_mentions]), do: "1", else: "0") } - pleroma_fe = - if instance_fe do - %{ - theme: Keyword.get(instance_fe, :theme), - background: Keyword.get(instance_fe, :background), - logo: Keyword.get(instance_fe, :logo), - logoMask: Keyword.get(instance_fe, :logo_mask), - logoMargin: Keyword.get(instance_fe, :logo_margin), - redirectRootNoLogin: Keyword.get(instance_fe, :redirect_root_no_login), - redirectRootLogin: Keyword.get(instance_fe, :redirect_root_login), - chatDisabled: !Keyword.get(instance_chat, :enabled), - showInstanceSpecificPanel: Keyword.get(instance_fe, :show_instance_panel), - scopeOptionsEnabled: Keyword.get(instance_fe, :scope_options_enabled), - formattingOptionsEnabled: Keyword.get(instance_fe, :formatting_options_enabled), - collapseMessageWithSubject: - Keyword.get(instance_fe, :collapse_message_with_subject), - hidePostStats: Keyword.get(instance_fe, :hide_post_stats), - hideUserStats: Keyword.get(instance_fe, :hide_user_stats), - scopeCopy: Keyword.get(instance_fe, :scope_copy), - subjectLineBehavior: Keyword.get(instance_fe, :subject_line_behavior), - alwaysShowSubjectInput: Keyword.get(instance_fe, :always_show_subject_input) - } - else - Pleroma.Config.get([:frontend_configurations, :pleroma_fe]) - end + pleroma_fe = Pleroma.Config.get([:frontend_configurations, :pleroma_fe]) managed_config = Keyword.get(instance, :managed_config) -- cgit v1.2.3 From f1e67bdc312ba16a37916024244d6cb9d4417c9e Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 15 May 2019 15:28:01 +0200 Subject: Search: Add optional rum indexing / searching. --- .../web/mastodon_api/mastodon_api_controller.ex | 43 +++++++++++++++++----- 1 file changed, 33 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 32677df95..fc0100b1e 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -1000,6 +1000,30 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end end + def status_search_query_with_gin(q, query) do + from([a, o] in q, + where: + fragment( + "to_tsvector('english', ?->>'content') @@ plainto_tsquery('english', ?)", + o.data, + ^query + ), + order_by: [desc: :id] + ) + end + + def status_search_query_with_rum(q, query) do + from([a, o] in q, + where: + fragment( + "? @@ plainto_tsquery('english', ?)", + o.fts_content, + ^query + ), + order_by: [fragment("? <=> now()::date", o.inserted_at)] + ) + end + def status_search(user, query) do fetched = if Regex.match?(~r/https?:/, query) do @@ -1013,20 +1037,19 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end || [] q = - from( - [a, o] in Activity.with_preloaded_object(Activity), + from([a, o] in Activity.with_preloaded_object(Activity), where: fragment("?->>'type' = 'Create'", a.data), where: "https://www.w3.org/ns/activitystreams#Public" in a.recipients, - where: - fragment( - "? @@ plainto_tsquery('english', ?)", - o.fts_content, - ^query - ), - limit: 20, - order_by: [fragment("? <=> now()::date", o.inserted_at)] + limit: 20 ) + q = + if Pleroma.Config.get([:database, :rum_enabled]) do + status_search_query_with_rum(q, query) + else + status_search_query_with_gin(q, query) + end + Repo.all(q) ++ fetched end -- cgit v1.2.3 From cbb3451023f557ece773bab20f79ac130f786d01 Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 15 May 2019 16:30:08 +0200 Subject: CommonAPI: Refactor visibility, forbid public to private replies. --- lib/pleroma/web/activity_pub/visibility.ex | 24 ++++++++++++++++++++ lib/pleroma/web/common_api/common_api.ex | 20 ++++++++++++----- lib/pleroma/web/mastodon_api/views/status_view.ex | 26 ++-------------------- lib/pleroma/web/twitter_api/views/activity_view.ex | 2 +- 4 files changed, 42 insertions(+), 30 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/visibility.ex b/lib/pleroma/web/activity_pub/visibility.ex index 6dee61dd6..b38ee0442 100644 --- a/lib/pleroma/web/activity_pub/visibility.ex +++ b/lib/pleroma/web/activity_pub/visibility.ex @@ -58,4 +58,28 @@ defmodule Pleroma.Web.ActivityPub.Visibility do visible_for_user?(tail, user) end end + + def get_visibility(object) do + public = "https://www.w3.org/ns/activitystreams#Public" + to = object.data["to"] || [] + cc = object.data["cc"] || [] + + cond do + public in to -> + "public" + + public in cc -> + "unlisted" + + # this should use the sql for the object's activity + Enum.any?(to, &String.contains?(&1, "/followers")) -> + "private" + + length(cc) > 0 -> + "private" + + true -> + "direct" + end + end end diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index b53869c75..c31e56d4c 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -126,22 +126,30 @@ defmodule Pleroma.Web.CommonAPI do "public" in_reply_to -> - # XXX: these heuristics should be moved out of MastodonAPI. - with %Object{} = object <- Object.normalize(in_reply_to) do - Pleroma.Web.MastodonAPI.StatusView.get_visibility(object) - end + get_replied_to_visibility(in_reply_to) end end def get_visibility(_), do: "public" + def get_replied_to_visibility(nil), do: nil + + def get_replied_to_visibility(activity) do + with %Object{} = object <- Object.normalize(activity) do + Pleroma.Web.ActivityPub.Visibility.get_visibility(object) + end + end + def post(user, %{"status" => status} = data) do - visibility = get_visibility(data) limit = Pleroma.Config.get([:instance, :limit]) with status <- String.trim(status), attachments <- attachments_from_ids(data), + visibility <- get_visibility(data), in_reply_to <- get_replied_to_activity(data["in_reply_to_status_id"]), + in_reply_to_visibility <- get_replied_to_visibility(in_reply_to), + {_, false} <- + {:private_to_public, in_reply_to_visibility == "direct" && visibility != "direct"}, {content_html, mentions, tags} <- make_content_html( status, @@ -185,6 +193,8 @@ defmodule Pleroma.Web.CommonAPI do ) res + else + e -> {:error, e} end end diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index bd2372944..c93d915e5 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -16,6 +16,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do alias Pleroma.Web.MastodonAPI.StatusView alias Pleroma.Web.MediaProxy + import Pleroma.Web.ActivityPub.Visibility, only: [get_visibility: 1] + # TODO: Add cached version. defp get_replied_to_activities(activities) do activities @@ -340,30 +342,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do end end - def get_visibility(object) do - public = "https://www.w3.org/ns/activitystreams#Public" - to = object.data["to"] || [] - cc = object.data["cc"] || [] - - cond do - public in to -> - "public" - - public in cc -> - "unlisted" - - # this should use the sql for the object's activity - Enum.any?(to, &String.contains?(&1, "/followers")) -> - "private" - - length(cc) > 0 -> - "private" - - true -> - "direct" - end - end - def render_content(%{data: %{"type" => "Video"}} = object) do with name when not is_nil(name) and name != "" <- object.data["name"] do "

#{name}

#{object.data["content"]}" diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex index d084ad734..44bcafe0e 100644 --- a/lib/pleroma/web/twitter_api/views/activity_view.ex +++ b/lib/pleroma/web/twitter_api/views/activity_view.ex @@ -310,7 +310,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do "tags" => tags, "activity_type" => "post", "possibly_sensitive" => possibly_sensitive, - "visibility" => StatusView.get_visibility(object), + "visibility" => Pleroma.Web.ActivityPub.Visibility.get_visibility(object), "summary" => summary, "summary_html" => summary |> Formatter.emojify(object.data["emoji"]), "card" => card, -- cgit v1.2.3 From 7a92e701b974aa5ee70d617be323292c953d08de Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 15 May 2019 16:35:33 +0200 Subject: CommonAPI: Visibility refactor. --- lib/pleroma/web/common_api/common_api.ex | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index c31e56d4c..29c4c1014 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -116,21 +116,16 @@ defmodule Pleroma.Web.CommonAPI do end end - def get_visibility(%{"visibility" => visibility}) + def get_visibility(%{"visibility" => visibility}, in_reply_to) when visibility in ~w{public unlisted private direct}, - do: visibility + do: {visibility, get_replied_to_visibility(in_reply_to)} - def get_visibility(%{"in_reply_to_status_id" => status_id}) when not is_nil(status_id) do - case get_replied_to_activity(status_id) do - nil -> - "public" - - in_reply_to -> - get_replied_to_visibility(in_reply_to) - end + def get_visibility(_, in_reply_to) when not is_nil(in_reply_to) do + visibility = get_replied_to_visibility(in_reply_to) + {visibility, visibility} end - def get_visibility(_), do: "public" + def get_visibility(_, in_reply_to), do: {"public", get_replied_to_visibility(in_reply_to)} def get_replied_to_visibility(nil), do: nil @@ -145,9 +140,8 @@ defmodule Pleroma.Web.CommonAPI do with status <- String.trim(status), attachments <- attachments_from_ids(data), - visibility <- get_visibility(data), in_reply_to <- get_replied_to_activity(data["in_reply_to_status_id"]), - in_reply_to_visibility <- get_replied_to_visibility(in_reply_to), + {visibility, in_reply_to_visibility} <- get_visibility(data, in_reply_to), {_, false} <- {:private_to_public, in_reply_to_visibility == "direct" && visibility != "direct"}, {content_html, mentions, tags} <- -- cgit v1.2.3 From 0387f5213805cdc4e0bf86f98797cefcd03ba61d Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 25 Mar 2019 00:06:02 +0000 Subject: activitypub: add restrict_thread_visibility() --- lib/pleroma/web/activity_pub/activity_pub.ex | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 233fee4fa..fec1bcd3e 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -569,6 +569,20 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do defp restrict_visibility(query, _visibility), do: query + defp restrict_thread_visibility(query, %{"user" => %User{ap_id: ap_id}}) do + query = + from( + a in query, + where: fragment("thread_visibility(?, (?)->>'id') = true", ^ap_id, a.data) + ) + + Ecto.Adapters.SQL.to_sql(:all, Repo, query) + + query + end + + defp restrict_thread_visibility(query, _), do: query + def fetch_user_activities(user, reading_user, params \\ %{}) do params = params @@ -848,6 +862,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> restrict_muted(opts) |> restrict_media(opts) |> restrict_visibility(opts) + |> restrict_thread_visibility(opts) |> restrict_replies(opts) |> restrict_reblogs(opts) |> restrict_pinned(opts) -- cgit v1.2.3 From de114ffbb0f92d24fd370adaaf43ff301ab04b4b Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 25 Mar 2019 00:10:20 +0000 Subject: activitypub: remove contain_timeline() --- lib/pleroma/web/activity_pub/activity_pub.ex | 8 -------- lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 1 - lib/pleroma/web/twitter_api/twitter_api_controller.ex | 4 +--- 3 files changed, 1 insertion(+), 12 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index fec1bcd3e..e544d0c50 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -980,12 +980,4 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do def contain_activity(%Activity{} = activity, %User{} = user) do contain_broken_threads(activity, user) end - - # do post-processing on a timeline - def contain_timeline(timeline, user) do - timeline - |> Enum.filter(fn activity -> - contain_activity(activity, user) - end) - end end diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 87e597074..66056a846 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -303,7 +303,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do activities = [user.ap_id | user.following] |> ActivityPub.fetch_activities(params) - |> ActivityPub.contain_timeline(user) |> Enum.reverse() conn diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index 3c5a70be9..31e86685a 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -101,9 +101,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do |> Map.put("blocking_user", user) |> Map.put("user", user) - activities = - ActivityPub.fetch_activities([user.ap_id | user.following], params) - |> ActivityPub.contain_timeline(user) + activities = ActivityPub.fetch_activities([user.ap_id | user.following], params) conn |> put_view(ActivityView) -- cgit v1.2.3 From 31db31c5879a2dedcc8dd4c671c4c9a79656355a Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Mon, 25 Mar 2019 00:38:28 +0000 Subject: activitypub: visibility: use SQL thread_visibility() function instead of manually walking the thread --- lib/pleroma/web/activity_pub/visibility.ex | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/visibility.ex b/lib/pleroma/web/activity_pub/visibility.ex index b38ee0442..46dd46575 100644 --- a/lib/pleroma/web/activity_pub/visibility.ex +++ b/lib/pleroma/web/activity_pub/visibility.ex @@ -1,6 +1,7 @@ defmodule Pleroma.Web.ActivityPub.Visibility do alias Pleroma.Activity alias Pleroma.Object + alias Pleroma.Repo alias Pleroma.User def is_public?(%Object{data: %{"type" => "Tombstone"}}), do: false @@ -38,25 +39,14 @@ defmodule Pleroma.Web.ActivityPub.Visibility do visible_for_user?(activity, nil) || Enum.any?(x, &(&1 in y)) end - # guard - def entire_thread_visible_for_user?(nil, _user), do: false + def entire_thread_visible_for_user?(%Activity{} = activity, %User{} = user) do + {:ok, %{rows: [[result]]}} = + Ecto.Adapters.SQL.query(Repo, "SELECT thread_visibility($1, $2)", [ + user.ap_id, + activity.data["id"] + ]) - # XXX: Probably even more inefficient than the previous implementation intended to be a placeholder untill https://git.pleroma.social/pleroma/pleroma/merge_requests/971 is in develop - # credo:disable-for-previous-line Credo.Check.Readability.MaxLineLength - - def entire_thread_visible_for_user?( - %Activity{} = tail, - # %Activity{data: %{"object" => %{"inReplyTo" => parent_id}}} = tail, - user - ) do - case Object.normalize(tail) do - %{data: %{"inReplyTo" => parent_id}} when is_binary(parent_id) -> - parent = Activity.get_in_reply_to_activity(tail) - visible_for_user?(tail, user) && entire_thread_visible_for_user?(parent, user) - - _ -> - visible_for_user?(tail, user) - end + result end def get_visibility(object) do -- cgit v1.2.3 From 0aada88b5594b6714b8d65f8bee9c325d77d6e7b Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Wed, 8 May 2019 23:17:51 +0000 Subject: bbs: chase timeline containment patch --- lib/pleroma/bbs/handler.ex | 1 - 1 file changed, 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/bbs/handler.ex b/lib/pleroma/bbs/handler.ex index 106fe5d18..f34be961f 100644 --- a/lib/pleroma/bbs/handler.ex +++ b/lib/pleroma/bbs/handler.ex @@ -95,7 +95,6 @@ defmodule Pleroma.BBS.Handler do activities = [user.ap_id | user.following] |> ActivityPub.fetch_activities(params) - |> ActivityPub.contain_timeline(user) Enum.each(activities, fn activity -> puts_activity(activity) -- cgit v1.2.3 From f09c3afdf51eea17103d1445b31b7a269c474538 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Wed, 15 May 2019 16:23:01 +0000 Subject: chase test failures --- lib/pleroma/filter.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/filter.ex b/lib/pleroma/filter.ex index 79efc29f0..90457dadf 100644 --- a/lib/pleroma/filter.ex +++ b/lib/pleroma/filter.ex @@ -38,7 +38,8 @@ defmodule Pleroma.Filter do query = from( f in Pleroma.Filter, - where: f.user_id == ^user_id + where: f.user_id == ^user_id, + order_by: [desc: :id] ) Repo.all(query) -- cgit v1.2.3 From a591ab6112abdf162f4d6fdfbbcdd85bbaf75058 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Wed, 15 May 2019 16:56:46 +0000 Subject: activity pub: remove Ecto SQL query dumps --- lib/pleroma/web/activity_pub/activity_pub.ex | 6 ------ 1 file changed, 6 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index e544d0c50..7cd5b889b 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -540,8 +540,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do ) ) - Ecto.Adapters.SQL.to_sql(:all, Repo, query) - query else Logger.error("Could not restrict visibility to #{visibility}") @@ -557,8 +555,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do fragment("activity_visibility(?, ?, ?) = ?", a.actor, a.recipients, a.data, ^visibility) ) - Ecto.Adapters.SQL.to_sql(:all, Repo, query) - query end @@ -576,8 +572,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do where: fragment("thread_visibility(?, (?)->>'id') = true", ^ap_id, a.data) ) - Ecto.Adapters.SQL.to_sql(:all, Repo, query) - query end -- cgit v1.2.3 From 62e42b03abd2cede85e85f62c35f62a8c42e8ea1 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 15 May 2019 20:10:16 +0300 Subject: Handle incoming Question objects --- lib/pleroma/web/activity_pub/transmogrifier.ex | 2 +- lib/pleroma/web/activity_pub/utils.ex | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 508f3532f..c2596cfec 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -399,7 +399,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do # - tags # - emoji def handle_incoming(%{"type" => "Create", "object" => %{"type" => objtype} = object} = data) - when objtype in ["Article", "Note", "Video", "Page"] do + when objtype in ["Article", "Note", "Video", "Page", "Question"] do actor = Containment.get_actor(data) data = diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 581b9d1ab..de91fa03f 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -19,7 +19,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do require Logger - @supported_object_types ["Article", "Note", "Video", "Page"] + @supported_object_types ["Article", "Note", "Video", "Page", "Question"] # 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. -- cgit v1.2.3 From 2b6119dfbf47f118dfb102fc09f6450e59ccf15e Mon Sep 17 00:00:00 2001 From: Aaron Tinio Date: Wed, 15 May 2019 07:59:24 +0800 Subject: Restrict reblogs of activities from blocked domains --- lib/pleroma/web/activity_pub/activity_pub.ex | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 233fee4fa..6087a1cdc 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -752,6 +752,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do from( activity in query, + inner_join: o in Object, + on: + fragment( + "(?->>'id') = COALESCE(?->'object'->>'id', ?->>'object')", + o.data, + activity.data, + activity.data + ), where: fragment("not (? = ANY(?))", activity.actor, ^blocks), where: fragment("not (? && ?)", activity.recipients, ^blocks), where: @@ -761,7 +769,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do activity.data, ^blocks ), - where: fragment("not (split_part(?, '/', 3) = ANY(?))", activity.actor, ^domain_blocks) + where: fragment("not (split_part(?, '/', 3) = ANY(?))", activity.actor, ^domain_blocks), + where: fragment("not (split_part(?->>'actor', '/', 3) = ANY(?))", o.data, ^domain_blocks) ) end -- cgit v1.2.3 From 793f1834d2bc37ba3d4ba11fb669078950994adb Mon Sep 17 00:00:00 2001 From: Aaron Tinio Date: Thu, 16 May 2019 06:25:14 +0800 Subject: Use named binding to conditionally join object --- lib/pleroma/activity.ex | 19 +++++++++++-------- lib/pleroma/web/activity_pub/activity_pub.ex | 13 ++++--------- 2 files changed, 15 insertions(+), 17 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index 4a0919478..3fd4003f8 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -60,21 +60,24 @@ defmodule Pleroma.Activity do timestamps() end - def with_preloaded_object(query) do - query - |> join( - :inner, - [activity], - o in Object, + def with_joined_object(query) do + join(query, :inner, [activity], o in Object, on: fragment( "(?->>'id') = COALESCE(?->'object'->>'id', ?->>'object')", o.data, activity.data, activity.data - ) + ), + as: :object ) - |> preload([activity, object], object: object) + end + + def with_preloaded_object(query) do + query + |> has_named_binding?(:object) + |> if(do: query, else: with_joined_object(query)) + |> preload([activity, object: object], object: object) end def with_preloaded_bookmark(query, %User{} = user) do diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 6087a1cdc..2fd073d3a 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -750,16 +750,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do blocks = info.blocks || [] domain_blocks = info.domain_blocks || [] + query = + if has_named_binding?(query, :object), do: query, else: Activity.with_joined_object(query) + from( - activity in query, - inner_join: o in Object, - on: - fragment( - "(?->>'id') = COALESCE(?->'object'->>'id', ?->>'object')", - o.data, - activity.data, - activity.data - ), + [activity, object: o] in query, where: fragment("not (? = ANY(?))", activity.actor, ^blocks), where: fragment("not (? && ?)", activity.recipients, ^blocks), where: -- cgit v1.2.3 From c31026423c8c73ab33dc0d38b9d187a0d2b68309 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Thu, 16 May 2019 04:41:27 +0000 Subject: publisher: use the correct queue name for outgoing federation --- lib/pleroma/web/federator/publisher.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/federator/publisher.ex b/lib/pleroma/web/federator/publisher.ex index 916bcdcba..fb4e8548d 100644 --- a/lib/pleroma/web/federator/publisher.ex +++ b/lib/pleroma/web/federator/publisher.ex @@ -31,7 +31,7 @@ defmodule Pleroma.Web.Federator.Publisher do """ @spec enqueue_one(module(), Map.t()) :: :ok def enqueue_one(module, %{} = params), - do: PleromaJobQueue.enqueue(:federation_outgoing, __MODULE__, [:publish_one, module, params]) + do: PleromaJobQueue.enqueue(:federator_outgoing, __MODULE__, [:publish_one, module, params]) @spec perform(atom(), module(), any()) :: {:ok, any()} | {:error, any()} def perform(:publish_one, module, params) do -- cgit v1.2.3 From aa11fa4864bf6ebdd4acfdba837675abbdcffc83 Mon Sep 17 00:00:00 2001 From: Alex S Date: Thu, 16 May 2019 12:49:40 +0700 Subject: add report uri and report to --- lib/pleroma/plugs/http_security_plug.ex | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/plugs/http_security_plug.ex b/lib/pleroma/plugs/http_security_plug.ex index a476f1d49..485ddfbc7 100644 --- a/lib/pleroma/plugs/http_security_plug.ex +++ b/lib/pleroma/plugs/http_security_plug.ex @@ -20,8 +20,9 @@ defmodule Pleroma.Plugs.HTTPSecurityPlug do defp headers do referrer_policy = Config.get([:http_security, :referrer_policy]) + report_uri = Config.get([:http_security, :report_uri]) - [ + headers = [ {"x-xss-protection", "1; mode=block"}, {"x-permitted-cross-domain-policies", "none"}, {"x-frame-options", "DENY"}, @@ -30,12 +31,27 @@ defmodule Pleroma.Plugs.HTTPSecurityPlug do {"x-download-options", "noopen"}, {"content-security-policy", csp_string() <> ";"} ] + + if report_uri do + report_group = %{ + "group" => "csp-endpoint", + "max-age" => 10_886_400, + "endpoints" => [ + %{"url" => report_uri} + ] + } + + headers ++ [{"reply-to", Jason.encode!(report_group)}] + else + headers + end end defp csp_string do scheme = Config.get([Pleroma.Web.Endpoint, :url])[:scheme] static_url = Pleroma.Web.Endpoint.static_url() websocket_url = Pleroma.Web.Endpoint.websocket_url() + report_uri = Config.get([:http_security, :report_uri]) connect_src = "connect-src 'self' #{static_url} #{websocket_url}" @@ -53,7 +69,7 @@ defmodule Pleroma.Plugs.HTTPSecurityPlug do "script-src 'self'" end - [ + main_part = [ "default-src 'none'", "base-uri 'self'", "frame-ancestors 'none'", @@ -63,11 +79,14 @@ defmodule Pleroma.Plugs.HTTPSecurityPlug do "font-src 'self'", "manifest-src 'self'", connect_src, - script_src, - if scheme == "https" do - "upgrade-insecure-requests" - end + script_src ] + + report = if report_uri, do: ["report-uri #{report_uri}; report-to csp-endpoint"], else: [] + + insecure = if scheme == "https", do: ["upgrade-insecure-requests"], else: [] + + (main_part ++ report ++ insecure) |> Enum.join("; ") end -- cgit v1.2.3 From 73ae58fdfaf0b9dc9630929b0b84ae3b6083684a Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Thu, 16 May 2019 13:23:41 +0000 Subject: Feature/896 toggling confirmation --- lib/mix/tasks/pleroma/user.ex | 19 +++++++++++++++++++ lib/pleroma/user.ex | 13 +++++++++++++ lib/pleroma/user/info.ex | 2 +- 3 files changed, 33 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index d130ff8c9..25fc40ea7 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -77,6 +77,10 @@ defmodule Mix.Tasks.Pleroma.User do ## Delete tags from a user. mix pleroma.user untag NICKNAME TAGS + + ## Toggle confirmation of the user's account. + + mix pleroma.user toggle_confirmed NICKNAME """ def run(["new", nickname, email | rest]) do {options, [], []} = @@ -388,6 +392,21 @@ defmodule Mix.Tasks.Pleroma.User do end end + def run(["toggle_confirmed", nickname]) do + Common.start_pleroma() + + with %User{} = user <- User.get_cached_by_nickname(nickname) do + {:ok, user} = User.toggle_confirmation(user) + + message = if user.info.confirmation_pending, do: "needs", else: "doesn't need" + + Mix.shell().info("#{nickname} #{message} confirmation.") + else + _ -> + Mix.shell().error("No local user #{nickname}") + end + end + defp set_moderator(user, value) do info_cng = User.Info.admin_api_update(user.info, %{is_moderator: value}) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index c6a562a61..1aa966dfc 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1378,4 +1378,17 @@ defmodule Pleroma.User do def showing_reblogs?(%User{} = user, %User{} = target) do target.ap_id not in user.info.muted_reblogs end + + @spec toggle_confirmation(User.t()) :: {:ok, User.t()} | {:error, Changeset.t()} + def toggle_confirmation(%User{} = user) do + need_confirmation? = !user.info.confirmation_pending + + info_changeset = + User.Info.confirmation_changeset(user.info, need_confirmation: need_confirmation?) + + user + |> change() + |> put_embed(:info, info_changeset) + |> update_and_set_cache() + end end diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 5a50ee639..5f0cefc00 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -212,7 +212,7 @@ defmodule Pleroma.User.Info do ]) end - @spec confirmation_changeset(Info.t(), keyword()) :: Ecto.Changerset.t() + @spec confirmation_changeset(Info.t(), keyword()) :: Changeset.t() def confirmation_changeset(info, opts) do need_confirmation? = Keyword.get(opts, :need_confirmation) -- cgit v1.2.3 From efa61c161085fd24f7e85ccf7f32ef823e335d7b Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Thu, 16 May 2019 13:14:48 -0500 Subject: Move to pleroma.database mix task --- lib/mix/tasks/pleroma/conversations.ex | 23 ----------------------- lib/mix/tasks/pleroma/database.ex | 11 +++++++++++ 2 files changed, 11 insertions(+), 23 deletions(-) delete mode 100644 lib/mix/tasks/pleroma/conversations.ex (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/conversations.ex b/lib/mix/tasks/pleroma/conversations.ex deleted file mode 100644 index b52b9921a..000000000 --- a/lib/mix/tasks/pleroma/conversations.ex +++ /dev/null @@ -1,23 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2018 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Mix.Tasks.Pleroma.Conversations do - use Mix.Task - alias Mix.Tasks.Pleroma.Common - alias Pleroma.Conversation - - @shortdoc "Manages Pleroma conversations." - @moduledoc """ - Manages Pleroma conversations. - - ## Create a conversation for all existing DMs. Can be safely re-run. - - mix pleroma.conversations bump_all - - """ - def run(["bump_all"]) do - Common.start_pleroma() - Conversation.bump_for_all_activities() - end -end diff --git a/lib/mix/tasks/pleroma/database.ex b/lib/mix/tasks/pleroma/database.ex index ab9a3a7ff..42753a1a4 100644 --- a/lib/mix/tasks/pleroma/database.ex +++ b/lib/mix/tasks/pleroma/database.ex @@ -4,6 +4,7 @@ defmodule Mix.Tasks.Pleroma.Database do alias Mix.Tasks.Pleroma.Common + alias Pleroma.Conversation require Logger use Mix.Task @@ -19,6 +20,11 @@ defmodule Mix.Tasks.Pleroma.Database do Options: - `--vacuum` - run `VACUUM FULL` after the embedded objects are replaced with their references + + ## Create a conversation for all existing DMs. Can be safely re-run. + + mix pleroma.database bump_all_conversations + """ def run(["remove_embedded_objects" | args]) do {options, [], []} = @@ -48,4 +54,9 @@ defmodule Mix.Tasks.Pleroma.Database do ) end end + + def run(["bump_all_conversations"]) do + Common.start_pleroma() + Conversation.bump_for_all_activities() + end end -- cgit v1.2.3 From e2b3a27204ca511a2e455a1151fdea36fdc0e53d Mon Sep 17 00:00:00 2001 From: Sergey Suprunenko Date: Thu, 16 May 2019 19:09:18 +0000 Subject: Add Reports to Admin API --- lib/pleroma/activity.ex | 2 +- lib/pleroma/emails/admin_email.ex | 2 +- lib/pleroma/web/activity_pub/activity_pub.ex | 7 ++ lib/pleroma/web/activity_pub/utils.ex | 78 +++++++++++++++++++++- lib/pleroma/web/admin_api/admin_api_controller.ex | 81 +++++++++++++++++++++++ lib/pleroma/web/admin_api/views/report_view.ex | 41 ++++++++++++ lib/pleroma/web/common_api/common_api.ex | 57 ++++++++++++++++ lib/pleroma/web/common_api/utils.ex | 10 ++- lib/pleroma/web/router.ex | 8 +++ 9 files changed, 277 insertions(+), 9 deletions(-) create mode 100644 lib/pleroma/web/admin_api/views/report_view.ex (limited to 'lib') diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index 3fd4003f8..4e54b15ba 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -111,7 +111,7 @@ defmodule Pleroma.Activity do def change(struct, params \\ %{}) do struct - |> cast(params, [:data]) + |> cast(params, [:data, :recipients]) |> validate_required([:data]) |> unique_constraint(:ap_id, name: :activities_unique_apid_index) end diff --git a/lib/pleroma/emails/admin_email.ex b/lib/pleroma/emails/admin_email.ex index df0f72f96..d0e254362 100644 --- a/lib/pleroma/emails/admin_email.ex +++ b/lib/pleroma/emails/admin_email.ex @@ -29,7 +29,7 @@ defmodule Pleroma.Emails.AdminEmail do end statuses_html = - if length(statuses) > 0 do + if is_list(statuses) && length(statuses) > 0 do statuses_list_html = statuses |> Enum.map(fn diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 6a186efbf..5c3156978 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -703,6 +703,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do defp restrict_type(query, _), do: query + defp restrict_state(query, %{"state" => state}) do + from(activity in query, where: fragment("?->>'state' = ?", activity.data, ^state)) + end + + defp restrict_state(query, _), do: query + defp restrict_favorited_by(query, %{"favorited_by" => ap_id}) do from( activity in query, @@ -855,6 +861,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> restrict_local(opts) |> restrict_actor(opts) |> restrict_type(opts) + |> restrict_state(opts) |> restrict_favorited_by(opts) |> restrict_blocked(opts) |> restrict_muted(opts) diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 236d1b4ac..ca8a0844b 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -20,6 +20,8 @@ defmodule Pleroma.Web.ActivityPub.Utils do require Logger @supported_object_types ["Article", "Note", "Video", "Page"] + @supported_report_states ~w(open closed resolved) + @valid_visibilities ~w(public unlisted private direct) # 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. @@ -670,7 +672,8 @@ defmodule Pleroma.Web.ActivityPub.Utils do "actor" => params.actor.ap_id, "content" => params.content, "object" => object, - "context" => params.context + "context" => params.context, + "state" => "open" } |> Map.merge(additional) end @@ -713,4 +716,77 @@ defmodule Pleroma.Web.ActivityPub.Utils do end end end + + #### Report-related helpers + + def update_report_state(%Activity{} = activity, state) when state in @supported_report_states do + with new_data <- Map.put(activity.data, "state", state), + changeset <- Changeset.change(activity, data: new_data), + {:ok, activity} <- Repo.update(changeset) do + {:ok, activity} + end + end + + def update_report_state(_, _), do: {:error, "Unsupported state"} + + def update_activity_visibility(activity, visibility) when visibility in @valid_visibilities do + [to, cc, recipients] = + activity + |> get_updated_targets(visibility) + |> Enum.map(&Enum.uniq/1) + + object_data = + activity.object.data + |> Map.put("to", to) + |> Map.put("cc", cc) + + {:ok, object} = + activity.object + |> Object.change(%{data: object_data}) + |> Object.update_and_set_cache() + + activity_data = + activity.data + |> Map.put("to", to) + |> Map.put("cc", cc) + + activity + |> Map.put(:object, object) + |> Activity.change(%{data: activity_data, recipients: recipients}) + |> Repo.update() + end + + def update_activity_visibility(_, _), do: {:error, "Unsupported visibility"} + + defp get_updated_targets( + %Activity{data: %{"to" => to} = data, recipients: recipients}, + visibility + ) do + cc = Map.get(data, "cc", []) + follower_address = User.get_cached_by_ap_id(data["actor"]).follower_address + public = "https://www.w3.org/ns/activitystreams#Public" + + case visibility do + "public" -> + to = [public | List.delete(to, follower_address)] + cc = [follower_address | List.delete(cc, public)] + recipients = [public | recipients] + [to, cc, recipients] + + "private" -> + to = [follower_address | List.delete(to, public)] + cc = List.delete(cc, public) + recipients = List.delete(recipients, public) + [to, cc, recipients] + + "unlisted" -> + to = [follower_address | List.delete(to, public)] + cc = [public | List.delete(cc, follower_address)] + recipients = recipients ++ [follower_address, public] + [to, cc, recipients] + + _ -> + [to, cc, recipients] + end + end end diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index e00b33aba..de2a13c01 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -4,11 +4,16 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do use Pleroma.Web, :controller + alias Pleroma.Activity alias Pleroma.User alias Pleroma.UserInviteToken + alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Relay alias Pleroma.Web.AdminAPI.AccountView + alias Pleroma.Web.AdminAPI.ReportView alias Pleroma.Web.AdminAPI.Search + alias Pleroma.Web.CommonAPI + alias Pleroma.Web.MastodonAPI.StatusView import Pleroma.Web.ControllerHelper, only: [json_response: 3] @@ -287,12 +292,88 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do |> json(token.token) end + def list_reports(conn, params) do + params = + params + |> Map.put("type", "Flag") + |> Map.put("skip_preload", true) + + reports = + [] + |> ActivityPub.fetch_activities(params) + |> Enum.reverse() + + conn + |> put_view(ReportView) + |> render("index.json", %{reports: reports}) + end + + def report_show(conn, %{"id" => id}) do + with %Activity{} = report <- Activity.get_by_id(id) do + conn + |> put_view(ReportView) + |> render("show.json", %{report: report}) + else + _ -> {:error, :not_found} + end + end + + def report_update_state(conn, %{"id" => id, "state" => state}) do + with {:ok, report} <- CommonAPI.update_report_state(id, state) do + conn + |> put_view(ReportView) + |> render("show.json", %{report: report}) + end + end + + def report_respond(%{assigns: %{user: user}} = conn, %{"id" => id} = params) do + with false <- is_nil(params["status"]), + %Activity{} <- Activity.get_by_id(id) do + params = + params + |> Map.put("in_reply_to_status_id", id) + |> Map.put("visibility", "direct") + + {:ok, activity} = CommonAPI.post(user, params) + + conn + |> put_view(StatusView) + |> render("status.json", %{activity: activity}) + else + true -> + {:param_cast, nil} + + nil -> + {:error, :not_found} + end + end + + def status_update(conn, %{"id" => id} = params) do + with {:ok, activity} <- CommonAPI.update_activity_scope(id, params) do + conn + |> put_view(StatusView) + |> render("status.json", %{activity: activity}) + end + end + + def status_delete(%{assigns: %{user: user}} = conn, %{"id" => id}) do + with {:ok, %Activity{}} <- CommonAPI.delete(id, user) do + json(conn, %{}) + end + end + def errors(conn, {:error, :not_found}) do conn |> put_status(404) |> json("Not found") end + def errors(conn, {:error, reason}) do + conn + |> put_status(400) + |> json(reason) + end + def errors(conn, {:param_cast, _}) do conn |> put_status(400) diff --git a/lib/pleroma/web/admin_api/views/report_view.ex b/lib/pleroma/web/admin_api/views/report_view.ex new file mode 100644 index 000000000..47a73dc7e --- /dev/null +++ b/lib/pleroma/web/admin_api/views/report_view.ex @@ -0,0 +1,41 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.AdminAPI.ReportView do + use Pleroma.Web, :view + alias Pleroma.Activity + alias Pleroma.User + alias Pleroma.Web.CommonAPI.Utils + alias Pleroma.Web.MastodonAPI.AccountView + alias Pleroma.Web.MastodonAPI.StatusView + + def render("index.json", %{reports: reports}) do + %{ + reports: render_many(reports, __MODULE__, "show.json", as: :report) + } + end + + def render("show.json", %{report: report}) do + user = User.get_cached_by_ap_id(report.data["actor"]) + created_at = Utils.to_masto_date(report.data["published"]) + + [account_ap_id | status_ap_ids] = report.data["object"] + account = User.get_cached_by_ap_id(account_ap_id) + + statuses = + Enum.map(status_ap_ids, fn ap_id -> + Activity.get_by_ap_id_with_object(ap_id) + end) + + %{ + id: report.id, + account: AccountView.render("account.json", %{user: account}), + actor: AccountView.render("account.json", %{user: user}), + content: report.data["content"], + created_at: created_at, + statuses: StatusView.render("index.json", %{activities: statuses, as: :activity}), + state: report.data["state"] + } + end +end diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 29c4c1014..208c12c7b 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -71,6 +71,9 @@ defmodule Pleroma.Web.CommonAPI do {:ok, _} <- unpin(activity_id, user), {:ok, delete} <- ActivityPub.delete(object) do {:ok, delete} + else + _ -> + {:error, "Could not delete"} end end @@ -315,6 +318,60 @@ defmodule Pleroma.Web.CommonAPI do end end + def update_report_state(activity_id, state) do + with %Activity{} = activity <- Activity.get_by_id(activity_id), + {:ok, activity} <- Utils.update_report_state(activity, state) do + {:ok, activity} + else + nil -> + {:error, :not_found} + + {:error, reason} -> + {:error, reason} + + _ -> + {:error, "Could not update state"} + end + end + + def update_activity_scope(activity_id, opts \\ %{}) do + with %Activity{} = activity <- Activity.get_by_id_with_object(activity_id), + {:ok, activity} <- toggle_sensitive(activity, opts), + {:ok, activity} <- set_visibility(activity, opts) do + {:ok, activity} + else + nil -> + {:error, :not_found} + + {:error, reason} -> + {:error, reason} + end + end + + defp toggle_sensitive(activity, %{"sensitive" => sensitive}) when sensitive in ~w(true false) do + toggle_sensitive(activity, %{"sensitive" => String.to_existing_atom(sensitive)}) + end + + defp toggle_sensitive(%Activity{object: object} = activity, %{"sensitive" => sensitive}) + when is_boolean(sensitive) do + new_data = Map.put(object.data, "sensitive", sensitive) + + {:ok, object} = + object + |> Object.change(%{data: new_data}) + |> Object.update_and_set_cache() + + {:ok, Map.put(activity, :object, object)} + end + + defp toggle_sensitive(activity, _), do: {:ok, activity} + + defp set_visibility(activity, %{"visibility" => visibility}) do + Utils.update_activity_visibility(activity, visibility) + end + + defp set_visibility(activity, _), do: {:ok, activity} + def hide_reblogs(user, muted) do ap_id = muted.ap_id diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 1dfe50b40..bee2fd159 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -237,13 +237,11 @@ defmodule Pleroma.Web.CommonAPI.Utils do "tag" => tags |> Enum.map(fn {_, tag} -> tag end) |> Enum.uniq() } - if in_reply_to do - in_reply_to_object = Object.normalize(in_reply_to) - - object - |> Map.put("inReplyTo", in_reply_to_object.data["id"]) + with false <- is_nil(in_reply_to), + %Object{} = in_reply_to_object <- Object.normalize(in_reply_to) do + Map.put(object, "inReplyTo", in_reply_to_object.data["id"]) else - object + _ -> object end end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 7fef82f82..6a4e4a1d4 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -194,6 +194,14 @@ defmodule Pleroma.Web.Router do get("/users", AdminAPIController, :list_users) get("/users/:nickname", AdminAPIController, :user_show) + + get("/reports", AdminAPIController, :list_reports) + get("/reports/:id", AdminAPIController, :report_show) + put("/reports/:id", AdminAPIController, :report_update_state) + post("/reports/:id/respond", AdminAPIController, :report_respond) + + put("/statuses/:id", AdminAPIController, :status_update) + delete("/statuses/:id", AdminAPIController, :status_delete) end scope "/", Pleroma.Web.TwitterAPI do -- cgit v1.2.3 From 2c303afc8b25ca92eaa229df3e9e4737856e890c Mon Sep 17 00:00:00 2001 From: Sergey Suprunenko Date: Thu, 16 May 2019 20:04:08 +0000 Subject: Remove duplicated entries in users' following lists --- lib/mix/tasks/pleroma/database.ex | 17 +++++++++++++++-- lib/pleroma/user.ex | 14 +++++++++++++- 2 files changed, 28 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/database.ex b/lib/mix/tasks/pleroma/database.ex index 42753a1a4..f650b447d 100644 --- a/lib/mix/tasks/pleroma/database.ex +++ b/lib/mix/tasks/pleroma/database.ex @@ -5,6 +5,8 @@ defmodule Mix.Tasks.Pleroma.Database do alias Mix.Tasks.Pleroma.Common alias Pleroma.Conversation + alias Pleroma.Repo + alias Pleroma.User require Logger use Mix.Task @@ -25,6 +27,9 @@ defmodule Mix.Tasks.Pleroma.Database do mix pleroma.database bump_all_conversations + ## Remove duplicated items from following and update followers count for all users + + mix pleroma.database update_users_following_followers_counts """ def run(["remove_embedded_objects" | args]) do {options, [], []} = @@ -38,7 +43,7 @@ defmodule Mix.Tasks.Pleroma.Database do Common.start_pleroma() Logger.info("Removing embedded objects") - Pleroma.Repo.query!( + Repo.query!( "update activities set data = jsonb_set(data, '{object}'::text[], data->'object'->'id') where data->'object'->>'id' is not null;", [], timeout: :infinity @@ -47,7 +52,7 @@ defmodule Mix.Tasks.Pleroma.Database do if Keyword.get(options, :vacuum) do Logger.info("Runnning VACUUM FULL") - Pleroma.Repo.query!( + Repo.query!( "vacuum full;", [], timeout: :infinity @@ -59,4 +64,12 @@ defmodule Mix.Tasks.Pleroma.Database do Common.start_pleroma() Conversation.bump_for_all_activities() end + + def run(["update_users_following_followers_counts"]) do + Common.start_pleroma() + + users = Repo.all(User) + Enum.each(users, &User.remove_duplicated_following/1) + Enum.each(users, &User.update_follower_count/1) + end end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 1aa966dfc..9ffb61300 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -166,7 +166,7 @@ defmodule Pleroma.User do def update_changeset(struct, params \\ %{}) do struct - |> cast(params, [:bio, :name, :avatar]) + |> cast(params, [:bio, :name, :avatar, :following]) |> unique_constraint(:nickname) |> validate_format(:nickname, local_nickname_regex()) |> validate_length(:bio, max: 5000) @@ -709,6 +709,18 @@ defmodule Pleroma.User do end end + def remove_duplicated_following(%User{following: following} = user) do + uniq_following = Enum.uniq(following) + + if length(following) == length(uniq_following) do + {:ok, user} + else + user + |> update_changeset(%{following: uniq_following}) + |> update_and_set_cache() + end + end + @spec get_users_from_set([String.t()], boolean()) :: [User.t()] def get_users_from_set(ap_ids, local_only \\ true) do criteria = %{ap_id: ap_ids, deactivated: false} -- cgit v1.2.3 From 70235ce840a4ed834080ab6afc3000185590c6cb Mon Sep 17 00:00:00 2001 From: Aaron Tinio Date: Fri, 17 May 2019 09:02:04 +0800 Subject: Fix typo: s/"tags"/"tag"/g --- lib/pleroma/web/activity_pub/mrf/simple_policy.ex | 2 +- lib/pleroma/web/activity_pub/mrf/tag_policy.ex | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex index 2f105700b..50426e920 100644 --- a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex @@ -55,7 +55,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do object = if Enum.member?(Pleroma.Config.get([:mrf_simple, :media_nsfw]), actor_host) do tags = (child_object["tag"] || []) ++ ["nsfw"] - child_object = Map.put(child_object, "tags", tags) + child_object = Map.put(child_object, "tag", tags) child_object = Map.put(child_object, "sensitive", true) Map.put(object, "object", child_object) else diff --git a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex index b52be30e7..6683b8d8e 100644 --- a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex @@ -31,7 +31,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do object = object - |> Map.put("tags", tags) + |> Map.put("tag", tags) |> Map.put("sensitive", true) message = Map.put(message, "object", object) -- cgit v1.2.3 From 68c75a08e8593d41f496a362ab1be43d054c09d5 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Fri, 17 May 2019 07:34:52 +0200 Subject: MastoAPI account_view.ex: requested is false when following is true Closes: https://git.pleroma.social/pleroma/pleroma/issues/903 --- lib/pleroma/web/mastodon_api/views/account_view.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 779b9a382..606a0f2ed 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -40,7 +40,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do follow_activity = Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(user, target) requested = - if follow_activity do + if follow_activity and !User.following?(target, user) do follow_activity.data["state"] == "pending" else false -- cgit v1.2.3 From 7ed682213faf88edc67b4c2a24b277ab1d992813 Mon Sep 17 00:00:00 2001 From: Alexander Strizhakov Date: Fri, 17 May 2019 07:25:20 +0000 Subject: Fix/902 random compile failing --- lib/pleroma/user.ex | 6 +++--- lib/pleroma/web/activity_pub/transmogrifier.ex | 1 - lib/pleroma/web/common_api/common_api.ex | 6 +++--- lib/pleroma/web/federator/publisher.ex | 8 ++++---- lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 2 +- lib/pleroma/web/oauth/authorization.ex | 2 +- lib/pleroma/web/oauth/token.ex | 2 +- lib/pleroma/web/web_finger/web_finger.ex | 2 +- 8 files changed, 14 insertions(+), 15 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 9ffb61300..9607c1f03 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -55,7 +55,7 @@ defmodule Pleroma.User do field(:last_refreshed_at, :naive_datetime_usec) has_many(:notifications, Notification) has_many(:registrations, Registration) - embeds_one(:info, Pleroma.User.Info) + embeds_one(:info, User.Info) timestamps() end @@ -233,7 +233,7 @@ defmodule Pleroma.User do |> validate_confirmation(:password) |> unique_constraint(:email) |> unique_constraint(:nickname) - |> validate_exclusion(:nickname, Pleroma.Config.get([Pleroma.User, :restricted_nicknames])) + |> validate_exclusion(:nickname, Pleroma.Config.get([User, :restricted_nicknames])) |> validate_format(:nickname, local_nickname_regex()) |> validate_format(:email, @email_regex) |> validate_length(:bio, max: 1000) @@ -278,7 +278,7 @@ defmodule Pleroma.User do with {:ok, user} <- Repo.insert(changeset), {:ok, user} <- autofollow_users(user), {:ok, user} <- set_cache(user), - {:ok, _} <- Pleroma.User.WelcomeMessage.post_welcome_message_to_user(user), + {:ok, _} <- User.WelcomeMessage.post_welcome_message_to_user(user), {:ok, _} <- try_send_confirmation_email(user) do {:ok, user} end diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 508f3532f..5edd8ccc7 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -11,7 +11,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do alias Pleroma.Object.Containment alias Pleroma.Repo alias Pleroma.User - alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.ActivityPub.Visibility diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 208c12c7b..a599ffee5 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -200,7 +200,7 @@ defmodule Pleroma.Web.CommonAPI do user = with emoji <- emoji_from_profile(user), source_data <- (user.info.source_data || %{}) |> Map.put("tag", emoji), - info_cng <- Pleroma.User.Info.set_source_data(user.info, source_data), + info_cng <- User.Info.set_source_data(user.info, source_data), change <- Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_cng), {:ok, user} <- User.update_and_set_cache(change) do user @@ -233,7 +233,7 @@ defmodule Pleroma.Web.CommonAPI do } = activity <- get_by_id_or_ap_id(id_or_ap_id), true <- Enum.member?(object_to, "https://www.w3.org/ns/activitystreams#Public"), %{valid?: true} = info_changeset <- - Pleroma.User.Info.add_pinnned_activity(user.info, activity), + User.Info.add_pinnned_activity(user.info, activity), changeset <- Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_changeset), {:ok, _user} <- User.update_and_set_cache(changeset) do @@ -250,7 +250,7 @@ defmodule Pleroma.Web.CommonAPI do def unpin(id_or_ap_id, user) do with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id), %{valid?: true} = info_changeset <- - Pleroma.User.Info.remove_pinnned_activity(user.info, activity), + User.Info.remove_pinnned_activity(user.info, activity), changeset <- Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_changeset), {:ok, _user} <- User.update_and_set_cache(changeset) do diff --git a/lib/pleroma/web/federator/publisher.ex b/lib/pleroma/web/federator/publisher.ex index fb4e8548d..70f870244 100644 --- a/lib/pleroma/web/federator/publisher.ex +++ b/lib/pleroma/web/federator/publisher.ex @@ -52,9 +52,9 @@ defmodule Pleroma.Web.Federator.Publisher do @doc """ Relays an activity to all specified peers. """ - @callback publish(Pleroma.User.t(), Pleroma.Activity.t()) :: :ok | {:error, any()} + @callback publish(User.t(), Activity.t()) :: :ok | {:error, any()} - @spec publish(Pleroma.User.t(), Pleroma.Activity.t()) :: :ok + @spec publish(User.t(), Activity.t()) :: :ok def publish(%User{} = user, %Activity{} = activity) do Config.get([:instance, :federation_publisher_modules]) |> Enum.each(fn module -> @@ -70,9 +70,9 @@ defmodule Pleroma.Web.Federator.Publisher do @doc """ Gathers links used by an outgoing federation module for WebFinger output. """ - @callback gather_webfinger_links(Pleroma.User.t()) :: list() + @callback gather_webfinger_links(User.t()) :: list() - @spec gather_webfinger_links(Pleroma.User.t()) :: list() + @spec gather_webfinger_links(User.t()) :: list() def gather_webfinger_links(%User{} = user) do Config.get([:instance, :federation_publisher_modules]) |> Enum.reduce([], fn module, links -> diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 66056a846..1b776fbca 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -1222,7 +1222,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do accounts |> Enum.each(fn account_id -> with %Pleroma.List{} = list <- Pleroma.List.get(id, user), - %User{} = followed <- Pleroma.User.get_cached_by_id(account_id) do + %User{} = followed <- User.get_cached_by_id(account_id) do Pleroma.List.unfollow(list, followed) end end) diff --git a/lib/pleroma/web/oauth/authorization.ex b/lib/pleroma/web/oauth/authorization.ex index b47688de1..18973413e 100644 --- a/lib/pleroma/web/oauth/authorization.ex +++ b/lib/pleroma/web/oauth/authorization.ex @@ -20,7 +20,7 @@ defmodule Pleroma.Web.OAuth.Authorization do field(:scopes, {:array, :string}, default: []) field(:valid_until, :naive_datetime_usec) field(:used, :boolean, default: false) - belongs_to(:user, Pleroma.User, type: Pleroma.FlakeId) + belongs_to(:user, User, type: Pleroma.FlakeId) belongs_to(:app, App) timestamps() diff --git a/lib/pleroma/web/oauth/token.ex b/lib/pleroma/web/oauth/token.ex index ef047d565..66c95c2e9 100644 --- a/lib/pleroma/web/oauth/token.ex +++ b/lib/pleroma/web/oauth/token.ex @@ -22,7 +22,7 @@ defmodule Pleroma.Web.OAuth.Token do field(:refresh_token, :string) field(:scopes, {:array, :string}, default: []) field(:valid_until, :naive_datetime_usec) - belongs_to(:user, Pleroma.User, type: Pleroma.FlakeId) + belongs_to(:user, User, type: Pleroma.FlakeId) belongs_to(:app, App) timestamps() diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex index 3a3b98a10..1239b962a 100644 --- a/lib/pleroma/web/web_finger/web_finger.ex +++ b/lib/pleroma/web/web_finger/web_finger.ex @@ -99,7 +99,7 @@ defmodule Pleroma.Web.WebFinger do info_cng = info - |> Pleroma.User.Info.set_keys(pem) + |> User.Info.set_keys(pem) cng = Ecto.Changeset.change(user) -- cgit v1.2.3 From 642a67dd4492f31b5b9fe457e34c1589c9d70c3f Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 17 May 2019 11:44:47 +0300 Subject: Render polls in statuses --- lib/pleroma/web/mastodon_api/views/status_view.ex | 52 +++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index bd2372944..6337c50e8 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -232,6 +232,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do spoiler_text: summary_html, visibility: get_visibility(object), media_attachments: attachments, + poll: render("poll.json", %{object: object, for: opts[:for]}), mentions: mentions, tags: build_tags(tags), application: %{ @@ -321,6 +322,57 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do } end + # TODO: Add tests for this view + def render("poll.json", %{object: object} = opts) do + {multiple, options} = + case object.data do + %{"anyOf" => options} when is_list(options) -> {true, options} + %{"oneOf" => options} when is_list(options) -> {false, options} + _ -> {nil, nil} + end + + if options do + end_time = + (object.data["closed"] || object.data["endTime"]) + |> NaiveDateTime.from_iso8601!() + + votes_count = object.data["votes_count"] || 0 + + expired = + end_time + |> NaiveDateTime.compare(NaiveDateTime.utc_now()) + |> case do + :lt -> true + _ -> false + end + + options = + Enum.map(options, fn %{"name" => name} = option -> + name = + HTML.filter_tags( + name, + User.html_filter_policy(opts[:for]) + ) + + %{title: name, votes_count: option["replies"]["votes_count"] || 0} + end) + + %{ + # 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, + expires_at: Utils.to_masto_date(end_time), + expired: expired, + multiple: multiple, + votes_count: votes_count, + options: options, + voted: false, + emojis: build_emojis(object.data["emoji"]) + } + else + nil + end + end + def get_reply_to(activity, %{replied_to_activities: replied_to_activities}) do object = Object.normalize(activity) -- cgit v1.2.3 From 249b31ffe53115ad187235890c405138ba190e14 Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 17 May 2019 11:49:13 +0200 Subject: Fix specs. --- lib/pleroma/user.ex | 1 - 1 file changed, 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 9607c1f03..28da310ee 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1144,7 +1144,6 @@ defmodule Pleroma.User do stream = ap_id |> Activity.query_by_actor() - |> Activity.with_preloaded_object() |> Repo.stream() Repo.transaction(fn -> Enum.each(stream, &delete_activity(&1)) end, timeout: :infinity) -- cgit v1.2.3 From 46684db84d0583cb5d88f8fcbd6b970ef95c84de Mon Sep 17 00:00:00 2001 From: lambda Date: Fri, 17 May 2019 09:53:44 +0000 Subject: Update account_view.ex --- lib/pleroma/web/mastodon_api/views/account_view.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 606a0f2ed..134c07b7e 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -40,7 +40,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do follow_activity = Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(user, target) requested = - if follow_activity and !User.following?(target, user) do + if follow_activity && !User.following?(target, user) do follow_activity.data["state"] == "pending" else false -- cgit v1.2.3 From f959bf7aa6b878ee5b669c4caabd5cdc4cc2dc9e Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 17 May 2019 18:21:11 +0200 Subject: MongooseIM: Add basic integration endpoints. --- .../web/mongooseim/mongoose_im_controller.ex | 41 ++++++++++++++++++++++ lib/pleroma/web/router.ex | 5 +++ 2 files changed, 46 insertions(+) create mode 100644 lib/pleroma/web/mongooseim/mongoose_im_controller.ex (limited to 'lib') diff --git a/lib/pleroma/web/mongooseim/mongoose_im_controller.ex b/lib/pleroma/web/mongooseim/mongoose_im_controller.ex new file mode 100644 index 000000000..f8c634653 --- /dev/null +++ b/lib/pleroma/web/mongooseim/mongoose_im_controller.ex @@ -0,0 +1,41 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.MongooseIM.MongooseIMController do + use Pleroma.Web, :controller + alias Comeonin.Pbkdf2 + alias Pleroma.User + alias Pleroma.Repo + + def user_exists(conn, %{"user" => username}) do + with %User{} <- Repo.get_by(User, nickname: username, local: true) do + conn + |> json(true) + else + _ -> + conn + |> put_status(:not_found) + |> json(false) + end + end + + def check_password(conn, %{"user" => username, "pass" => password}) do + with %User{password_hash: password_hash} <- + Repo.get_by(User, nickname: username, local: true), + true <- Pbkdf2.checkpw(password, password_hash) do + conn + |> json(true) + else + false -> + conn + |> put_status(403) + |> json(false) + + _ -> + conn + |> put_status(:not_found) + |> json(false) + end + end +end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 6a4e4a1d4..552778c92 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -704,6 +704,11 @@ defmodule Pleroma.Web.Router do end end + scope "/", Pleroma.Web.MongooseIM do + get("/user_exists", MongooseIMController, :user_exists) + get("/check_password", MongooseIMController, :check_password) + end + scope "/", Fallback do get("/registration/:token", RedirectController, :registration_page) get("/:maybe_nickname_or_id", RedirectController, :redirector_with_meta) -- cgit v1.2.3 From 075eecec907b0a623a90eed44a0378a6812d8037 Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 17 May 2019 18:32:30 +0200 Subject: Linting. --- lib/pleroma/web/mongooseim/mongoose_im_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/mongooseim/mongoose_im_controller.ex b/lib/pleroma/web/mongooseim/mongoose_im_controller.ex index f8c634653..489d5d3a5 100644 --- a/lib/pleroma/web/mongooseim/mongoose_im_controller.ex +++ b/lib/pleroma/web/mongooseim/mongoose_im_controller.ex @@ -5,8 +5,8 @@ defmodule Pleroma.Web.MongooseIM.MongooseIMController do use Pleroma.Web, :controller alias Comeonin.Pbkdf2 - alias Pleroma.User alias Pleroma.Repo + alias Pleroma.User def user_exists(conn, %{"user" => username}) do with %User{} <- Repo.get_by(User, nickname: username, local: true) do -- cgit v1.2.3 From 78588dbd80580fbef53819dd87ee8fcc26cb09e9 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Fri, 17 May 2019 18:49:10 +0000 Subject: mrf: simple policy: mark all posts instead of posts with media as sensitive if they match media_nsfw --- lib/pleroma/web/activity_pub/mrf/simple_policy.ex | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex index 50426e920..9627c3400 100644 --- a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex @@ -48,10 +48,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do %{host: actor_host} = _actor_info, %{ "type" => "Create", - "object" => %{"attachment" => child_attachment} = child_object + "object" => child_object } = object - ) - when length(child_attachment) > 0 do + ) do object = if Enum.member?(Pleroma.Config.get([:mrf_simple, :media_nsfw]), actor_host) do tags = (child_object["tag"] || []) ++ ["nsfw"] -- cgit v1.2.3 From 0da1233e8e093ff7c69994f9e81d58611be60507 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Fri, 17 May 2019 18:49:43 +0000 Subject: rich media: suppress link previews if post is marked as sensitive --- lib/pleroma/web/rich_media/helpers.ex | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/pleroma/web/rich_media/helpers.ex b/lib/pleroma/web/rich_media/helpers.ex index 0162a5be9..9bc8f2559 100644 --- a/lib/pleroma/web/rich_media/helpers.ex +++ b/lib/pleroma/web/rich_media/helpers.ex @@ -24,6 +24,7 @@ defmodule Pleroma.Web.RichMedia.Helpers do def fetch_data_for_activity(%Activity{data: %{"type" => "Create"}} = activity) do with true <- Pleroma.Config.get([:rich_media, :enabled]), %Object{} = object <- Object.normalize(activity), + false <- object.data["sensitive"] || false, {:ok, page_url} <- HTML.extract_first_external_url(object, object.data["content"]), :ok <- validate_page_url(page_url), {:ok, rich_media} <- Parser.parse(page_url) do -- cgit v1.2.3 From d3b8cd342ff6d1fe87bcfe6305424faf49666252 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Fri, 17 May 2019 19:03:19 +0000 Subject: http: request builder: send user-agent when making requests --- lib/pleroma/http/request_builder.ex | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/http/request_builder.ex b/lib/pleroma/http/request_builder.ex index 5f2cff2c0..522728da1 100644 --- a/lib/pleroma/http/request_builder.ex +++ b/lib/pleroma/http/request_builder.ex @@ -45,8 +45,9 @@ defmodule Pleroma.HTTP.RequestBuilder do Add headers to the request """ @spec headers(map(), list(tuple)) :: map() - def headers(request, h) do - Map.put_new(request, :headers, h) + def headers(request, header_list) do + header_list = header_list ++ [{"User-Agent", Pleroma.Application.user_agent()}] + Map.put_new(request, :headers, header_list) end @doc """ -- cgit v1.2.3 From 290f5b2cfe91dd2acba56f79ef137f15c68a0db0 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Fri, 17 May 2019 20:28:58 +0000 Subject: config: make sending the user agent configurable, disable sending the user agent in tests --- lib/pleroma/http/request_builder.ex | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/http/request_builder.ex b/lib/pleroma/http/request_builder.ex index 522728da1..e23457999 100644 --- a/lib/pleroma/http/request_builder.ex +++ b/lib/pleroma/http/request_builder.ex @@ -46,7 +46,13 @@ defmodule Pleroma.HTTP.RequestBuilder do """ @spec headers(map(), list(tuple)) :: map() def headers(request, header_list) do - header_list = header_list ++ [{"User-Agent", Pleroma.Application.user_agent()}] + header_list = + if Pleroma.Config.get([:http, :send_user_agent]) do + header_list ++ [{"User-Agent", Pleroma.Application.user_agent()}] + else + header_list + end + Map.put_new(request, :headers, header_list) end -- cgit v1.2.3 From dc081595385084fe6b382e4b38c17cb51cf0a611 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Fri, 17 May 2019 20:42:51 +0000 Subject: also suppress link previews from posts marked #nsfw --- lib/pleroma/web/common_api/common_api.ex | 4 +++- lib/pleroma/web/common_api/utils.ex | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index a599ffee5..5a312d673 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -157,6 +157,7 @@ defmodule Pleroma.Web.CommonAPI do {to, cc} <- to_for_user_and_mentions(user, mentions, in_reply_to, visibility), context <- make_context(in_reply_to), cw <- data["spoiler_text"] || "", + sensitive <- data["sensitive"] || Enum.member?(tags, {"#nsfw", "nsfw"}), full_payload <- String.trim(status <> cw), length when length in 1..limit <- String.length(full_payload), object <- @@ -169,7 +170,8 @@ defmodule Pleroma.Web.CommonAPI do in_reply_to, tags, cw, - cc + cc, + sensitive ), object <- Map.put( diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index bee2fd159..8d6160976 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -223,7 +223,8 @@ defmodule Pleroma.Web.CommonAPI.Utils do in_reply_to, tags, cw \\ nil, - cc \\ [] + cc \\ [], + sensitive \\ false ) do object = %{ "type" => "Note", @@ -231,6 +232,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do "cc" => cc, "content" => content_html, "summary" => cw, + "sensitive" => sensitive, "context" => context, "attachment" => attachments, "actor" => actor, -- cgit v1.2.3 From c4a55e167afcfd25cf4c1efb46886f2defe72c22 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Fri, 17 May 2019 20:43:31 +0000 Subject: add Changelog entry --- lib/pleroma/web/common_api/utils.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 8d6160976..d93c0d46e 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -232,7 +232,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do "cc" => cc, "content" => content_html, "summary" => cw, - "sensitive" => sensitive, + "sensitive" => !Enum.member?(["false", "False", "0", false], sensitive), "context" => context, "attachment" => attachments, "actor" => actor, -- cgit v1.2.3 From fd920c897339b9cedea042dd6698d14380cedae7 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sat, 18 May 2019 13:29:28 +0300 Subject: Mastodon API: Add support for posting polls --- lib/pleroma/web/common_api/common_api.ex | 4 +- lib/pleroma/web/common_api/utils.ex | 64 ++++++++++++++++++++++++++++---- 2 files changed, 59 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index b53869c75..335ae70b0 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -149,6 +149,7 @@ defmodule Pleroma.Web.CommonAPI do data, visibility ), + {poll, mentions, tags} <- make_poll_data(data, mentions, tags), {to, cc} <- to_for_user_and_mentions(user, mentions, in_reply_to, visibility), context <- make_context(in_reply_to), cw <- data["spoiler_text"] || "", @@ -164,7 +165,8 @@ defmodule Pleroma.Web.CommonAPI do in_reply_to, tags, cw, - cc + cc, + poll ), object <- Map.put( diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 1dfe50b40..13cdffbbd 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -102,6 +102,48 @@ defmodule Pleroma.Web.CommonAPI.Utils do end end + def make_poll_data( + %{"poll" => %{"options" => options, "expires_in" => expires_in}} = data, + mentions, + tags + ) + when is_list(options) and is_integer(expires_in) do + content_type = get_content_type(data["content_type"]) + # XXX: There is probably a more performant/cleaner way to do this + {poll, {mentions, tags}} = + Enum.map_reduce(options, {mentions, tags}, fn option, {mentions, tags} -> + # TODO: Custom emoji + {option, mentions_merge, tags_merge} = format_input(option, content_type) + mentions = mentions ++ mentions_merge + tags = tags ++ tags_merge + + {%{ + "name" => option, + "type" => "Note", + "replies" => %{"type" => "Collection", "totalItems" => 0} + }, {mentions, tags}} + end) + + end_time = + NaiveDateTime.utc_now() + |> NaiveDateTime.add(expires_in) + |> NaiveDateTime.to_iso8601() + + poll = + if Pleroma.Web.ControllerHelper.truthy_param?(data["poll"]["multiple"]) do + %{"type" => "Question", "anyOf" => poll, "closed" => end_time} + else + %{"type" => "Question", "oneOf" => poll, "closed" => end_time} + end + + {poll, mentions, tags} + end + + def make_poll_data(data, mentions, tags) do + IO.inspect(data, label: "data") + {%{}, mentions, tags} + end + def make_content_html( status, attachments, @@ -223,8 +265,11 @@ defmodule Pleroma.Web.CommonAPI.Utils do in_reply_to, tags, cw \\ nil, - cc \\ [] + cc \\ [], + merge \\ %{} ) do + IO.inspect(merge, label: "merge") + object = %{ "type" => "Note", "to" => to, @@ -237,14 +282,17 @@ defmodule Pleroma.Web.CommonAPI.Utils do "tag" => tags |> Enum.map(fn {_, tag} -> tag end) |> Enum.uniq() } - if in_reply_to do - in_reply_to_object = Object.normalize(in_reply_to) + object = + if in_reply_to do + in_reply_to_object = Object.normalize(in_reply_to) - object - |> Map.put("inReplyTo", in_reply_to_object.data["id"]) - else - object - end + object + |> Map.put("inReplyTo", in_reply_to_object.data["id"]) + else + object + end + + Map.merge(object, merge) end def format_naive_asctime(date) do -- cgit v1.2.3 From 1d90f9b96999f8bad3fa3e3ec58bf50c8666be4f Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sun, 19 May 2019 17:06:44 +0300 Subject: Remove tags/mentions/rich text from poll options because Mastodon and add custom emoji --- lib/pleroma/web/common_api/common_api.ex | 4 ++-- lib/pleroma/web/common_api/utils.ex | 25 +++++++---------------- lib/pleroma/web/mastodon_api/views/status_view.ex | 14 ++++++------- 3 files changed, 15 insertions(+), 28 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index bc8f80389..374967a1b 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -154,7 +154,7 @@ defmodule Pleroma.Web.CommonAPI do data, visibility ), - {poll, mentions, tags} <- make_poll_data(data, mentions, tags), + {poll, poll_emoji} <- make_poll_data(data), {to, cc} <- to_for_user_and_mentions(user, mentions, in_reply_to, visibility), context <- make_context(in_reply_to), cw <- data["spoiler_text"] || "", @@ -179,7 +179,7 @@ defmodule Pleroma.Web.CommonAPI do Map.put( object, "emoji", - Formatter.get_emoji_map(full_payload) + Map.merge(Formatter.get_emoji_map(full_payload), poll_emoji) ) do res = ActivityPub.create( diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 2ea997789..cd8483c11 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -102,26 +102,15 @@ defmodule Pleroma.Web.CommonAPI.Utils do end end - def make_poll_data( - %{"poll" => %{"options" => options, "expires_in" => expires_in}} = data, - mentions, - tags - ) + def make_poll_data(%{"poll" => %{"options" => options, "expires_in" => expires_in}} = data) when is_list(options) and is_integer(expires_in) do - content_type = get_content_type(data["content_type"]) - # XXX: There is probably a more performant/cleaner way to do this - {poll, {mentions, tags}} = - Enum.map_reduce(options, {mentions, tags}, fn option, {mentions, tags} -> - # TODO: Custom emoji - {option, mentions_merge, tags_merge} = format_input(option, content_type) - mentions = mentions ++ mentions_merge - tags = tags ++ tags_merge - + {poll, emoji} = + Enum.map_reduce(options, %{}, fn option, emoji -> {%{ "name" => option, "type" => "Note", "replies" => %{"type" => "Collection", "totalItems" => 0} - }, {mentions, tags}} + }, Map.merge(emoji, Formatter.get_emoji_map(option))} end) end_time = @@ -136,11 +125,11 @@ defmodule Pleroma.Web.CommonAPI.Utils do %{"type" => "Question", "oneOf" => poll, "closed" => end_time} end - {poll, mentions, tags} + {poll, emoji} end - def make_poll_data(_data, mentions, tags) do - {%{}, mentions, tags} + def make_poll_data(_data) do + {%{}, %{}} end def make_content_html( diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 2a5691e1f..0df8bb5c2 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -325,7 +325,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do end # TODO: Add tests for this view - def render("poll.json", %{object: object} = opts) do + def render("poll.json", %{object: object} = _opts) do {multiple, options} = case object.data do %{"anyOf" => options} when is_list(options) -> {true, options} @@ -350,13 +350,10 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do options = Enum.map(options, fn %{"name" => name} = option -> - name = - HTML.filter_tags( - name, - User.html_filter_policy(opts[:for]) - ) - - %{title: name, votes_count: option["replies"]["votes_count"] || 0} + %{ + title: HTML.strip_tags(name), + votes_count: option["replies"]["votes_count"] || 0 + } end) %{ @@ -367,6 +364,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do multiple: multiple, votes_count: votes_count, options: options, + # TODO: Actually check for a vote voted: false, emojis: build_emojis(object.data["emoji"]) } -- cgit v1.2.3 From 6430cb1bf78e7949cc023a30df7a8d1547c36524 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sun, 19 May 2019 17:44:18 +0300 Subject: Restrict poll replies from fetch queries by default --- lib/pleroma/web/activity_pub/activity_pub.ex | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 5c3156978..035fb75d5 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -820,6 +820,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do defp restrict_muted_reblogs(query, _), do: query + defp restrict_poll_replies(query, %{"include_poll_replies" => "true"}), do: query + + defp restrict_poll_replies(query, _) do + if has_named_binding?(query, :object) do + from([activity, object: o] in query, where: fragment("?->'name' is null", o.data)) + else + query + end + end + defp maybe_preload_objects(query, %{"skip_preload" => true}), do: query defp maybe_preload_objects(query, _) do @@ -873,6 +883,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> restrict_pinned(opts) |> restrict_muted_reblogs(opts) |> Activity.restrict_deactivated_users() + |> restrict_poll_replies(opts) end def fetch_activities(recipients, opts \\ %{}) do -- cgit v1.2.3 From 2375e9a95ba9042958ff7e8f75830df4ab53fed2 Mon Sep 17 00:00:00 2001 From: Aaron Tinio Date: Mon, 20 May 2019 06:02:50 +0800 Subject: Add report filtering to MRF.SimplePolicy --- lib/pleroma/web/activity_pub/mrf/simple_policy.ex | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex index 9627c3400..7190652d2 100644 --- a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex @@ -94,6 +94,16 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do {:ok, object} end + defp check_report_removal(%{host: actor_host} = _actor_info, %{"type" => "Flag"} = object) do + if actor_host in Pleroma.Config.get([:mrf_simple, :report_removal]) do + {:reject, nil} + else + {:ok, object} + end + end + + defp check_report_removal(_actor_info, object), do: {:ok, object} + @impl true def filter(object) do actor_info = URI.parse(object["actor"]) @@ -102,7 +112,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do {:ok, object} <- check_reject(actor_info, object), {:ok, object} <- check_media_removal(actor_info, object), {:ok, object} <- check_media_nsfw(actor_info, object), - {:ok, object} <- check_ftl_removal(actor_info, object) do + {:ok, object} <- check_ftl_removal(actor_info, object), + {:ok, object} <- check_report_removal(actor_info, object) do {:ok, object} else _e -> {:reject, nil} -- cgit v1.2.3 From 54e9cb5c2db580bc12441f3651fa87a7b976137d Mon Sep 17 00:00:00 2001 From: Sadposter Date: Mon, 20 May 2019 12:39:23 +0100 Subject: Add API endpoints for a custom user mascot --- lib/pleroma/user/info.ex | 21 +++++++++++++ .../web/mastodon_api/mastodon_api_controller.ex | 36 +++++++++++++++++++++- lib/pleroma/web/router.ex | 3 ++ 3 files changed, 59 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 5f0cefc00..ffcd06e3e 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -43,6 +43,19 @@ defmodule Pleroma.User.Info do field(:hide_favorites, :boolean, default: true) field(:pinned_activities, {:array, :string}, default: []) field(:flavour, :string, default: nil) + + field(:mascot, :map, + default: %{ + id: "pleromatan", + url: "/images/pleroma-fox-tan-smol.png", + type: "image", + preview_url: "/images/pleroma-fox-tan-smol.png", + pleroma: %{ + mime_type: "image/png" + } + } + ) + field(:emoji, {:array, :map}, default: []) field(:notification_settings, :map, @@ -248,6 +261,14 @@ defmodule Pleroma.User.Info do |> validate_required([:flavour]) end + def mascot_update(info, url) do + params = %{mascot: url} + + info + |> cast(params, [:mascot]) + |> validate_required([:mascot]) + end + def set_source_data(info, source_data) do params = %{source_data: source_data} diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 1051861ff..67f363859 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -707,6 +707,40 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end end + def set_mascot(%{assigns: %{user: user}} = conn, %{"file" => file}) do + with {:ok, object} <- ActivityPub.upload(file, actor: User.ap_id(user)), + %{} = attachment_data <- Map.put(object.data, "id", object.id), + %{type: type} = rendered <- + StatusView.render("attachment.json", %{attachment: attachment_data}) do + # Reject if not an image + if type == "image" do + # Sure! + # Save to the user's info + info_changeset = User.Info.mascot_update(user.info, rendered) + + user_changeset = + user + |> Ecto.Changeset.change() + |> Ecto.Changeset.put_embed(:info, info_changeset) + + {:ok, _user} = User.update_and_set_cache(user_changeset) + + conn + |> json(rendered) + else + conn + |> send_resp(415, Jason.encode!(%{"error" => "mascots can only be images"})) + end + end + end + + def get_mascot(%{assigns: %{user: user}} = conn, _params) do + %{info: %{mascot: mascot}} = user + + conn + |> json(mascot) + end + def favourited_by(%{assigns: %{user: user}} = conn, %{"id" => id}) do with %Activity{data: %{"object" => object}} <- Repo.get(Activity, id), %Object{data: %{"likes" => likes}} <- Object.normalize(object) do @@ -1329,7 +1363,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do display_sensitive_media: false, reduce_motion: false, max_toot_chars: limit, - mascot: "/images/pleroma-fox-tan-smol.png" + mascot: Map.get(user.info.mascot, "url", "/images/pleroma-fox-tan-smol.png") }, rights: %{ delete_others_notice: present?(user.info.is_moderator), diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 6a4e4a1d4..4c29b24eb 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -352,6 +352,9 @@ defmodule Pleroma.Web.Router do post("/pleroma/flavour/:flavour", MastodonAPIController, :set_flavour) + get("/pleroma/mascot", MastodonAPIController, :get_mascot) + put("/pleroma/mascot", MastodonAPIController, :set_mascot) + post("/reports", MastodonAPIController, :reports) end -- cgit v1.2.3 From e81f0fc6d45249dd70656c58af926c21c70c482f Mon Sep 17 00:00:00 2001 From: Sadposter Date: Mon, 20 May 2019 12:58:06 +0100 Subject: Add mascot get/set tests --- lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 67f363859..d7f095a1f 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -729,6 +729,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do |> json(rendered) else conn + |> put_resp_content_type("application/json") |> send_resp(415, Jason.encode!(%{"error" => "mascots can only be images"})) end end -- cgit v1.2.3 From 3d0d9e7a5680bcb1b79e5f4aab0e8c514fc9e5ff Mon Sep 17 00:00:00 2001 From: Sadposter Date: Mon, 20 May 2019 13:10:04 +0100 Subject: Use string map for default mascot --- lib/pleroma/user/info.ex | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index ffcd06e3e..e76d04d7f 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -46,12 +46,12 @@ defmodule Pleroma.User.Info do field(:mascot, :map, default: %{ - id: "pleromatan", - url: "/images/pleroma-fox-tan-smol.png", - type: "image", - preview_url: "/images/pleroma-fox-tan-smol.png", - pleroma: %{ - mime_type: "image/png" + "id" => "pleromatan", + "url" => "/images/pleroma-fox-tan-smol.png", + "type" => "image", + "preview_url" => "/images/pleroma-fox-tan-smol.png", + "pleroma" => %{ + "mime_type" => "image/png" } } ) -- cgit v1.2.3 From daeae8e2e7c506b72c66dea6ac790408f948ec16 Mon Sep 17 00:00:00 2001 From: Sadposter Date: Mon, 20 May 2019 16:12:55 +0100 Subject: Move default mascot configuration to `config/` --- lib/pleroma/user.ex | 20 ++++++++++++++++++++ lib/pleroma/user/info.ex | 14 +------------- .../web/mastodon_api/mastodon_api_controller.ex | 4 ++-- 3 files changed, 23 insertions(+), 15 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 28da310ee..05fe58f7c 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1402,4 +1402,24 @@ defmodule Pleroma.User do |> put_embed(:info, info_changeset) |> update_and_set_cache() end + + def get_mascot(%{info: %{mascot: %{} = mascot}}) when not is_nil(mascot) do + mascot + end + + def get_mascot(%{info: %{mascot: mascot}}) when is_nil(mascot) do + # use instance-default + config = Pleroma.Config.get([:assets, :mascots]) + default_mascot = Pleroma.Config.get([:assets, :default_mascot]) + mascot = Keyword.get(config, default_mascot) + + %{ + "id" => "default-mascot", + "url" => mascot[:url], + "preview_url" => mascot[:url], + "pleroma" => %{ + "mime_type" => mascot[:mime_type] + } + } + end end diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index e76d04d7f..6397e2737 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -43,19 +43,7 @@ defmodule Pleroma.User.Info do field(:hide_favorites, :boolean, default: true) field(:pinned_activities, {:array, :string}, default: []) field(:flavour, :string, default: nil) - - field(:mascot, :map, - default: %{ - "id" => "pleromatan", - "url" => "/images/pleroma-fox-tan-smol.png", - "type" => "image", - "preview_url" => "/images/pleroma-fox-tan-smol.png", - "pleroma" => %{ - "mime_type" => "image/png" - } - } - ) - + field(:mascot, :map, default: nil) field(:emoji, {:array, :map}, default: []) field(:notification_settings, :map, diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index d7f095a1f..1ec0f30a1 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -736,7 +736,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end def get_mascot(%{assigns: %{user: user}} = conn, _params) do - %{info: %{mascot: mascot}} = user + mascot = User.get_mascot(user) conn |> json(mascot) @@ -1364,7 +1364,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do display_sensitive_media: false, reduce_motion: false, max_toot_chars: limit, - mascot: Map.get(user.info.mascot, "url", "/images/pleroma-fox-tan-smol.png") + mascot: User.get_mascot(user)["url"] }, rights: %{ delete_others_notice: present?(user.info.is_moderator), -- cgit v1.2.3 From eb02edcad9cb0d65fc216408960aec63713e5d2b Mon Sep 17 00:00:00 2001 From: Aaron Tinio Date: Tue, 21 May 2019 00:35:46 +0800 Subject: Add virtual :thread_muted? field that may be set when fetching activities --- lib/pleroma/activity.ex | 12 ++++++++++++ lib/pleroma/web/activity_pub/activity_pub.ex | 8 ++++++++ lib/pleroma/web/mastodon_api/views/status_view.ex | 8 +++++++- lib/pleroma/web/twitter_api/views/activity_view.ex | 8 +++++++- 4 files changed, 34 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index 4e54b15ba..99589590c 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -10,6 +10,7 @@ defmodule Pleroma.Activity do alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Repo + alias Pleroma.ThreadMute alias Pleroma.User import Ecto.Changeset @@ -37,6 +38,7 @@ defmodule Pleroma.Activity do field(:local, :boolean, default: true) field(:actor, :string) field(:recipients, {:array, :string}, default: []) + field(:thread_muted?, :boolean, virtual: true) # This is a fake relation, do not use outside of with_preloaded_bookmark/get_bookmark has_one(:bookmark, Bookmark) has_many(:notifications, Notification, on_delete: :delete_all) @@ -90,6 +92,16 @@ defmodule Pleroma.Activity do def with_preloaded_bookmark(query, _), do: query + def with_set_thread_muted_field(query, %User{} = user) do + from([a] in query, + left_join: tm in ThreadMute, + on: tm.user_id == ^user.id and tm.context == fragment("?->>'context'", a.data), + select: %Activity{a | thread_muted?: not is_nil(tm.id)} + ) + end + + def with_set_thread_muted_field(query, _), do: query + def get_by_ap_id(ap_id) do Repo.one( from( diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 5c3156978..3d9679ec0 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -834,6 +834,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> Activity.with_preloaded_bookmark(opts["user"]) end + defp maybe_set_thread_muted_field(query, %{"skip_preload" => true}), do: query + + defp maybe_set_thread_muted_field(query, opts) do + query + |> Activity.with_set_thread_muted_field(opts["user"]) + end + defp maybe_order(query, %{order: :desc}) do query |> order_by(desc: :id) @@ -852,6 +859,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do base_query |> maybe_preload_objects(opts) |> maybe_preload_bookmarks(opts) + |> maybe_set_thread_muted_field(opts) |> maybe_order(opts) |> restrict_recipients(recipients, opts["user"]) |> restrict_tag(opts) diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index c93d915e5..e55f9b96e 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -157,6 +157,12 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do bookmarked = Activity.get_bookmark(activity, opts[:for]) != nil + thread_muted? = + case activity.thread_muted? do + thread_muted? when is_boolean(thread_muted?) -> thread_muted? + nil -> CommonAPI.thread_muted?(user, activity) + end + attachment_data = object.data["attachment"] || [] attachments = render_many(attachment_data, StatusView, "attachment.json", as: :attachment) @@ -228,7 +234,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do reblogged: reblogged?(activity, opts[:for]), favourited: present?(favorited), bookmarked: present?(bookmarked), - muted: CommonAPI.thread_muted?(user, activity) || User.mutes?(opts[:for], user), + muted: thread_muted? || User.mutes?(opts[:for], user), pinned: pinned?(activity, user), sensitive: sensitive, spoiler_text: summary_html, diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex index 44bcafe0e..e84af84dc 100644 --- a/lib/pleroma/web/twitter_api/views/activity_view.ex +++ b/lib/pleroma/web/twitter_api/views/activity_view.ex @@ -284,6 +284,12 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) ) + thread_muted? = + case activity.thread_muted? do + thread_muted? when is_boolean(thread_muted?) -> thread_muted? + nil -> CommonAPI.thread_muted?(user, activity) + end + %{ "id" => activity.id, "uri" => object.data["id"], @@ -314,7 +320,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do "summary" => summary, "summary_html" => summary |> Formatter.emojify(object.data["emoji"]), "card" => card, - "muted" => CommonAPI.thread_muted?(user, activity) || User.mutes?(opts[:for], user) + "muted" => thread_muted? || User.mutes?(opts[:for], user) } end -- cgit v1.2.3 From f96e9b28bb5ee241a3f0ca6a622b925ca560c141 Mon Sep 17 00:00:00 2001 From: Aaron Tinio Date: Tue, 21 May 2019 07:30:18 +0800 Subject: Fix prometheus-ecto error when not configured --- lib/pleroma/application.ex | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index eeb415084..dab45a0b2 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -131,19 +131,22 @@ defmodule Pleroma.Application do defp setup_instrumenters do require Prometheus.Registry - :ok = - :telemetry.attach( - "prometheus-ecto", - [:pleroma, :repo, :query], - &Pleroma.Repo.Instrumenter.handle_event/4, - %{} - ) + if Application.get_env(:prometheus, Pleroma.Repo.Instrumenter) do + :ok = + :telemetry.attach( + "prometheus-ecto", + [:pleroma, :repo, :query], + &Pleroma.Repo.Instrumenter.handle_event/4, + %{} + ) + + Pleroma.Repo.Instrumenter.setup() + end Prometheus.Registry.register_collector(:prometheus_process_collector) Pleroma.Web.Endpoint.MetricsExporter.setup() Pleroma.Web.Endpoint.PipelineInstrumenter.setup() Pleroma.Web.Endpoint.Instrumenter.setup() - Pleroma.Repo.Instrumenter.setup() end def enabled_hackney_pools do -- cgit v1.2.3 From c972d0bb14ee5a65f053b8c9629d93fc9b94ca78 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Tue, 21 May 2019 04:58:26 +0000 Subject: http: bump connection timeout to 10 seconds --- lib/pleroma/http/connection.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/http/connection.ex b/lib/pleroma/http/connection.ex index c0173465a..558005c19 100644 --- a/lib/pleroma/http/connection.ex +++ b/lib/pleroma/http/connection.ex @@ -8,7 +8,7 @@ defmodule Pleroma.HTTP.Connection do """ @hackney_options [ - connect_timeout: 2_000, + connect_timeout: 10_000, recv_timeout: 20_000, follow_redirect: true, pool: :federation -- cgit v1.2.3 From 76a7429befb2e9a819b653ff8328cc42a565c29d Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 21 May 2019 09:13:10 +0300 Subject: Add poll limits to /api/v1/instance and initial state --- lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 1051861ff..81cc5a972 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -197,7 +197,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do languages: ["en"], registrations: Pleroma.Config.get([:instance, :registrations_open]), # Extra (not present in Mastodon): - max_toot_chars: Keyword.get(instance, :limit) + max_toot_chars: Keyword.get(instance, :limit), + poll_limits: Keyword.get(instance, :poll_limits) } json(conn, response) @@ -1331,6 +1332,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do max_toot_chars: limit, mascot: "/images/pleroma-fox-tan-smol.png" }, + poll_limits: Config.get([:instance, :poll_limits]), rights: %{ delete_others_notice: present?(user.info.is_moderator), admin: present?(user.info.is_admin) -- cgit v1.2.3 From 3f96b3e4b8114ec1cf924d452907b17c2aea2003 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 21 May 2019 10:54:20 +0300 Subject: Enforce poll limits and add error handling for MastodonAPI's post endpoint --- lib/pleroma/web/common_api/utils.ex | 69 ++++++++++++++++------ .../web/mastodon_api/mastodon_api_controller.ex | 45 +++++++++----- 2 files changed, 82 insertions(+), 32 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index cd8483c11..97172fd94 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -104,28 +104,61 @@ defmodule Pleroma.Web.CommonAPI.Utils do def make_poll_data(%{"poll" => %{"options" => options, "expires_in" => expires_in}} = data) when is_list(options) and is_integer(expires_in) do - {poll, emoji} = - Enum.map_reduce(options, %{}, fn option, emoji -> - {%{ - "name" => option, - "type" => "Note", - "replies" => %{"type" => "Collection", "totalItems" => 0} - }, Map.merge(emoji, Formatter.get_emoji_map(option))} - end) + %{max_expiration: max_expiration, min_expiration: min_expiration} = + limits = Pleroma.Config.get([:instance, :poll_limits]) - end_time = - NaiveDateTime.utc_now() - |> NaiveDateTime.add(expires_in) - |> NaiveDateTime.to_iso8601() + # XXX: There is probably a cleaner way of doing this + try do + if Enum.count(options) > limits.max_options do + raise ArgumentError, message: "Poll can't contain more than #{limits.max_options} options" + end - poll = - if Pleroma.Web.ControllerHelper.truthy_param?(data["poll"]["multiple"]) do - %{"type" => "Question", "anyOf" => poll, "closed" => end_time} - else - %{"type" => "Question", "oneOf" => poll, "closed" => end_time} + {poll, emoji} = + Enum.map_reduce(options, %{}, fn option, emoji -> + if String.length(option) > limits.max_option_chars do + raise ArgumentError, + message: + "Poll options cannot be longer than #{limits.max_option_chars} characters each" + end + + {%{ + "name" => option, + "type" => "Note", + "replies" => %{"type" => "Collection", "totalItems" => 0} + }, Map.merge(emoji, Formatter.get_emoji_map(option))} + end) + + case expires_in do + expires_in when expires_in > max_expiration -> + raise ArgumentError, message: "Expiration date is too far in the future" + + expires_in when expires_in < min_expiration -> + raise ArgumentError, message: "Expiration date is too soon" + + _ -> + :noop end - {poll, emoji} + end_time = + NaiveDateTime.utc_now() + |> NaiveDateTime.add(expires_in) + |> NaiveDateTime.to_iso8601() + + poll = + if Pleroma.Web.ControllerHelper.truthy_param?(data["poll"]["multiple"]) do + %{"type" => "Question", "anyOf" => poll, "closed" => end_time} + else + %{"type" => "Question", "oneOf" => poll, "closed" => end_time} + end + + {poll, emoji} + rescue + e in ArgumentError -> e.message + end + end + + def make_poll_data(%{"poll" => _}) do + "Invalid poll" end def make_poll_data(_data) do diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 81cc5a972..e2cab86f1 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -473,12 +473,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do params |> Map.put("in_reply_to_status_id", params["in_reply_to_id"]) - idempotency_key = - case get_req_header(conn, "idempotency-key") do - [key] -> key - _ -> Ecto.UUID.generate() - end - scheduled_at = params["scheduled_at"] if scheduled_at && ScheduledActivity.far_enough?(scheduled_at) do @@ -491,17 +485,40 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do else params = Map.drop(params, ["scheduled_at"]) - {:ok, activity} = - Cachex.fetch!(:idempotency_cache, idempotency_key, fn _ -> - CommonAPI.post(user, params) - end) - - conn - |> put_view(StatusView) - |> try_render("status.json", %{activity: activity, for: user, as: :activity}) + case get_cached_status_or_post(conn, params) do + {:ignore, message} -> + conn + |> put_status(401) + |> json(%{error: message}) + + {:error, message} -> + conn + |> put_status(401) + |> json(%{error: message}) + + {_, activity} -> + conn + |> put_view(StatusView) + |> try_render("status.json", %{activity: activity, for: user, as: :activity}) + end end end + defp get_cached_status_or_post(%{assigns: %{user: user}} = conn, params) do + idempotency_key = + case get_req_header(conn, "idempotency-key") do + [key] -> key + _ -> Ecto.UUID.generate() + end + + Cachex.fetch(:idempotency_cache, idempotency_key, fn _ -> + case CommonAPI.post(user, params) do + {:ok, activity} -> activity + {:error, message} -> {:ignore, message} + end + end) + end + def delete_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do with {:ok, %Activity{}} <- CommonAPI.delete(id, user) do json(conn, %{}) -- cgit v1.2.3 From aafe30d94e68ccf251c56139d07bda154dde3af9 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 21 May 2019 14:12:10 +0300 Subject: Handle poll votes --- lib/pleroma/object.ex | 30 ++++++++++++++++++++++++++++ lib/pleroma/web/activity_pub/activity_pub.ex | 10 ++++++++++ 2 files changed, 40 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index 740d687a3..a0f7659eb 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -188,4 +188,34 @@ defmodule Pleroma.Object do _ -> {:error, "Not found"} end end + + def increase_vote_count(ap_id, name) do + with %Object{} = object <- Object.normalize(ap_id), + "Question" <- object.data["type"] do + multiple = Map.has_key?(object.data, "anyOf") + + options = + (object.data["anyOf"] || object.data["oneOf"] || []) + |> Enum.map(fn + %{"name" => ^name} = option -> + Kernel.update_in(option["replies"]["totalItems"], &(&1 + 1)) + + option -> + option + end) + + data = + if multiple do + Map.put(object.data, "anyOf", options) + else + Map.put(object.data, "oneOf", options) + end + + object + |> Object.change(%{data: data}) + |> update_and_set_cache() + else + _ -> :noop + end + end end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 035fb75d5..ce78d895b 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -108,6 +108,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do def decrease_replies_count_if_reply(_object), do: :noop + def increase_poll_votes_if_vote(%{ + "object" => %{"inReplyTo" => reply_ap_id, "name" => name}, + "type" => "Create" + }) do + Object.increase_vote_count(reply_ap_id, name) + end + + def increase_poll_votes_if_vote(_create_data), do: :noop + def insert(map, local \\ true, fake \\ false) when is_map(map) do with nil <- Activity.normalize(map), map <- lazy_put_activity_defaults(map, fake), @@ -235,6 +244,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do {:ok, activity} <- insert(create_data, local, fake), {:fake, false, activity} <- {:fake, fake, activity}, _ <- increase_replies_count_if_reply(create_data), + _ <- increase_poll_votes_if_vote(create_data), # Changing note count prior to enqueuing federation task in order to avoid # race conditions on updating user.info {:ok, _actor} <- increase_note_count_if_public(actor, activity), -- cgit v1.2.3 From a53d06273080525fdda332291838b0c95ed69690 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 21 May 2019 14:19:03 +0300 Subject: Fix posting non-polls from mastofe --- lib/pleroma/web/common_api/utils.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 97172fd94..66153a105 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -157,7 +157,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do end end - def make_poll_data(%{"poll" => _}) do + def make_poll_data(%{"poll" => poll}) when is_map(poll) do "Invalid poll" end -- cgit v1.2.3 From f28747858bf3265e8b82eb587919f5a89386bed7 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 21 May 2019 14:27:09 +0300 Subject: Actual vote count in poll view --- lib/pleroma/web/mastodon_api/views/status_view.ex | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 0df8bb5c2..c501c213c 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -338,8 +338,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do (object.data["closed"] || object.data["endTime"]) |> NaiveDateTime.from_iso8601!() - votes_count = object.data["votes_count"] || 0 - expired = end_time |> NaiveDateTime.compare(NaiveDateTime.utc_now()) @@ -348,12 +346,14 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do _ -> false end - options = - Enum.map(options, fn %{"name" => name} = option -> - %{ - title: HTML.strip_tags(name), - votes_count: option["replies"]["votes_count"] || 0 - } + {options, votes_count} = + Enum.map_reduce(options, 0, fn %{"name" => name} = option, count -> + current_count = option["replies"]["totalItems"] || 0 + + {%{ + title: HTML.strip_tags(name), + votes_count: current_count + }, current_count + count} end) %{ -- cgit v1.2.3 From d7c4d029c82c833278b3640d585235dc704f30d1 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 21 May 2019 14:35:20 +0300 Subject: Restrict poll replies when fetching activiites for context --- lib/pleroma/web/activity_pub/activity_pub.ex | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index ce78d895b..c04e6c2b8 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -491,6 +491,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do from(activity in Activity) |> restrict_blocked(opts) + |> restrict_poll_replies(opts) |> restrict_recipients(recipients, opts["user"]) |> where( [activity], -- cgit v1.2.3 From ee682441415d7abe4acb2643e1d76fe8d78e80c1 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 21 May 2019 16:58:15 +0300 Subject: Do not stream out poll replies --- lib/pleroma/web/activity_pub/activity_pub.ex | 54 ++++++++++++++-------------- 1 file changed, 28 insertions(+), 26 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index c04e6c2b8..fdebf1f6b 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -192,40 +192,42 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do public = "https://www.w3.org/ns/activitystreams#Public" if activity.data["type"] in ["Create", "Announce", "Delete"] do - Pleroma.Web.Streamer.stream("user", activity) - Pleroma.Web.Streamer.stream("list", activity) + object = Object.normalize(activity) + # Do not stream out poll replies + unless object.data["name"] do + Pleroma.Web.Streamer.stream("user", activity) + Pleroma.Web.Streamer.stream("list", activity) - if Enum.member?(activity.data["to"], public) do - Pleroma.Web.Streamer.stream("public", activity) + if Enum.member?(activity.data["to"], public) do + Pleroma.Web.Streamer.stream("public", activity) - if activity.local do - Pleroma.Web.Streamer.stream("public:local", activity) - end - - if activity.data["type"] in ["Create"] do - object = Object.normalize(activity) + if activity.local do + Pleroma.Web.Streamer.stream("public:local", activity) + end - object.data - |> Map.get("tag", []) - |> Enum.filter(fn tag -> is_bitstring(tag) end) - |> Enum.each(fn tag -> Pleroma.Web.Streamer.stream("hashtag:" <> tag, activity) end) + if activity.data["type"] in ["Create"] do + object.data + |> Map.get("tag", []) + |> Enum.filter(fn tag -> is_bitstring(tag) end) + |> Enum.each(fn tag -> Pleroma.Web.Streamer.stream("hashtag:" <> tag, activity) end) - if object.data["attachment"] != [] do - Pleroma.Web.Streamer.stream("public:media", activity) + if object.data["attachment"] != [] do + Pleroma.Web.Streamer.stream("public:media", activity) - if activity.local do - Pleroma.Web.Streamer.stream("public:local:media", activity) + if activity.local do + Pleroma.Web.Streamer.stream("public:local:media", activity) + end end end + else + # TODO: Write test, replace with visibility test + if !Enum.member?(activity.data["cc"] || [], public) && + !Enum.member?( + activity.data["to"], + User.get_cached_by_ap_id(activity.data["actor"]).follower_address + ), + do: Pleroma.Web.Streamer.stream("direct", activity) end - else - # TODO: Write test, replace with visibility test - if !Enum.member?(activity.data["cc"] || [], public) && - !Enum.member?( - activity.data["to"], - User.get_cached_by_ap_id(activity.data["actor"]).follower_address - ), - do: Pleroma.Web.Streamer.stream("direct", activity) end end end -- cgit v1.2.3 From 0407ffe75f7e91db240d491492eadf1385b1726b Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 21 May 2019 17:12:38 +0300 Subject: Change validation error status codes to be more appropriate --- lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index e2cab86f1..aef2abf0b 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -488,12 +488,12 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do case get_cached_status_or_post(conn, params) do {:ignore, message} -> conn - |> put_status(401) + |> put_status(422) |> json(%{error: message}) {:error, message} -> conn - |> put_status(401) + |> put_status(422) |> json(%{error: message}) {_, activity} -> -- cgit v1.2.3 From 5f67c26baf2bdc98480fa4cda5895f33351b13ab Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 21 May 2019 17:30:51 +0300 Subject: Accept strings in expires_in because sasuga javascript --- lib/pleroma/web/common_api/utils.ex | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 66153a105..1a239de97 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -103,12 +103,15 @@ defmodule Pleroma.Web.CommonAPI.Utils do end def make_poll_data(%{"poll" => %{"options" => options, "expires_in" => expires_in}} = data) - when is_list(options) and is_integer(expires_in) do + when is_list(options) do %{max_expiration: max_expiration, min_expiration: min_expiration} = limits = Pleroma.Config.get([:instance, :poll_limits]) # XXX: There is probably a cleaner way of doing this try do + # In some cases mastofe sends out strings instead of integers + expires_in = if is_binary(expires_in), do: String.to_integer(expires_in), else: expires_in + if Enum.count(options) > limits.max_options do raise ArgumentError, message: "Poll can't contain more than #{limits.max_options} options" end -- cgit v1.2.3 From ff61d345020b9ee79b243fb8d23a37a06cc41b8e Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 21 May 2019 17:33:54 +0300 Subject: Accept question objects for conversations --- lib/pleroma/conversation.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/conversation.ex b/lib/pleroma/conversation.ex index 238c1acf2..bc97b39ca 100644 --- a/lib/pleroma/conversation.ex +++ b/lib/pleroma/conversation.ex @@ -49,7 +49,7 @@ defmodule Pleroma.Conversation do with true <- Pleroma.Web.ActivityPub.Visibility.is_direct?(activity), "Create" <- activity.data["type"], object <- Pleroma.Object.normalize(activity), - "Note" <- object.data["type"], + true <- object.data["type"] in ["Note", "Question"], ap_id when is_binary(ap_id) and byte_size(ap_id) > 0 <- object.data["context"] do {:ok, conversation} = create_for_ap_id(ap_id) -- cgit v1.2.3 From 63b0b7190cb652cd27d236e3f9daaaf5e50701a6 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Tue, 21 May 2019 20:40:35 +0300 Subject: MastoAPI: Add GET /api/v1/polls/:id --- lib/pleroma/object.ex | 3 +++ .../web/mastodon_api/mastodon_api_controller.ex | 20 ++++++++++++++++++++ lib/pleroma/web/router.ex | 2 ++ 3 files changed, 25 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index a0f7659eb..3ffa290eb 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -35,6 +35,9 @@ defmodule Pleroma.Object do |> unique_constraint(:ap_id, name: :objects_unique_apid_index) end + def get_by_id(nil), do: nil + def get_by_id(id), do: Repo.get(Object, id) + def get_by_ap_id(nil), do: nil def get_by_ap_id(ap_id) do diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index aef2abf0b..ecb7df459 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -410,6 +410,26 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do end end + def get_poll(%{assigns: %{user: user}} = conn, %{"id" => id}) do + with %Object{} = object <- Object.get_by_id(id), + %Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]), + true <- Visibility.visible_for_user?(activity, user) do + conn + |> put_view(StatusView) + |> try_render("poll.json", %{object: object, for: user}) + else + nil -> + conn + |> put_status(404) + |> json(%{error: "Record not found"}) + + false -> + conn + |> put_status(404) + |> json(%{error: "Record not found"}) + end + end + def scheduled_statuses(%{assigns: %{user: user}} = conn, params) do with scheduled_activities <- MastodonAPI.get_scheduled_activities(user, params) do conn diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 6a4e4a1d4..e0611e3fc 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -423,6 +423,8 @@ defmodule Pleroma.Web.Router do get("/statuses/:id", MastodonAPIController, :get_status) get("/statuses/:id/context", MastodonAPIController, :get_context) + get("/polls/:id", MastodonAPIController, :get_poll) + get("/accounts/:id/statuses", MastodonAPIController, :user_statuses) get("/accounts/:id/followers", MastodonAPIController, :followers) get("/accounts/:id/following", MastodonAPIController, :following) -- cgit v1.2.3 From c2b0b82e6a6d40f945feacc001ad984a17e23336 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Tue, 21 May 2019 00:41:40 +0000 Subject: object: add Object.prune() --- lib/pleroma/object.ex | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index 740d687a3..cc6fc9c5d 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -130,6 +130,13 @@ defmodule Pleroma.Object do end end + def prune(%Object{data: %{"id" => id}} = object) do + with {:ok, object} <- Repo.delete(object), + {:ok, true} <- Cachex.del(:object_cache, "object:#{id}") do + {:ok, object} + end + end + def set_cache(%Object{data: %{"id" => ap_id}} = object) do Cachex.put(:object_cache, "object:#{ap_id}", object) {:ok, object} -- cgit v1.2.3 From 73df9d690d5c1a9c11f0f04b8d877c0677022591 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Tue, 21 May 2019 00:41:58 +0000 Subject: object: fetcher: add support for reinjecting pruned objects --- lib/pleroma/object/fetcher.ex | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index 8d4bcc95e..bb9388d4f 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -8,6 +8,19 @@ defmodule Pleroma.Object.Fetcher do @httpoison Application.get_env(:pleroma, :httpoison) + defp reinject_object(data) do + Logger.debug("Reinjecting object #{data["id"]}") + + with data <- Transmogrifier.fix_object(data), + {:ok, object} <- Object.create(data) do + {:ok, object} + else + e -> + Logger.error("Error while processing object: #{inspect(e)}") + {:error, e} + end + end + # TODO: # This will create a Create activity, which we need internally at the moment. def fetch_object_from_id(id) do @@ -26,12 +39,17 @@ defmodule Pleroma.Object.Fetcher do "object" => data }, :ok <- Containment.contain_origin(id, params), - {:ok, activity} <- Transmogrifier.handle_incoming(params) do - {:ok, Object.normalize(activity, false)} + {:ok, activity} <- Transmogrifier.handle_incoming(params), + {:object, _data, %Object{} = object} <- + {:object, data, Object.normalize(activity, false)} do + {:ok, object} else {:error, {:reject, nil}} -> {:reject, nil} + {:object, data, nil} -> + reinject_object(data) + object = %Object{} -> {:ok, object} -- cgit v1.2.3 From 16b260fb19cca02463766c2e36a41bfcc823af9b Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Tue, 21 May 2019 01:21:28 +0000 Subject: add mix task to prune the object database using a configured retention period --- lib/mix/tasks/pleroma/database.ex | 40 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/database.ex b/lib/mix/tasks/pleroma/database.ex index f650b447d..fdb216037 100644 --- a/lib/mix/tasks/pleroma/database.ex +++ b/lib/mix/tasks/pleroma/database.ex @@ -23,6 +23,10 @@ defmodule Mix.Tasks.Pleroma.Database do Options: - `--vacuum` - run `VACUUM FULL` after the embedded objects are replaced with their references + ## Prune old objects from the database + + mix pleroma.database prune_objects + ## Create a conversation for all existing DMs. Can be safely re-run. mix pleroma.database bump_all_conversations @@ -72,4 +76,40 @@ defmodule Mix.Tasks.Pleroma.Database do Enum.each(users, &User.remove_duplicated_following/1) Enum.each(users, &User.update_follower_count/1) end + + def run(["prune_objects" | args]) do + {options, [], []} = + OptionParser.parse( + args, + strict: [ + vacuum: :boolean + ] + ) + + Common.start_pleroma() + + deadline = Pleroma.Config.get([:instance, :remote_post_retention_days]) + + Logger.info("Pruning objects older than #{deadline} days") + + time_deadline = + NaiveDateTime.utc_now() + |> NaiveDateTime.add(-(deadline * 86_400)) + + Repo.query!( + "DELETE FROM objects WHERE inserted_at < $1 AND split_part(data->>'actor', '/', 3) != $2", + [time_deadline, Pleroma.Web.Endpoint.host()], + timeout: :infinity + ) + + if Keyword.get(options, :vacuum) do + Logger.info("Runnning VACUUM FULL") + + Repo.query!( + "vacuum full;", + [], + timeout: :infinity + ) + end + end end -- cgit v1.2.3 From 3ab9255eda21a5f8a25047375af9608e0c0c7592 Mon Sep 17 00:00:00 2001 From: Aaron Tinio Date: Tue, 21 May 2019 09:40:29 +0800 Subject: Respond with a 404 Not implemented JSON error message when requested API is not implemented --- lib/pleroma/web/router.ex | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 4c29b24eb..49e28cc2d 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -710,6 +710,7 @@ defmodule Pleroma.Web.Router do scope "/", Fallback do get("/registration/:token", RedirectController, :registration_page) get("/:maybe_nickname_or_id", RedirectController, :redirector_with_meta) + get("/api*path", RedirectController, :api_not_implemented) get("/*path", RedirectController, :redirector) options("/*path", RedirectController, :empty) @@ -721,6 +722,12 @@ defmodule Fallback.RedirectController do alias Pleroma.User alias Pleroma.Web.Metadata + 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") -- cgit v1.2.3 From a023ca004cbd90e330cab35e4dfda16346d08668 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Wed, 22 May 2019 03:12:48 +0000 Subject: prune objects task: use Repo.delete_all() --- lib/mix/tasks/pleroma/database.ex | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/database.ex b/lib/mix/tasks/pleroma/database.ex index fdb216037..f9bafb277 100644 --- a/lib/mix/tasks/pleroma/database.ex +++ b/lib/mix/tasks/pleroma/database.ex @@ -5,6 +5,7 @@ defmodule Mix.Tasks.Pleroma.Database do alias Mix.Tasks.Pleroma.Common alias Pleroma.Conversation + alias Pleroma.Object alias Pleroma.Repo alias Pleroma.User require Logger @@ -78,6 +79,8 @@ defmodule Mix.Tasks.Pleroma.Database do end def run(["prune_objects" | args]) do + import Ecto.Query + {options, [], []} = OptionParser.parse( args, @@ -96,11 +99,15 @@ defmodule Mix.Tasks.Pleroma.Database do NaiveDateTime.utc_now() |> NaiveDateTime.add(-(deadline * 86_400)) - Repo.query!( - "DELETE FROM objects WHERE inserted_at < $1 AND split_part(data->>'actor', '/', 3) != $2", - [time_deadline, Pleroma.Web.Endpoint.host()], - timeout: :infinity + public = "https://www.w3.org/ns/activitystreams#Public" + + from(o in Object, + where: fragment("?->'to' \\? ? OR ?->'cc' \\? ?", o.data, ^public, o.data, ^public), + where: o.inserted_at < ^time_deadline, + where: + fragment("split_part(?->>'actor', '/', 3) != ?", o.data, ^Pleroma.Web.Endpoint.host()) ) + |> Repo.delete_all() if Keyword.get(options, :vacuum) do Logger.info("Runnning VACUUM FULL") -- cgit v1.2.3 From 045803346d70c1f9c6ea770485904fd7cc52969a Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Wed, 22 May 2019 03:58:15 +0000 Subject: move key generation functions into Pleroma.Keys module --- lib/pleroma/keys.ex | 44 ++++++++++++++++++++++ lib/pleroma/signature.ex | 7 ++-- lib/pleroma/user.ex | 21 +++++++++++ .../web/activity_pub/activity_pub_controller.ex | 14 +++---- lib/pleroma/web/activity_pub/views/user_view.ex | 11 +++--- lib/pleroma/web/federator/federator.ex | 6 +-- lib/pleroma/web/salmon/salmon.ex | 44 ++-------------------- lib/pleroma/web/web_finger/web_finger.ex | 26 +------------ 8 files changed, 87 insertions(+), 86 deletions(-) create mode 100644 lib/pleroma/keys.ex (limited to 'lib') diff --git a/lib/pleroma/keys.ex b/lib/pleroma/keys.ex new file mode 100644 index 000000000..b7bc7a4da --- /dev/null +++ b/lib/pleroma/keys.ex @@ -0,0 +1,44 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Keys do + # Native generation of RSA keys is only available since OTP 20+ and in default build conditions + # We try at compile time to generate natively an RSA key otherwise we fallback on the old way. + try do + _ = :public_key.generate_key({:rsa, 2048, 65_537}) + + def generate_rsa_pem do + key = :public_key.generate_key({:rsa, 2048, 65_537}) + entry = :public_key.pem_entry_encode(:RSAPrivateKey, key) + pem = :public_key.pem_encode([entry]) |> String.trim_trailing() + {:ok, pem} + end + rescue + _ -> + def generate_rsa_pem do + port = Port.open({:spawn, "openssl genrsa"}, [:binary]) + + {:ok, pem} = + receive do + {^port, {:data, pem}} -> {:ok, pem} + end + + Port.close(port) + + if Regex.match?(~r/RSA PRIVATE KEY/, pem) do + {:ok, pem} + else + :error + end + end + end + + def keys_from_pem(pem) do + [private_key_code] = :public_key.pem_decode(pem) + private_key = :public_key.pem_entry_decode(private_key_code) + {:RSAPrivateKey, _, modulus, exponent, _, _, _, _, _, _, _} = private_key + public_key = {:RSAPublicKey, modulus, exponent} + {:ok, private_key, public_key} + end +end diff --git a/lib/pleroma/signature.ex b/lib/pleroma/signature.ex index b7ecf00a0..1a4d54c62 100644 --- a/lib/pleroma/signature.ex +++ b/lib/pleroma/signature.ex @@ -5,11 +5,10 @@ defmodule Pleroma.Signature do @behaviour HTTPSignatures.Adapter + alias Pleroma.Keys alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Utils - alias Pleroma.Web.Salmon - alias Pleroma.Web.WebFinger def fetch_public_key(conn) do with actor_id <- Utils.get_ap_id(conn.params["actor"]), @@ -33,8 +32,8 @@ defmodule Pleroma.Signature do end def sign(%User{} = user, headers) do - with {:ok, %{info: %{keys: keys}}} <- WebFinger.ensure_keys_present(user), - {:ok, private_key, _} <- Salmon.keys_from_pem(keys) do + with {:ok, %{info: %{keys: keys}}} <- User.ensure_keys_present(user), + {:ok, private_key, _} <- Keys.keys_from_pem(keys) do HTTPSignatures.sign(private_key, user.ap_id <> "#main-key", headers) end end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 05fe58f7c..653dec95f 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -10,6 +10,7 @@ defmodule Pleroma.User do alias Comeonin.Pbkdf2 alias Pleroma.Activity + alias Pleroma.Keys alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Registration @@ -1422,4 +1423,24 @@ defmodule Pleroma.User do } } end + + def ensure_keys_present(user) do + info = user.info + + if info.keys do + {:ok, user} + else + {:ok, pem} = Keys.generate_rsa_pem() + + info_cng = + info + |> User.Info.set_keys(pem) + + cng = + Ecto.Changeset.change(user) + |> Ecto.Changeset.put_embed(:info, info_cng) + + update_and_set_cache(cng) + end + end end diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index c967ab7a9..ad2ca1e54 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -39,7 +39,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do def user(conn, %{"nickname" => nickname}) do with %User{} = user <- User.get_cached_by_nickname(nickname), - {:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do + {:ok, user} <- User.ensure_keys_present(user) do conn |> put_resp_header("content-type", "application/activity+json") |> json(UserView.render("user.json", %{user: user})) @@ -106,7 +106,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do def following(conn, %{"nickname" => nickname, "page" => page}) do with %User{} = user <- User.get_cached_by_nickname(nickname), - {:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do + {:ok, user} <- User.ensure_keys_present(user) do {page, _} = Integer.parse(page) conn @@ -117,7 +117,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do def following(conn, %{"nickname" => nickname}) do with %User{} = user <- User.get_cached_by_nickname(nickname), - {:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do + {:ok, user} <- User.ensure_keys_present(user) do conn |> put_resp_header("content-type", "application/activity+json") |> json(UserView.render("following.json", %{user: user})) @@ -126,7 +126,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do def followers(conn, %{"nickname" => nickname, "page" => page}) do with %User{} = user <- User.get_cached_by_nickname(nickname), - {:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do + {:ok, user} <- User.ensure_keys_present(user) do {page, _} = Integer.parse(page) conn @@ -137,7 +137,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do def followers(conn, %{"nickname" => nickname}) do with %User{} = user <- User.get_cached_by_nickname(nickname), - {:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do + {:ok, user} <- User.ensure_keys_present(user) do conn |> put_resp_header("content-type", "application/activity+json") |> json(UserView.render("followers.json", %{user: user})) @@ -146,7 +146,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do def outbox(conn, %{"nickname" => nickname} = params) do with %User{} = user <- User.get_cached_by_nickname(nickname), - {:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do + {:ok, user} <- User.ensure_keys_present(user) do conn |> put_resp_header("content-type", "application/activity+json") |> json(UserView.render("outbox.json", %{user: user, max_id: params["max_id"]})) @@ -195,7 +195,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do def relay(conn, _params) do with %User{} = user <- Relay.get_actor(), - {:ok, user} <- Pleroma.Web.WebFinger.ensure_keys_present(user) do + {:ok, user} <- User.ensure_keys_present(user) do conn |> put_resp_header("content-type", "application/activity+json") |> json(UserView.render("user.json", %{user: user})) diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 1254fdf6c..327e0e05b 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -5,6 +5,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do use Pleroma.Web, :view + alias Pleroma.Keys alias Pleroma.Repo alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPub @@ -12,8 +13,6 @@ defmodule Pleroma.Web.ActivityPub.UserView do alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.Endpoint alias Pleroma.Web.Router.Helpers - alias Pleroma.Web.Salmon - alias Pleroma.Web.WebFinger import Ecto.Query @@ -34,8 +33,8 @@ defmodule Pleroma.Web.ActivityPub.UserView do # the instance itself is not a Person, but instead an Application def render("user.json", %{user: %{nickname: nil} = user}) do - {:ok, user} = WebFinger.ensure_keys_present(user) - {:ok, _, public_key} = Salmon.keys_from_pem(user.info.keys) + {: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) public_key = :public_key.pem_encode([public_key]) @@ -62,8 +61,8 @@ defmodule Pleroma.Web.ActivityPub.UserView do end def render("user.json", %{user: user}) do - {:ok, user} = WebFinger.ensure_keys_present(user) - {:ok, _, public_key} = Salmon.keys_from_pem(user.info.keys) + {: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) public_key = :public_key.pem_encode([public_key]) diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex index 169fdf4dc..6b0b75284 100644 --- a/lib/pleroma/web/federator/federator.ex +++ b/lib/pleroma/web/federator/federator.ex @@ -11,7 +11,6 @@ defmodule Pleroma.Web.Federator do alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.Federator.Publisher alias Pleroma.Web.Federator.RetryQueue - alias Pleroma.Web.WebFinger alias Pleroma.Web.Websub require Logger @@ -77,9 +76,8 @@ defmodule Pleroma.Web.Federator do def perform(:publish, activity) do Logger.debug(fn -> "Running publish for #{activity.data["id"]}" end) - with actor when not is_nil(actor) <- User.get_cached_by_ap_id(activity.data["actor"]) do - {:ok, actor} = WebFinger.ensure_keys_present(actor) - + with %User{} = actor <- User.get_cached_by_ap_id(activity.data["actor"]), + {:ok, actor} <- User.ensure_keys_present(actor) do Publisher.publish(actor, activity) end end diff --git a/lib/pleroma/web/salmon/salmon.ex b/lib/pleroma/web/salmon/salmon.ex index 42709ab47..fa30f73cd 100644 --- a/lib/pleroma/web/salmon/salmon.ex +++ b/lib/pleroma/web/salmon/salmon.ex @@ -10,6 +10,7 @@ defmodule Pleroma.Web.Salmon do use Bitwise alias Pleroma.Activity + alias Pleroma.Keys alias Pleroma.Instances alias Pleroma.User alias Pleroma.Web.ActivityPub.Visibility @@ -89,45 +90,6 @@ defmodule Pleroma.Web.Salmon do "RSA.#{modulus_enc}.#{exponent_enc}" end - # Native generation of RSA keys is only available since OTP 20+ and in default build conditions - # We try at compile time to generate natively an RSA key otherwise we fallback on the old way. - try do - _ = :public_key.generate_key({:rsa, 2048, 65_537}) - - def generate_rsa_pem do - key = :public_key.generate_key({:rsa, 2048, 65_537}) - entry = :public_key.pem_entry_encode(:RSAPrivateKey, key) - pem = :public_key.pem_encode([entry]) |> String.trim_trailing() - {:ok, pem} - end - rescue - _ -> - def generate_rsa_pem do - port = Port.open({:spawn, "openssl genrsa"}, [:binary]) - - {:ok, pem} = - receive do - {^port, {:data, pem}} -> {:ok, pem} - end - - Port.close(port) - - if Regex.match?(~r/RSA PRIVATE KEY/, pem) do - {:ok, pem} - else - :error - end - end - end - - def keys_from_pem(pem) do - [private_key_code] = :public_key.pem_decode(pem) - private_key = :public_key.pem_entry_decode(private_key_code) - {:RSAPrivateKey, _, modulus, exponent, _, _, _, _, _, _, _} = private_key - public_key = {:RSAPublicKey, modulus, exponent} - {:ok, private_key, public_key} - end - def encode(private_key, doc) do type = "application/atom+xml" encoding = "base64url" @@ -227,7 +189,7 @@ defmodule Pleroma.Web.Salmon do |> :xmerl.export_simple(:xmerl_xml) |> to_string - {:ok, private, _} = keys_from_pem(keys) + {:ok, private, _} = Keys.keys_from_pem(keys) {:ok, feed} = encode(private, feed) remote_users = remote_users(activity) @@ -253,7 +215,7 @@ defmodule Pleroma.Web.Salmon do def publish(%{id: id}, _), do: Logger.debug(fn -> "Keys missing for user #{id}" end) def gather_webfinger_links(%User{} = user) do - {:ok, _private, public} = keys_from_pem(user.info.keys) + {:ok, _private, public} = Keys.keys_from_pem(user.info.keys) magic_key = encode_key(public) [ diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex index 1239b962a..c5b7d4acb 100644 --- a/lib/pleroma/web/web_finger/web_finger.ex +++ b/lib/pleroma/web/web_finger/web_finger.ex @@ -8,7 +8,6 @@ defmodule Pleroma.Web.WebFinger do alias Pleroma.User alias Pleroma.Web alias Pleroma.Web.Federator.Publisher - alias Pleroma.Web.Salmon alias Pleroma.Web.XML alias Pleroma.XmlBuilder require Jason @@ -61,7 +60,7 @@ defmodule Pleroma.Web.WebFinger do end def represent_user(user, "JSON") do - {:ok, user} = ensure_keys_present(user) + {:ok, user} = User.ensure_keys_present(user) %{ "subject" => "acct:#{user.nickname}@#{Pleroma.Web.Endpoint.host()}", @@ -71,7 +70,7 @@ defmodule Pleroma.Web.WebFinger do end def represent_user(user, "XML") do - {:ok, user} = ensure_keys_present(user) + {:ok, user} = User.ensure_keys_present(user) links = gather_links(user) @@ -88,27 +87,6 @@ defmodule Pleroma.Web.WebFinger do |> XmlBuilder.to_doc() end - # This seems a better fit in Salmon - def ensure_keys_present(user) do - info = user.info - - if info.keys do - {:ok, user} - else - {:ok, pem} = Salmon.generate_rsa_pem() - - info_cng = - info - |> User.Info.set_keys(pem) - - cng = - Ecto.Changeset.change(user) - |> Ecto.Changeset.put_embed(:info, info_cng) - - User.update_and_set_cache(cng) - end - end - defp get_magic_key(magic_key) do "data:application/magic-public-key," <> magic_key = magic_key {:ok, magic_key} -- cgit v1.2.3 From 913484817076bf5ca4bdbe7c3c1ff34f7debd3e5 Mon Sep 17 00:00:00 2001 From: Sergey Suprunenko Date: Wed, 22 May 2019 04:04:20 +0000 Subject: Do not truncate DM when it contains newlines and safe_dm_mentions is set to true --- lib/pleroma/formatter.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex index 3d7c36d21..3e3b9fe97 100644 --- a/lib/pleroma/formatter.ex +++ b/lib/pleroma/formatter.ex @@ -8,7 +8,7 @@ defmodule Pleroma.Formatter do alias Pleroma.User alias Pleroma.Web.MediaProxy - @safe_mention_regex ~r/^(\s*(?@.+?\s+)+)(?.*)/ + @safe_mention_regex ~r/^(\s*(?@.+?\s+)+)(?.*)/s @link_regex ~r"((?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~%:/?#[\]@!\$&'\(\)\*\+,;=.]+)|[0-9a-z+\-\.]+:[0-9a-z$-_.+!*'(),]+"ui @markdown_characters_regex ~r/(`|\*|_|{|}|[|]|\(|\)|#|\+|-|\.|!)/ -- cgit v1.2.3 From 0e2c215a006c7ca5756e80a357ff6395a4325946 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Wed, 22 May 2019 07:22:19 +0200 Subject: MastoAPI AccountView: fill source.note with plaintext version of note Closes: https://git.pleroma.social/pleroma/pleroma/issues/926 --- lib/pleroma/web/mastodon_api/views/account_view.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 134c07b7e..b82d3319b 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -112,7 +112,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do fields: fields, bot: bot, source: %{ - note: "", + note: HTML.strip_tags((user.bio || "") |> String.replace("
", "\n")), sensitive: false, pleroma: %{} }, -- cgit v1.2.3 From 1344c85e2fe636fd6b9d033eb7add1c3a9701c7f Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Wed, 22 May 2019 05:58:51 +0000 Subject: salmon: fix credo --- lib/pleroma/web/salmon/salmon.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/salmon/salmon.ex b/lib/pleroma/web/salmon/salmon.ex index fa30f73cd..f25d92fad 100644 --- a/lib/pleroma/web/salmon/salmon.ex +++ b/lib/pleroma/web/salmon/salmon.ex @@ -10,8 +10,8 @@ defmodule Pleroma.Web.Salmon do use Bitwise alias Pleroma.Activity - alias Pleroma.Keys alias Pleroma.Instances + alias Pleroma.Keys alias Pleroma.User alias Pleroma.Web.ActivityPub.Visibility alias Pleroma.Web.Federator.Publisher -- cgit v1.2.3 From 620908a2db86942a00bc0ba9c71c037061e26967 Mon Sep 17 00:00:00 2001 From: Maksim Date: Wed, 22 May 2019 15:44:50 +0000 Subject: [#699] add worker to clean expired oauth tokens --- lib/pleroma/application.ex | 1 + lib/pleroma/web/oauth/token.ex | 36 +++++++++---------- lib/pleroma/web/oauth/token/clean_worker.ex | 41 +++++++++++++++++++++ lib/pleroma/web/oauth/token/query.ex | 55 +++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 20 deletions(-) create mode 100644 lib/pleroma/web/oauth/token/clean_worker.ex create mode 100644 lib/pleroma/web/oauth/token/query.ex (limited to 'lib') diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index dab45a0b2..76df3945e 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -110,6 +110,7 @@ defmodule Pleroma.Application do hackney_pool_children() ++ [ worker(Pleroma.Web.Federator.RetryQueue, []), + worker(Pleroma.Web.OAuth.Token.CleanWorker, []), worker(Pleroma.Stats, []), worker(Task, [&Pleroma.Web.Push.init/0], restart: :temporary, id: :web_push_init), worker(Task, [&Pleroma.Web.Federator.init/0], restart: :temporary, id: :federator_init) diff --git a/lib/pleroma/web/oauth/token.ex b/lib/pleroma/web/oauth/token.ex index 66c95c2e9..f412f7eb2 100644 --- a/lib/pleroma/web/oauth/token.ex +++ b/lib/pleroma/web/oauth/token.ex @@ -5,7 +5,6 @@ defmodule Pleroma.Web.OAuth.Token do use Ecto.Schema - import Ecto.Query import Ecto.Changeset alias Pleroma.Repo @@ -13,6 +12,7 @@ defmodule Pleroma.Web.OAuth.Token do alias Pleroma.Web.OAuth.App alias Pleroma.Web.OAuth.Authorization alias Pleroma.Web.OAuth.Token + alias Pleroma.Web.OAuth.Token.Query @expires_in Pleroma.Config.get([:oauth2, :token_expires_in], 600) @type t :: %__MODULE__{} @@ -31,17 +31,17 @@ defmodule Pleroma.Web.OAuth.Token do @doc "Gets token for app by access token" @spec get_by_token(App.t(), String.t()) :: {:ok, t()} | {:error, :not_found} def get_by_token(%App{id: app_id} = _app, token) do - from(t in __MODULE__, where: t.app_id == ^app_id and t.token == ^token) + Query.get_by_app(app_id) + |> Query.get_by_token(token) |> Repo.find_resource() end @doc "Gets token for app by refresh token" @spec get_by_refresh_token(App.t(), String.t()) :: {:ok, t()} | {:error, :not_found} def get_by_refresh_token(%App{id: app_id} = _app, token) do - from(t in __MODULE__, - where: t.app_id == ^app_id and t.refresh_token == ^token, - preload: [:user] - ) + Query.get_by_app(app_id) + |> Query.get_by_refresh_token(token) + |> Query.preload([:user]) |> Repo.find_resource() end @@ -97,29 +97,25 @@ defmodule Pleroma.Web.OAuth.Token do end def delete_user_tokens(%User{id: user_id}) do - from( - t in Token, - where: t.user_id == ^user_id - ) + Query.get_by_user(user_id) |> Repo.delete_all() end def delete_user_token(%User{id: user_id}, token_id) do - from( - t in Token, - where: t.user_id == ^user_id, - where: t.id == ^token_id - ) + Query.get_by_user(user_id) + |> Query.get_by_id(token_id) + |> Repo.delete_all() + end + + def delete_expired_tokens do + Query.get_expired_tokens() |> Repo.delete_all() end def get_user_tokens(%User{id: user_id}) do - from( - t in Token, - where: t.user_id == ^user_id - ) + Query.get_by_user(user_id) + |> Query.preload([:app]) |> Repo.all() - |> Repo.preload(:app) end def is_expired?(%__MODULE__{valid_until: valid_until}) do diff --git a/lib/pleroma/web/oauth/token/clean_worker.ex b/lib/pleroma/web/oauth/token/clean_worker.ex new file mode 100644 index 000000000..dca852449 --- /dev/null +++ b/lib/pleroma/web/oauth/token/clean_worker.ex @@ -0,0 +1,41 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2018 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.OAuth.Token.CleanWorker do + @moduledoc """ + The module represents functions to clean an expired oauth tokens. + """ + + # 10 seconds + @start_interval 10_000 + @interval Pleroma.Config.get( + # 24 hours + [:oauth2, :clean_expired_tokens_interval], + 86_400_000 + ) + @queue :background + + alias Pleroma.Web.OAuth.Token + + def start_link, do: GenServer.start_link(__MODULE__, nil) + + def init(_) do + if Pleroma.Config.get([:oauth2, :clean_expired_tokens], false) do + Process.send_after(self(), :perform, @start_interval) + {:ok, nil} + else + :ignore + end + end + + @doc false + def handle_info(:perform, state) do + Process.send_after(self(), :perform, @interval) + PleromaJobQueue.enqueue(@queue, __MODULE__, [:clean]) + {:noreply, state} + end + + # Job Worker Callbacks + def perform(:clean), do: Token.delete_expired_tokens() +end diff --git a/lib/pleroma/web/oauth/token/query.ex b/lib/pleroma/web/oauth/token/query.ex new file mode 100644 index 000000000..d92e1f071 --- /dev/null +++ b/lib/pleroma/web/oauth/token/query.ex @@ -0,0 +1,55 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2018 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.OAuth.Token.Query do + @moduledoc """ + Contains queries for OAuth Token. + """ + + import Ecto.Query, only: [from: 2] + + @type query :: Ecto.Queryable.t() | Token.t() + + alias Pleroma.Web.OAuth.Token + + @spec get_by_refresh_token(query, String.t()) :: query + def get_by_refresh_token(query \\ Token, refresh_token) do + from(q in query, where: q.refresh_token == ^refresh_token) + end + + @spec get_by_token(query, String.t()) :: query + def get_by_token(query \\ Token, token) do + from(q in query, where: q.token == ^token) + end + + @spec get_by_app(query, String.t()) :: query + def get_by_app(query \\ Token, app_id) do + from(q in query, where: q.app_id == ^app_id) + end + + @spec get_by_id(query, String.t()) :: query + def get_by_id(query \\ Token, id) do + from(q in query, where: q.id == ^id) + end + + @spec get_expired_tokens(query, DateTime.t() | nil) :: query + def get_expired_tokens(query \\ Token, date \\ nil) do + expired_date = date || Timex.now() + from(q in query, where: fragment("?", q.valid_until) < ^expired_date) + end + + @spec get_by_user(query, String.t()) :: query + def get_by_user(query \\ Token, user_id) do + from(q in query, where: q.user_id == ^user_id) + end + + @spec preload(query, any) :: query + def preload(query \\ Token, assoc_preload \\ []) + + def preload(query, assoc_preload) when is_list(assoc_preload) do + from(q in query, preload: ^assoc_preload) + end + + def preload(query, _assoc_preload), do: query +end -- cgit v1.2.3 From 54e10a3e55fe46b71ef7f330605baf8bcccd5a44 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 22 May 2019 20:10:52 +0300 Subject: Disable timeouts for object pruning query --- lib/mix/tasks/pleroma/database.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/database.ex b/lib/mix/tasks/pleroma/database.ex index f9bafb277..4d480ac3f 100644 --- a/lib/mix/tasks/pleroma/database.ex +++ b/lib/mix/tasks/pleroma/database.ex @@ -107,7 +107,7 @@ defmodule Mix.Tasks.Pleroma.Database do where: fragment("split_part(?->>'actor', '/', 3) != ?", o.data, ^Pleroma.Web.Endpoint.host()) ) - |> Repo.delete_all() + |> Repo.delete_all(timeout: :infinity) if Keyword.get(options, :vacuum) do Logger.info("Runnning VACUUM FULL") -- cgit v1.2.3 From 19c90d47c4f649d0962098050f6cbc65eeb889d0 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 22 May 2019 21:17:57 +0300 Subject: Normalize poll votes to Answer objects --- lib/pleroma/web/activity_pub/activity_pub.ex | 14 +------------- lib/pleroma/web/activity_pub/transmogrifier.ex | 22 +++++++++++++++++++++- lib/pleroma/web/activity_pub/utils.ex | 2 +- 3 files changed, 23 insertions(+), 15 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index fdebf1f6b..5b3fb7e84 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -194,7 +194,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do if activity.data["type"] in ["Create", "Announce", "Delete"] do object = Object.normalize(activity) # Do not stream out poll replies - unless object.data["name"] do + unless object.data["type"] == "Answer" do Pleroma.Web.Streamer.stream("user", activity) Pleroma.Web.Streamer.stream("list", activity) @@ -493,7 +493,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do from(activity in Activity) |> restrict_blocked(opts) - |> restrict_poll_replies(opts) |> restrict_recipients(recipients, opts["user"]) |> where( [activity], @@ -833,16 +832,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do defp restrict_muted_reblogs(query, _), do: query - defp restrict_poll_replies(query, %{"include_poll_replies" => "true"}), do: query - - defp restrict_poll_replies(query, _) do - if has_named_binding?(query, :object) do - from([activity, object: o] in query, where: fragment("?->'name' is null", o.data)) - else - query - end - end - defp maybe_preload_objects(query, %{"skip_preload" => true}), do: query defp maybe_preload_objects(query, _) do @@ -896,7 +885,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> restrict_pinned(opts) |> restrict_muted_reblogs(opts) |> Activity.restrict_deactivated_users() - |> restrict_poll_replies(opts) end def fetch_activities(recipients, opts \\ %{}) do diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 8b2427258..70b467b3f 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -35,6 +35,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do |> fix_likes |> fix_addressing |> fix_summary + |> fix_type end def fix_summary(%{"summary" => nil} = object) do @@ -328,6 +329,18 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do def fix_content_map(object), do: object + def fix_type(%{"inReplyTo" => reply_id} = object) when is_binary(reply_id) do + reply = Object.normalize(reply_id) + + if reply.data["type"] == "Question" and object["name"] do + Map.put(object, "type", "Answer") + else + object + end + end + + def fix_type(object), do: object + defp mastodon_follow_hack(%{"id" => id, "actor" => follower_id}, followed) do with true <- id =~ "follows", %User{local: true} = follower <- User.get_cached_by_ap_id(follower_id), @@ -398,7 +411,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do # - tags # - emoji def handle_incoming(%{"type" => "Create", "object" => %{"type" => objtype} = object} = data) - when objtype in ["Article", "Note", "Video", "Page", "Question"] do + when objtype in ["Article", "Note", "Video", "Page", "Question", "Answer"] do actor = Containment.get_actor(data) data = @@ -731,6 +744,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do |> set_reply_to_uri |> strip_internal_fields |> strip_internal_tags + |> set_type end # @doc @@ -895,6 +909,12 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do Map.put(object, "sensitive", "nsfw" in tags) end + def set_type(%{"type" => "Answer"} = object) do + Map.put(object, "type", "Note") + end + + def set_type(object), do: object + def add_attributed_to(object) do attributed_to = object["attributedTo"] || object["actor"] diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 63454e3f7..9646bbee9 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -19,7 +19,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do require Logger - @supported_object_types ["Article", "Note", "Video", "Page", "Question"] + @supported_object_types ["Article", "Note", "Video", "Page", "Question", "Answer"] @supported_report_states ~w(open closed resolved) @valid_visibilities ~w(public unlisted private direct) -- cgit v1.2.3 From ac7702f8009bf244a9e77cba39114dbb6584739f Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 22 May 2019 21:49:19 +0300 Subject: Exclude Answers from fetching by default --- lib/pleroma/web/activity_pub/activity_pub.ex | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 5b3fb7e84..db5a4a7ee 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -492,6 +492,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do if opts["user"], do: [opts["user"].ap_id | opts["user"].following] ++ public, else: public from(activity in Activity) + |> Activity.with_preloaded_object() + |> exclude_poll_votes(opts) |> restrict_blocked(opts) |> restrict_recipients(recipients, opts["user"]) |> where( @@ -832,6 +834,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do defp restrict_muted_reblogs(query, _), do: query + defp exclude_poll_votes(query, %{"include_poll_votes" => "true"}), do: query + + defp exclude_poll_votes(query, _) do + if has_named_binding?(query, :object) do + from([activity, object: o] in query, + where: fragment("not(?->>'type' = ?)", o.data, "Answer") + ) + else + query + end + end + defp maybe_preload_objects(query, %{"skip_preload" => true}), do: query defp maybe_preload_objects(query, _) do @@ -865,6 +879,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> maybe_preload_objects(opts) |> maybe_preload_bookmarks(opts) |> maybe_order(opts) + |> exclude_poll_votes(opts) |> restrict_recipients(recipients, opts["user"]) |> restrict_tag(opts) |> restrict_tag_reject(opts) -- cgit v1.2.3 From 75b6c4b00433560fb5ee502f13e8261b4b8a246a Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Wed, 22 May 2019 04:15:59 +0000 Subject: mrf: defang policy modules for filtering user profile objects --- lib/pleroma/web/activity_pub/mrf/simple_policy.ex | 6 ++++-- lib/pleroma/web/activity_pub/mrf/user_allowlist.ex | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex index 7190652d2..ffaa4b7db 100644 --- a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex @@ -105,8 +105,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do defp check_report_removal(_actor_info, object), do: {:ok, object} @impl true - def filter(object) do - actor_info = URI.parse(object["actor"]) + def filter(%{"actor" => actor} = object) do + actor_info = URI.parse(actor) with {:ok, object} <- check_accept(actor_info, object), {:ok, object} <- check_reject(actor_info, object), @@ -119,4 +119,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do _e -> {:reject, nil} end end + + def filter(object), do: {:ok, object} end diff --git a/lib/pleroma/web/activity_pub/mrf/user_allowlist.ex b/lib/pleroma/web/activity_pub/mrf/user_allowlist.ex index f5078d818..47663414a 100644 --- a/lib/pleroma/web/activity_pub/mrf/user_allowlist.ex +++ b/lib/pleroma/web/activity_pub/mrf/user_allowlist.ex @@ -19,10 +19,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.UserAllowListPolicy do end @impl true - def filter(object) do - actor_info = URI.parse(object["actor"]) + def filter(%{"actor" => actor} = object) do + actor_info = URI.parse(actor) allow_list = Config.get([:mrf_user_allowlist, String.to_atom(actor_info.host)], []) filter_by_list(object, allow_list) end + + def filter(object), do: {:ok, object} end -- cgit v1.2.3 From 60f882b09f5f837546d59f8eef56b905e065ec60 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Wed, 22 May 2019 04:33:10 +0000 Subject: activitypub: run user objects through MRF filters --- lib/pleroma/web/activity_pub/activity_pub.ex | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 3d9679ec0..aa0229db7 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -909,7 +909,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end end - def user_data_from_user_object(data) do + defp object_to_user_data(data) do avatar = data["icon"]["url"] && %{ @@ -956,9 +956,19 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do {:ok, user_data} end + def user_data_from_user_object(data) do + with {:ok, data} <- MRF.filter(data), + {:ok, data} <- object_to_user_data(data) do + {:ok, data} + else + e -> {:error, e} + end + end + def fetch_and_prepare_user_from_ap_id(ap_id) do - with {:ok, data} <- Fetcher.fetch_and_contain_remote_object_from_id(ap_id) do - user_data_from_user_object(data) + with {:ok, data} <- Fetcher.fetch_and_contain_remote_object_from_id(ap_id), + {:ok, data} <- user_data_from_user_object(data) do + {:ok, data} else e -> Logger.error("Could not decode user at fetch #{ap_id}, #{inspect(e)}") end -- cgit v1.2.3 From baf72d6c580e5c05ef5fea8a57c57150a5d38589 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Wed, 22 May 2019 04:55:16 +0000 Subject: mrf: simple policy: add the ability to strip avatars and banners from user profiles --- lib/pleroma/web/activity_pub/mrf/simple_policy.ex | 32 +++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex index ffaa4b7db..890d70a7a 100644 --- a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex @@ -104,6 +104,26 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do defp check_report_removal(_actor_info, object), do: {:ok, object} + defp check_avatar_removal(%{host: actor_host} = _actor_info, %{"icon" => _icon} = object) do + if actor_host in Pleroma.Config.get([:mrf_simple, :avatar_removal]) do + {:ok, Map.delete(object, "icon")} + else + {:ok, object} + end + end + + defp check_avatar_removal(_actor_info, object), do: {:ok, object} + + defp check_banner_removal(%{host: actor_host} = _actor_info, %{"image" => _image} = object) do + if actor_host in Pleroma.Config.get([:mrf_simple, :banner_removal]) do + {:ok, Map.delete(object, "image")} + else + {:ok, object} + end + end + + defp check_banner_removal(_actor_info, object), do: {:ok, object} + @impl true def filter(%{"actor" => actor} = object) do actor_info = URI.parse(actor) @@ -120,5 +140,17 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do end end + def filter(%{"id" => actor, "type" => obj_type} = object) + when obj_type in ["Application", "Group", "Organization", "Person", "Service"] do + actor_info = URI.parse(actor) + + with {:ok, object} <- check_avatar_removal(actor_info, object), + {:ok, object} <- check_banner_removal(actor_info, object) do + {:ok, object} + else + _e -> {:reject, nil} + end + end + def filter(object), do: {:ok, object} end -- cgit v1.2.3 From e6b175ed6cafcd6a05120e003cfe40a04b38849f Mon Sep 17 00:00:00 2001 From: rinpatch Date: Wed, 22 May 2019 21:57:46 +0300 Subject: Fix credo issues --- lib/pleroma/web/mastodon_api/views/status_view.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index c501c213c..7a393a817 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -357,7 +357,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do end) %{ - # Mastodon uses separate ids for polls, but an object can't have more than one poll embedded so object id is fine + # 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, expires_at: Utils.to_masto_date(end_time), expired: expired, -- cgit v1.2.3 From 8b2d39c1ec8f47df8a2159c23eabdc61b983ddf0 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 23 May 2019 14:03:16 +0300 Subject: Change the order of preloading when fetching activities for context --- lib/pleroma/web/activity_pub/activity_pub.ex | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index db5a4a7ee..b06200cb5 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -492,7 +492,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do if opts["user"], do: [opts["user"].ap_id | opts["user"].following] ++ public, else: public from(activity in Activity) - |> Activity.with_preloaded_object() + |> maybe_preload_objects(opts) |> exclude_poll_votes(opts) |> restrict_blocked(opts) |> restrict_recipients(recipients, opts["user"]) @@ -513,7 +513,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do def fetch_activities_for_context(context, opts \\ %{}) do context |> fetch_activities_for_context_query(opts) - |> Activity.with_preloaded_object() |> Repo.all() end @@ -521,7 +520,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do Pleroma.FlakeId.t() | nil def fetch_latest_activity_id_for_context(context, opts \\ %{}) do context - |> fetch_activities_for_context_query(opts) + |> fetch_activities_for_context_query(Map.merge(%{"skip_preload" => true}, opts)) |> limit(1) |> select([a], a.id) |> Repo.one() -- cgit v1.2.3 From f916e4cdd9a502b83c615146c598be135f47e57a Mon Sep 17 00:00:00 2001 From: feld Date: Fri, 24 May 2019 20:33:55 +0000 Subject: Move the Cache Control header test to its own file We can consolidate our cache control header tests here --- lib/pleroma/web/endpoint.ex | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex index 9ef30e885..8cd7a2270 100644 --- a/lib/pleroma/web/endpoint.ex +++ b/lib/pleroma/web/endpoint.ex @@ -16,17 +16,32 @@ defmodule Pleroma.Web.Endpoint do plug(Pleroma.Plugs.UploadedMedia) + @static_cache_control "public, no-cache" + # InstanceStatic needs to be before Plug.Static to be able to override shipped-static files # If you're adding new paths to `only:` you'll need to configure them in InstanceStatic as well - plug(Pleroma.Plugs.InstanceStatic, at: "/") + # Cache-control headers are duplicated in case we turn off etags in the future + plug(Pleroma.Plugs.InstanceStatic, + at: "/", + gzip: true, + cache_control_for_etags: @static_cache_control, + headers: %{ + "cache-control" => @static_cache_control + } + ) plug( Plug.Static, at: "/", from: :pleroma, only: - ~w(index.html robots.txt static finmoji emoji packs sounds images instance sw.js sw-pleroma.js favicon.png schemas doc) + ~w(index.html robots.txt static finmoji emoji packs sounds images instance sw.js sw-pleroma.js favicon.png schemas doc), # credo:disable-for-previous-line Credo.Check.Readability.MaxLineLength + gzip: true, + cache_control_for_etags: @static_cache_control, + headers: %{ + "cache-control" => @static_cache_control + } ) plug(Plug.Static.IndexHtml, at: "/pleroma/admin/") -- cgit v1.2.3 From bbea5691da67916151a883f09e24da7c2e27d9ba Mon Sep 17 00:00:00 2001 From: Sergey Suprunenko Date: Fri, 24 May 2019 20:34:23 +0000 Subject: Mention all people in the beginning of DM --- lib/pleroma/formatter.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex index 3e3b9fe97..607843a5b 100644 --- a/lib/pleroma/formatter.ex +++ b/lib/pleroma/formatter.ex @@ -8,7 +8,7 @@ defmodule Pleroma.Formatter do alias Pleroma.User alias Pleroma.Web.MediaProxy - @safe_mention_regex ~r/^(\s*(?@.+?\s+)+)(?.*)/s + @safe_mention_regex ~r/^(\s*(?(@.+?\s+){1,})+)(?.*)/s @link_regex ~r"((?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~%:/?#[\]@!\$&'\(\)\*\+,;=.]+)|[0-9a-z+\-\.]+:[0-9a-z$-_.+!*'(),]+"ui @markdown_characters_regex ~r/(`|\*|_|{|}|[|]|\(|\)|#|\+|-|\.|!)/ -- cgit v1.2.3 From 9415932af5829f2aa19e362076e0653dd1ce9c5a Mon Sep 17 00:00:00 2001 From: Aaron Tinio Date: Sat, 25 May 2019 08:15:12 +0800 Subject: Keep nodeinfo available when not federating --- lib/pleroma/web/nodeinfo/nodeinfo_controller.ex | 2 -- 1 file changed, 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex index 3bf2a0fbc..45f90c579 100644 --- a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex +++ b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex @@ -12,8 +12,6 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do alias Pleroma.Web.ActivityPub.MRF alias Pleroma.Web.Federator.Publisher - plug(Pleroma.Web.FederatingPlug) - def schemas(conn, _params) do response = %{ links: [ -- cgit v1.2.3 From 9bec891eb4d5d06e6bd84dd2c95259d2c1a4f563 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sat, 25 May 2019 04:24:21 +0000 Subject: kill @httpoison --- lib/pleroma/object/fetcher.ex | 5 ++--- lib/pleroma/reverse_proxy.ex | 5 +++-- lib/pleroma/uploaders/mdii.ex | 5 ++--- lib/pleroma/web/activity_pub/publisher.ex | 5 ++--- lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 4 ++-- lib/pleroma/web/ostatus/ostatus.ex | 7 +++---- lib/pleroma/web/salmon/salmon.ex | 5 ++--- lib/pleroma/web/web_finger/web_finger.ex | 9 ++++----- lib/pleroma/web/websub/websub.ex | 11 +++++------ 9 files changed, 25 insertions(+), 31 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index bb9388d4f..ca980c629 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -1,4 +1,5 @@ defmodule Pleroma.Object.Fetcher do + alias Pleroma.HTTP alias Pleroma.Object alias Pleroma.Object.Containment alias Pleroma.Web.ActivityPub.Transmogrifier @@ -6,8 +7,6 @@ defmodule Pleroma.Object.Fetcher do require Logger - @httpoison Application.get_env(:pleroma, :httpoison) - defp reinject_object(data) do Logger.debug("Reinjecting object #{data["id"]}") @@ -78,7 +77,7 @@ defmodule Pleroma.Object.Fetcher do with true <- String.starts_with?(id, "http"), {:ok, %{body: body, status: code}} when code in 200..299 <- - @httpoison.get( + HTTP.get( id, [{:Accept, "application/activity+json"}] ), diff --git a/lib/pleroma/reverse_proxy.ex b/lib/pleroma/reverse_proxy.ex index a3f177fec..6e5feb4c3 100644 --- a/lib/pleroma/reverse_proxy.ex +++ b/lib/pleroma/reverse_proxy.ex @@ -3,6 +3,8 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.ReverseProxy do + alias Pleroma.HTTP + @keep_req_headers ~w(accept user-agent accept-encoding cache-control if-modified-since) ++ ~w(if-unmodified-since if-none-match if-range range) @resp_cache_headers ~w(etag date last-modified cache-control) @@ -60,7 +62,6 @@ defmodule Pleroma.ReverseProxy do """ @hackney Application.get_env(:pleroma, :hackney, :hackney) - @httpoison Application.get_env(:pleroma, :httpoison, HTTPoison) @default_hackney_options [] @@ -97,7 +98,7 @@ defmodule Pleroma.ReverseProxy do hackney_opts = @default_hackney_options |> Keyword.merge(Keyword.get(opts, :http, [])) - |> @httpoison.process_request_options() + |> HTTP.process_request_options() req_headers = build_req_headers(conn.req_headers, opts) diff --git a/lib/pleroma/uploaders/mdii.ex b/lib/pleroma/uploaders/mdii.ex index 190ed9f3a..237544337 100644 --- a/lib/pleroma/uploaders/mdii.ex +++ b/lib/pleroma/uploaders/mdii.ex @@ -4,11 +4,10 @@ defmodule Pleroma.Uploaders.MDII do alias Pleroma.Config + alias Pleroma.HTTP @behaviour Pleroma.Uploaders.Uploader - @httpoison Application.get_env(:pleroma, :httpoison) - # MDII-hosted images are never passed through the MediaPlug; only local media. # Delegate to Pleroma.Uploaders.Local def get_file(file) do @@ -25,7 +24,7 @@ defmodule Pleroma.Uploaders.MDII do query = "#{cgi}?#{extension}" with {:ok, %{status: 200, body: body}} <- - @httpoison.post(query, file_data, [], adapter: [pool: :default]) do + HTTP.post(query, file_data, [], adapter: [pool: :default]) do remote_file_name = String.split(body) |> List.first() public_url = "#{files}/#{remote_file_name}.#{extension}" {:ok, {:url, public_url}} diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex index 11dba87de..8f1399ce6 100644 --- a/lib/pleroma/web/activity_pub/publisher.ex +++ b/lib/pleroma/web/activity_pub/publisher.ex @@ -5,6 +5,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do alias Pleroma.Activity alias Pleroma.Config + alias Pleroma.HTTP alias Pleroma.Instances alias Pleroma.User alias Pleroma.Web.ActivityPub.Relay @@ -16,8 +17,6 @@ defmodule Pleroma.Web.ActivityPub.Publisher do require Logger - @httpoison Application.get_env(:pleroma, :httpoison) - @moduledoc """ ActivityPub outgoing federation module. """ @@ -63,7 +62,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do with {:ok, %{status: code}} when code in 200..299 <- result = - @httpoison.post( + HTTP.post( inbox, json, [ diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 1ec0f30a1..0fe09c285 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -11,6 +11,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do alias Pleroma.Conversation.Participation alias Pleroma.Filter alias Pleroma.Formatter + alias Pleroma.HTTP alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Object.Fetcher @@ -55,7 +56,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do when action in [:account_register] ) - @httpoison Application.get_env(:pleroma, :httpoison) @local_mastodon_name "Mastodon-Local" action_fallback(:errors) @@ -1691,7 +1691,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do |> String.replace("{{user}}", user) with {:ok, %{status: 200, body: body}} <- - @httpoison.get( + HTTP.get( url, [], adapter: [ diff --git a/lib/pleroma/web/ostatus/ostatus.ex b/lib/pleroma/web/ostatus/ostatus.ex index 61515b31e..6ed089d84 100644 --- a/lib/pleroma/web/ostatus/ostatus.ex +++ b/lib/pleroma/web/ostatus/ostatus.ex @@ -3,13 +3,12 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.OStatus do - @httpoison Application.get_env(:pleroma, :httpoison) - import Ecto.Query import Pleroma.Web.XML require Logger alias Pleroma.Activity + alias Pleroma.HTTP alias Pleroma.Object alias Pleroma.Repo alias Pleroma.User @@ -363,7 +362,7 @@ defmodule Pleroma.Web.OStatus do def fetch_activity_from_atom_url(url) do with true <- String.starts_with?(url, "http"), {:ok, %{body: body, status: code}} when code in 200..299 <- - @httpoison.get( + HTTP.get( url, [{:Accept, "application/atom+xml"}] ) do @@ -380,7 +379,7 @@ defmodule Pleroma.Web.OStatus do Logger.debug("Trying to fetch #{url}") with true <- String.starts_with?(url, "http"), - {:ok, %{body: body}} <- @httpoison.get(url, []), + {:ok, %{body: body}} <- HTTP.get(url, []), {:ok, atom_url} <- get_atom_url(body) do fetch_activity_from_atom_url(atom_url) else diff --git a/lib/pleroma/web/salmon/salmon.ex b/lib/pleroma/web/salmon/salmon.ex index f25d92fad..9e91a5a40 100644 --- a/lib/pleroma/web/salmon/salmon.ex +++ b/lib/pleroma/web/salmon/salmon.ex @@ -5,11 +5,10 @@ defmodule Pleroma.Web.Salmon do @behaviour Pleroma.Web.Federator.Publisher - @httpoison Application.get_env(:pleroma, :httpoison) - use Bitwise alias Pleroma.Activity + alias Pleroma.HTTP alias Pleroma.Instances alias Pleroma.Keys alias Pleroma.User @@ -138,7 +137,7 @@ defmodule Pleroma.Web.Salmon do def publish_one(%{recipient: url, feed: feed} = params) when is_binary(url) do with {:ok, %{status: code}} when code in 200..299 <- - @httpoison.post( + HTTP.post( url, feed, [{"Content-Type", "application/magic-envelope+xml"}] diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex index c5b7d4acb..3fca72de8 100644 --- a/lib/pleroma/web/web_finger/web_finger.ex +++ b/lib/pleroma/web/web_finger/web_finger.ex @@ -3,8 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.WebFinger do - @httpoison Application.get_env(:pleroma, :httpoison) - + alias Pleroma.HTTP alias Pleroma.User alias Pleroma.Web alias Pleroma.Web.Federator.Publisher @@ -176,11 +175,11 @@ defmodule Pleroma.Web.WebFinger do def find_lrdd_template(domain) do with {:ok, %{status: status, body: body}} when status in 200..299 <- - @httpoison.get("http://#{domain}/.well-known/host-meta", []) do + HTTP.get("http://#{domain}/.well-known/host-meta", []) do get_template_from_xml(body) else _ -> - with {:ok, %{body: body}} <- @httpoison.get("https://#{domain}/.well-known/host-meta", []) do + with {:ok, %{body: body}} <- HTTP.get("https://#{domain}/.well-known/host-meta", []) do get_template_from_xml(body) else e -> {:error, "Can't find LRDD template: #{inspect(e)}"} @@ -209,7 +208,7 @@ defmodule Pleroma.Web.WebFinger do end with response <- - @httpoison.get( + HTTP.get( address, Accept: "application/xrd+xml,application/jrd+json" ), diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex index 7ad0414ab..b61f388b8 100644 --- a/lib/pleroma/web/websub/websub.ex +++ b/lib/pleroma/web/websub/websub.ex @@ -5,6 +5,7 @@ defmodule Pleroma.Web.Websub do alias Ecto.Changeset alias Pleroma.Activity + alias Pleroma.HTTP alias Pleroma.Instances alias Pleroma.Repo alias Pleroma.User @@ -24,9 +25,7 @@ defmodule Pleroma.Web.Websub do @behaviour Pleroma.Web.Federator.Publisher - @httpoison Application.get_env(:pleroma, :httpoison) - - def verify(subscription, getter \\ &@httpoison.get/3) do + def verify(subscription, getter \\ &HTTP.get/3) do challenge = Base.encode16(:crypto.strong_rand_bytes(8)) lease_seconds = NaiveDateTime.diff(subscription.valid_until, subscription.updated_at) lease_seconds = lease_seconds |> to_string @@ -207,7 +206,7 @@ defmodule Pleroma.Web.Websub do requester.(subscription) end - def gather_feed_data(topic, getter \\ &@httpoison.get/1) do + def gather_feed_data(topic, getter \\ &HTTP.get/1) do with {:ok, response} <- getter.(topic), status when status in 200..299 <- response.status, body <- response.body, @@ -236,7 +235,7 @@ defmodule Pleroma.Web.Websub do end end - def request_subscription(websub, poster \\ &@httpoison.post/3, timeout \\ 10_000) do + def request_subscription(websub, poster \\ &HTTP.post/3, timeout \\ 10_000) do data = [ "hub.mode": "subscribe", "hub.topic": websub.topic, @@ -294,7 +293,7 @@ defmodule Pleroma.Web.Websub do Logger.info(fn -> "Pushing #{topic} to #{callback}" end) with {:ok, %{status: code}} when code in 200..299 <- - @httpoison.post( + HTTP.post( callback, xml, [ -- cgit v1.2.3 From 56fd7dbdd7e3f1a0bb05430ed4805d8715e54935 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sat, 25 May 2019 04:39:32 +0000 Subject: remove @websub and @ostatus module-level constants --- lib/pleroma/web/federator/federator.ex | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex index 6b0b75284..f4c9fe284 100644 --- a/lib/pleroma/web/federator/federator.ex +++ b/lib/pleroma/web/federator/federator.ex @@ -11,13 +11,11 @@ defmodule Pleroma.Web.Federator do alias Pleroma.Web.ActivityPub.Utils alias Pleroma.Web.Federator.Publisher alias Pleroma.Web.Federator.RetryQueue + alias Pleroma.Web.OStatus alias Pleroma.Web.Websub require Logger - @websub Application.get_env(:pleroma, :websub) - @ostatus Application.get_env(:pleroma, :ostatus) - def init do # 1 minute Process.sleep(1000 * 60) @@ -87,12 +85,12 @@ defmodule Pleroma.Web.Federator do "Running WebSub verification for #{websub.id} (#{websub.topic}, #{websub.callback})" end) - @websub.verify(websub) + Websub.verify(websub) end def perform(:incoming_doc, doc) do Logger.info("Got document, trying to parse") - @ostatus.handle_incoming(doc) + OStatus.handle_incoming(doc) end def perform(:incoming_ap_doc, params) do -- cgit v1.2.3 From 4030837d91b7ff8525513589d5d810e9a1a6b959 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sat, 25 May 2019 05:19:47 +0000 Subject: notification: add non_follows/non_followers notification control settings --- lib/pleroma/notification.ex | 32 +++++++++++++++++++++++++++++++- lib/pleroma/user/info.ex | 11 +++++++++-- 2 files changed, 40 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 844264307..4095e0474 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -166,7 +166,17 @@ defmodule Pleroma.Notification do def get_notified_from_activity(_, _local_only), do: [] def skip?(activity, user) do - [:self, :blocked, :local, :muted, :followers, :follows, :recently_followed] + [ + :self, + :blocked, + :local, + :muted, + :followers, + :follows, + :non_followers, + :non_follows, + :recently_followed + ] |> Enum.any?(&skip?(&1, activity, user)) end @@ -201,12 +211,32 @@ defmodule Pleroma.Notification do User.following?(follower, user) end + def skip?( + :non_followers, + activity, + %{info: %{notification_settings: %{"non_followers" => false}}} = user + ) do + actor = activity.data["actor"] + follower = User.get_cached_by_ap_id(actor) + !User.following?(follower, user) + end + def skip?(:follows, activity, %{info: %{notification_settings: %{"follows" => false}}} = user) do actor = activity.data["actor"] followed = User.get_cached_by_ap_id(actor) User.following?(user, followed) end + def skip?( + :non_follows, + activity, + %{info: %{notification_settings: %{"non_follows" => false}}} = user + ) do + actor = activity.data["actor"] + followed = User.get_cached_by_ap_id(actor) + !User.following?(user, followed) + end + def skip?(:recently_followed, %{data: %{"type" => "Follow"}} = activity, user) do actor = activity.data["actor"] diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index 6397e2737..fb4cf3cc3 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -47,7 +47,14 @@ defmodule Pleroma.User.Info do field(:emoji, {:array, :map}, default: []) field(:notification_settings, :map, - default: %{"remote" => true, "local" => true, "followers" => true, "follows" => true} + default: %{ + "remote" => true, + "local" => true, + "followers" => true, + "follows" => true, + "non_follows" => true, + "non_followers" => true + } ) # Found in the wild @@ -71,7 +78,7 @@ defmodule Pleroma.User.Info do notification_settings = info.notification_settings |> Map.merge(settings) - |> Map.take(["remote", "local", "followers", "follows"]) + |> Map.take(["remote", "local", "followers", "follows", "non_follows", "non_followers"]) params = %{notification_settings: notification_settings} -- cgit v1.2.3 From 59a703fcbe6436c92d0e276caaf55f599c3165f4 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sat, 25 May 2019 05:31:13 +0000 Subject: twitter api: user view: expose user notification settings under pleroma object --- lib/pleroma/web/twitter_api/views/user_view.ex | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex index f0a4ddbd3..550f35f5f 100644 --- a/lib/pleroma/web/twitter_api/views/user_view.ex +++ b/lib/pleroma/web/twitter_api/views/user_view.ex @@ -121,6 +121,7 @@ defmodule Pleroma.Web.TwitterAPI.UserView do "tags" => user.tags } |> maybe_with_activation_status(user, for_user) + |> with_notification_settings(user, for_user) } |> maybe_with_user_settings(user, for_user) |> maybe_with_role(user, for_user) @@ -132,6 +133,12 @@ defmodule Pleroma.Web.TwitterAPI.UserView do end end + defp with_notification_settings(data, %User{id: user_id} = user, %User{id: user_id}) do + Map.put(data, "notification_settings", user.info.notification_settings) + end + + defp with_notification_settings(data, _, _), do: data + defp maybe_with_activation_status(data, user, %User{info: %{is_admin: true}}) do Map.put(data, "deactivated", user.info.deactivated) end -- cgit v1.2.3 From e7e2e7a1a633e2f7e493d040e290c931320d8cc8 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sat, 25 May 2019 05:54:02 +0000 Subject: user info: allow formdata for notification settings like every other API --- lib/pleroma/user/info.ex | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index fb4cf3cc3..b0bfdf4f4 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -75,6 +75,11 @@ defmodule Pleroma.User.Info do end def update_notification_settings(info, settings) do + settings = + settings + |> Enum.map(fn {k, v} -> {k, v in [true, "true", "True", "1"]} end) + |> Map.new() + notification_settings = info.notification_settings |> Map.merge(settings) -- cgit v1.2.3 From 750ede5764d30063587182696f7ebc50c05f8278 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 26 May 2019 00:05:47 +0000 Subject: notification: remove local/remote match rules (too complicated) --- lib/pleroma/notification.ex | 7 ------- lib/pleroma/user/info.ex | 4 +--- 2 files changed, 1 insertion(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 4095e0474..35beffb87 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -169,7 +169,6 @@ defmodule Pleroma.Notification do [ :self, :blocked, - :local, :muted, :followers, :follows, @@ -189,12 +188,6 @@ defmodule Pleroma.Notification do User.blocks?(user, %{ap_id: actor}) end - def skip?(:local, %{local: true}, %{info: %{notification_settings: %{"local" => false}}}), - do: true - - def skip?(:local, %{local: false}, %{info: %{notification_settings: %{"remote" => false}}}), - do: true - def skip?(:muted, activity, user) do actor = activity.data["actor"] diff --git a/lib/pleroma/user/info.ex b/lib/pleroma/user/info.ex index b0bfdf4f4..74573ba83 100644 --- a/lib/pleroma/user/info.ex +++ b/lib/pleroma/user/info.ex @@ -48,8 +48,6 @@ defmodule Pleroma.User.Info do field(:notification_settings, :map, default: %{ - "remote" => true, - "local" => true, "followers" => true, "follows" => true, "non_follows" => true, @@ -83,7 +81,7 @@ defmodule Pleroma.User.Info do notification_settings = info.notification_settings |> Map.merge(settings) - |> Map.take(["remote", "local", "followers", "follows", "non_follows", "non_followers"]) + |> Map.take(["followers", "follows", "non_follows", "non_followers"]) params = %{notification_settings: notification_settings} -- cgit v1.2.3 From 79503ce90f6d85f00ee9e2dbc6358df2237d5036 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 26 May 2019 01:57:22 +0000 Subject: mrf: simple policy: fix matching imported activitypub and ostatus statuses --- lib/pleroma/web/activity_pub/mrf/simple_policy.ex | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex index 890d70a7a..433d23c5f 100644 --- a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex @@ -74,8 +74,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do actor_host ), user <- User.get_cached_by_ap_id(object["actor"]), - true <- "https://www.w3.org/ns/activitystreams#Public" in object["to"], - true <- user.follower_address in object["cc"] do + true <- "https://www.w3.org/ns/activitystreams#Public" in object["to"] do to = List.delete(object["to"], "https://www.w3.org/ns/activitystreams#Public") ++ [user.follower_address] -- cgit v1.2.3 From 9f3bcf0efe7fa06e2b8970386c099c1ea2974d0a Mon Sep 17 00:00:00 2001 From: jeff Date: Tue, 28 May 2019 06:49:53 +0000 Subject: Respect proxy settings federation --- lib/pleroma/http/connection.ex | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/http/connection.ex b/lib/pleroma/http/connection.ex index 558005c19..c216cdcb1 100644 --- a/lib/pleroma/http/connection.ex +++ b/lib/pleroma/http/connection.ex @@ -32,9 +32,11 @@ defmodule Pleroma.HTTP.Connection do defp hackney_options(opts) do options = Keyword.get(opts, :adapter, []) adapter_options = Pleroma.Config.get([:http, :adapter], []) + proxy_url = Pleroma.Config.get([:http, :proxy_url], nil) @hackney_options |> Keyword.merge(adapter_options) |> Keyword.merge(options) + |> Keyword.merge(proxy: proxy_url) end end -- cgit v1.2.3 From 0159a6dbe97330150d2913c7d7a060151f83f7eb Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Wed, 29 May 2019 10:58:45 +0000 Subject: router: require oauth_read for searching Search calls are generally expensive and allow unauthenticated users to crawl the instance for user profiles or posts which contain specified keywords. An adversary can build a distributed search engine which not only will consume significant instance resources, but also can be used for undesirable purposes such as datamining. Accordingly, require authenticated access to use the search API endpoints. This acts as a nice balance as it allows guest users to make use of most functionality available in Pleroma FE while ensuring that Pleroma instances are reasonably protected from resource exhaustion. It also removes Pleroma as a potential vector in distributed search engines. --- lib/pleroma/web/router.ex | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 352268b96..08c74a742 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -414,7 +414,12 @@ defmodule Pleroma.Web.Router do get("/trends", MastodonAPIController, :empty_array) - get("/accounts/search", MastodonAPIController, :account_search) + scope [] do + pipe_through(:oauth_read) + + get("/search", MastodonAPIController, :search) + get("/accounts/search", MastodonAPIController, :account_search) + end scope [] do pipe_through(:oauth_read_or_public) @@ -431,14 +436,12 @@ defmodule Pleroma.Web.Router do get("/accounts/:id/following", MastodonAPIController, :following) get("/accounts/:id", MastodonAPIController, :user) - get("/search", MastodonAPIController, :search) - get("/pleroma/accounts/:id/favourites", MastodonAPIController, :user_favourites) end end scope "/api/v2", Pleroma.Web.MastodonAPI do - pipe_through([:api, :oauth_read_or_public]) + pipe_through([:api, :oauth_read]) get("/search", MastodonAPIController, :search2) end @@ -480,9 +483,14 @@ defmodule Pleroma.Web.Router do get("/statuses/show/:id", TwitterAPI.Controller, :fetch_status) get("/statusnet/conversation/:id", TwitterAPI.Controller, :fetch_conversation) - get("/search", TwitterAPI.Controller, :search) get("/statusnet/tags/timeline/:tag", TwitterAPI.Controller, :public_and_external_timeline) end + + scope [] do + pipe_through(:oauth_read) + + get("/search", TwitterAPI.Controller, :search) + end end scope "/api", Pleroma.Web do @@ -500,7 +508,7 @@ defmodule Pleroma.Web.Router do end scope "/api", Pleroma.Web, as: :twitter_api_search do - pipe_through([:api, :oauth_read_or_public]) + pipe_through([:api, :oauth_read]) get("/pleroma/search_user", TwitterAPI.Controller, :search_user) end -- cgit v1.2.3 From 672fddb7213b69f3ee8b9a7728426373090847ed Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Wed, 29 May 2019 08:06:26 -0500 Subject: Default search limit should be 40 https://docs.joinmastodon.org/api/rest/search/ --- lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 0fe09c285..2110027c3 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -1084,7 +1084,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do from([a, o] in Activity.with_preloaded_object(Activity), where: fragment("?->>'type' = 'Create'", a.data), where: "https://www.w3.org/ns/activitystreams#Public" in a.recipients, - limit: 20 + limit: 40 ) q = -- cgit v1.2.3 From 6aec0d1b58c12db2fa669fcff043338174290a35 Mon Sep 17 00:00:00 2001 From: kaniini Date: Wed, 29 May 2019 22:10:16 +0000 Subject: Revert "Merge branch 'feature/search-authenticated-only' into 'develop'" This reverts merge request !1209 --- lib/pleroma/web/router.ex | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 08c74a742..352268b96 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -414,12 +414,7 @@ defmodule Pleroma.Web.Router do get("/trends", MastodonAPIController, :empty_array) - scope [] do - pipe_through(:oauth_read) - - get("/search", MastodonAPIController, :search) - get("/accounts/search", MastodonAPIController, :account_search) - end + get("/accounts/search", MastodonAPIController, :account_search) scope [] do pipe_through(:oauth_read_or_public) @@ -436,12 +431,14 @@ defmodule Pleroma.Web.Router do get("/accounts/:id/following", MastodonAPIController, :following) get("/accounts/:id", MastodonAPIController, :user) + get("/search", MastodonAPIController, :search) + get("/pleroma/accounts/:id/favourites", MastodonAPIController, :user_favourites) end end scope "/api/v2", Pleroma.Web.MastodonAPI do - pipe_through([:api, :oauth_read]) + pipe_through([:api, :oauth_read_or_public]) get("/search", MastodonAPIController, :search2) end @@ -483,13 +480,8 @@ defmodule Pleroma.Web.Router do get("/statuses/show/:id", TwitterAPI.Controller, :fetch_status) get("/statusnet/conversation/:id", TwitterAPI.Controller, :fetch_conversation) - get("/statusnet/tags/timeline/:tag", TwitterAPI.Controller, :public_and_external_timeline) - end - - scope [] do - pipe_through(:oauth_read) - get("/search", TwitterAPI.Controller, :search) + get("/statusnet/tags/timeline/:tag", TwitterAPI.Controller, :public_and_external_timeline) end end @@ -508,7 +500,7 @@ defmodule Pleroma.Web.Router do end scope "/api", Pleroma.Web, as: :twitter_api_search do - pipe_through([:api, :oauth_read]) + pipe_through([:api, :oauth_read_or_public]) get("/pleroma/search_user", TwitterAPI.Controller, :search_user) end -- cgit v1.2.3 From 99f70c7e2011ab29746a8a61d3a4b354f4513045 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Thu, 30 May 2019 15:33:58 +0700 Subject: Use Pleroma.Config everywhere --- lib/healthcheck.ex | 4 +- lib/pleroma/emoji.ex | 4 +- lib/pleroma/html.ex | 20 ++----- lib/pleroma/http/http.ex | 7 +-- lib/pleroma/plugs/federating_plug.ex | 2 +- lib/pleroma/reverse_proxy.ex | 2 +- lib/pleroma/user.ex | 4 +- lib/pleroma/web/activity_pub/activity_pub.ex | 12 ++-- .../web/activity_pub/activity_pub_controller.ex | 2 +- lib/pleroma/web/activity_pub/mrf.ex | 4 +- lib/pleroma/web/endpoint.ex | 2 +- lib/pleroma/web/media_proxy/media_proxy.ex | 30 +++++----- lib/pleroma/web/nodeinfo/nodeinfo_controller.ex | 66 +++++++++------------- lib/pleroma/web/templates/layout/app.html.eex | 4 +- .../templates/mastodon_api/mastodon/index.html.eex | 2 +- .../web/twitter_api/twitter_api_controller.ex | 2 +- 16 files changed, 68 insertions(+), 99 deletions(-) (limited to 'lib') diff --git a/lib/healthcheck.ex b/lib/healthcheck.ex index 646fb3b9d..32aafc210 100644 --- a/lib/healthcheck.ex +++ b/lib/healthcheck.ex @@ -29,13 +29,13 @@ defmodule Pleroma.Healthcheck do end defp assign_db_info(healthcheck) do - database = Application.get_env(:pleroma, Repo)[:database] + database = Pleroma.Config.get([Repo, :database]) query = "select state, count(pid) from pg_stat_activity where datname = '#{database}' group by state;" result = Repo.query!(query) - pool_size = Application.get_env(:pleroma, Repo)[:pool_size] + pool_size = Pleroma.Config.get([Repo, :pool_size]) db_info = Enum.reduce(result.rows, %{active: 0, idle: 0}, fn [state, cnt], states -> diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex index 6390cce4c..7d12eff7f 100644 --- a/lib/pleroma/emoji.ex +++ b/lib/pleroma/emoji.ex @@ -22,7 +22,7 @@ defmodule Pleroma.Emoji do @ets __MODULE__.Ets @ets_options [:ordered_set, :protected, :named_table, {:read_concurrency, true}] - @groups Application.get_env(:pleroma, :emoji)[:groups] + @groups Pleroma.Config.get([:emoji, :groups]) @doc false def start_link do @@ -112,7 +112,7 @@ defmodule Pleroma.Emoji do # Compat thing for old custom emoji handling & default emoji, # it should run even if there are no emoji packs - shortcode_globs = Application.get_env(:pleroma, :emoji)[:shortcode_globs] || [] + shortcode_globs = Pleroma.Config.get([:emoji, :shortcode_globs], []) emojis = (load_from_file("config/emoji.txt") ++ diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex index d1da746de..e5e78ee4f 100644 --- a/lib/pleroma/html.ex +++ b/lib/pleroma/html.ex @@ -104,7 +104,6 @@ defmodule Pleroma.HTML.Scrubber.TwitterText do paragraphs, breaks and links are allowed through the filter. """ - @markup Application.get_env(:pleroma, :markup) @valid_schemes Pleroma.Config.get([:uri_schemes, :valid_schemes], []) require HtmlSanitizeEx.Scrubber.Meta @@ -142,9 +141,7 @@ defmodule Pleroma.HTML.Scrubber.TwitterText do Meta.allow_tag_with_these_attributes("span", []) # allow inline images for custom emoji - @allow_inline_images Keyword.get(@markup, :allow_inline_images) - - if @allow_inline_images do + if Pleroma.Config.get([:markup, :allow_inline_images]) do # restrict img tags to http/https only, because of MediaProxy. Meta.allow_tag_with_uri_attributes("img", ["src"], ["http", "https"]) @@ -168,7 +165,6 @@ defmodule Pleroma.HTML.Scrubber.Default do # credo:disable-for-previous-line # No idea how to fix this one… - @markup Application.get_env(:pleroma, :markup) @valid_schemes Pleroma.Config.get([:uri_schemes, :valid_schemes], []) Meta.remove_cdata_sections_before_scrub() @@ -213,7 +209,7 @@ defmodule Pleroma.HTML.Scrubber.Default do Meta.allow_tag_with_this_attribute_values("span", "class", ["h-card"]) Meta.allow_tag_with_these_attributes("span", []) - @allow_inline_images Keyword.get(@markup, :allow_inline_images) + @allow_inline_images Pleroma.Config.get([:markup, :allow_inline_images]) if @allow_inline_images do # restrict img tags to http/https only, because of MediaProxy. @@ -228,9 +224,7 @@ defmodule Pleroma.HTML.Scrubber.Default do ]) end - @allow_tables Keyword.get(@markup, :allow_tables) - - if @allow_tables do + if Pleroma.Config.get([:markup, :allow_tables]) do Meta.allow_tag_with_these_attributes("table", []) Meta.allow_tag_with_these_attributes("tbody", []) Meta.allow_tag_with_these_attributes("td", []) @@ -239,9 +233,7 @@ defmodule Pleroma.HTML.Scrubber.Default do Meta.allow_tag_with_these_attributes("tr", []) end - @allow_headings Keyword.get(@markup, :allow_headings) - - if @allow_headings do + if Pleroma.Config.get([:markup, :allow_headings]) do Meta.allow_tag_with_these_attributes("h1", []) Meta.allow_tag_with_these_attributes("h2", []) Meta.allow_tag_with_these_attributes("h3", []) @@ -249,9 +241,7 @@ defmodule Pleroma.HTML.Scrubber.Default do Meta.allow_tag_with_these_attributes("h5", []) end - @allow_fonts Keyword.get(@markup, :allow_fonts) - - if @allow_fonts do + if Pleroma.Config.get([:markup, :allow_fonts]) do Meta.allow_tag_with_these_attributes("font", ["face"]) end diff --git a/lib/pleroma/http/http.ex b/lib/pleroma/http/http.ex index c5f720bc9..c96ee7353 100644 --- a/lib/pleroma/http/http.ex +++ b/lib/pleroma/http/http.ex @@ -65,12 +65,9 @@ defmodule Pleroma.HTTP do end def process_request_options(options) do - config = Application.get_env(:pleroma, :http, []) - proxy = Keyword.get(config, :proxy_url, nil) - - case proxy do + case Pleroma.Config.get([:http, :proxy_url]) do nil -> options - _ -> options ++ [proxy: proxy] + proxy -> options ++ [proxy: proxy] end end diff --git a/lib/pleroma/plugs/federating_plug.ex b/lib/pleroma/plugs/federating_plug.ex index effc154bf..4dc4e9279 100644 --- a/lib/pleroma/plugs/federating_plug.ex +++ b/lib/pleroma/plugs/federating_plug.ex @@ -10,7 +10,7 @@ defmodule Pleroma.Web.FederatingPlug do end def call(conn, _opts) do - if Keyword.get(Application.get_env(:pleroma, :instance), :federating) do + if Pleroma.Config.get([:instance, :federating]) do conn else conn diff --git a/lib/pleroma/reverse_proxy.ex b/lib/pleroma/reverse_proxy.ex index 6e5feb4c3..983e156f5 100644 --- a/lib/pleroma/reverse_proxy.ex +++ b/lib/pleroma/reverse_proxy.ex @@ -61,7 +61,7 @@ defmodule Pleroma.ReverseProxy do * `http`: options for [hackney](https://github.com/benoitc/hackney). """ - @hackney Application.get_env(:pleroma, :hackney, :hackney) + @hackney Pleroma.Config.get(:hackney, :hackney) @default_hackney_options [] diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 653dec95f..5c91dc7d4 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -366,9 +366,7 @@ defmodule Pleroma.User do end def follow(%User{} = follower, %User{info: info} = followed) do - user_config = Application.get_env(:pleroma, :user) - deny_follow_blocked = Keyword.get(user_config, :deny_follow_blocked) - + deny_follow_blocked = Pleroma.Config.get([:user, :deny_follow_blocked]) ap_followers = followed.follower_address cond do diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index aa0229db7..bdd7e78d2 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -399,16 +399,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end def block(blocker, blocked, activity_id \\ nil, local \\ true) do - ap_config = Application.get_env(:pleroma, :activitypub) - unfollow_blocked = Keyword.get(ap_config, :unfollow_blocked) - outgoing_blocks = Keyword.get(ap_config, :outgoing_blocks) + outgoing_blocks = Pleroma.Config.get([:activitypub, :outgoing_blocks]) + unfollow_blocked = Pleroma.Config.get([:activitypub, :unfollow_blocked]) - with true <- unfollow_blocked do + if unfollow_blocked do follow_activity = fetch_latest_follow(blocker, blocked) - - if follow_activity do - unfollow(blocker, blocked, nil, local) - end + if follow_activity, do: unfollow(blocker, blocked, nil, local) end with true <- outgoing_blocks, diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index ad2ca1e54..0182bda46 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -27,7 +27,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do plug(:relay_active? when action in [:relay]) def relay_active?(conn, _) do - if Keyword.get(Application.get_env(:pleroma, :instance), :allow_relay) do + if Pleroma.Config.get([:instance, :allow_relay]) do conn else conn diff --git a/lib/pleroma/web/activity_pub/mrf.ex b/lib/pleroma/web/activity_pub/mrf.ex index 1aaa20050..3bf7955f3 100644 --- a/lib/pleroma/web/activity_pub/mrf.ex +++ b/lib/pleroma/web/activity_pub/mrf.ex @@ -17,9 +17,7 @@ defmodule Pleroma.Web.ActivityPub.MRF do end def get_policies do - Application.get_env(:pleroma, :instance, []) - |> Keyword.get(:rewrite_policy, []) - |> get_policies() + Pleroma.Config.get([:instance, :rewrite_policy], []) |> get_policies() end defp get_policies(policy) when is_atom(policy), do: [policy] diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex index 8cd7a2270..bd76e4295 100644 --- a/lib/pleroma/web/endpoint.ex +++ b/lib/pleroma/web/endpoint.ex @@ -66,7 +66,7 @@ defmodule Pleroma.Web.Endpoint do parsers: [:urlencoded, :multipart, :json], pass: ["*/*"], json_decoder: Jason, - length: Application.get_env(:pleroma, :instance) |> Keyword.get(:upload_limit), + length: Pleroma.Config.get([:instance, :upload_limit]), body_reader: {Pleroma.Web.Plugs.DigestPlug, :read_body, []} ) diff --git a/lib/pleroma/web/media_proxy/media_proxy.ex b/lib/pleroma/web/media_proxy/media_proxy.ex index 5762e767b..cee6d8481 100644 --- a/lib/pleroma/web/media_proxy/media_proxy.ex +++ b/lib/pleroma/web/media_proxy/media_proxy.ex @@ -12,25 +12,27 @@ defmodule Pleroma.Web.MediaProxy do def url("/" <> _ = url), do: url def url(url) do - config = Application.get_env(:pleroma, :media_proxy, []) - domain = URI.parse(url).host + if !enabled?() or local?(url) or whitelisted?(url) do + url + else + encode_url(url) + end + end - cond do - !Keyword.get(config, :enabled, false) or String.starts_with?(url, Pleroma.Web.base_url()) -> - url + defp enabled?, do: Pleroma.Config.get([:media_proxy, :enabled], false) - Enum.any?(Pleroma.Config.get([:media_proxy, :whitelist]), fn pattern -> - String.equivalent?(domain, pattern) - end) -> - url + defp local?(url), do: String.starts_with?(url, Pleroma.Web.base_url()) - true -> - encode_url(url) - end + defp whitelisted?(url) do + %{host: domain} = URI.parse(url) + + Enum.any?(Pleroma.Config.get([:media_proxy, :whitelist]), fn pattern -> + String.equivalent?(domain, pattern) + end) end def encode_url(url) do - secret = Application.get_env(:pleroma, Pleroma.Web.Endpoint)[:secret_key_base] + secret = Pleroma.Config.get([Pleroma.Web.Endpoint, :secret_key_base]) # Must preserve `%2F` for compatibility with S3 # https://git.pleroma.social/pleroma/pleroma/issues/580 @@ -52,7 +54,7 @@ defmodule Pleroma.Web.MediaProxy do end def decode_url(sig, url) do - secret = Application.get_env(:pleroma, Pleroma.Web.Endpoint)[:secret_key_base] + secret = Pleroma.Config.get([Pleroma.Web.Endpoint, :secret_key_base]) sig = Base.url_decode64!(sig, @base64_opts) local_sig = :crypto.hmac(:sha, secret, url) diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex index 45f90c579..59f3d4e11 100644 --- a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex +++ b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex @@ -32,20 +32,15 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do # returns a nodeinfo 2.0 map, since 2.1 just adds a repository field # under software. def raw_nodeinfo do - instance = Application.get_env(:pleroma, :instance) - media_proxy = Application.get_env(:pleroma, :media_proxy) - suggestions = Application.get_env(:pleroma, :suggestions) - chat = Application.get_env(:pleroma, :chat) - gopher = Application.get_env(:pleroma, :gopher) stats = Stats.get_stats() mrf_simple = - Application.get_env(:pleroma, :mrf_simple) + Config.get(:mrf_simple) |> Enum.into(%{}) # This horror is needed to convert regex sigils to strings mrf_keyword = - Application.get_env(:pleroma, :mrf_keyword, []) + Config.get(:mrf_keyword, []) |> Enum.map(fn {key, value} -> {key, Enum.map(value, fn @@ -74,14 +69,7 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do MRF.get_policies() |> Enum.map(fn policy -> to_string(policy) |> String.split(".") |> List.last() end) - quarantined = Keyword.get(instance, :quarantined_instances) - - quarantined = - if is_list(quarantined) do - quarantined - else - [] - end + quarantined = Config.get([:instance, :quarantined_instances], []) staff_accounts = User.all_superusers() @@ -92,7 +80,7 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do |> Enum.into(%{}, fn {k, v} -> {k, length(v)} end) federation_response = - if Keyword.get(instance, :mrf_transparency) do + if Config.get([:instance, :mrf_transparency]) do %{ mrf_policies: mrf_policies, mrf_simple: mrf_simple, @@ -109,22 +97,22 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do "pleroma_api", "mastodon_api", "mastodon_api_streaming", - if Keyword.get(media_proxy, :enabled) do + if Config.get([:media_proxy, :enabled]) do "media_proxy" end, - if Keyword.get(gopher, :enabled) do + if Config.get([:gopher, :enabled]) do "gopher" end, - if Keyword.get(chat, :enabled) do + if Config.get([:chat, :enabled]) do "chat" end, - if Keyword.get(suggestions, :enabled) do + if Config.get([:suggestions, :enabled]) do "suggestions" end, - if Keyword.get(instance, :allow_relay) do + if Config.get([:instance, :allow_relay]) do "relay" end, - if Keyword.get(instance, :safe_dm_mentions) do + if Config.get([:instance, :safe_dm_mentions]) do "safe_dm_mentions" end ] @@ -141,7 +129,7 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do inbound: [], outbound: [] }, - openRegistrations: Keyword.get(instance, :registrations_open), + openRegistrations: Config.get([:instance, :registrations_open]), usage: %{ users: %{ total: stats.user_count || 0 @@ -149,29 +137,29 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do localPosts: stats.status_count || 0 }, metadata: %{ - nodeName: Keyword.get(instance, :name), - nodeDescription: Keyword.get(instance, :description), - private: !Keyword.get(instance, :public, true), + nodeName: Config.get([:instance, :name]), + nodeDescription: Config.get([:instance, :description]), + private: !Config.get([:instance, :public], true), suggestions: %{ - enabled: Keyword.get(suggestions, :enabled, false), - thirdPartyEngine: Keyword.get(suggestions, :third_party_engine, ""), - timeout: Keyword.get(suggestions, :timeout, 5000), - limit: Keyword.get(suggestions, :limit, 23), - web: Keyword.get(suggestions, :web, "") + enabled: Config.get([:suggestions, :enabled], false), + thirdPartyEngine: Config.get([:suggestions, :third_party_engine], ""), + timeout: Config.get([:suggestions, :timeout], 5000), + limit: Config.get([:suggestions, :limit], 23), + web: Config.get([:suggestions, :web], "") }, staffAccounts: staff_accounts, federation: federation_response, - postFormats: Keyword.get(instance, :allowed_post_formats), + postFormats: Config.get([:instance, :allowed_post_formats]), uploadLimits: %{ - general: Keyword.get(instance, :upload_limit), - avatar: Keyword.get(instance, :avatar_upload_limit), - banner: Keyword.get(instance, :banner_upload_limit), - background: Keyword.get(instance, :background_upload_limit) + general: Config.get([:instance, :upload_limit]), + avatar: Config.get([:instance, :avatar_upload_limit]), + banner: Config.get([:instance, :banner_upload_limit]), + background: Config.get([:instance, :background_upload_limit]) }, - accountActivationRequired: Keyword.get(instance, :account_activation_required, false), - invitesEnabled: Keyword.get(instance, :invites_enabled, false), + accountActivationRequired: Config.get([:instance, :account_activation_required], false), + invitesEnabled: Config.get([:instance, :invites_enabled], false), features: features, - restrictedNicknames: Pleroma.Config.get([Pleroma.User, :restricted_nicknames]) + restrictedNicknames: Config.get([Pleroma.User, :restricted_nicknames]) } } end diff --git a/lib/pleroma/web/templates/layout/app.html.eex b/lib/pleroma/web/templates/layout/app.html.eex index 3389c91cc..85ec4d76c 100644 --- a/lib/pleroma/web/templates/layout/app.html.eex +++ b/lib/pleroma/web/templates/layout/app.html.eex @@ -4,7 +4,7 @@ - <%= Application.get_env(:pleroma, :instance)[:name] %> + <%= Pleroma.Config.get([:instance, :name]) %>