diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/pleroma/formatter.ex | 14 | ||||
| -rw-r--r-- | lib/pleroma/html.ex | 8 | ||||
| -rw-r--r-- | lib/pleroma/http/http.ex | 3 | ||||
| -rw-r--r-- | lib/pleroma/http/request_builder.ex | 7 | ||||
| -rw-r--r-- | lib/pleroma/stats.ex | 5 | ||||
| -rw-r--r-- | lib/pleroma/upload.ex | 11 | ||||
| -rw-r--r-- | lib/pleroma/user.ex | 36 | ||||
| -rw-r--r-- | lib/pleroma/web/activity_pub/activity_pub.ex | 26 | ||||
| -rw-r--r-- | lib/pleroma/web/activity_pub/relay.ex | 2 | ||||
| -rw-r--r-- | lib/pleroma/web/activity_pub/transmogrifier.ex | 3 | ||||
| -rw-r--r-- | lib/pleroma/web/activity_pub/utils.ex | 8 | ||||
| -rw-r--r-- | lib/pleroma/web/activity_pub/views/object_view.ex | 2 | ||||
| -rw-r--r-- | lib/pleroma/web/common_api/common_api.ex | 9 | ||||
| -rw-r--r-- | lib/pleroma/web/common_api/utils.ex | 14 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/mastodon_api_controller.ex | 1 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/views/status_view.ex | 19 | ||||
| -rw-r--r-- | lib/pleroma/web/twitter_api/views/activity_view.ex | 12 | ||||
| -rw-r--r-- | lib/pleroma/web/websub/websub.ex | 6 | ||||
| -rw-r--r-- | lib/pleroma/web/websub/websub_controller.ex | 7 | 
19 files changed, 129 insertions, 64 deletions
| diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex index d80ae6576..37737853a 100644 --- a/lib/pleroma/formatter.ex +++ b/lib/pleroma/formatter.ex @@ -120,7 +120,7 @@ defmodule Pleroma.Formatter do    end    @doc "Adds the links to mentioned users" -  def add_user_links({subs, text}, mentions) do +  def add_user_links({subs, text}, mentions, options \\ []) do      mentions =        mentions        |> Enum.sort_by(fn {name, _} -> -String.length(name) end) @@ -142,10 +142,16 @@ defmodule Pleroma.Formatter do                ap_id              end -          short_match = String.split(match, "@") |> tl() |> hd() +          nickname = +            if options[:format] == :full do +              User.full_nickname(match) +            else +              User.local_nickname(match) +            end            {uuid, -           "<span><a data-user='#{id}' class='mention' href='#{ap_id}'>@<span>#{short_match}</span></a></span>"} +           "<span class='h-card'><a data-user='#{id}' class='u-url mention' href='#{ap_id}'>" <> +             "@<span>#{nickname}</span></a></span>"}          end)      {subs, uuid_text} @@ -168,7 +174,7 @@ defmodule Pleroma.Formatter do        subs ++          Enum.map(tags, fn {tag_text, tag, uuid} ->            url = -            "<a data-tag='#{tag}' href='#{Pleroma.Web.base_url()}/tag/#{tag}' rel='tag'>#{ +            "<a class='hashtag' data-tag='#{tag}' href='#{Pleroma.Web.base_url()}/tag/#{tag}' rel='tag'>#{                tag_text              }</a>" diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex index 0c5b0f03f..f5c6e5033 100644 --- a/lib/pleroma/html.ex +++ b/lib/pleroma/html.ex @@ -78,14 +78,14 @@ defmodule Pleroma.HTML.Scrubber.TwitterText do    # links    Meta.allow_tag_with_uri_attributes("a", ["href", "data-user", "data-tag"], @valid_schemes) -  Meta.allow_tag_with_these_attributes("a", ["name", "title"]) +  Meta.allow_tag_with_these_attributes("a", ["name", "title", "class"])    # paragraphs and linebreaks    Meta.allow_tag_with_these_attributes("br", [])    Meta.allow_tag_with_these_attributes("p", [])    # microformats -  Meta.allow_tag_with_these_attributes("span", []) +  Meta.allow_tag_with_these_attributes("span", ["class"])    # allow inline images for custom emoji    @allow_inline_images Keyword.get(@markup, :allow_inline_images) @@ -119,7 +119,7 @@ defmodule Pleroma.HTML.Scrubber.Default do    Meta.strip_comments()    Meta.allow_tag_with_uri_attributes("a", ["href", "data-user", "data-tag"], @valid_schemes) -  Meta.allow_tag_with_these_attributes("a", ["name", "title"]) +  Meta.allow_tag_with_these_attributes("a", ["name", "title", "class"])    Meta.allow_tag_with_these_attributes("abbr", ["title"]) @@ -134,7 +134,7 @@ defmodule Pleroma.HTML.Scrubber.Default do    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("span", []) +  Meta.allow_tag_with_these_attributes("span", ["class"])    Meta.allow_tag_with_these_attributes("strong", [])    Meta.allow_tag_with_these_attributes("u", [])    Meta.allow_tag_with_these_attributes("ul", []) diff --git a/lib/pleroma/http/http.ex b/lib/pleroma/http/http.ex index b8103cef6..75c58e6c9 100644 --- a/lib/pleroma/http/http.ex +++ b/lib/pleroma/http/http.ex @@ -31,12 +31,15 @@ defmodule Pleroma.HTTP do        process_request_options(options)        |> process_sni_options(url) +    params = Keyword.get(options, :params, []) +      %{}      |> Builder.method(method)      |> Builder.headers(headers)      |> Builder.opts(options)      |> Builder.url(url)      |> Builder.add_param(:body, :body, body) +    |> Builder.add_param(:query, :query, params)      |> Enum.into([])      |> (&Tesla.request(Connection.new(), &1)).()    end diff --git a/lib/pleroma/http/request_builder.ex b/lib/pleroma/http/request_builder.ex index bffc7c6fe..5f2cff2c0 100644 --- a/lib/pleroma/http/request_builder.ex +++ b/lib/pleroma/http/request_builder.ex @@ -100,6 +100,8 @@ defmodule Pleroma.HTTP.RequestBuilder do    Map    """    @spec add_param(map(), atom, atom, any()) :: map() +  def add_param(request, :query, :query, values), do: Map.put(request, :query, values) +    def add_param(request, :body, :body, value), do: Map.put(request, :body, value)    def add_param(request, :body, key, value) do @@ -107,7 +109,10 @@ defmodule Pleroma.HTTP.RequestBuilder do      |> Map.put_new_lazy(:body, &Tesla.Multipart.new/0)      |> Map.update!(        :body, -      &Tesla.Multipart.add_field(&1, key, Poison.encode!(value), +      &Tesla.Multipart.add_field( +        &1, +        key, +        Jason.encode!(value),          headers: [{:"Content-Type", "application/json"}]        )      ) diff --git a/lib/pleroma/stats.ex b/lib/pleroma/stats.ex index 8a030ecd0..b3566ceb6 100644 --- a/lib/pleroma/stats.ex +++ b/lib/pleroma/stats.ex @@ -34,10 +34,11 @@ defmodule Pleroma.Stats do      peers =        from(          u in Pleroma.User, -        select: fragment("distinct ?->'host'", u.info), +        select: fragment("distinct split_part(?, '@', 2)", u.nickname),          where: u.local != ^true        )        |> Repo.all() +      |> Enum.filter(& &1)      domain_count = Enum.count(peers) @@ -45,7 +46,7 @@ defmodule Pleroma.Stats do        from(u in User.local_user_query(), select: fragment("sum((?->>'note_count')::int)", u.info))      status_count = Repo.one(status_query) -    user_count = Repo.aggregate(User.local_user_query(), :count, :id) +    user_count = Repo.aggregate(User.active_local_user_query(), :count, :id)      Agent.update(__MODULE__, fn _ ->        {peers, %{domain_count: domain_count, status_count: status_count, user_count: user_count}} diff --git a/lib/pleroma/upload.ex b/lib/pleroma/upload.ex index 0b1bdeec4..0a19e737b 100644 --- a/lib/pleroma/upload.ex +++ b/lib/pleroma/upload.ex @@ -34,8 +34,9 @@ defmodule Pleroma.Upload do    require Logger    @type source :: -          Plug.Upload.t() | data_uri_string :: -          String.t() | {:from_local, name :: String.t(), id :: String.t(), path :: String.t()} +          Plug.Upload.t() +          | (data_uri_string :: String.t()) +          | {:from_local, name :: String.t(), id :: String.t(), path :: String.t()}    @type option ::            {:type, :avatar | :banner | :background} @@ -215,6 +216,12 @@ defmodule Pleroma.Upload do    end    defp url_from_spec(base_url, {:file, path}) do +    path = +      path +      |> URI.encode() +      |> String.replace("?", "%3F") +      |> String.replace(":", "%3A") +      [base_url, "media", path]      |> Path.join()    end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 955808e28..06084b117 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -447,8 +447,7 @@ defmodule Pleroma.User do    def get_by_nickname(nickname) do      Repo.get_by(User, nickname: nickname) ||        if Regex.match?(~r(@#{Pleroma.Web.Endpoint.host()})i, nickname) do -        [local_nickname, _] = String.split(nickname, "@") -        Repo.get_by(User, nickname: local_nickname) +        Repo.get_by(User, nickname: local_nickname(nickname))        end    end @@ -891,7 +890,7 @@ defmodule Pleroma.User do      update_and_set_cache(cng)    end -  def local_user_query() do +  def local_user_query do      from(        u in User,        where: u.local == true, @@ -899,7 +898,14 @@ defmodule Pleroma.User do      )    end -  def moderator_user_query() do +  def active_local_user_query do +    from( +      u in local_user_query(), +      where: fragment("?->'deactivated' @> 'false'", u.info) +    ) +  end + +  def moderator_user_query do      from(        u in User,        where: u.local == true, @@ -1085,7 +1091,7 @@ defmodule Pleroma.User do        end)      bio -    |> CommonUtils.format_input(mentions, tags, "text/plain") +    |> CommonUtils.format_input(mentions, tags, "text/plain", user_links: [format: :full])      |> Formatter.emojify(emoji)    end @@ -1135,4 +1141,24 @@ defmodule Pleroma.User do        @strict_local_nickname_regex      end    end + +  def local_nickname(nickname_or_mention) do +    nickname_or_mention +    |> full_nickname() +    |> String.split("@") +    |> hd() +  end + +  def full_nickname(nickname_or_mention), +    do: String.trim_leading(nickname_or_mention, "@") + +  def error_user(ap_id) do +    %User{ +      name: ap_id, +      ap_id: ap_id, +      info: %User.Info{}, +      nickname: "erroruser@example.com", +      inserted_at: NaiveDateTime.utc_now() +    } +  end  end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 9c1eb377f..130c06028 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -224,10 +224,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do          %User{ap_id: _} = user,          %Object{data: %{"id" => _}} = object,          activity_id \\ nil, -        local \\ true +        local \\ true, +        public \\ true        ) do      with true <- is_public?(object), -         announce_data <- make_announce_data(user, object, activity_id), +         announce_data <- make_announce_data(user, object, activity_id, public),           {:ok, activity} <- insert(announce_data, local),           {:ok, object} <- add_announce_to_object(activity, object),           :ok <- maybe_federate(activity) do @@ -515,15 +516,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do    defp restrict_reblogs(query, _), do: query -  # Only search through last 100_000 activities by default -  defp restrict_recent(query, %{"whole_db" => true}), do: query - -  defp restrict_recent(query, _) do -    since = (Repo.aggregate(Activity, :max, :id) || 0) - 100_000 - -    from(activity in query, where: activity.id > ^since) -  end -    defp restrict_blocked(query, %{"blocking_user" => %User{info: info}}) do      blocks = info.blocks || []      domain_blocks = info.domain_blocks || [] @@ -574,7 +566,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do      |> restrict_actor(opts)      |> restrict_type(opts)      |> restrict_favorited_by(opts) -    |> restrict_recent(opts)      |> restrict_blocked(opts)      |> restrict_media(opts)      |> restrict_visibility(opts) @@ -806,13 +797,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do      end    end -  def is_public?(%Object{data: %{"type" => "Tombstone"}}) do -    false -  end +  def is_public?(%Object{data: %{"type" => "Tombstone"}}), do: false +  def is_public?(%Object{data: data}), do: is_public?(data) +  def is_public?(%Activity{data: data}), do: is_public?(data) -  def is_public?(activity) do -    "https://www.w3.org/ns/activitystreams#Public" in (activity.data["to"] ++ -                                                         (activity.data["cc"] || [])) +  def is_public?(data) do +    "https://www.w3.org/ns/activitystreams#Public" in (data["to"] ++ (data["cc"] || []))    end    def visible_for_user?(activity, nil) do diff --git a/lib/pleroma/web/activity_pub/relay.ex b/lib/pleroma/web/activity_pub/relay.ex index abddbc790..c0a52e349 100644 --- a/lib/pleroma/web/activity_pub/relay.ex +++ b/lib/pleroma/web/activity_pub/relay.ex @@ -40,7 +40,7 @@ defmodule Pleroma.Web.ActivityPub.Relay do    def publish(%Activity{data: %{"type" => "Create"}} = activity) do      with %User{} = user <- get_actor(),           %Object{} = object <- Object.normalize(activity.data["object"]["id"]) do -      ActivityPub.announce(user, object) +      ActivityPub.announce(user, object, nil, true, false)      else        e -> Logger.error("error: #{inspect(e)}")      end diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 86d11c874..fa3abe3d8 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -451,7 +451,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do      with actor <- get_actor(data),           %User{} = actor <- User.get_or_fetch_by_ap_id(actor),           {:ok, object} <- get_obj_helper(object_id) || fetch_obj_helper(object_id), -         {:ok, activity, _object} <- ActivityPub.announce(actor, object, id, false) do +         public <- ActivityPub.is_public?(data), +         {:ok, activity, _object} <- ActivityPub.announce(actor, object, id, false, public) do        {:ok, activity}      else        _e -> :error diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 6ecab773c..d2e457a68 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -386,9 +386,10 @@ defmodule Pleroma.Web.ActivityPub.Utils do    """    # for relayed messages, we only want to send to subscribers    def make_announce_data( -        %User{ap_id: ap_id, nickname: nil} = user, +        %User{ap_id: ap_id} = user,          %Object{data: %{"id" => id}} = object, -        activity_id +        activity_id, +        false        ) do      data = %{        "type" => "Announce", @@ -405,7 +406,8 @@ defmodule Pleroma.Web.ActivityPub.Utils do    def make_announce_data(          %User{ap_id: ap_id} = user,          %Object{data: %{"id" => id}} = object, -        activity_id +        activity_id, +        true        ) do      data = %{        "type" => "Announce", diff --git a/lib/pleroma/web/activity_pub/views/object_view.ex b/lib/pleroma/web/activity_pub/views/object_view.ex index 193042056..394d82fbc 100644 --- a/lib/pleroma/web/activity_pub/views/object_view.ex +++ b/lib/pleroma/web/activity_pub/views/object_view.ex @@ -46,7 +46,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectView do        "id" => "#{ap_id}/likes",        "type" => "OrderedCollection",        "totalItems" => length(likes), -      "first" => collection(likes, "#{ap_id}/followers", 1) +      "first" => collection(likes, "#{ap_id}/likes", 1)      }      |> Map.merge(Pleroma.Web.ActivityPub.Utils.make_json_ld_header())    end diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 2902905fd..504670439 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -103,7 +103,14 @@ defmodule Pleroma.Web.CommonAPI do               attachments,               tags,               get_content_type(data["content_type"]), -             Enum.member?([true, "true"], data["no_attachment_links"]) +             Enum.member?( +               [true, "true"], +               Map.get( +                 data, +                 "no_attachment_links", +                 Pleroma.Config.get([:instance, :no_attachment_links], false) +               ) +             )             ),           context <- make_context(inReplyTo),           cw <- data["spoiler_text"], diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 7e30d224c..a36ab5c15 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -116,16 +116,18 @@ defmodule Pleroma.Web.CommonAPI.Utils do      Enum.join([text | attachment_text], "<br>")    end +  def format_input(text, mentions, tags, format, options \\ []) +    @doc """    Formatting text to plain text.    """ -  def format_input(text, mentions, tags, "text/plain") do +  def format_input(text, mentions, tags, "text/plain", options) do      text      |> Formatter.html_escape("text/plain")      |> String.replace(~r/\r?\n/, "<br>")      |> (&{[], &1}).()      |> Formatter.add_links() -    |> Formatter.add_user_links(mentions) +    |> Formatter.add_user_links(mentions, options[:user_links] || [])      |> Formatter.add_hashtag_links(tags)      |> Formatter.finalize()    end @@ -133,24 +135,24 @@ defmodule Pleroma.Web.CommonAPI.Utils do    @doc """    Formatting text to html.    """ -  def format_input(text, mentions, _tags, "text/html") do +  def format_input(text, mentions, _tags, "text/html", options) do      text      |> Formatter.html_escape("text/html")      |> (&{[], &1}).() -    |> Formatter.add_user_links(mentions) +    |> Formatter.add_user_links(mentions, options[:user_links] || [])      |> Formatter.finalize()    end    @doc """    Formatting text to markdown.    """ -  def format_input(text, mentions, tags, "text/markdown") do +  def format_input(text, mentions, tags, "text/markdown", options) do      text      |> Formatter.mentions_escape(mentions)      |> Earmark.as_html!()      |> Formatter.html_escape("text/html")      |> (&{[], &1}).() -    |> Formatter.add_user_links(mentions) +    |> Formatter.add_user_links(mentions, options[:user_links] || [])      |> Formatter.add_hashtag_links(tags)      |> Formatter.finalize()    end diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index 54367f586..882d336be 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -341,7 +341,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do      params =        params        |> Map.put("in_reply_to_status_id", params["in_reply_to_id"]) -      |> Map.put("no_attachment_links", true)      idempotency_key =        case get_req_header(conn, "idempotency-key") do diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index db543ffe5..7f5a52ea3 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -32,6 +32,19 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do      end)    end +  defp get_user(ap_id) do +    cond do +      user = User.get_cached_by_ap_id(ap_id) -> +        user + +      user = User.get_by_guessed_nickname(ap_id) -> +        user + +      true -> +        User.error_user(ap_id) +    end +  end +    def render("index.json", opts) do      replied_to_activities = get_replied_to_activities(opts.activities) @@ -48,7 +61,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do          "status.json",          %{activity: %{data: %{"type" => "Announce", "object" => object}} = activity} = opts        ) do -    user = User.get_cached_by_ap_id(activity.data["actor"]) +    user = get_user(activity.data["actor"])      created_at = Utils.to_masto_date(activity.data["published"])      reblogged = Activity.get_create_activity_by_object_ap_id(object) @@ -93,7 +106,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do    end    def render("status.json", %{activity: %{data: %{"object" => object}} = activity} = opts) do -    user = User.get_cached_by_ap_id(activity.data["actor"]) +    user = get_user(activity.data["actor"])      like_count = object["like_count"] || 0      announcement_count = object["announcement_count"] || 0 @@ -116,7 +129,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do      created_at = Utils.to_masto_date(object["published"])      reply_to = get_reply_to(activity, opts) -    reply_to_user = reply_to && User.get_cached_by_ap_id(reply_to.data["actor"]) +    reply_to_user = reply_to && get_user(reply_to.data["actor"])      content =        object diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex index 108e7bfc5..03708d84c 100644 --- a/lib/pleroma/web/twitter_api/views/activity_view.ex +++ b/lib/pleroma/web/twitter_api/views/activity_view.ex @@ -101,20 +101,10 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do          user        true -> -        error_user(ap_id) +        User.error_user(ap_id)      end    end -  defp error_user(ap_id) do -    %User{ -      name: ap_id, -      ap_id: ap_id, -      info: %User.Info{}, -      nickname: "erroruser@example.com", -      inserted_at: NaiveDateTime.utc_now() -    } -  end -    def render("index.json", opts) do      context_ids = collect_context_ids(opts.activities)      users = collect_users(opts.activities) diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex index 3a287edd9..7ca62c83b 100644 --- a/lib/pleroma/web/websub/websub.ex +++ b/lib/pleroma/web/websub/websub.ex @@ -121,6 +121,12 @@ defmodule Pleroma.Web.Websub do      end    end +  def incoming_subscription_request(user, params) do +    Logger.info("Unhandled WebSub request for #{user.nickname}: #{inspect(params)}") + +    {:error, "Invalid WebSub request"} +  end +    defp get_subscription(topic, callback) do      Repo.get_by(WebsubServerSubscription, topic: topic, callback: callback) ||        %WebsubServerSubscription{} diff --git a/lib/pleroma/web/websub/websub_controller.ex b/lib/pleroma/web/websub/websub_controller.ex index 27304d988..e58f144e5 100644 --- a/lib/pleroma/web/websub/websub_controller.ex +++ b/lib/pleroma/web/websub/websub_controller.ex @@ -67,6 +67,13 @@ defmodule Pleroma.Web.Websub.WebsubController do      end    end +  def websub_subscription_confirmation(conn, params) do +    Logger.info("Invalid WebSub confirmation request: #{inspect(params)}") + +    conn +    |> send_resp(500, "Invalid parameters") +  end +    def websub_incoming(conn, %{"id" => id}) do      with "sha1=" <> signature <- hd(get_req_header(conn, "x-hub-signature")),           signature <- String.downcase(signature), | 
