diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/mix/tasks/pleroma/notification_settings.ex | 83 | ||||
-rw-r--r-- | lib/mix/tasks/pleroma/user.ex | 6 | ||||
-rw-r--r-- | lib/pleroma/application.ex | 1 | ||||
-rw-r--r-- | lib/pleroma/html.ex | 232 | ||||
-rw-r--r-- | lib/pleroma/notification.ex | 42 | ||||
-rw-r--r-- | lib/pleroma/plugs/parsers_plug.ex | 21 | ||||
-rw-r--r-- | lib/pleroma/user.ex | 26 | ||||
-rw-r--r-- | lib/pleroma/user/notification_setting.ex | 40 | ||||
-rw-r--r-- | lib/pleroma/web/endpoint.ex | 9 | ||||
-rw-r--r-- | lib/pleroma/web/push/impl.ex | 27 | ||||
-rw-r--r-- | lib/pleroma/workers/web_pusher_worker.ex | 2 |
11 files changed, 222 insertions, 267 deletions
diff --git a/lib/mix/tasks/pleroma/notification_settings.ex b/lib/mix/tasks/pleroma/notification_settings.ex new file mode 100644 index 000000000..7d65f0587 --- /dev/null +++ b/lib/mix/tasks/pleroma/notification_settings.ex @@ -0,0 +1,83 @@ +defmodule Mix.Tasks.Pleroma.NotificationSettings do + @shortdoc "Enable&Disable privacy option for push notifications" + @moduledoc """ + Example: + + > mix pleroma.notification_settings --privacy-option=false --nickname-users="parallel588" # set false only for parallel588 user + > mix pleroma.notification_settings --privacy-option=true # set true for all users + + """ + + use Mix.Task + import Mix.Pleroma + import Ecto.Query + + def run(args) do + start_pleroma() + + {options, _, _} = + OptionParser.parse( + args, + strict: [ + privacy_option: :boolean, + email_users: :string, + nickname_users: :string + ] + ) + + privacy_option = Keyword.get(options, :privacy_option) + + if not is_nil(privacy_option) do + privacy_option + |> build_query(options) + |> Pleroma.Repo.update_all([]) + end + + shell_info("Done") + end + + defp build_query(privacy_option, options) do + query = + from(u in Pleroma.User, + update: [ + set: [ + notification_settings: + fragment( + "jsonb_set(notification_settings, '{privacy_option}', ?)", + ^privacy_option + ) + ] + ] + ) + + user_emails = + options + |> Keyword.get(:email_users, "") + |> String.split(",") + |> Enum.map(&String.trim(&1)) + |> Enum.reject(&(&1 == "")) + + query = + if length(user_emails) > 0 do + where(query, [u], u.email in ^user_emails) + else + query + end + + user_nicknames = + options + |> Keyword.get(:nickname_users, "") + |> String.split(",") + |> Enum.map(&String.trim(&1)) + |> Enum.reject(&(&1 == "")) + + query = + if length(user_nicknames) > 0 do + where(query, [u], u.nickname in ^user_nicknames) + else + query + end + + query + end +end diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index bc8eacda8..0adb78fe3 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -373,9 +373,9 @@ defmodule Mix.Tasks.Pleroma.User do users |> Enum.each(fn user -> shell_info( - "#{user.nickname} moderator: #{user.info.is_moderator}, admin: #{user.info.is_admin}, locked: #{ - user.info.locked - }, deactivated: #{user.info.deactivated}" + "#{user.nickname} moderator: #{user.is_moderator}, admin: #{user.is_admin}, locked: #{ + user.locked + }, deactivated: #{user.deactivated}" ) end) end) diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 0f7b40840..ab7f6d502 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -30,6 +30,7 @@ defmodule Pleroma.Application do # See http://elixir-lang.org/docs/stable/elixir/Application.html # for more information on OTP Applications def start(_type, _args) do + Pleroma.HTML.compile_scrubbers() Pleroma.Config.DeprecationWarnings.warn() setup_instrumenters() diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex index 71c53ce0e..2cae29f35 100644 --- a/lib/pleroma/html.ex +++ b/lib/pleroma/html.ex @@ -3,6 +3,25 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.HTML do + # Scrubbers are compiled on boot so they can be configured in OTP releases + # @on_load :compile_scrubbers + + def compile_scrubbers do + dir = Path.join(:code.priv_dir(:pleroma), "scrubbers") + + dir + |> File.ls!() + |> Enum.map(&Path.join(dir, &1)) + |> Kernel.ParallelCompiler.compile() + |> case do + {:error, _errors, _warnings} -> + raise "Compiling scrubbers failed" + + {:ok, _modules, _warnings} -> + :ok + end + end + defp get_scrubbers(scrubber) when is_atom(scrubber), do: [scrubber] defp get_scrubbers(scrubbers) when is_list(scrubbers), do: scrubbers defp get_scrubbers(_), do: [Pleroma.HTML.Scrubber.Default] @@ -99,216 +118,3 @@ defmodule Pleroma.HTML do end) end end - -defmodule Pleroma.HTML.Scrubber.TwitterText do - @moduledoc """ - An HTML scrubbing policy which limits to twitter-style text. Only - paragraphs, breaks and links are allowed through the filter. - """ - - @valid_schemes Pleroma.Config.get([:uri_schemes, :valid_schemes], []) - - require FastSanitize.Sanitizer.Meta - alias FastSanitize.Sanitizer.Meta - - Meta.strip_comments() - - # links - Meta.allow_tag_with_uri_attributes(:a, ["href", "data-user", "data-tag"], @valid_schemes) - - Meta.allow_tag_with_this_attribute_values(:a, "class", [ - "hashtag", - "u-url", - "mention", - "u-url mention", - "mention u-url" - ]) - - Meta.allow_tag_with_this_attribute_values(:a, "rel", [ - "tag", - "nofollow", - "noopener", - "noreferrer" - ]) - - Meta.allow_tag_with_these_attributes(:a, ["name", "title"]) - - # paragraphs and linebreaks - Meta.allow_tag_with_these_attributes(:br, []) - Meta.allow_tag_with_these_attributes(:p, []) - - # microformats - Meta.allow_tag_with_this_attribute_values(:span, "class", ["h-card"]) - Meta.allow_tag_with_these_attributes(:span, []) - - # allow inline images for custom emoji - 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"]) - - Meta.allow_tag_with_these_attributes(:img, [ - "width", - "height", - "class", - "title", - "alt" - ]) - end - - Meta.strip_everything_not_covered() -end - -defmodule Pleroma.HTML.Scrubber.Default do - @doc "The default HTML scrubbing policy: no " - - require FastSanitize.Sanitizer.Meta - alias FastSanitize.Sanitizer.Meta - - # credo:disable-for-previous-line - # No idea how to fix this one… - - @valid_schemes Pleroma.Config.get([:uri_schemes, :valid_schemes], []) - - Meta.strip_comments() - - Meta.allow_tag_with_uri_attributes(:a, ["href", "data-user", "data-tag"], @valid_schemes) - - Meta.allow_tag_with_this_attribute_values(:a, "class", [ - "hashtag", - "u-url", - "mention", - "u-url mention", - "mention u-url" - ]) - - Meta.allow_tag_with_this_attribute_values(:a, "rel", [ - "tag", - "nofollow", - "noopener", - "noreferrer", - "ugc" - ]) - - Meta.allow_tag_with_these_attributes(:a, ["name", "title"]) - - Meta.allow_tag_with_these_attributes(:abbr, ["title"]) - - Meta.allow_tag_with_these_attributes(:b, []) - Meta.allow_tag_with_these_attributes(:blockquote, []) - Meta.allow_tag_with_these_attributes(:br, []) - Meta.allow_tag_with_these_attributes(:code, []) - Meta.allow_tag_with_these_attributes(:del, []) - Meta.allow_tag_with_these_attributes(:em, []) - Meta.allow_tag_with_these_attributes(:i, []) - Meta.allow_tag_with_these_attributes(:li, []) - Meta.allow_tag_with_these_attributes(:ol, []) - Meta.allow_tag_with_these_attributes(:p, []) - Meta.allow_tag_with_these_attributes(:pre, []) - Meta.allow_tag_with_these_attributes(:strong, []) - Meta.allow_tag_with_these_attributes(:sub, []) - Meta.allow_tag_with_these_attributes(:sup, []) - Meta.allow_tag_with_these_attributes(:u, []) - Meta.allow_tag_with_these_attributes(:ul, []) - - Meta.allow_tag_with_this_attribute_values(:span, "class", ["h-card"]) - Meta.allow_tag_with_these_attributes(:span, []) - - @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. - Meta.allow_tag_with_uri_attributes(:img, ["src"], ["http", "https"]) - - Meta.allow_tag_with_these_attributes(:img, [ - "width", - "height", - "class", - "title", - "alt" - ]) - end - - 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, []) - Meta.allow_tag_with_these_attributes(:th, []) - Meta.allow_tag_with_these_attributes(:thead, []) - Meta.allow_tag_with_these_attributes(:tr, []) - end - - 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, []) - Meta.allow_tag_with_these_attributes(:h4, []) - Meta.allow_tag_with_these_attributes(:h5, []) - end - - if Pleroma.Config.get([:markup, :allow_fonts]) do - Meta.allow_tag_with_these_attributes(:font, ["face"]) - end - - Meta.strip_everything_not_covered() -end - -defmodule Pleroma.HTML.Transform.MediaProxy do - @moduledoc "Transforms inline image URIs to use MediaProxy." - - alias Pleroma.Web.MediaProxy - - def before_scrub(html), do: html - - def scrub_attribute(:img, {"src", "http" <> target}) do - media_url = - ("http" <> target) - |> MediaProxy.url() - - {"src", media_url} - end - - def scrub_attribute(_tag, attribute), do: attribute - - def scrub({:img, attributes, children}) do - attributes = - attributes - |> Enum.map(fn attr -> scrub_attribute(:img, attr) end) - |> Enum.reject(&is_nil(&1)) - - {:img, attributes, children} - end - - def scrub({:comment, _text, _children}), do: "" - - def scrub({tag, attributes, children}), do: {tag, attributes, children} - def scrub({_tag, children}), do: children - def scrub(text), do: text -end - -defmodule Pleroma.HTML.Scrubber.LinksOnly do - @moduledoc """ - An HTML scrubbing policy which limits to links only. - """ - - @valid_schemes Pleroma.Config.get([:uri_schemes, :valid_schemes], []) - - require FastSanitize.Sanitizer.Meta - alias FastSanitize.Sanitizer.Meta - - Meta.strip_comments() - - # links - Meta.allow_tag_with_uri_attributes(:a, ["href"], @valid_schemes) - - Meta.allow_tag_with_this_attribute_values(:a, "rel", [ - "tag", - "nofollow", - "noopener", - "noreferrer", - "me", - "ugc" - ]) - - Meta.allow_tag_with_these_attributes(:a, ["name", "title"]) - Meta.strip_everything_not_covered() -end diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 71423ce5e..8f3e46af9 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -121,10 +121,28 @@ defmodule Pleroma.Notification do when is_list(visibility) do if Enum.all?(visibility, &(&1 in @valid_visibilities)) do query + |> join(:left, [n, a], mutated_activity in Pleroma.Activity, + on: + fragment("?->>'context'", a.data) == + fragment("?->>'context'", mutated_activity.data) and + fragment("(?->>'type' = 'Like' or ?->>'type' = 'Announce')", a.data, a.data) and + fragment("?->>'type'", mutated_activity.data) == "Create", + as: :mutated_activity + ) |> where( - [n, a], + [n, a, mutated_activity: mutated_activity], not fragment( - "activity_visibility(?, ?, ?) = ANY (?)", + """ + CASE WHEN (?->>'type') = 'Like' or (?->>'type') = 'Announce' + THEN (activity_visibility(?, ?, ?) = ANY (?)) + ELSE (activity_visibility(?, ?, ?) = ANY (?)) END + """, + a.data, + a.data, + mutated_activity.actor, + mutated_activity.recipients, + mutated_activity.data, + ^visibility, a.actor, a.recipients, a.data, @@ -139,17 +157,7 @@ defmodule Pleroma.Notification do defp exclude_visibility(query, %{exclude_visibilities: visibility}) when visibility in @valid_visibilities do - query - |> where( - [n, a], - not fragment( - "activity_visibility(?, ?, ?) = (?)", - a.actor, - a.recipients, - a.data, - ^visibility - ) - ) + exclude_visibility(query, [visibility]) end defp exclude_visibility(query, %{exclude_visibilities: visibility}) @@ -347,7 +355,7 @@ defmodule Pleroma.Notification do def skip?( :followers, activity, - %{notification_settings: %{"followers" => false}} = user + %{notification_settings: %{followers: false}} = user ) do actor = activity.data["actor"] follower = User.get_cached_by_ap_id(actor) @@ -357,14 +365,14 @@ defmodule Pleroma.Notification do def skip?( :non_followers, activity, - %{notification_settings: %{"non_followers" => false}} = user + %{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, %{notification_settings: %{"follows" => false}} = user) do + def skip?(:follows, activity, %{notification_settings: %{follows: false}} = user) do actor = activity.data["actor"] followed = User.get_cached_by_ap_id(actor) User.following?(user, followed) @@ -373,7 +381,7 @@ defmodule Pleroma.Notification do def skip?( :non_follows, activity, - %{notification_settings: %{"non_follows" => false}} = user + %{notification_settings: %{non_follows: false}} = user ) do actor = activity.data["actor"] followed = User.get_cached_by_ap_id(actor) diff --git a/lib/pleroma/plugs/parsers_plug.ex b/lib/pleroma/plugs/parsers_plug.ex new file mode 100644 index 000000000..2e493ce0e --- /dev/null +++ b/lib/pleroma/plugs/parsers_plug.ex @@ -0,0 +1,21 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Plugs.Parsers do + @moduledoc "Initializes Plug.Parsers with upload limit set at boot time" + + @behaviour Plug + + def init(_opts) do + Plug.Parsers.init( + parsers: [:urlencoded, :multipart, :json], + pass: ["*/*"], + json_decoder: Jason, + length: Pleroma.Config.get([:instance, :upload_limit]), + body_reader: {Pleroma.Web.Plugs.DigestPlug, :read_body, []} + ) + end + + defdelegate call(conn, opts), to: Plug.Parsers +end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index b7f50e5ac..e2afc6de8 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -129,13 +129,10 @@ defmodule Pleroma.User do field(:skip_thread_containment, :boolean, default: false) field(:also_known_as, {:array, :string}, default: []) - field(:notification_settings, :map, - default: %{ - "followers" => true, - "follows" => true, - "non_follows" => true, - "non_followers" => true - } + embeds_one( + :notification_settings, + Pleroma.User.NotificationSetting, + on_replace: :update ) has_many(:notifications, Notification) @@ -1221,20 +1218,9 @@ defmodule Pleroma.User do end def update_notification_settings(%User{} = user, settings) do - settings = - settings - |> Enum.map(fn {k, v} -> {k, v in [true, "true", "True", "1"]} end) - |> Map.new() - - notification_settings = - user.notification_settings - |> Map.merge(settings) - |> Map.take(["followers", "follows", "non_follows", "non_followers"]) - - params = %{notification_settings: notification_settings} - user - |> cast(params, [:notification_settings]) + |> cast(%{notification_settings: settings}, []) + |> cast_embed(:notification_settings) |> validate_required([:notification_settings]) |> update_and_set_cache() end diff --git a/lib/pleroma/user/notification_setting.ex b/lib/pleroma/user/notification_setting.ex new file mode 100644 index 000000000..f0899613e --- /dev/null +++ b/lib/pleroma/user/notification_setting.ex @@ -0,0 +1,40 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.User.NotificationSetting do + use Ecto.Schema + import Ecto.Changeset + + @derive Jason.Encoder + @primary_key false + + embedded_schema do + field(:followers, :boolean, default: true) + field(:follows, :boolean, default: true) + field(:non_follows, :boolean, default: true) + field(:non_followers, :boolean, default: true) + field(:privacy_option, :boolean, default: false) + end + + def changeset(schema, params) do + schema + |> cast(prepare_attrs(params), [ + :followers, + :follows, + :non_follows, + :non_followers, + :privacy_option + ]) + end + + defp prepare_attrs(params) do + Enum.reduce(params, %{}, fn + {k, v}, acc when is_binary(v) -> + Map.put(acc, k, String.downcase(v)) + + {k, v}, acc -> + Map.put(acc, k, v) + end) + end +end diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex index 49735b5c2..bbea31682 100644 --- a/lib/pleroma/web/endpoint.ex +++ b/lib/pleroma/web/endpoint.ex @@ -61,14 +61,7 @@ defmodule Pleroma.Web.Endpoint do plug(Plug.RequestId) plug(Plug.Logger) - plug( - Plug.Parsers, - parsers: [:urlencoded, :multipart, :json], - pass: ["*/*"], - json_decoder: Jason, - length: Pleroma.Config.get([:instance, :upload_limit]), - body_reader: {Pleroma.Web.Plugs.DigestPlug, :read_body, []} - ) + plug(Pleroma.Plugs.Parsers) plug(Plug.MethodOverride) plug(Plug.Head) diff --git a/lib/pleroma/web/push/impl.ex b/lib/pleroma/web/push/impl.ex index a6a924d02..34ec1d8d9 100644 --- a/lib/pleroma/web/push/impl.ex +++ b/lib/pleroma/web/push/impl.ex @@ -22,8 +22,8 @@ defmodule Pleroma.Web.Push.Impl do @spec perform(Notification.t()) :: list(any) | :error def perform( %{ - activity: %{data: %{"type" => activity_type}, id: activity_id} = activity, - user_id: user_id + activity: %{data: %{"type" => activity_type}} = activity, + user: %User{id: user_id} } = notif ) when activity_type in @types do @@ -39,18 +39,17 @@ defmodule Pleroma.Web.Push.Impl do for subscription <- fetch_subsriptions(user_id), get_in(subscription.data, ["alerts", type]) do %{ - title: format_title(notif), access_token: subscription.token.token, - body: format_body(notif, actor, object), notification_id: notif.id, notification_type: type, icon: avatar_url, preferred_locale: "en", pleroma: %{ - activity_id: activity_id, + activity_id: notif.activity.id, direct_conversation_id: direct_conversation_id } } + |> Map.merge(build_content(notif, actor, object)) |> Jason.encode!() |> push_message(build_sub(subscription), gcm_api_key, subscription) end @@ -100,6 +99,24 @@ defmodule Pleroma.Web.Push.Impl do } end + def build_content( + %{ + activity: %{data: %{"directMessage" => true}}, + user: %{notification_settings: %{privacy_option: true}} + }, + actor, + _ + ) do + %{title: "New Direct Message", body: "@#{actor.nickname}"} + end + + def build_content(notif, actor, object) do + %{ + title: format_title(notif), + body: format_body(notif, actor, object) + } + end + def format_body( %{activity: %{data: %{"type" => "Create"}}}, actor, diff --git a/lib/pleroma/workers/web_pusher_worker.ex b/lib/pleroma/workers/web_pusher_worker.ex index 61b451e3e..a978c4013 100644 --- a/lib/pleroma/workers/web_pusher_worker.ex +++ b/lib/pleroma/workers/web_pusher_worker.ex @@ -13,7 +13,7 @@ defmodule Pleroma.Workers.WebPusherWorker do notification = Notification |> Repo.get(notification_id) - |> Repo.preload([:activity]) + |> Repo.preload([:activity, :user]) Pleroma.Web.Push.Impl.perform(notification) end |