From bd53bfc46bdbe53011be61e7dad27da92b0e390d Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Thu, 8 Apr 2021 16:41:49 +0200 Subject: [PATCH 01/13] Fix usage of is_bitstring instead of is_binary Signed-off-by: Thomas Citharel --- lib/federation/activity_pub/refresher.ex | 2 +- lib/federation/activity_pub/relay.ex | 2 +- lib/federation/activity_pub/utils.ex | 4 ++-- lib/federation/activity_stream/converter/event.ex | 2 +- lib/federation/activity_stream/converter/media.ex | 2 +- lib/federation/activity_stream/converter/utils.ex | 2 +- lib/graphql/resolvers/admin.ex | 12 +++++++++--- lib/graphql/resolvers/participant.ex | 2 +- lib/mobilizon/admin/admin.ex | 2 +- lib/service/geospatial/provider.ex | 2 +- 10 files changed, 19 insertions(+), 13 deletions(-) diff --git a/lib/federation/activity_pub/refresher.ex b/lib/federation/activity_pub/refresher.ex index f28dd623b..6f485ba4b 100644 --- a/lib/federation/activity_pub/refresher.ex +++ b/lib/federation/activity_pub/refresher.ex @@ -127,7 +127,7 @@ defmodule Mobilizon.Federation.ActivityPub.Refresher do do: process_collection(first, on_behalf_of) defp process_collection(%{"type" => "OrderedCollection", "first" => first}, on_behalf_of) - when is_bitstring(first) do + when is_binary(first) do Logger.debug("OrderedCollection has a first property pointing to an URI") with {:ok, data} <- Fetcher.fetch(first, on_behalf_of: on_behalf_of) do diff --git a/lib/federation/activity_pub/relay.ex b/lib/federation/activity_pub/relay.ex index 13a8b2f12..be98b908b 100644 --- a/lib/federation/activity_pub/relay.ex +++ b/lib/federation/activity_pub/relay.ex @@ -126,7 +126,7 @@ defmodule Mobilizon.Federation.ActivityPub.Relay do end end - defp fetch_object(object) when is_bitstring(object), do: {object, object} + defp fetch_object(object) when is_binary(object), do: {object, object} @spec fetch_actor(String.t()) :: {:ok, String.t()} | {:error, String.t()} # Dirty hack diff --git a/lib/federation/activity_pub/utils.ex b/lib/federation/activity_pub/utils.ex index 988d32333..b21a5bdcc 100644 --- a/lib/federation/activity_pub/utils.ex +++ b/lib/federation/activity_pub/utils.ex @@ -26,7 +26,7 @@ defmodule Mobilizon.Federation.ActivityPub.Utils do # Some implementations send the actor URI as the actor field, others send the entire actor object, # so figure out what the actor's URI is based on what we have. def get_url(%{"id" => id}), do: id - def get_url(id) when is_bitstring(id), do: id + def get_url(id) when is_binary(id), do: id def get_url(ids) when is_list(ids), do: get_url(hd(ids)) def get_url(_), do: nil @@ -223,7 +223,7 @@ defmodule Mobilizon.Federation.ActivityPub.Utils do end end - def get_actor(%{"actor" => %{"id" => id}}) when is_bitstring(id) do + def get_actor(%{"actor" => %{"id" => id}}) when is_binary(id) do id end diff --git a/lib/federation/activity_stream/converter/event.ex b/lib/federation/activity_stream/converter/event.ex index e1b8efa87..d2e932358 100644 --- a/lib/federation/activity_stream/converter/event.ex +++ b/lib/federation/activity_stream/converter/event.ex @@ -155,7 +155,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do end @spec get_address(map | binary | nil) :: integer | nil - defp get_address(address_url) when is_bitstring(address_url) do + defp get_address(address_url) when is_binary(address_url) do get_address(%{"id" => address_url}) end diff --git a/lib/federation/activity_stream/converter/media.ex b/lib/federation/activity_stream/converter/media.ex index 40ddb90b4..0f1b350e2 100644 --- a/lib/federation/activity_stream/converter/media.ex +++ b/lib/federation/activity_stream/converter/media.ex @@ -38,7 +38,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Media do %{"type" => "Document", "url" => media_url, "name" => name}, actor_id ) - when is_bitstring(media_url) do + when is_binary(media_url) do with {:ok, %{body: body}} <- Tesla.get(media_url, opts: @http_options), {:ok, %{name: name, url: url, content_type: content_type, size: size}} <- Upload.store(%{body: body, name: name}), diff --git a/lib/federation/activity_stream/converter/utils.ex b/lib/federation/activity_stream/converter/utils.ex index beb08fe03..79c604a63 100644 --- a/lib/federation/activity_stream/converter/utils.ex +++ b/lib/federation/activity_stream/converter/utils.ex @@ -94,7 +94,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Utils do end end - defp fetch_tag(tag) when is_bitstring(tag), do: [tag_without_hash(tag)] + defp fetch_tag(tag) when is_binary(tag), do: [tag_without_hash(tag)] defp tag_without_hash("#" <> tag_title), do: tag_title defp tag_without_hash(tag_title), do: tag_title diff --git a/lib/graphql/resolvers/admin.ex b/lib/graphql/resolvers/admin.ex index b8485d0ae..9bdbe4901 100644 --- a/lib/graphql/resolvers/admin.ex +++ b/lib/graphql/resolvers/admin.ex @@ -321,7 +321,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Admin do {:ok, _activity, follow} -> {:ok, follow} - {:error, {:error, err}} when is_bitstring(err) -> + {:error, {:error, err}} when is_binary(err) -> {:error, err} end end @@ -336,7 +336,10 @@ defmodule Mobilizon.GraphQL.Resolvers.Admin do {:ok, _activity, follow} -> {:ok, follow} - {:error, {:error, err}} when is_bitstring(err) -> + {:error, {:error, err}} when is_binary(err) -> + {:error, err} + + {:error, err} when is_binary(err) -> {:error, err} end end @@ -351,7 +354,10 @@ defmodule Mobilizon.GraphQL.Resolvers.Admin do {:ok, _activity, follow} -> {:ok, follow} - {:error, {:error, err}} when is_bitstring(err) -> + {:error, {:error, err}} when is_binary(err) -> + {:error, err} + + {:error, err} when is_binary(err) -> {:error, err} end end diff --git a/lib/graphql/resolvers/participant.ex b/lib/graphql/resolvers/participant.ex index e41137597..ede77f0dd 100644 --- a/lib/graphql/resolvers/participant.ex +++ b/lib/graphql/resolvers/participant.ex @@ -264,7 +264,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Participant do @spec valid_email?(String.t() | nil) :: boolean defp valid_email?(email) when is_nil(email), do: false - defp valid_email?(email) when is_bitstring(email) do + defp valid_email?(email) when is_binary(email) do email |> String.trim() |> Checker.valid?() diff --git a/lib/mobilizon/admin/admin.ex b/lib/mobilizon/admin/admin.ex index 66bcc6c5b..b307ef6af 100644 --- a/lib/mobilizon/admin/admin.ex +++ b/lib/mobilizon/admin/admin.ex @@ -78,7 +78,7 @@ defmodule Mobilizon.Admin do defp stringify_struct(struct), do: struct def get_admin_setting_value(group, name, fallback \\ nil) - when is_bitstring(group) and is_bitstring(name) do + when is_binary(group) and is_binary(name) do case Repo.get_by(Setting, group: group, name: name) do nil -> fallback diff --git a/lib/service/geospatial/provider.ex b/lib/service/geospatial/provider.ex index 2bc7b7f4c..4d9fadd11 100644 --- a/lib/service/geospatial/provider.ex +++ b/lib/service/geospatial/provider.ex @@ -74,7 +74,7 @@ defmodule Mobilizon.Service.Geospatial.Provider do %Geo.Point{coordinates: {x, y}, srid: srid} end - def coordinates([x, y], srid) when is_bitstring(x) and is_bitstring(y) do + def coordinates([x, y], srid) when is_binary(x) and is_binary(y) do %Geo.Point{coordinates: {String.to_float(x), String.to_float(y)}, srid: srid} end From b34958d3aff044796a06ca4b63fb46feba52677c Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Fri, 9 Apr 2021 10:19:25 +0200 Subject: [PATCH 02/13] Refactor Webfinger module, use XRD host-meta to find webfinger endpoint Signed-off-by: Thomas Citharel --- lib/federation/activity_pub/activity_pub.ex | 2 +- lib/federation/activity_pub/relay.ex | 2 +- lib/federation/web_finger/web_finger.ex | 179 +++++++++++++----- lib/service/http/host_meta_client.ex | 24 +++ mix.exs | 1 + mix.lock | 2 + .../federation/web_finger/web_finger_test.exs | 20 +- .../vcr_cassettes/webfinger/friendica.json | 73 ++++++- .../vcr_cassettes/webfinger/mastodon.json | 64 +++++-- .../vcr_cassettes/webfinger/peertube.json | 83 ++++++-- .../vcr_cassettes/webfinger/pleroma.json | 105 ++++++++-- .../controllers/webfinger_controller_test.exs | 4 +- 12 files changed, 442 insertions(+), 117 deletions(-) create mode 100644 lib/service/http/host_meta_client.ex diff --git a/lib/federation/activity_pub/activity_pub.ex b/lib/federation/activity_pub/activity_pub.ex index 651aa768a..608955b0b 100644 --- a/lib/federation/activity_pub/activity_pub.ex +++ b/lib/federation/activity_pub/activity_pub.ex @@ -654,7 +654,7 @@ defmodule Mobilizon.Federation.ActivityPub do @spec make_actor_from_nickname(String.t()) :: {:ok, %Actor{}} | {:error, any()} def make_actor_from_nickname(nickname) do case WebFinger.finger(nickname) do - {:ok, %{"url" => url}} when not is_nil(url) -> + {:ok, url} when is_binary(url) -> make_actor_from_url(url) _e -> diff --git a/lib/federation/activity_pub/relay.ex b/lib/federation/activity_pub/relay.ex index be98b908b..b0a8997c9 100644 --- a/lib/federation/activity_pub/relay.ex +++ b/lib/federation/activity_pub/relay.ex @@ -159,7 +159,7 @@ defmodule Mobilizon.Federation.ActivityPub.Relay do @spec finger_actor(String.t()) :: {:ok, String.t()} | {:error, String.t()} defp finger_actor(nickname) do case WebFinger.finger(nickname) do - {:ok, %{"url" => url}} when not is_nil(url) -> + {:ok, url} when is_binary(url) -> {:ok, url} _e -> diff --git a/lib/federation/web_finger/web_finger.ex b/lib/federation/web_finger/web_finger.ex index c0b44e6c9..fbde57e4b 100644 --- a/lib/federation/web_finger/web_finger.ex +++ b/lib/federation/web_finger/web_finger.ex @@ -12,26 +12,37 @@ defmodule Mobilizon.Federation.WebFinger do alias Mobilizon.Actors.Actor alias Mobilizon.Federation.ActivityPub alias Mobilizon.Federation.WebFinger.XmlBuilder - alias Mobilizon.Service.HTTP.WebfingerClient + alias Mobilizon.Service.HTTP.{HostMetaClient, WebfingerClient} alias Mobilizon.Web.Endpoint alias Mobilizon.Web.Router.Helpers, as: Routes require Jason require Logger + import SweetXml def host_meta do base_url = Endpoint.url() + %URI{host: host} = URI.parse(base_url) { :XRD, - %{xmlns: "http://docs.oasis-open.org/ns/xri/xrd-1.0"}, - { - :Link, - %{ - rel: "lrdd", - type: "application/xrd+xml", - template: "#{base_url}/.well-known/webfinger?resource={uri}" + %{ + xmlns: "http://docs.oasis-open.org/ns/xri/xrd-1.0", + "xmlns:hm": "http://host-meta.net/ns/1.0" + }, + [ + { + :"hm:Host", + host + }, + { + :Link, + %{ + rel: "lrdd", + type: "application/jrd+json", + template: "#{base_url}/.well-known/webfinger?resource={uri}" + } } - } + ] } |> XmlBuilder.to_doc() end @@ -56,29 +67,116 @@ defmodule Mobilizon.Federation.WebFinger do end @spec represent_actor(Actor.t()) :: struct() - def represent_actor(actor), do: represent_actor(actor, "JSON") + def represent_actor(%Actor{} = actor), do: represent_actor(actor, "JSON") @spec represent_actor(Actor.t(), String.t()) :: struct() - def represent_actor(actor, "JSON") do - %{ - "subject" => "acct:#{actor.preferred_username}@#{Endpoint.host()}", - "aliases" => [actor.url], - "links" => [ + def represent_actor(%Actor{} = actor, "JSON") do + links = + [ %{"rel" => "self", "type" => "application/activity+json", "href" => actor.url}, - %{ - "rel" => "https://webfinger.net/rel/profile-page/", - "type" => "text/html", - "href" => actor.url - }, %{ "rel" => "http://ostatus.org/schema/1.0/subscribe", "template" => "#{Routes.page_url(Endpoint, :interact, uri: nil)}{uri}" } ] + |> maybe_add_avatar(actor) + |> maybe_add_profile_page(actor) + + %{ + "subject" => "acct:#{actor.preferred_username}@#{Endpoint.host()}", + "aliases" => [actor.url], + "links" => links } end - defp webfinger_from_json(doc) do + defp maybe_add_avatar(data, %Actor{avatar: avatar}) when not is_nil(avatar) do + data ++ + [ + %{ + "rel" => "http://webfinger.net/rel/avatar", + "type" => avatar.content_type, + "href" => avatar.url + } + ] + end + + defp maybe_add_avatar(data, _actor), do: data + + defp maybe_add_profile_page(data, %Actor{type: :Group, url: url}) do + data ++ + [ + %{ + "rel" => "http://webfinger.net/rel/profile-page/", + "type" => "text/html", + "href" => url + } + ] + end + + defp maybe_add_profile_page(data, _actor), do: data + + @doc """ + Finger an actor to retreive it's ActivityPub ID/URL + + Fetches the Extensible Resource Descriptor endpoint `/.well-known/host-meta` to find the Webfinger endpoint (usually `/.well-known/webfinger?resource=`) with `find_webfinger_endpoint/1` and then performs a Webfinger query to get the ActivityPub ID associated to an actor. + """ + @spec finger(String.t()) :: {:ok, String.t()} | {:error, atom()} + def finger(actor) do + actor = String.trim_leading(actor, "@") + + with address when is_binary(address) <- apply_webfinger_endpoint(actor), + false <- address_invalid(address), + {:ok, %{body: body, status: code}} when code in 200..299 <- + WebfingerClient.get(address), + {:ok, %{"url" => url}} <- webfinger_from_json(body) do + {:ok, url} + else + e -> + Logger.debug("Couldn't finger #{actor}") + Logger.debug(inspect(e)) + {:error, e} + end + end + + @doc """ + Fetches the Extensible Resource Descriptor endpoint `/.well-known/host-meta` to find the Webfinger endpoint (usually `/.well-known/webfinger?resource=`) + """ + @spec find_webfinger_endpoint(String.t()) :: String.t() + def find_webfinger_endpoint(domain) when is_binary(domain) do + with {:ok, %{body: body}} <- fetch_document("http://#{domain}/.well-known/host-meta"), + link_template <- find_link_from_template(body) do + {:ok, link_template} + end + end + + @spec apply_webfinger_endpoint(String.t()) :: String.t() | {:error, :host_not_found} + defp apply_webfinger_endpoint(actor) do + with {:ok, domain} <- domain_from_federated_actor(actor) do + case find_webfinger_endpoint(domain) do + {:ok, link_template} -> + String.replace(link_template, "{uri}", "acct:#{actor}") + + _ -> + "http://#{domain}/.well-known/webfinger?resource=acct:#{actor}" + end + end + end + + @spec domain_from_federated_actor(String.t()) :: {:ok, String.t()} | {:error, :host_not_found} + defp domain_from_federated_actor(actor) do + case String.split(actor, "@") do + [_name, domain] -> + {:ok, domain} + + _e -> + host = URI.parse(actor).host + if is_nil(host), do: {:error, :host_not_found}, else: {:ok, host} + end + end + + @spec webfinger_from_json(map() | String.t()) :: + {:ok, map()} | {:error, :webfinger_information_not_json} + defp webfinger_from_json(doc) when is_map(doc) do data = Enum.reduce(doc["links"], %{"subject" => doc["subject"]}, fn link, data -> case {link["type"], link["rel"]} do @@ -97,31 +195,26 @@ defmodule Mobilizon.Federation.WebFinger do {:ok, data} end - def finger(actor) do - actor = String.trim_leading(actor, "@") + defp webfinger_from_json(_doc), do: {:error, :webfinger_information_not_json} - domain = - case String.split(actor, "@") do - [_name, domain] -> - domain + @spec find_link_from_template(String.t()) :: String.t() | {:error, :link_not_found} + defp find_link_from_template(doc) do + with res when res in [nil, ""] <- + xpath(doc, ~x"//Link[@rel=\"lrdd\"][@type=\"application/json\"]/@template"s), + res when res in [nil, ""] <- xpath(doc, ~x"//Link[@rel=\"lrdd\"]/@template"s), + do: {:error, :link_not_found} + end - _e -> - URI.parse(actor).host - end + @spec fetch_document(String.t()) :: Tesla.Env.result() + defp fetch_document(endpoint) do + with {:error, err} <- HostMetaClient.get(endpoint), do: {:error, err} + end - address = "http://#{domain}/.well-known/webfinger?resource=acct:#{actor}" - - Logger.debug(inspect(address)) - - with false <- is_nil(domain), - {:ok, %{body: body, status: code}} when code in 200..299 <- - WebfingerClient.get(address) do - webfinger_from_json(body) - else - e -> - Logger.debug(fn -> "Couldn't finger #{actor}" end) - Logger.debug(fn -> inspect(e) end) - {:error, e} + @spec address_invalid(String.t()) :: false | {:error, :invalid_address} + defp address_invalid(address) do + with %URI{host: host, scheme: scheme} <- URI.parse(address), + true <- is_nil(host) or is_nil(scheme) do + {:error, :invalid_address} end end end diff --git a/lib/service/http/host_meta_client.ex b/lib/service/http/host_meta_client.ex new file mode 100644 index 000000000..4ebe0cf2d --- /dev/null +++ b/lib/service/http/host_meta_client.ex @@ -0,0 +1,24 @@ +defmodule Mobilizon.Service.HTTP.HostMetaClient do + @moduledoc """ + Tesla HTTP Basic Client + with XML middleware + """ + + use Tesla + alias Mobilizon.Config + + @default_opts [ + recv_timeout: 20_000 + ] + + adapter(Tesla.Adapter.Hackney, @default_opts) + + plug(Tesla.Middleware.FollowRedirects) + + plug(Tesla.Middleware.Timeout, timeout: 10_000) + + plug(Tesla.Middleware.Headers, [ + {"User-Agent", Config.instance_user_agent()}, + {"Accept", "application/xrd+xml, application/xml, text/xml"} + ]) +end diff --git a/mix.exs b/mix.exs index 1ff25a1aa..000924be5 100644 --- a/mix.exs +++ b/mix.exs @@ -144,6 +144,7 @@ defmodule Mobilizon.Mixfile do {:slugger, "~> 0.3"}, {:sentry, "~> 8.0"}, {:html_entities, "~> 0.5"}, + {:sweet_xml, "~> 0.6.6"}, # Dev and test dependencies {:phoenix_live_reload, "~> 1.2", only: [:dev, :e2e]}, {:ex_machina, "~> 2.3", only: [:dev, :test]}, diff --git a/mix.lock b/mix.lock index dfaad220a..9123929f6 100644 --- a/mix.lock +++ b/mix.lock @@ -33,6 +33,7 @@ "elixir_feed_parser": {:hex, :elixir_feed_parser, "2.1.0", "bb96fb6422158dc7ad59de62ef211cc69d264acbbe63941a64a5dce97bbbc2e6", [:mix], [{:timex, "~> 3.4", [hex: :timex, repo: "hexpm", optional: false]}], "hexpm", "2d3c62fe7b396ee3b73d7160bc8fadbd78bfe9597c98c7d79b3f1038d9cba28f"}, "elixir_make": {:hex, :elixir_make, "0.6.2", "7dffacd77dec4c37b39af867cedaabb0b59f6a871f89722c25b28fcd4bd70530", [:mix], [], "hexpm", "03e49eadda22526a7e5279d53321d1cced6552f344ba4e03e619063de75348d9"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, + "erlsom": {:hex, :erlsom, "1.5.0", "c5a5cdd0ee0e8dca62bcc4b13ff08da24fdefc16ccd8b25282a2fda2ba1be24a", [:rebar3], [], "hexpm", "55a9dbf9cfa77fcfc108bd8e2c4f9f784dea228a8f4b06ea10b684944946955a"}, "eternal": {:hex, :eternal, "1.2.2", "d1641c86368de99375b98d183042dd6c2b234262b8d08dfd72b9eeaafc2a1abd", [:mix], [], "hexpm", "2c9fe32b9c3726703ba5e1d43a1d255a4f3f2d8f8f9bc19f094c7cb1a7a9e782"}, "ex_cldr": {:hex, :ex_cldr, "2.20.0", "571a4b490c333809be59cc984a21be2deaab1db9e2418e323d5935aec8b1394a", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:cldr_utils, "~> 2.15", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.13", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "06147e4a27be62e6fe92db14cf5048c645927bfc530aa1cc6af8c92d65e32427"}, "ex_cldr_calendars": {:hex, :ex_cldr_calendars, "1.13.0", "6bea6f3c54d74c0ed131dd17e1cff68e02b7053f24c2fac91f129e5221ff723a", [:mix], [{:calendar_interval, "~> 0.2", [hex: :calendar_interval, repo: "hexpm", optional: true]}, {:earmark, "~> 1.0", [hex: :earmark, repo: "hexpm", optional: false]}, {:ex_cldr_numbers, "~> 2.17", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:ex_cldr_units, "~> 3.5", [hex: :ex_cldr_units, repo: "hexpm", optional: true]}, {:ex_doc, "~> 0.21", [hex: :ex_doc, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "d07ab6b2164b6a0861de6ecb600747aab61c94a0b9c001e36c2e0b731eeb567a"}, @@ -122,6 +123,7 @@ "slugger": {:hex, :slugger, "0.3.0", "efc667ab99eee19a48913ccf3d038b1fb9f165fa4fbf093be898b8099e61b6ed", [:mix], [], "hexpm", "20d0ded0e712605d1eae6c5b4889581c3460d92623a930ddda91e0e609b5afba"}, "sobelow": {:hex, :sobelow, "0.11.1", "23438964486f8112b41e743bbfd402da3e5b296fdc9eacab29914b79c48916dd", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "9897363a7eff96f4809304a90aad819e2ad5e5d24db547af502885146746a53c"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"}, + "sweet_xml": {:hex, :sweet_xml, "0.6.6", "fc3e91ec5dd7c787b6195757fbcf0abc670cee1e4172687b45183032221b66b8", [:mix], [], "hexpm", "2e1ec458f892ffa81f9f8386e3f35a1af6db7a7a37748a64478f13163a1f3573"}, "telemetry": {:hex, :telemetry, "0.4.2", "2808c992455e08d6177322f14d3bdb6b625fbcfd233a73505870d8738a2f4599", [:rebar3], [], "hexpm", "2d1419bd9dda6a206d7b5852179511722e2b18812310d304620c7bd92a13fcef"}, "tesla": {:hex, :tesla, "1.4.1", "ff855f1cac121e0d16281b49e8f066c4a0d89965f98864515713878cca849ac8", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.3", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "~> 4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "95f5de35922c8c4b3945bee7406f66eb680b0955232f78f5fb7e853aa1ce201a"}, "timex": {:hex, :timex, "3.7.5", "3eca56e23bfa4e0848f0b0a29a92fa20af251a975116c6d504966e8a90516dfd", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "a15608dca680f2ef663d71c95842c67f0af08a0f3b1d00e17bbd22872e2874e4"}, diff --git a/test/federation/web_finger/web_finger_test.exs b/test/federation/web_finger/web_finger_test.exs index 6aba2c594..19b9724d9 100644 --- a/test/federation/web_finger/web_finger_test.exs +++ b/test/federation/web_finger/web_finger_test.exs @@ -54,10 +54,7 @@ defmodule Mobilizon.Federation.WebFingerTest do describe "fingering" do test "a mastodon actor" do use_cassette "webfinger/mastodon" do - res = %{ - "subject" => "acct:" <> @mastodon_account, - "url" => "https://social.tcit.fr/users/#{@mastodon_account_username}" - } + res = "https://social.tcit.fr/users/#{@mastodon_account_username}" assert {:ok, res} == WebFinger.finger(@mastodon_account) end @@ -65,10 +62,7 @@ defmodule Mobilizon.Federation.WebFingerTest do test "a pleroma actor" do use_cassette "webfinger/pleroma" do - res = %{ - "subject" => "acct:" <> @pleroma_account, - "url" => "https://pleroma.soykaf.com/users/#{@pleroma_account_username}" - } + res = "https://pleroma.soykaf.com/users/#{@pleroma_account_username}" assert {:ok, res} == WebFinger.finger(@pleroma_account) end @@ -76,10 +70,7 @@ defmodule Mobilizon.Federation.WebFingerTest do test "a peertube actor" do use_cassette "webfinger/peertube" do - res = %{ - "subject" => "acct:" <> @peertube_account, - "url" => "https://framatube.org/accounts/#{@peertube_account_username}" - } + res = "https://framatube.org/accounts/#{@peertube_account_username}" assert {:ok, res} == WebFinger.finger(@peertube_account) end @@ -87,10 +78,7 @@ defmodule Mobilizon.Federation.WebFingerTest do test "a friendica actor" do use_cassette "webfinger/friendica" do - res = %{ - "subject" => "acct:" <> @friendica_account, - "url" => "https://squeet.me/profile/#{@friendica_account_username}" - } + res = "https://squeet.me/profile/#{@friendica_account_username}" assert {:ok, res} == WebFinger.finger(@friendica_account) end diff --git a/test/fixtures/vcr_cassettes/webfinger/friendica.json b/test/fixtures/vcr_cassettes/webfinger/friendica.json index 470269a07..dcbc3b4b0 100644 --- a/test/fixtures/vcr_cassettes/webfinger/friendica.json +++ b/test/fixtures/vcr_cassettes/webfinger/friendica.json @@ -3,28 +3,81 @@ "request": { "body": "", "headers": { + "User-Agent": "localhost - Mobilizon 1.1.0-32-gbd53bfc4-dirty", + "Accept": "application/xrd+xml, application/xml, text/xml" + }, + "method": "get", + "options": { + "recv_timeout": 20000 + }, + "request_body": "", + "url": "http://squeet.me/.well-known/host-meta" + }, + "response": { + "binary": false, + "body": "\n\n301 Moved Permanently\n\n

Moved Permanently

\n

The document has moved here.

\n
\n
Apache/2.4.25 (Debian) Server at squeet.me Port 80
\n\n", + "headers": { + "Date": "Fri, 09 Apr 2021 08:08:52 GMT", + "Server": "Apache/2.4.25 (Debian)", + "Location": "https://squeet.me/.well-known/host-meta", + "Content-Length": "322", + "Content-Type": "text/html; charset=iso-8859-1" + }, + "status_code": 301, + "type": "ok" + } + }, + { + "request": { + "body": "", + "headers": { + "User-Agent": "localhost - Mobilizon 1.1.0-32-gbd53bfc4-dirty", + "Accept": "application/xrd+xml, application/xml, text/xml" + }, + "method": "get", + "options": { + "recv_timeout": 20000 + }, + "request_body": "", + "url": "https://squeet.me/.well-known/host-meta" + }, + "response": { + "binary": false, + "body": "\n\n \n squeet.me\n \n \n \n \n \n\t\n\n RSA.xlM2BNDH9hnO3W6vOUfJ5-tcUCaX-rx-kKydQd4ht21At4D4d1MrZ6nAQu7rnf5or9YZRhIpgvJvXBqWSo0zmALkUZUVrsS9WhH65I0qt24XNTPZJ1FdPDd7c1C131GzkymCbXBie3U2JaT7t0oimhWKUeA45gNfXk1T1l-7v4k.AQAB\n\n", + "headers": { + "Date": "Fri, 09 Apr 2021 08:08:52 GMT", + "Server": "Apache/2.4.25 (Debian)", + "X-Account-Management-Status": "none", + "Vary": "Accept-Encoding", + "Transfer-Encoding": "chunked", + "Content-Type": "text/xml;charset=UTF-8" + }, + "status_code": 200, + "type": "ok" + } + }, + { + "request": { + "body": "", + "headers": { + "User-Agent": "localhost - Mobilizon 1.1.0-32-gbd53bfc4-dirty", "Accept": "application/json, application/activity+json, application/jrd+json" }, "method": "get", "options": { - "follow_redirect": "true" + "recv_timeout": 20000 }, "request_body": "", - "url": "http://squeet.me/.well-known/webfinger?resource=acct:lain@squeet.me" + "url": "https://squeet.me/.well-known/webfinger?resource=acct:lain@squeet.me" }, "response": { "binary": false, - "body": "{\"subject\":\"acct:lain@squeet.me\",\"aliases\":[\"https:\\/\\/squeet.me\\/~lain\",\"https:\\/\\/squeet.me\\/profile\\/lain\"],\"links\":[{\"rel\":\"http:\\/\\/purl.org\\/macgirvin\\/dfrn\\/1.0\",\"href\":\"https:\\/\\/squeet.me\\/profile\\/lain\"},{\"rel\":\"http:\\/\\/schemas.google.com\\/g\\/2010#updates-from\",\"type\":\"application\\/atom+xml\",\"href\":\"https:\\/\\/squeet.me\\/dfrn_poll\\/lain\"},{\"rel\":\"http:\\/\\/webfinger.net\\/rel\\/profile-page\",\"type\":\"text\\/html\",\"href\":\"https:\\/\\/squeet.me\\/profile\\/lain\"},{\"rel\":\"self\",\"type\":\"application\\/activity+json\",\"href\":\"https:\\/\\/squeet.me\\/profile\\/lain\"},{\"rel\":\"http:\\/\\/microformats.org\\/profile\\/hcard\",\"type\":\"text\\/html\",\"href\":\"https:\\/\\/squeet.me\\/hcard\\/lain\"},{\"rel\":\"http:\\/\\/portablecontacts.net\\/spec\\/1.0\",\"href\":\"https:\\/\\/squeet.me\\/poco\\/lain\"},{\"rel\":\"http:\\/\\/webfinger.net\\/rel\\/avatar\",\"type\":\"image\\/jpeg\",\"href\":\"https:\\/\\/squeet.me\\/photo\\/profile\\/301.jpg\"},{\"rel\":\"http:\\/\\/joindiaspora.com\\/seed_location\",\"type\":\"text\\/html\",\"href\":\"https:\\/\\/squeet.me\"},{\"rel\":\"salmon\",\"href\":\"https:\\/\\/squeet.me\\/salmon\\/lain\"},{\"rel\":\"http:\\/\\/salmon-protocol.org\\/ns\\/salmon-replies\",\"href\":\"https:\\/\\/squeet.me\\/salmon\\/lain\"},{\"rel\":\"http:\\/\\/salmon-protocol.org\\/ns\\/salmon-mention\",\"href\":\"https:\\/\\/squeet.me\\/salmon\\/lain\\/mention\"},{\"rel\":\"http:\\/\\/ostatus.org\\/schema\\/1.0\\/subscribe\",\"template\":\"https:\\/\\/squeet.me\\/follow?url={uri}\"},{\"rel\":\"magic-public-key\",\"href\":\"data:application\\/magic-public-key,RSA.AMwa8FUs2fWEjX0xN7yRQgegQffhBpuKNC6fa5VNSVorFjGZhRrlPMn7TQOeihlc9lBz2OsHlIedbYn2uJ7yCs0.AQAB\"},{\"rel\":\"http:\\/\\/purl.org\\/openwebauth\\/v1\",\"type\":\"application\\/x-dfrn+json\",\"href\":\"https:\\/\\/squeet.me\\/owa\"}]}", + "body": "{\"subject\":\"acct:lain@squeet.me\",\"aliases\":[\"https:\\/\\/squeet.me\\/~lain\",\"https:\\/\\/squeet.me\\/profile\\/lain\"],\"links\":[{\"rel\":\"http:\\/\\/purl.org\\/macgirvin\\/dfrn\\/1.0\",\"href\":\"https:\\/\\/squeet.me\\/profile\\/lain\"},{\"rel\":\"http:\\/\\/schemas.google.com\\/g\\/2010#updates-from\",\"type\":\"application\\/atom+xml\",\"href\":\"https:\\/\\/squeet.me\\/dfrn_poll\\/lain\"},{\"rel\":\"http:\\/\\/webfinger.net\\/rel\\/profile-page\",\"type\":\"text\\/html\",\"href\":\"https:\\/\\/squeet.me\\/profile\\/lain\"},{\"rel\":\"self\",\"type\":\"application\\/activity+json\",\"href\":\"https:\\/\\/squeet.me\\/profile\\/lain\"},{\"rel\":\"http:\\/\\/microformats.org\\/profile\\/hcard\",\"type\":\"text\\/html\",\"href\":\"https:\\/\\/squeet.me\\/hcard\\/lain\"},{\"rel\":\"http:\\/\\/portablecontacts.net\\/spec\\/1.0\",\"href\":\"https:\\/\\/squeet.me\\/poco\\/lain\"},{\"rel\":\"http:\\/\\/webfinger.net\\/rel\\/avatar\",\"type\":\"image\\/jpeg\",\"href\":\"https:\\/\\/squeet.me\\/photo\\/abf2ee40bfcb044ac7fd1d143c82f63a-4.jpg?ts=1526641378\"},{\"rel\":\"http:\\/\\/joindiaspora.com\\/seed_location\",\"type\":\"text\\/html\",\"href\":\"https:\\/\\/squeet.me\"},{\"rel\":\"salmon\",\"href\":\"https:\\/\\/squeet.me\\/salmon\\/lain\"},{\"rel\":\"http:\\/\\/salmon-protocol.org\\/ns\\/salmon-replies\",\"href\":\"https:\\/\\/squeet.me\\/salmon\\/lain\"},{\"rel\":\"http:\\/\\/salmon-protocol.org\\/ns\\/salmon-mention\",\"href\":\"https:\\/\\/squeet.me\\/salmon\\/lain\\/mention\"},{\"rel\":\"http:\\/\\/ostatus.org\\/schema\\/1.0\\/subscribe\",\"template\":\"https:\\/\\/squeet.me\\/follow?url={uri}\"},{\"rel\":\"magic-public-key\",\"href\":\"data:application\\/magic-public-key,RSA.zBrwVSzZ9YSNfTE3vJFCB6BB9-EGm4o0Lp9rlU1JWisWMZmFGuU8yftNA56KGVz2UHPY6weUh51tifa4nvIKzQ.AQAB\"},{\"rel\":\"http:\\/\\/purl.org\\/openwebauth\\/v1\",\"type\":\"application\\/x-zot+json\",\"href\":\"https:\\/\\/squeet.me\\/owa\"}]}", "headers": { - "Date": "Tue, 13 Nov 2018 11:11:09 GMT", - "Server": "Apache", - "Expires": "Thu, 19 Nov 1981 08:52:00 GMT", - "Cache-Control": "no-store, no-cache, must-revalidate", - "Pragma": "no-cache", + "Date": "Fri, 09 Apr 2021 08:08:52 GMT", + "Server": "Apache/2.4.25 (Debian)", "X-Account-Management-Status": "none", "Access-Control-Allow-Origin": "*", - "Set-Cookie": "PHPSESSID=330arcps63iok272c5hqdsfhp3; path=/; secure; HttpOnly", - "Strict-Transport-Security": "max-age=31536000; includeSubDomains", "Transfer-Encoding": "chunked", "Content-Type": "application/json; charset=utf-8" }, diff --git a/test/fixtures/vcr_cassettes/webfinger/mastodon.json b/test/fixtures/vcr_cassettes/webfinger/mastodon.json index a9d77ba2c..99bc062cb 100644 --- a/test/fixtures/vcr_cassettes/webfinger/mastodon.json +++ b/test/fixtures/vcr_cassettes/webfinger/mastodon.json @@ -3,26 +3,26 @@ "request": { "body": "", "headers": { - "User-Agent": "localhost - Mobilizon 1.0.0-rc.2-5-g6701e6a4", - "Accept": "application/json, application/activity+json, application/jrd+json" + "User-Agent": "localhost - Mobilizon 1.1.0-32-gbd53bfc4-dirty", + "Accept": "application/xrd+xml, application/xml, text/xml" }, "method": "get", "options": { "recv_timeout": 20000 }, "request_body": "", - "url": "http://social.tcit.fr/.well-known/webfinger?resource=acct:tcit@social.tcit.fr" + "url": "http://social.tcit.fr/.well-known/host-meta" }, "response": { "binary": false, - "body": "\r\n301 Moved Permanently\r\n\r\n

301 Moved Permanently

\r\n
nginx/1.19.3
\r\n\r\n\r\n", + "body": "\r\n301 Moved Permanently\r\n\r\n

301 Moved Permanently

\r\n
nginx/1.14.2
\r\n\r\n\r\n", "headers": { - "Server": "nginx/1.19.3", - "Date": "Wed, 21 Oct 2020 09:07:41 GMT", + "Server": "nginx/1.14.2", + "Date": "Thu, 08 Apr 2021 18:59:56 GMT", "Content-Type": "text/html", - "Content-Length": "169", + "Content-Length": "185", "Connection": "keep-alive", - "Location": "https://social.tcit.fr/.well-known/webfinger?resource=acct:tcit@social.tcit.fr" + "Location": "https://social.tcit.fr/.well-known/host-meta" }, "status_code": 301, "type": "ok" @@ -32,7 +32,47 @@ "request": { "body": "", "headers": { - "User-Agent": "localhost - Mobilizon 1.0.0-rc.2-5-g6701e6a4", + "User-Agent": "localhost - Mobilizon 1.1.0-32-gbd53bfc4-dirty", + "Accept": "application/xrd+xml, application/xml, text/xml" + }, + "method": "get", + "options": { + "recv_timeout": 20000 + }, + "request_body": "", + "url": "https://social.tcit.fr/.well-known/host-meta" + }, + "response": { + "binary": false, + "body": "\n\n \n\n", + "headers": { + "Date": "Thu, 08 Apr 2021 18:59:56 GMT", + "Content-Type": "application/xrd+xml; charset=utf-8", + "Transfer-Encoding": "chunked", + "Connection": "keep-alive", + "Server": "Mastodon", + "X-Frame-Options": "DENY", + "X-Content-Type-Options": "nosniff", + "X-XSS-Protection": "1; mode=block", + "Referrer-Policy": "same-origin", + "Strict-Transport-Security": "max-age=63072000; includeSubDomains; preload", + "X-Clacks-Overhead": "GNU Natalie Nguyen", + "Vary": "Accept, Accept-Encoding, Origin", + "Cache-Control": "max-age=259200, public", + "ETag": "W/\"b397089bfee005b03360ba4435bb4aad\"", + "X-Request-Id": "41e837ba-21a6-4324-bda8-cac28a8d1778", + "X-Runtime": "0.004198", + "X-Cached": "MISS" + }, + "status_code": 200, + "type": "ok" + } + }, + { + "request": { + "body": "", + "headers": { + "User-Agent": "localhost - Mobilizon 1.1.0-32-gbd53bfc4-dirty", "Accept": "application/json, application/activity+json, application/jrd+json" }, "method": "get", @@ -46,7 +86,7 @@ "binary": false, "body": "{\"subject\":\"acct:tcit@social.tcit.fr\",\"aliases\":[\"https://social.tcit.fr/@tcit\",\"https://social.tcit.fr/users/tcit\"],\"links\":[{\"rel\":\"http://webfinger.net/rel/profile-page\",\"type\":\"text/html\",\"href\":\"https://social.tcit.fr/@tcit\"},{\"rel\":\"self\",\"type\":\"application/activity+json\",\"href\":\"https://social.tcit.fr/users/tcit\"},{\"rel\":\"http://ostatus.org/schema/1.0/subscribe\",\"template\":\"https://social.tcit.fr/authorize_interaction?uri={uri}\"}]}", "headers": { - "Date": "Wed, 21 Oct 2020 09:07:41 GMT", + "Date": "Thu, 08 Apr 2021 18:59:56 GMT", "Content-Type": "application/jrd+json; charset=utf-8", "Transfer-Encoding": "chunked", "Connection": "keep-alive", @@ -60,8 +100,8 @@ "Vary": "Accept, Accept-Encoding, Origin", "Cache-Control": "max-age=259200, public", "ETag": "W/\"37760e35c1537b8e02b6d4b4f9ebfe82\"", - "X-Request-Id": "429bb891-1033-498b-91bb-12835984223f", - "X-Runtime": "0.072046", + "X-Request-Id": "4c8384d6-d921-4ef6-8a18-1fcbf35ee6bc", + "X-Runtime": "0.009277", "X-Cached": "MISS" }, "status_code": 200, diff --git a/test/fixtures/vcr_cassettes/webfinger/peertube.json b/test/fixtures/vcr_cassettes/webfinger/peertube.json index bc97f4a06..53d979e2e 100644 --- a/test/fixtures/vcr_cassettes/webfinger/peertube.json +++ b/test/fixtures/vcr_cassettes/webfinger/peertube.json @@ -3,33 +3,88 @@ "request": { "body": "", "headers": { + "User-Agent": "localhost - Mobilizon 1.1.0-32-gbd53bfc4-dirty", + "Accept": "application/xrd+xml, application/xml, text/xml" + }, + "method": "get", + "options": { + "recv_timeout": 20000 + }, + "request_body": "", + "url": "http://framatube.org/.well-known/host-meta" + }, + "response": { + "binary": false, + "body": "\r\n301 Moved Permanently\r\n\r\n

301 Moved Permanently

\r\n
nginx/1.14.2
\r\n\r\n\r\n", + "headers": { + "Server": "nginx/1.14.2", + "Date": "Thu, 08 Apr 2021 18:59:59 GMT", + "Content-Type": "text/html", + "Content-Length": "185", + "Connection": "keep-alive", + "Location": "https://framatube.org/.well-known/host-meta" + }, + "status_code": 301, + "type": "ok" + } + }, + { + "request": { + "body": "", + "headers": { + "User-Agent": "localhost - Mobilizon 1.1.0-32-gbd53bfc4-dirty", + "Accept": "application/xrd+xml, application/xml, text/xml" + }, + "method": "get", + "options": { + "recv_timeout": 20000 + }, + "request_body": "", + "url": "https://framatube.org/.well-known/host-meta" + }, + "response": { + "binary": false, + "body": "\n\n \n", + "headers": { + "Server": "nginx/1.14.2", + "Date": "Thu, 08 Apr 2021 18:59:59 GMT", + "Content-Type": "application/xml; charset=utf-8", + "Content-Length": "219", + "Connection": "keep-alive", + "Tk": "N", + "Access-Control-Allow-Origin": "*", + "ETag": "W/\"db-l6RCFQ8UK40DPZ9VQ8G/SKn3A64\"" + }, + "status_code": 200, + "type": "ok" + } + }, + { + "request": { + "body": "", + "headers": { + "User-Agent": "localhost - Mobilizon 1.1.0-32-gbd53bfc4-dirty", "Accept": "application/json, application/activity+json, application/jrd+json" }, "method": "get", "options": { - "follow_redirect": "true" + "recv_timeout": 20000 }, "request_body": "", - "url": "http://framatube.org/.well-known/webfinger?resource=acct:framasoft@framatube.org" + "url": "https://framatube.org/.well-known/webfinger?resource=acct:framasoft@framatube.org" }, "response": { "binary": false, - "body": "{\"subject\":\"acct:framasoft@framatube.org\",\"aliases\":[\"https://framatube.org/accounts/framasoft\"],\"links\":[{\"rel\":\"self\",\"type\":\"application/activity+json\",\"href\":\"https://framatube.org/accounts/framasoft\"}]}", + "body": "{\"subject\":\"acct:framasoft@framatube.org\",\"aliases\":[\"https://framatube.org/accounts/framasoft\"],\"links\":[{\"rel\":\"self\",\"type\":\"application/activity+json\",\"href\":\"https://framatube.org/accounts/framasoft\"},{\"rel\":\"http://ostatus.org/schema/1.0/subscribe\",\"template\":\"https://framatube.org/remote-interaction?uri={uri}\"}]}", "headers": { - "Server": "nginx/1.10.3", - "Date": "Tue, 13 Nov 2018 11:11:11 GMT", + "Server": "nginx/1.14.2", + "Date": "Thu, 08 Apr 2021 18:59:59 GMT", "Content-Type": "application/json; charset=utf-8", - "Content-Length": "207", + "Content-Length": "321", "Connection": "keep-alive", - "X-DNS-Prefetch-Control": "off", - "X-Frame-Options": "DENY", - "X-Download-Options": "noopen", - "X-Content-Type-Options": "nosniff", - "X-XSS-Protection": "1; mode=block", "Tk": "N", - "ETag": "W/\"cf-VoWlsif7OQ4xxqki7jRAnOPKRes\"", - "Strict-Transport-Security": "max-age=63072000; includeSubDomains; preload", - "X-Robots-Tag": "none" + "Access-Control-Allow-Origin": "*", + "ETag": "W/\"141-yxvvlAPayX5y2q2Yra8qYVtz4VU\"" }, "status_code": 200, "type": "ok" diff --git a/test/fixtures/vcr_cassettes/webfinger/pleroma.json b/test/fixtures/vcr_cassettes/webfinger/pleroma.json index bf129a2be..1d2b53997 100644 --- a/test/fixtures/vcr_cassettes/webfinger/pleroma.json +++ b/test/fixtures/vcr_cassettes/webfinger/pleroma.json @@ -3,38 +3,107 @@ "request": { "body": "", "headers": { + "User-Agent": "localhost - Mobilizon 1.1.0-32-gbd53bfc4-dirty", + "Accept": "application/xrd+xml, application/xml, text/xml" + }, + "method": "get", + "options": { + "recv_timeout": 20000 + }, + "request_body": "", + "url": "http://pleroma.soykaf.com/.well-known/host-meta" + }, + "response": { + "binary": false, + "body": "\r\n301 Moved Permanently\r\n\r\n

301 Moved Permanently

\r\n
nginx/1.18.0 (Ubuntu)
\r\n\r\n\r\n", + "headers": { + "Server": "nginx/1.18.0 (Ubuntu)", + "Date": "Thu, 08 Apr 2021 18:59:57 GMT", + "Content-Type": "text/html", + "Content-Length": "178", + "Connection": "keep-alive", + "Location": "https://pleroma.soykaf.com/.well-known/host-meta" + }, + "status_code": 301, + "type": "ok" + } + }, + { + "request": { + "body": "", + "headers": { + "User-Agent": "localhost - Mobilizon 1.1.0-32-gbd53bfc4-dirty", + "Accept": "application/xrd+xml, application/xml, text/xml" + }, + "method": "get", + "options": { + "recv_timeout": 20000 + }, + "request_body": "", + "url": "https://pleroma.soykaf.com/.well-known/host-meta" + }, + "response": { + "binary": false, + "body": "", + "headers": { + "Server": "nginx/1.18.0 (Ubuntu)", + "Date": "Thu, 08 Apr 2021 18:59:57 GMT", + "Content-Type": "application/xrd+xml; charset=utf-8", + "Content-Length": "220", + "Connection": "keep-alive", + "access-control-allow-credentials": "true", + "access-control-allow-origin": "*", + "access-control-expose-headers": "Link,X-RateLimit-Reset,X-RateLimit-Limit,X-RateLimit-Remaining,X-Request-Id,Idempotency-Key", + "cache-control": "max-age=0, private, must-revalidate", + "content-security-policy": "upgrade-insecure-requests;script-src 'self';connect-src 'self' blob: https://pleroma.soykaf.com wss://pleroma.soykaf.com;media-src 'self';img-src 'self' data: blob:;default-src 'none';base-uri 'self';frame-ancestors 'none';style-src 'self' 'unsafe-inline';font-src 'self';manifest-src 'self';", + "referrer-policy": "same-origin", + "x-content-type-options": "nosniff", + "x-download-options": "noopen", + "x-frame-options": "DENY", + "x-permitted-cross-domain-policies": "none", + "x-request-id": "FnP3HZA8tRWC7E4EYzyS", + "x-xss-protection": "1; mode=block" + }, + "status_code": 200, + "type": "ok" + } + }, + { + "request": { + "body": "", + "headers": { + "User-Agent": "localhost - Mobilizon 1.1.0-32-gbd53bfc4-dirty", "Accept": "application/json, application/activity+json, application/jrd+json" }, "method": "get", "options": { - "follow_redirect": "true" + "recv_timeout": 20000 }, "request_body": "", - "url": "http://pleroma.soykaf.com/.well-known/webfinger?resource=acct:lain@pleroma.soykaf.com" + "url": "https://pleroma.soykaf.com/.well-known/webfinger?resource=acct:lain@pleroma.soykaf.com" }, "response": { "binary": false, - "body": "{\"aliases\":[\"https://pleroma.soykaf.com/users/lain\"],\"links\":[{\"href\":\"https://pleroma.soykaf.com/users/lain/feed.atom\",\"rel\":\"http://schemas.google.com/g/2010#updates-from\",\"type\":\"application/atom+xml\"},{\"href\":\"https://pleroma.soykaf.com/users/lain\",\"rel\":\"http://webfinger.net/rel/profile-page\",\"type\":\"text/html\"},{\"href\":\"https://pleroma.soykaf.com/users/lain/salmon\",\"rel\":\"salmon\"},{\"href\":\"data:application/magic-public-key,RSA.u39dKLin8N4PywPvasEGXstOMsgg9m1OEKnpfHnSHqc6UOtIPs5-aI_LcLbhIEH2EVl6jstvtqMIloPch1FizZ3OBiKz81dXTiEZ3NfKgj_GJfIlipChAadxrmUyWT_Pr0qPaF1vhPrkSTwR8iDNUiQ-OEggRPpJVkJ619MXNdsJE59yklZiD1WY0vC9aG9m-dh0BANKNwSjwfZ3uFjDh0UosMATKjPTSO_I59nK_lArex_jAwTnVm6Dryk2qR2XXZyzTzZAHuYqSM77RlsNTJUCOaSadl816eZAvU3TF-ibIou0D-0sN-M-QehRh93sVJ95U40GQz8jOGc_5wK8xw==.AQAB\",\"rel\":\"magic-public-key\"},{\"href\":\"https://pleroma.soykaf.com/users/lain\",\"rel\":\"self\",\"type\":\"application/activity+json\"},{\"href\":\"https://pleroma.soykaf.com/users/lain\",\"rel\":\"self\",\"type\":\"application/ld+json; profile=\\\"https://www.w3.org/ns/activitystreams\\\"\"},{\"rel\":\"http://ostatus.org/schema/1.0/subscribe\",\"template\":\"https://pleroma.soykaf.com/ostatus_subscribe?acct={uri}\"}],\"subject\":\"acct:lain@pleroma.soykaf.com\"}", + "body": "{\"aliases\":[\"https://pleroma.soykaf.com/users/lain\"],\"links\":[{\"href\":\"https://pleroma.soykaf.com/users/lain\",\"rel\":\"http://webfinger.net/rel/profile-page\",\"type\":\"text/html\"},{\"href\":\"https://pleroma.soykaf.com/users/lain\",\"rel\":\"self\",\"type\":\"application/activity+json\"},{\"href\":\"https://pleroma.soykaf.com/users/lain\",\"rel\":\"self\",\"type\":\"application/ld+json; profile=\\\"https://www.w3.org/ns/activitystreams\\\"\"},{\"rel\":\"http://ostatus.org/schema/1.0/subscribe\",\"template\":\"https://pleroma.soykaf.com/ostatus_subscribe?acct={uri}\"}],\"subject\":\"acct:lain@pleroma.soykaf.com\"}", "headers": { - "Server": "nginx/1.10.3", - "Date": "Tue, 13 Nov 2018 11:11:11 GMT", + "Server": "nginx/1.18.0 (Ubuntu)", + "Date": "Thu, 08 Apr 2021 18:59:57 GMT", "Content-Type": "application/json; charset=utf-8", - "Content-Length": "1214", + "Content-Length": "576", "Connection": "keep-alive", "Vary": "Accept-Encoding", - "cache-control": "max-age=0, private, must-revalidate", - "x-request-id": "2ljal4oljell0gfni41am571", - "access-control-allow-origin": "*", - "access-control-expose-headers": "", "access-control-allow-credentials": "true", - "Access-Control-Allow-Methods": "POST, GET, OPTIONS", - "Access-Control-Allow-Headers": "Authorization, Content-Type", - "X-XSS-Protection": "1; mode=block", - "X-Permitted-Cross-Domain-Policies": "none", - "X-Frame-Options": "DENY", - "X-Content-Type-Options": "nosniff", - "Referrer-Policy": "same-origin", - "X-Download-Options": "noopen" + "access-control-allow-origin": "*", + "access-control-expose-headers": "Link,X-RateLimit-Reset,X-RateLimit-Limit,X-RateLimit-Remaining,X-Request-Id,Idempotency-Key", + "cache-control": "max-age=0, private, must-revalidate", + "content-security-policy": "upgrade-insecure-requests;script-src 'self';connect-src 'self' blob: https://pleroma.soykaf.com wss://pleroma.soykaf.com;media-src 'self';img-src 'self' data: blob:;default-src 'none';base-uri 'self';frame-ancestors 'none';style-src 'self' 'unsafe-inline';font-src 'self';manifest-src 'self';", + "referrer-policy": "same-origin", + "x-content-type-options": "nosniff", + "x-download-options": "noopen", + "x-frame-options": "DENY", + "x-permitted-cross-domain-policies": "none", + "x-request-id": "FnP3HZJ_kh8ymy8E1OCx", + "x-xss-protection": "1; mode=block" }, "status_code": 200, "type": "ok" diff --git a/test/web/controllers/webfinger_controller_test.exs b/test/web/controllers/webfinger_controller_test.exs index 5d407bdbe..d5dfff832 100644 --- a/test/web/controllers/webfinger_controller_test.exs +++ b/test/web/controllers/webfinger_controller_test.exs @@ -23,9 +23,9 @@ defmodule Mobilizon.Web.WebFingerControllerTest do conn = get(conn, "/.well-known/host-meta") assert response(conn, 200) == - "mobilizon.test" + }/.well-known/webfinger?resource={uri}\" type=\"application/jrd+json\" />" assert {"content-type", "application/xrd+xml; charset=utf-8"} in conn.resp_headers end From e991d7d373c0fdf3ed88b328dd073f29ab2608fb Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Fri, 9 Apr 2021 10:43:34 +0200 Subject: [PATCH 03/13] Fix content type and size missing for profile avatars Signed-off-by: Thomas Citharel --- lib/graphql/resolvers/person.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/graphql/resolvers/person.ex b/lib/graphql/resolvers/person.ex index 21f686c12..70c720a81 100644 --- a/lib/graphql/resolvers/person.ex +++ b/lib/graphql/resolvers/person.ex @@ -225,9 +225,9 @@ defmodule Mobilizon.GraphQL.Resolvers.Person do end defp save_picture(media, key) do - with {:ok, %{name: name, url: url, content_type: content_type, size: _size}} <- + with {:ok, %{name: name, url: url, content_type: content_type, size: size}} <- Upload.store(media.file, type: key, description: media.alt) do - %{"name" => name, "url" => url, "mediaType" => content_type} + %{"name" => name, "url" => url, "content_type" => content_type, "size" => size} end end From 5ac02bae5dd7eee21c82772c10b26306a44e4577 Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Fri, 9 Apr 2021 10:43:45 +0200 Subject: [PATCH 04/13] Use runtime configuration for HTTP clients user-agent Signed-off-by: Thomas Citharel --- lib/service/http/activity_pub.ex | 10 ++++------ lib/service/http/geospatial_client.ex | 4 +--- lib/service/http/remote_media_downloader_client.ex | 4 +--- lib/service/http/rich_media_preview_client.ex | 4 +--- lib/service/http/webfinger_client.ex | 4 +--- 5 files changed, 8 insertions(+), 18 deletions(-) diff --git a/lib/service/http/activity_pub.ex b/lib/service/http/activity_pub.ex index ee5b21630..db9683d9b 100644 --- a/lib/service/http/activity_pub.ex +++ b/lib/service/http/activity_pub.ex @@ -5,28 +5,26 @@ defmodule Mobilizon.Service.HTTP.ActivityPub do alias Mobilizon.Config - @adapter Application.get_env(:tesla, __MODULE__, [])[:adapter] || Tesla.Adapter.Hackney @default_opts [ recv_timeout: 20_000 ] - @user_agent Config.instance_user_agent() def client(options \\ []) do headers = Keyword.get(options, :headers, []) + adapter = Application.get_env(:tesla, __MODULE__, [])[:adapter] || Tesla.Adapter.Hackney opts = Keyword.merge(@default_opts, Keyword.get(options, :opts, [])) middleware = [ {Tesla.Middleware.Headers, - [{"User-Agent", @user_agent}, {"Accept", "application/activity+json"}] ++ headers}, + [{"User-Agent", Config.instance_user_agent()}, {"Accept", "application/activity+json"}] ++ + headers}, Tesla.Middleware.FollowRedirects, {Tesla.Middleware.Timeout, timeout: 10_000}, {Tesla.Middleware.JSON, decode_content_types: ["application/activity+json", "application/ld+json"]} ] - adapter = {@adapter, opts} - - Tesla.client(middleware, adapter) + Tesla.client(middleware, {adapter, opts}) end def get(client, url) do diff --git a/lib/service/http/geospatial_client.ex b/lib/service/http/geospatial_client.ex index 1b578c9de..064fee4c4 100644 --- a/lib/service/http/geospatial_client.ex +++ b/lib/service/http/geospatial_client.ex @@ -13,13 +13,11 @@ defmodule Mobilizon.Service.HTTP.GeospatialClient do adapter(Tesla.Adapter.Hackney, @default_opts) - @user_agent Config.instance_user_agent() - plug(Tesla.Middleware.FollowRedirects) plug(Tesla.Middleware.Timeout, timeout: 10_000) - plug(Tesla.Middleware.Headers, [{"User-Agent", @user_agent}]) + plug(Tesla.Middleware.Headers, [{"User-Agent", Config.instance_user_agent()}]) plug(Tesla.Middleware.JSON) end diff --git a/lib/service/http/remote_media_downloader_client.ex b/lib/service/http/remote_media_downloader_client.ex index 06af2bf9d..f8be88793 100644 --- a/lib/service/http/remote_media_downloader_client.ex +++ b/lib/service/http/remote_media_downloader_client.ex @@ -12,11 +12,9 @@ defmodule Mobilizon.Service.HTTP.RemoteMediaDownloaderClient do adapter(Tesla.Adapter.Hackney, @default_opts) - @user_agent Config.instance_user_agent() - plug(Tesla.Middleware.FollowRedirects) plug(Tesla.Middleware.Timeout, timeout: 10_000) - plug(Tesla.Middleware.Headers, [{"User-Agent", @user_agent}]) + plug(Tesla.Middleware.Headers, [{"User-Agent", Config.instance_user_agent()}]) end diff --git a/lib/service/http/rich_media_preview_client.ex b/lib/service/http/rich_media_preview_client.ex index 8f3983548..520839241 100644 --- a/lib/service/http/rich_media_preview_client.ex +++ b/lib/service/http/rich_media_preview_client.ex @@ -12,11 +12,9 @@ defmodule Mobilizon.Service.HTTP.RichMediaPreviewClient do adapter(Tesla.Adapter.Hackney, @default_opts) - @user_agent Config.instance_user_agent() - plug(Tesla.Middleware.FollowRedirects) plug(Tesla.Middleware.Timeout, timeout: 10_000) - plug(Tesla.Middleware.Headers, [{"User-Agent", @user_agent}]) + plug(Tesla.Middleware.Headers, [{"User-Agent", Config.instance_user_agent()}]) end diff --git a/lib/service/http/webfinger_client.ex b/lib/service/http/webfinger_client.ex index 13b578a0d..d5c02e357 100644 --- a/lib/service/http/webfinger_client.ex +++ b/lib/service/http/webfinger_client.ex @@ -13,14 +13,12 @@ defmodule Mobilizon.Service.HTTP.WebfingerClient do adapter(Tesla.Adapter.Hackney, @default_opts) - @user_agent Config.instance_user_agent() - plug(Tesla.Middleware.FollowRedirects) plug(Tesla.Middleware.Timeout, timeout: 10_000) plug(Tesla.Middleware.Headers, [ - {"User-Agent", @user_agent}, + {"User-Agent", Config.instance_user_agent()}, {"Accept", "application/json, application/activity+json, application/jrd+json"} ]) From cbf772f28250d93016d7a80f69fd5f6418783699 Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Fri, 9 Apr 2021 10:52:40 +0200 Subject: [PATCH 05/13] Add a check for valid URI before fetching it in AP Client Signed-off-by: Thomas Citharel --- lib/federation/activity_pub/fetcher.ex | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/federation/activity_pub/fetcher.ex b/lib/federation/activity_pub/fetcher.ex index e23c7d163..58fcf7937 100644 --- a/lib/federation/activity_pub/fetcher.ex +++ b/lib/federation/activity_pub/fetcher.ex @@ -17,7 +17,8 @@ defmodule Mobilizon.Federation.ActivityPub.Fetcher do def fetch(url, options \\ []) do on_behalf_of = Keyword.get(options, :on_behalf_of, Relay.get_actor()) - with date <- Signature.generate_date_header(), + with false <- address_invalid(url), + date <- Signature.generate_date_header(), headers <- [{:Accept, "application/activity+json"}] |> maybe_date_fetch(date) @@ -90,4 +91,12 @@ defmodule Mobilizon.Federation.ActivityPub.Fetcher do {:error, err} end end + + @spec address_invalid(String.t()) :: false | {:error, :invalid_url} + defp address_invalid(address) do + with %URI{host: host, scheme: scheme} <- URI.parse(address), + true <- is_nil(host) or is_nil(scheme) do + {:error, :invalid_url} + end + end end From bbfe3de471ee25d17a48a49ae5aa64eefb77e55b Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Fri, 9 Apr 2021 11:57:53 +0200 Subject: [PATCH 06/13] Handle NotAcceptableError better Signed-off-by: Thomas Citharel --- lib/web/plugs/not_acceptable_error.ex | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 lib/web/plugs/not_acceptable_error.ex diff --git a/lib/web/plugs/not_acceptable_error.ex b/lib/web/plugs/not_acceptable_error.ex new file mode 100644 index 000000000..0b1556c4e --- /dev/null +++ b/lib/web/plugs/not_acceptable_error.ex @@ -0,0 +1,4 @@ +defimpl Plug.Exception, for: Phoenix.NotAcceptableError do + def status(_exception), do: 406 + def actions(_exception), do: [] +end From 4079af6f72019575540b4dbc0bd1e7dc1e0c7c9b Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Fri, 9 Apr 2021 12:12:06 +0200 Subject: [PATCH 07/13] Make sure arg for Actors.get_actor_by_name/2 doesn't start with @ Signed-off-by: Thomas Citharel --- lib/mobilizon/actors/actors.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mobilizon/actors/actors.ex b/lib/mobilizon/actors/actors.ex index e55f10702..21dc47a8b 100644 --- a/lib/mobilizon/actors/actors.ex +++ b/lib/mobilizon/actors/actors.ex @@ -156,7 +156,7 @@ defmodule Mobilizon.Actors do query |> filter_by_type(type) - |> filter_by_name(String.split(name, "@")) + |> filter_by_name(name |> String.trim() |> String.trim_leading("@") |> String.split("@")) |> Repo.one() end From fb614cf8777e4c52c2a5d307decbf98cdf57553b Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Fri, 9 Apr 2021 14:01:40 +0200 Subject: [PATCH 08/13] Handle AP fetch issues properly Signed-off-by: Thomas Citharel --- lib/federation/activity_pub/fetcher.ex | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/federation/activity_pub/fetcher.ex b/lib/federation/activity_pub/fetcher.ex index 58fcf7937..65971b6c7 100644 --- a/lib/federation/activity_pub/fetcher.ex +++ b/lib/federation/activity_pub/fetcher.ex @@ -39,6 +39,9 @@ defmodule Mobilizon.Federation.ActivityPub.Fetcher do {:ok, %Tesla.Env{} = res} -> {:error, res} + + {:error, err} -> + {:error, err} end end From 0210b677c5bc0f04585f580c96fb98098c0cfc2b Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Mon, 12 Apr 2021 10:13:11 +0200 Subject: [PATCH 09/13] Expose maximum picture sizes Signed-off-by: Thomas Citharel --- config/config.exs | 6 +++--- js/src/graphql/config.ts | 5 +++++ js/src/types/config.model.ts | 5 +++++ js/tests/unit/specs/mocks/config.ts | 6 ++++++ lib/graphql/resolvers/config.ex | 5 +++++ lib/graphql/schema/config.ex | 11 +++++++++++ lib/web/endpoint.ex | 5 ++++- 7 files changed, 39 insertions(+), 4 deletions(-) diff --git a/config/config.exs b/config/config.exs index ea57f6449..e99cea93a 100644 --- a/config/config.exs +++ b/config/config.exs @@ -25,9 +25,9 @@ config :mobilizon, :instance, allow_relay: true, federating: true, remote_limit: 100_000, - upload_limit: 10_000_000, - avatar_upload_limit: 2_000_000, - banner_upload_limit: 4_000_000, + upload_limit: 10_485_760, + avatar_upload_limit: 2_097_152, + banner_upload_limit: 4_194_304, remove_orphan_uploads: true, orphan_upload_grace_period_hours: 48, remove_unconfirmed_users: true, diff --git a/js/src/graphql/config.ts b/js/src/graphql/config.ts index 6e514ef35..80e79b624 100644 --- a/js/src/graphql/config.ts +++ b/js/src/graphql/config.ts @@ -75,6 +75,11 @@ export const CONFIG = gql` label } } + uploadLimits { + default + avatar + banner + } } } `; diff --git a/js/src/types/config.model.ts b/js/src/types/config.model.ts index 6d391d0a8..d4105a63f 100644 --- a/js/src/types/config.model.ts +++ b/js/src/types/config.model.ts @@ -89,4 +89,9 @@ export interface IConfig { ldap: boolean; oauthProviders: IOAuthProvider[]; }; + uploadLimits: { + default: number; + avatar: number; + banner: number; + }; } diff --git a/js/tests/unit/specs/mocks/config.ts b/js/tests/unit/specs/mocks/config.ts index 856288302..70ee08d75 100644 --- a/js/tests/unit/specs/mocks/config.ts +++ b/js/tests/unit/specs/mocks/config.ts @@ -102,6 +102,12 @@ export const configMock = { }, ], slogan: null, + uploadLimits: { + __typename: "UploadLimits", + default: 10_000_000, + avatar: 2_000_000, + banner: 4_000_000, + }, }, }, }; diff --git a/lib/graphql/resolvers/config.ex b/lib/graphql/resolvers/config.ex index a1b8c3e8c..f7b15a063 100644 --- a/lib/graphql/resolvers/config.ex +++ b/lib/graphql/resolvers/config.ex @@ -134,6 +134,11 @@ defmodule Mobilizon.GraphQL.Resolvers.Config do auth: %{ ldap: Config.ldap_enabled?(), oauth_providers: Config.oauth_consumer_strategies() + }, + upload_limits: %{ + default: Config.get([:instance, :upload_limit]), + avatar: Config.get([:instance, :avatar_upload_limit]), + banner: Config.get([:instance, :banner_upload_limit]) } } end diff --git a/lib/graphql/schema/config.ex b/lib/graphql/schema/config.ex index a2d9d02ab..1feafb1bb 100644 --- a/lib/graphql/schema/config.ex +++ b/lib/graphql/schema/config.ex @@ -33,6 +33,8 @@ defmodule Mobilizon.GraphQL.Schema.ConfigType do description: "The instance's enabled resource providers" ) + field(:upload_limits, :upload_limits, description: "The configuration for upload limits") + field(:timezones, list_of(:string), description: "The instance's available timezones") field(:features, :features, description: "The instance's features") field(:version, :string, description: "The instance's version") @@ -283,6 +285,15 @@ defmodule Mobilizon.GraphQL.Schema.ConfigType do field(:label, :string, description: "The label for the auth provider") end + @desc """ + An upload limits configuration + """ + object :upload_limits do + field(:default, :integer, description: "The default limitation, in bytes") + field(:avatar, :integer, description: "The avatar limitation, in bytes") + field(:banner, :integer, description: "The banner limitation, in bytes") + end + object :config_queries do @desc "Get the instance config" field :config, :config do diff --git a/lib/web/endpoint.ex b/lib/web/endpoint.ex index 40b1aa74c..5d062f6a5 100644 --- a/lib/web/endpoint.ex +++ b/lib/web/endpoint.ex @@ -62,9 +62,12 @@ defmodule Mobilizon.Web.Endpoint do plug(Plug.RequestId) plug(Plug.Logger) + upload_limit = + Keyword.get(Application.get_env(:mobilizon, :instance, []), :upload_limit, 10_485_760) + plug( Plug.Parsers, - parsers: [:urlencoded, {:multipart, length: 10_000_000}, :json, Absinthe.Plug.Parser], + parsers: [:urlencoded, {:multipart, length: upload_limit}, :json, Absinthe.Plug.Parser], pass: ["*/*"], json_decoder: Jason ) From 947d0b0cdb296b45b8e46b098b0c2435c3d7787e Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Mon, 12 Apr 2021 10:13:45 +0200 Subject: [PATCH 10/13] Handle maximum file sizes better Signed-off-by: Thomas Citharel --- lib/graphql/resolvers/group.ex | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/lib/graphql/resolvers/group.ex b/lib/graphql/resolvers/group.ex index 6c5ffe5cb..fca02e768 100644 --- a/lib/graphql/resolvers/group.ex +++ b/lib/graphql/resolvers/group.ex @@ -96,7 +96,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Group do # TODO Move me to somewhere cleaner defp save_attached_pictures(args) do Enum.reduce([:avatar, :banner], args, fn key, args -> - if Map.has_key?(args, key) && !is_nil(args[key][:media]) do + if is_map(args) && Map.has_key?(args, key) && !is_nil(args[key][:media]) do pic = args[key][:media] with {:ok, %{name: name, url: url, content_type: content_type, size: _size}} <- @@ -122,14 +122,17 @@ defmodule Mobilizon.GraphQL.Resolvers.Group do } ) do with %Actor{id: creator_actor_id} = creator_actor <- Users.get_actor_for_user(user), - args <- Map.update(args, :preferred_username, "", &String.downcase/1), - args <- Map.put(args, :creator_actor, creator_actor), - args <- Map.put(args, :creator_actor_id, creator_actor_id), - args <- save_attached_pictures(args), + args when is_map(args) <- Map.update(args, :preferred_username, "", &String.downcase/1), + args when is_map(args) <- Map.put(args, :creator_actor, creator_actor), + args when is_map(args) <- Map.put(args, :creator_actor_id, creator_actor_id), + {:picture, args} when is_map(args) <- {:picture, save_attached_pictures(args)}, {:ok, _activity, %Actor{type: :Group} = group} <- API.Groups.create_group(args) do {:ok, group} else + {:picture, {:error, :file_too_large}} -> + {:error, dgettext("errors", "The provided picture is too heavy")} + {:error, err} when is_binary(err) -> {:error, err} end @@ -154,12 +157,15 @@ defmodule Mobilizon.GraphQL.Resolvers.Group do with %Actor{} = updater_actor <- Users.get_actor_for_user(user), {:administrator, true} <- {:administrator, Actors.is_administrator?(updater_actor.id, group_id)}, - args <- Map.put(args, :updater_actor, updater_actor), - args <- save_attached_pictures(args), + args when is_map(args) <- Map.put(args, :updater_actor, updater_actor), + {:picture, args} when is_map(args) <- {:picture, save_attached_pictures(args)}, {:ok, _activity, %Actor{type: :Group} = group} <- API.Groups.update_group(args) do {:ok, group} else + {:picture, {:error, :file_too_large}} -> + {:error, dgettext("errors", "The provided picture is too heavy")} + {:error, err} when is_binary(err) -> {:error, err} From e2721af456a0e27f645c878e09dc9126a299662e Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Mon, 12 Apr 2021 10:43:04 +0200 Subject: [PATCH 11/13] Refactor picture-upload and take into account picture size limits Signed-off-by: Thomas Citharel --- js/src/components/PictureUpload.vue | 107 ++++++++++++++---- js/src/i18n/en_US.json | 7 +- js/src/i18n/fr_FR.json | 7 +- .../views/Account/children/EditIdentity.vue | 26 +++++ js/src/views/Group/Create.vue | 45 +++++++- js/src/views/Group/GroupSettings.vue | 59 +++++++++- 6 files changed, 214 insertions(+), 37 deletions(-) diff --git a/js/src/components/PictureUpload.vue b/js/src/components/PictureUpload.vue index 11a65579f..34a46ac3d 100644 --- a/js/src/components/PictureUpload.vue +++ b/js/src/components/PictureUpload.vue @@ -1,15 +1,35 @@