From 0b864c3696e47ba1def6047905dad9065b0bee0e Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Tue, 28 May 2024 08:49:34 -0400 Subject: [PATCH 01/10] Dialyzer: fix invalid @spec lib/pleroma/notification.ex:492:invalid_contract The @spec for the function does not match the success typing of the function. Function: Pleroma.Notification.get_notified_from_activity/2 Success typing: @spec get_notified_from_activity(_, _) :: [any()] --- lib/pleroma/notification.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 4f714b25f..f521a2998 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -489,7 +489,7 @@ def create_poll_notifications(%Activity{} = activity) do NOTE: might be called for FAKE Activities, see ActivityPub.Utils.get_notified_from_object/1 """ - @spec get_notified_from_activity(Activity.t(), boolean()) :: {list(User.t()), list(User.t())} + @spec get_notified_from_activity(Activity.t(), boolean()) :: list(User.t()) def get_notified_from_activity(activity, local_only \\ true) def get_notified_from_activity(%Activity{data: %{"type" => type}} = activity, local_only) From 42c5f7c74e93b7b489456578f8285d06320c15dc Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Tue, 28 May 2024 08:55:18 -0400 Subject: [PATCH 02/10] Dialyzer: fix invalid @spec The callback already defines the @spec and these do not match it. lib/pleroma/upload/filter/exiftool/strip_location.ex:12:callback_spec_type_mismatch The @spec return type does not match the expected return type for filter/1 callback in Pleroma.Upload.Filter behaviour. Actual: @spec filter(...) :: {:ok, _} Expected: @spec filter(...) :: {:error, _} | {:ok, :filtered | :noop} | {:ok, :filtered, struct()} --- lib/pleroma/upload/filter/exiftool/strip_location.ex | 2 -- lib/pleroma/upload/filter/mogrifun.ex | 1 - lib/pleroma/upload/filter/mogrify.ex | 1 - 3 files changed, 4 deletions(-) diff --git a/lib/pleroma/upload/filter/exiftool/strip_location.ex b/lib/pleroma/upload/filter/exiftool/strip_location.ex index f2bcc4622..8becee712 100644 --- a/lib/pleroma/upload/filter/exiftool/strip_location.ex +++ b/lib/pleroma/upload/filter/exiftool/strip_location.ex @@ -9,8 +9,6 @@ defmodule Pleroma.Upload.Filter.Exiftool.StripLocation do """ @behaviour Pleroma.Upload.Filter - @spec filter(Pleroma.Upload.t()) :: {:ok, any()} | {:error, String.t()} - # Formats not compatible with exiftool at this time def filter(%Pleroma.Upload{content_type: "image/heic"}), do: {:ok, :noop} def filter(%Pleroma.Upload{content_type: "image/webp"}), do: {:ok, :noop} diff --git a/lib/pleroma/upload/filter/mogrifun.ex b/lib/pleroma/upload/filter/mogrifun.ex index a0f247b70..9716580a8 100644 --- a/lib/pleroma/upload/filter/mogrifun.ex +++ b/lib/pleroma/upload/filter/mogrifun.ex @@ -38,7 +38,6 @@ defmodule Pleroma.Upload.Filter.Mogrifun do [{"fill", "yellow"}, {"tint", "40"}] ] - @spec filter(Pleroma.Upload.t()) :: {:ok, atom()} | {:error, String.t()} def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _}) do try do Filter.Mogrify.do_filter(file, [Enum.random(@filters)]) diff --git a/lib/pleroma/upload/filter/mogrify.ex b/lib/pleroma/upload/filter/mogrify.ex index 06efbf321..d1e166022 100644 --- a/lib/pleroma/upload/filter/mogrify.ex +++ b/lib/pleroma/upload/filter/mogrify.ex @@ -8,7 +8,6 @@ defmodule Pleroma.Upload.Filter.Mogrify do @type conversion :: action :: String.t() | {action :: String.t(), opts :: String.t()} @type conversions :: conversion() | [conversion()] - @spec filter(Pleroma.Upload.t()) :: {:ok, :atom} | {:error, String.t()} def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _}) do try do do_filter(file, Pleroma.Config.get!([__MODULE__, :args])) From f8ce639e3f76257097793c666d3ebf8f22539a30 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Tue, 28 May 2024 09:30:19 -0400 Subject: [PATCH 03/10] Dialyzer: guard clause can never succeed lib/pleroma/web/activity_pub/mrf/dnsrbl_policy.ex:106:guard_fail The guard clause: when _ :: [ binary() | [string() | char()] | {string() | integer(), string()} | {{byte(), byte(), byte(), byte()}, integer(), binary()} | {integer(), integer(), integer(), string() | byte()} | {integer(), integer(), string(), string(), string(), string()} | {string(), string(), integer(), integer(), integer(), integer(), integer()} | {char(), char(), char(), char(), char(), char(), char(), char()} ] === nil can never succeed. --- lib/pleroma/web/activity_pub/mrf/dnsrbl_policy.ex | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/activity_pub/mrf/dnsrbl_policy.ex b/lib/pleroma/web/activity_pub/mrf/dnsrbl_policy.ex index 9543cc545..7c6bb888f 100644 --- a/lib/pleroma/web/activity_pub/mrf/dnsrbl_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/dnsrbl_policy.ex @@ -103,7 +103,11 @@ defp check_rbl(%{host: actor_host}, object) do {:ok, object} else Task.start(fn -> - reason = rblquery(query, :txt) || "undefined" + reason = + case rblquery(query, :txt) do + [[result]] -> result + _ -> "undefined" + end Logger.warning( "DNSRBL Rejected activity from #{actor_host} for reason: #{inspect(reason)}" From 18835bf7012e8e234eb27456a437f4d1e8796645 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Tue, 28 May 2024 09:38:36 -0400 Subject: [PATCH 04/10] Use the configured http client options for mediaproxy --- lib/pleroma/helpers/media_helper.ex | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/helpers/media_helper.ex b/lib/pleroma/helpers/media_helper.ex index e44114d9d..0ac07fa41 100644 --- a/lib/pleroma/helpers/media_helper.ex +++ b/lib/pleroma/helpers/media_helper.ex @@ -25,7 +25,7 @@ def missing_dependencies do end def image_resize(url, options) do - with {:ok, env} <- HTTP.get(url, [], pool: :media), + with {:ok, env} <- HTTP.get(url, [], http_client_opts()), {:ok, resized} <- Operation.thumbnail_buffer(env.body, options.max_width, height: options.max_height, @@ -46,7 +46,7 @@ def image_resize(url, options) do def video_framegrab(url) do with executable when is_binary(executable) <- System.find_executable("ffmpeg"), false <- @cachex.exists?(:failed_media_helper_cache, url), - {:ok, env} <- HTTP.get(url, [], pool: :media), + {:ok, env} <- HTTP.get(url, [], http_client_opts()), {:ok, pid} <- StringIO.open(env.body) do body_stream = IO.binstream(pid, 1) @@ -84,4 +84,6 @@ def video_framegrab(url) do {:error, _} = error -> error end end + + defp http_client_opts, do: Pleroma.Config.get([:media_proxy, :proxy_opts, :http], pool: :media) end From 17ebb2df8404474ef66c6a38e974143166b5e49b Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Tue, 28 May 2024 09:43:35 -0400 Subject: [PATCH 05/10] Dialyzer: fix pattern matches preventing video thumbnailing from working lib/pleroma/web/media_proxy/media_proxy_controller.ex:154:pattern_match The pattern can never match the type. Pattern: {:ok, _thumbnail_binary} Type: {:error, boolean() | {:ffmpeg, :command_not_found}} --- changelog.d/video-thumbs.fix | 1 + lib/pleroma/helpers/media_helper.ex | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) create mode 100644 changelog.d/video-thumbs.fix diff --git a/changelog.d/video-thumbs.fix b/changelog.d/video-thumbs.fix new file mode 100644 index 000000000..03e862f3d --- /dev/null +++ b/changelog.d/video-thumbs.fix @@ -0,0 +1 @@ +Video thumbnails were not being generated due to a negative cache lookup logic error diff --git a/lib/pleroma/helpers/media_helper.ex b/lib/pleroma/helpers/media_helper.ex index 0ac07fa41..8566ab3ea 100644 --- a/lib/pleroma/helpers/media_helper.ex +++ b/lib/pleroma/helpers/media_helper.ex @@ -45,7 +45,7 @@ def image_resize(url, options) do @spec video_framegrab(String.t()) :: {:ok, binary()} | {:error, any()} def video_framegrab(url) do with executable when is_binary(executable) <- System.find_executable("ffmpeg"), - false <- @cachex.exists?(:failed_media_helper_cache, url), + {:ok, false} <- @cachex.exists?(:failed_media_helper_cache, url), {:ok, env} <- HTTP.get(url, [], http_client_opts()), {:ok, pid} <- StringIO.open(env.body) do body_stream = IO.binstream(pid, 1) @@ -71,13 +71,13 @@ def video_framegrab(url) do end) case Task.yield(task, 5_000) do - nil -> + {:ok, result} -> + {:ok, result} + + _ -> Task.shutdown(task) @cachex.put(:failed_media_helper_cache, url, nil) {:error, {:ffmpeg, :timeout}} - - result -> - {:ok, result} end else nil -> {:error, {:ffmpeg, :command_not_found}} From 1b3c84e241f8ed1066d113346365ce489971ac14 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Tue, 28 May 2024 09:58:44 -0400 Subject: [PATCH 06/10] Dialyzer: no_local_return WebPushEncryption.send_web_push/4 was written to raise on erroroneus input, so we must guard against that. lib/pleroma/web/push/impl.ex:65:no_return Function push_message/4 has no local return. --- lib/pleroma/web/push/impl.ex | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/lib/pleroma/web/push/impl.ex b/lib/pleroma/web/push/impl.ex index 9e68d827b..53334e72c 100644 --- a/lib/pleroma/web/push/impl.ex +++ b/lib/pleroma/web/push/impl.ex @@ -63,19 +63,25 @@ def perform(_) do @doc "Push message to web" def push_message(body, sub, api_key, subscription) do - case WebPushEncryption.send_web_push(body, sub, api_key) do - {:ok, %{status: code}} when code in 400..499 -> - Logger.debug("Removing subscription record") - Repo.delete!(subscription) - :ok + try do + case WebPushEncryption.send_web_push(body, sub, api_key) do + {:ok, %{status: code}} when code in 400..499 -> + Logger.debug("Removing subscription record") + Repo.delete!(subscription) + :ok - {:ok, %{status: code}} when code in 200..299 -> - :ok + {:ok, %{status: code}} when code in 200..299 -> + :ok - {:ok, %{status: code}} -> - Logger.error("Web Push Notification failed with code: #{code}") - :error + {:ok, %{status: code}} -> + Logger.error("Web Push Notification failed with code: #{code}") + :error + error -> + Logger.error("Web Push Notification failed with #{inspect(error)}") + :error + end + rescue error -> Logger.error("Web Push Notification failed with #{inspect(error)}") :error From 8743c6c640d395ff6d7d268df1e382ba0fb0ca96 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Tue, 28 May 2024 10:36:00 -0400 Subject: [PATCH 07/10] Dialyzer: The pattern can never match the type We will never pass :plain to query_with/4, so remove that match and change it to query_with/3 lib/pleroma/search/database_search.ex:127:pattern_match The pattern can never match the type. Pattern: _q, :rum, _search_query, :plain Type: %Ecto.Query{ :aliases => _, :assocs => _, :combinations => _, :distinct => _, :from => _, :group_bys => _, :havings => _, :joins => _, :limit => _, :lock => _, :offset => _, :order_bys => _, :prefix => _, :preloads => _, :select => _, :sources => _, :updates => _, :wheres => _, :windows => _, :with_ctes => _ }, :rum, _, :websearch --- lib/pleroma/search/database_search.ex | 36 +++------------------------ 1 file changed, 3 insertions(+), 33 deletions(-) diff --git a/lib/pleroma/search/database_search.ex b/lib/pleroma/search/database_search.ex index c6fe8a9bd..aef5d1e74 100644 --- a/lib/pleroma/search/database_search.ex +++ b/lib/pleroma/search/database_search.ex @@ -28,7 +28,7 @@ def search(user, search_query, options \\ []) do |> Activity.with_preloaded_object() |> Activity.restrict_deactivated_users() |> restrict_public(user) - |> query_with(index_type, search_query, :websearch) + |> query_with(index_type, search_query) |> maybe_restrict_local(user) |> maybe_restrict_author(author) |> maybe_restrict_blocked(user) @@ -88,25 +88,7 @@ defp restrict_public(q, _user) do ) end - defp query_with(q, :gin, search_query, :plain) do - %{rows: [[tsc]]} = - Ecto.Adapters.SQL.query!( - Pleroma.Repo, - "select current_setting('default_text_search_config')::regconfig::oid;" - ) - - from([a, o] in q, - where: - fragment( - "to_tsvector(?::oid::regconfig, ?->>'content') @@ plainto_tsquery(?)", - ^tsc, - o.data, - ^search_query - ) - ) - end - - defp query_with(q, :gin, search_query, :websearch) do + defp query_with(q, :gin, search_query) do %{rows: [[tsc]]} = Ecto.Adapters.SQL.query!( Pleroma.Repo, @@ -124,19 +106,7 @@ defp query_with(q, :gin, search_query, :websearch) do ) end - defp query_with(q, :rum, search_query, :plain) do - from([a, o] in q, - where: - fragment( - "? @@ plainto_tsquery(?)", - o.fts_content, - ^search_query - ), - order_by: [fragment("? <=> now()::date", o.inserted_at)] - ) - end - - defp query_with(q, :rum, search_query, :websearch) do + defp query_with(q, :rum, search_query) do from([a, o] in q, where: fragment( From 6551ca2db7a0907252bbc649c7d082b3edf92a93 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Tue, 28 May 2024 10:40:54 -0400 Subject: [PATCH 08/10] Dialyzer: overlapping_contract Wrong @spec name for remove_from_block/2 lib/pleroma/user.ex:2721:overlapping_contract Overloaded contract for Pleroma.User.add_to_block/2 has overlapping domains; such contracts are currently unsupported and are simply ignored. --- lib/pleroma/user.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 6d6aa98b5..d94b68ce0 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -2727,7 +2727,7 @@ defp add_to_block(%User{} = user, %User{} = blocked) do end end - @spec add_to_block(User.t(), User.t()) :: + @spec remove_from_block(User.t(), User.t()) :: {:ok, UserRelationship.t()} | {:ok, nil} | {:error, Ecto.Changeset.t()} defp remove_from_block(%User{} = user, %User{} = blocked) do with {:ok, relationship} <- UserRelationship.delete_block(user, blocked) do From 6b6a2adb07c3b9a52cd0a5adf435a916088bb4d7 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Tue, 28 May 2024 10:49:43 -0400 Subject: [PATCH 09/10] Dialyzer: The function call will not succeed. :idna.encode/1 expects a charlist even though it will accept a binary string. That functionality is undocumented / not part of its typespec, so we should turn it into a charlist first. Also switch to using match?/2 lib/pleroma/user.ex:2056:call The function call will not succeed. :idna.encode(_host :: binary()) will never return since the success typing is: (string()) :: string() and the contract is (string()) :: string() --- lib/pleroma/user.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index d94b68ce0..884c1f302 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -2053,7 +2053,8 @@ defp verify_field_link(field, profile_urls) do %{scheme: scheme, userinfo: nil, host: host} when not_empty_string(host) and scheme in ["http", "https"] <- URI.parse(value), - {:not_idn, true} <- {:not_idn, to_string(:idna.encode(host)) == host}, + {:not_idn, true} <- + {:not_idn, match?(^host, to_string(:idna.encode(to_charlist(host))))}, "me" <- Pleroma.Web.RelMe.maybe_put_rel_me(value, profile_urls) do CommonUtils.to_masto_date(NaiveDateTime.utc_now()) else From 79c418bcb7534ae3645ee0b7728f8e65a031f7a4 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Tue, 28 May 2024 11:07:28 -0400 Subject: [PATCH 10/10] Dialyzer: fix invalid @spec --- lib/pleroma/web/o_auth/token.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/o_auth/token.ex b/lib/pleroma/web/o_auth/token.ex index a5ad2e909..9b1198b42 100644 --- a/lib/pleroma/web/o_auth/token.ex +++ b/lib/pleroma/web/o_auth/token.ex @@ -96,7 +96,7 @@ defp put_valid_until(changeset, attrs) do |> validate_required([:valid_until]) end - @spec create(App.t(), User.t(), map()) :: {:ok, Token} | {:error, Ecto.Changeset.t()} + @spec create(App.t(), User.t(), map()) :: {:ok, Token.t()} | {:error, Ecto.Changeset.t()} def create(%App{} = app, %User{} = user, attrs \\ %{}) do with {:ok, token} <- do_create(app, user, attrs) do if Pleroma.Config.get([:oauth2, :clean_expired_tokens]) do