diff options
Diffstat (limited to 'lib')
35 files changed, 591 insertions, 227 deletions
diff --git a/lib/mix/tasks/pleroma/database.ex b/lib/mix/tasks/pleroma/database.ex index ab9a3a7ff..f650b447d 100644 --- a/lib/mix/tasks/pleroma/database.ex +++ b/lib/mix/tasks/pleroma/database.ex @@ -4,6 +4,9 @@ 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 @@ -19,6 +22,14 @@ 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 + + ## 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, [], []} = @@ -32,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 @@ -41,11 +52,24 @@ 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 ) end end + + def run(["bump_all_conversations"]) 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/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/activity.ex b/lib/pleroma/activity.ex index 4a0919478..4e54b15ba 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 @@ -108,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/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) diff --git a/lib/pleroma/conversation.ex b/lib/pleroma/conversation.ex index 0db195988..238c1acf2 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), "Create" <- activity.data["type"], object <- Pleroma.Object.normalize(activity), @@ -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) @@ -72,4 +72,21 @@ 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(fn a -> create_or_bump_for(a, read: true) end) + end, + timeout: :infinity + ) + end end 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/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/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) 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 <https://pleroma.social/> +# 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 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 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 <https://pleroma.social/> +# 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/user.ex b/lib/pleroma/user.ex index c6a562a61..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 @@ -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) @@ -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 @@ -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} @@ -1378,4 +1390,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) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 233fee4fa..5c3156978 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 @@ -569,6 +565,18 @@ 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) + ) + + query + end + + defp restrict_thread_visibility(query, _), do: query + def fetch_user_activities(user, reading_user, params \\ %{}) do params = params @@ -695,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, @@ -750,8 +764,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, + [activity, object: o] in query, where: fragment("not (? = ANY(?))", activity.actor, ^blocks), where: fragment("not (? && ?)", activity.recipients, ^blocks), where: @@ -761,7 +778,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 @@ -843,11 +861,13 @@ 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) |> restrict_media(opts) |> restrict_visibility(opts) + |> restrict_thread_visibility(opts) |> restrict_replies(opts) |> restrict_reblogs(opts) |> restrict_pinned(opts) @@ -966,11 +986,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub 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) + def fetch_direct_messages_query do + Activity + |> restrict_type(%{"type" => "Create"}) + |> restrict_visibility(%{visibility: "direct"}) + |> order_by([activity], asc: activity.id) end end 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) 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/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/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/activity_pub/visibility.ex b/lib/pleroma/web/activity_pub/visibility.ex index 6dee61dd6..93b50ee47 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 @@ -13,11 +14,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 @@ -38,24 +40,37 @@ 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 + result + 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" - 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) + length(cc) > 0 -> + "private" - _ -> - visible_for_user?(tail, user) + true -> + "direct" 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 <https://pleroma.social/> +# 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 b53869c75..a599ffee5 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 @@ -116,32 +119,34 @@ 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" + 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(_, in_reply_to), do: {"public", get_replied_to_visibility(in_reply_to)} - 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 + 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 get_visibility(_), do: "public" - 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), in_reply_to <- get_replied_to_activity(data["in_reply_to_status_id"]), + {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} <- make_content_html( status, @@ -185,6 +190,8 @@ defmodule Pleroma.Web.CommonAPI do ) res + else + e -> {:error, e} end end @@ -193,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 @@ -226,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 @@ -243,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 @@ -311,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/federator/publisher.ex b/lib/pleroma/web/federator/publisher.ex index 916bcdcba..70f870244 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 @@ -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/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 <https://pleroma.social/> -# 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 diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 87e597074..1b776fbca 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 @@ -1223,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/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 "<p><a href=\"#{object.data["id"]}\">#{name}</a></p>#{object.data["content"]}" 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/router.ex b/lib/pleroma/web/router.ex index 80af0afe1..6a4e4a1d4 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 @@ -192,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 @@ -404,7 +414,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 +435,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 +465,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 +483,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 +497,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 +681,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 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) 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, 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) |