logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma git clone https://anongit.hacktivis.me/git/pleroma.git/

parser.ex (2772B)


  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.Web.RichMedia.Parser do
  5. alias Pleroma.Web.RichMedia.Helpers
  6. require Logger
  7. @config_impl Application.compile_env(:pleroma, [__MODULE__, :config_impl], Pleroma.Config)
  8. defp parsers do
  9. Pleroma.Config.get([:rich_media, :parsers])
  10. end
  11. @type parse_errors :: {:error, :rich_media_disabled | :validate}
  12. @spec parse(String.t()) ::
  13. {:ok, map()} | parse_errors() | Helpers.get_errors()
  14. def parse(url) when is_binary(url) do
  15. with {_, true} <- {:config, @config_impl.get([:rich_media, :enabled])},
  16. {_, :ok} <- {:validate, validate_page_url(url)},
  17. {_, {:ok, data}} <- {:parse, parse_url(url)} do
  18. data = Map.put(data, "url", url)
  19. {:ok, data}
  20. else
  21. {:config, _} -> {:error, :rich_media_disabled}
  22. {:validate, _} -> {:error, :validate}
  23. {:parse, error} -> error
  24. end
  25. end
  26. defp parse_url(url) do
  27. with {:ok, body} <- Helpers.rich_media_get(url),
  28. {:ok, html} <- Floki.parse_document(body) do
  29. html
  30. |> maybe_parse()
  31. |> clean_parsed_data()
  32. |> check_parsed_data()
  33. end
  34. end
  35. defp maybe_parse(html) do
  36. Enum.reduce_while(parsers(), %{}, fn parser, acc ->
  37. case parser.parse(html, acc) do
  38. data when data != %{} -> {:halt, data}
  39. _ -> {:cont, acc}
  40. end
  41. end)
  42. end
  43. defp check_parsed_data(%{"title" => title} = data)
  44. when is_binary(title) and title != "" do
  45. {:ok, data}
  46. end
  47. defp check_parsed_data(_data) do
  48. {:error, :invalid_metadata}
  49. end
  50. defp clean_parsed_data(data) do
  51. data
  52. |> Enum.reject(fn {key, val} ->
  53. not match?({:ok, _}, Jason.encode(%{key => val}))
  54. end)
  55. |> Map.new()
  56. end
  57. @spec validate_page_url(URI.t() | binary()) :: :ok | :error
  58. defp validate_page_url(page_url) when is_binary(page_url) do
  59. validate_tld = @config_impl.get([Pleroma.Formatter, :validate_tld])
  60. page_url
  61. |> Linkify.Parser.url?(scheme: true, validate_tld: validate_tld)
  62. |> parse_uri(page_url)
  63. end
  64. defp validate_page_url(%URI{host: host, scheme: "https"}) do
  65. cond do
  66. Linkify.Parser.ip?(host) ->
  67. :error
  68. host in @config_impl.get([:rich_media, :ignore_hosts], []) ->
  69. :error
  70. get_tld(host) in @config_impl.get([:rich_media, :ignore_tld], []) ->
  71. :error
  72. true ->
  73. :ok
  74. end
  75. end
  76. defp validate_page_url(_), do: :error
  77. defp parse_uri(true, url) do
  78. url
  79. |> URI.parse()
  80. |> validate_page_url
  81. end
  82. defp parse_uri(_, _), do: :error
  83. defp get_tld(host) do
  84. host
  85. |> String.split(".")
  86. |> Enum.reverse()
  87. |> hd
  88. end
  89. end