logo

pleroma

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

parser.ex (2442B)


  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. require Logger
  6. @config_impl Application.compile_env(:pleroma, [__MODULE__, :config_impl], Pleroma.Config)
  7. defp parsers do
  8. Pleroma.Config.get([:rich_media, :parsers])
  9. end
  10. def parse(nil), do: nil
  11. @spec parse(String.t()) :: {:ok, map()} | {:error, any()}
  12. def parse(url) do
  13. with :ok <- validate_page_url(url),
  14. {:ok, data} <- parse_url(url) do
  15. data = Map.put(data, "url", url)
  16. {:ok, data}
  17. end
  18. end
  19. defp parse_url(url) do
  20. with {:ok, %Tesla.Env{body: html}} <- Pleroma.Web.RichMedia.Helpers.rich_media_get(url),
  21. {:ok, html} <- Floki.parse_document(html) do
  22. html
  23. |> maybe_parse()
  24. |> clean_parsed_data()
  25. |> check_parsed_data()
  26. end
  27. end
  28. defp maybe_parse(html) do
  29. Enum.reduce_while(parsers(), %{}, fn parser, acc ->
  30. case parser.parse(html, acc) do
  31. data when data != %{} -> {:halt, data}
  32. _ -> {:cont, acc}
  33. end
  34. end)
  35. end
  36. defp check_parsed_data(%{"title" => title} = data)
  37. when is_binary(title) and title != "" do
  38. {:ok, data}
  39. end
  40. defp check_parsed_data(data) do
  41. {:error, {:invalid_metadata, data}}
  42. end
  43. defp clean_parsed_data(data) do
  44. data
  45. |> Enum.reject(fn {key, val} ->
  46. not match?({:ok, _}, Jason.encode(%{key => val}))
  47. end)
  48. |> Map.new()
  49. end
  50. @spec validate_page_url(URI.t() | binary()) :: :ok | :error
  51. defp validate_page_url(page_url) when is_binary(page_url) do
  52. validate_tld = @config_impl.get([Pleroma.Formatter, :validate_tld])
  53. page_url
  54. |> Linkify.Parser.url?(scheme: true, validate_tld: validate_tld)
  55. |> parse_uri(page_url)
  56. end
  57. defp validate_page_url(%URI{host: host, scheme: "https"}) do
  58. cond do
  59. Linkify.Parser.ip?(host) ->
  60. :error
  61. host in @config_impl.get([:rich_media, :ignore_hosts], []) ->
  62. :error
  63. get_tld(host) in @config_impl.get([:rich_media, :ignore_tld], []) ->
  64. :error
  65. true ->
  66. :ok
  67. end
  68. end
  69. defp validate_page_url(_), do: :error
  70. defp parse_uri(true, url) do
  71. url
  72. |> URI.parse()
  73. |> validate_page_url
  74. end
  75. defp parse_uri(_, _), do: :error
  76. defp get_tld(host) do
  77. host
  78. |> String.split(".")
  79. |> Enum.reverse()
  80. |> hd
  81. end
  82. end