diff options
Diffstat (limited to 'lib')
38 files changed, 677 insertions, 458 deletions
| diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index f30fcd1e4..eedad7675 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -10,9 +10,9 @@ defmodule Pleroma.Application do      # Define workers and child supervisors to be supervised      children =        [ -        worker(Pleroma.Config, [Application.get_all_env(:pleroma)]),          # Start the Ecto repository          supervisor(Pleroma.Repo, []), +        worker(Pleroma.Emoji, []),          # Start the endpoint when the application starts          supervisor(Pleroma.Web.Endpoint, []),          # Start your own worker by calling: Pleroma.Worker.start_link(arg1, arg2, arg3) @@ -57,8 +57,8 @@ defmodule Pleroma.Application do            id: :cachex_idem          ),          worker(Pleroma.Web.Federator, []), -        worker(Pleroma.Gopher.Server, []), -        worker(Pleroma.Stats, []) +        worker(Pleroma.Stats, []), +        worker(Pleroma.Gopher.Server, [])        ] ++          if Mix.env() == :test,            do: [], diff --git a/lib/pleroma/config.ex b/lib/pleroma/config.ex index 510d8d498..15f771b6e 100644 --- a/lib/pleroma/config.ex +++ b/lib/pleroma/config.ex @@ -1,15 +1,42 @@  defmodule Pleroma.Config do -  use Agent +  defmodule Error do +    defexception [:message] +  end + +  def get(key), do: get(key, nil) + +  def get([key], default), do: get(key, default) + +  def get([parent_key | keys], default) do +    Application.get_env(:pleroma, parent_key) +    |> get_in(keys) || default +  end -  def start_link(initial) do -    Agent.start_link(fn -> initial end, name: __MODULE__) +  def get(key, default) do +    Application.get_env(:pleroma, key, default)    end -  def get(path) do -    Agent.get(__MODULE__, Kernel, :get_in, [path]) +  def get!(key) do +    value = get(key, nil) + +    if value == nil do +      raise(Error, message: "Missing configuration value: #{inspect(key)}") +    else +      value +    end +  end + +  def put([key], value), do: put(key, value) + +  def put([parent_key | keys], value) do +    parent = +      Application.get_env(:pleroma, parent_key) +      |> put_in(keys, value) + +    Application.put_env(:pleroma, parent_key, parent)    end -  def put(path, value) do -    Agent.update(__MODULE__, Kernel, :put_in, [path, value]) +  def put(key, value) do +    Application.put_env(:pleroma, key, value)    end  end diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex new file mode 100644 index 000000000..0a5e1d5ce --- /dev/null +++ b/lib/pleroma/emoji.ex @@ -0,0 +1,194 @@ +defmodule Pleroma.Emoji do +  @moduledoc """ +  The emojis are loaded from: + +    * the built-in Finmojis (if enabled in configuration), +    * the files: `config/emoji.txt` and `config/custom_emoji.txt` +    * glob paths + +  This GenServer stores in an ETS table the list of the loaded emojis, and also allows to reload the list at runtime. +  """ +  use GenServer +  @ets __MODULE__.Ets +  @ets_options [:set, :protected, :named_table, {:read_concurrency, true}] + +  @doc false +  def start_link() do +    GenServer.start_link(__MODULE__, [], name: __MODULE__) +  end + +  @doc "Reloads the emojis from disk." +  @spec reload() :: :ok +  def reload() do +    GenServer.call(__MODULE__, :reload) +  end + +  @doc "Returns the path of the emoji `name`." +  @spec get(String.t()) :: String.t() | nil +  def get(name) do +    case :ets.lookup(@ets, name) do +      [{_, path}] -> path +      _ -> nil +    end +  end + +  @doc "Returns all the emojos!!" +  @spec get_all() :: [{String.t(), String.t()}, ...] +  def get_all() do +    :ets.tab2list(@ets) +  end + +  @doc false +  def init(_) do +    @ets = :ets.new(@ets, @ets_options) +    GenServer.cast(self(), :reload) +    {:ok, nil} +  end + +  @doc false +  def handle_cast(:reload, state) do +    load() +    {:noreply, state} +  end + +  @doc false +  def handle_call(:reload, _from, state) do +    load() +    {:reply, :ok, state} +  end + +  @doc false +  def terminate(_, _) do +    :ok +  end + +  @doc false +  def code_change(_old_vsn, state, _extra) do +    load() +    {:ok, state} +  end + +  defp load() do +    emojis = +      (load_finmoji(Keyword.get(Application.get_env(:pleroma, :instance), :finmoji_enabled)) ++ +         load_from_file("config/emoji.txt") ++ +         load_from_file("config/custom_emoji.txt") ++ +         load_from_globs( +           Keyword.get(Application.get_env(:pleroma, :emoji, []), :shortcode_globs, []) +         )) +      |> Enum.reject(fn value -> value == nil end) + +    true = :ets.insert(@ets, emojis) +    :ok +  end + +  @finmoji [ +    "a_trusted_friend", +    "alandislands", +    "association", +    "auroraborealis", +    "baby_in_a_box", +    "bear", +    "black_gold", +    "christmasparty", +    "crosscountryskiing", +    "cupofcoffee", +    "education", +    "fashionista_finns", +    "finnishlove", +    "flag", +    "forest", +    "four_seasons_of_bbq", +    "girlpower", +    "handshake", +    "happiness", +    "headbanger", +    "icebreaker", +    "iceman", +    "joulutorttu", +    "kaamos", +    "kalsarikannit_f", +    "kalsarikannit_m", +    "karjalanpiirakka", +    "kicksled", +    "kokko", +    "lavatanssit", +    "losthopes_f", +    "losthopes_m", +    "mattinykanen", +    "meanwhileinfinland", +    "moominmamma", +    "nordicfamily", +    "out_of_office", +    "peacemaker", +    "perkele", +    "pesapallo", +    "polarbear", +    "pusa_hispida_saimensis", +    "reindeer", +    "sami", +    "sauna_f", +    "sauna_m", +    "sauna_whisk", +    "sisu", +    "stuck", +    "suomimainittu", +    "superfood", +    "swan", +    "the_cap", +    "the_conductor", +    "the_king", +    "the_voice", +    "theoriginalsanta", +    "tomoffinland", +    "torillatavataan", +    "unbreakable", +    "waiting", +    "white_nights", +    "woollysocks" +  ] +  defp load_finmoji(true) do +    Enum.map(@finmoji, fn finmoji -> +      {finmoji, "/finmoji/128px/#{finmoji}-128.png"} +    end) +  end + +  defp load_finmoji(_), do: [] + +  defp load_from_file(file) do +    if File.exists?(file) do +      load_from_file_stream(File.stream!(file)) +    else +      [] +    end +  end + +  defp load_from_file_stream(stream) do +    stream +    |> Stream.map(&String.strip/1) +    |> Stream.map(fn line -> +      case String.split(line, ~r/,\s*/) do +        [name, file] -> {name, file} +        _ -> nil +      end +    end) +    |> Enum.to_list() +  end + +  defp load_from_globs(globs) do +    static_path = Path.join(:code.priv_dir(:pleroma), "static") + +    paths = +      Enum.map(globs, fn glob -> +        Path.join(static_path, glob) +        |> Path.wildcard() +      end) +      |> Enum.concat() + +    Enum.map(paths, fn path -> +      shortcode = Path.basename(path, Path.extname(path)) +      external_path = Path.join("/", Path.relative_to(path, static_path)) +      {shortcode, external_path} +    end) +  end +end diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex index ecc102b62..26bb17377 100644 --- a/lib/pleroma/formatter.ex +++ b/lib/pleroma/formatter.ex @@ -2,6 +2,7 @@ defmodule Pleroma.Formatter do    alias Pleroma.User    alias Pleroma.Web.MediaProxy    alias Pleroma.HTML +  alias Pleroma.Emoji    @tag_regex ~r/\#\w+/u    def parse_tags(text, data \\ %{}) do @@ -28,125 +29,10 @@ defmodule Pleroma.Formatter do      |> Enum.filter(fn {_match, user} -> user end)    end -  @finmoji [ -    "a_trusted_friend", -    "alandislands", -    "association", -    "auroraborealis", -    "baby_in_a_box", -    "bear", -    "black_gold", -    "christmasparty", -    "crosscountryskiing", -    "cupofcoffee", -    "education", -    "fashionista_finns", -    "finnishlove", -    "flag", -    "forest", -    "four_seasons_of_bbq", -    "girlpower", -    "handshake", -    "happiness", -    "headbanger", -    "icebreaker", -    "iceman", -    "joulutorttu", -    "kaamos", -    "kalsarikannit_f", -    "kalsarikannit_m", -    "karjalanpiirakka", -    "kicksled", -    "kokko", -    "lavatanssit", -    "losthopes_f", -    "losthopes_m", -    "mattinykanen", -    "meanwhileinfinland", -    "moominmamma", -    "nordicfamily", -    "out_of_office", -    "peacemaker", -    "perkele", -    "pesapallo", -    "polarbear", -    "pusa_hispida_saimensis", -    "reindeer", -    "sami", -    "sauna_f", -    "sauna_m", -    "sauna_whisk", -    "sisu", -    "stuck", -    "suomimainittu", -    "superfood", -    "swan", -    "the_cap", -    "the_conductor", -    "the_king", -    "the_voice", -    "theoriginalsanta", -    "tomoffinland", -    "torillatavataan", -    "unbreakable", -    "waiting", -    "white_nights", -    "woollysocks" -  ] - -  @instance Application.get_env(:pleroma, :instance) - -  @finmoji_with_filenames (if Keyword.get(@instance, :finmoji_enabled) do -                             Enum.map(@finmoji, fn finmoji -> -                               {finmoji, "/finmoji/128px/#{finmoji}-128.png"} -                             end) -                           else -                             [] -                           end) - -  @emoji_from_file (with {:ok, default} <- File.read("config/emoji.txt") do -                      custom = -                        with {:ok, custom} <- File.read("config/custom_emoji.txt") do -                          custom -                        else -                          _e -> "" -                        end - -                      (default <> "\n" <> custom) -                      |> String.trim() -                      |> String.split(~r/\n+/) -                      |> Enum.map(fn line -> -                        [name, file] = String.split(line, ~r/,\s*/) -                        {name, file} -                      end) -                    else -                      _ -> [] -                    end) - -  @emoji_from_globs ( -                      static_path = Path.join(:code.priv_dir(:pleroma), "static") - -                      globs = -                        Application.get_env(:pleroma, :emoji, []) -                        |> Keyword.get(:shortcode_globs, []) - -                      paths = -                        Enum.map(globs, fn glob -> -                          Path.join(static_path, glob) -                          |> Path.wildcard() -                        end) -                        |> Enum.concat() - -                      Enum.map(paths, fn path -> -                        shortcode = Path.basename(path, Path.extname(path)) -                        external_path = Path.join("/", Path.relative_to(path, static_path)) -                        {shortcode, external_path} -                      end) -                    ) - -  @emoji @finmoji_with_filenames ++ @emoji_from_globs ++ @emoji_from_file +  def emojify(text) do +    emojify(text, Emoji.get_all()) +  end -  def emojify(text, emoji \\ @emoji)    def emojify(text, nil), do: text    def emojify(text, emoji) do @@ -166,15 +52,11 @@ defmodule Pleroma.Formatter do    end    def get_emoji(text) when is_binary(text) do -    Enum.filter(@emoji, fn {emoji, _} -> String.contains?(text, ":#{emoji}:") end) +    Enum.filter(Emoji.get_all(), fn {emoji, _} -> String.contains?(text, ":#{emoji}:") end)    end    def get_emoji(_), do: [] -  def get_custom_emoji() do -    @emoji -  end -    @link_regex ~r/[0-9a-z+\-\.]+:[0-9a-z$-_.+!*'(),]+/ui    @uri_schemes Application.get_env(:pleroma, :uri_schemes, []) diff --git a/lib/pleroma/gopher/server.ex b/lib/pleroma/gopher/server.ex index d34037f4f..e6361a82c 100644 --- a/lib/pleroma/gopher/server.ex +++ b/lib/pleroma/gopher/server.ex @@ -1,16 +1,16 @@  defmodule Pleroma.Gopher.Server do    use GenServer    require Logger -  @gopher Application.get_env(:pleroma, :gopher)    def start_link() do -    ip = Keyword.get(@gopher, :ip, {0, 0, 0, 0}) -    port = Keyword.get(@gopher, :port, 1234) +    config = Pleroma.Config.get(:gopher, []) +    ip = Keyword.get(config, :ip, {0, 0, 0, 0}) +    port = Keyword.get(config, :port, 1234)      GenServer.start_link(__MODULE__, [ip, port], [])    end    def init([ip, port]) do -    if Keyword.get(@gopher, :enabled, false) do +    if Pleroma.Config.get([:gopher, :enabled], false) do        Logger.info("Starting gopher server on #{port}")        :ranch.start_listener( @@ -37,9 +37,6 @@ defmodule Pleroma.Gopher.Server.ProtocolHandler do    alias Pleroma.Repo    alias Pleroma.HTML -  @instance Application.get_env(:pleroma, :instance) -  @gopher Application.get_env(:pleroma, :gopher) -    def start_link(ref, socket, transport, opts) do      pid = spawn_link(__MODULE__, :init, [ref, socket, transport, opts])      {:ok, pid} @@ -62,7 +59,7 @@ defmodule Pleroma.Gopher.Server.ProtocolHandler do    def link(name, selector, type \\ 1) do      address = Pleroma.Web.Endpoint.host() -    port = Keyword.get(@gopher, :port, 1234) +    port = Pleroma.Config.get([:gopher, :port], 1234)      "#{type}#{name}\t#{selector}\t#{address}\t#{port}\r\n"    end @@ -85,7 +82,7 @@ defmodule Pleroma.Gopher.Server.ProtocolHandler do    end    def response("") do -    info("Welcome to #{Keyword.get(@instance, :name, "Pleroma")}!") <> +    info("Welcome to #{Pleroma.Config.get([:instance, :name], "Pleroma")}!") <>        link("Public Timeline", "/main/public") <>        link("Federated Timeline", "/main/all") <> ".\r\n"    end diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex index 00b26963d..1b920d7fd 100644 --- a/lib/pleroma/html.ex +++ b/lib/pleroma/html.ex @@ -1,14 +1,12 @@  defmodule Pleroma.HTML do    alias HtmlSanitizeEx.Scrubber -  @markup Application.get_env(:pleroma, :markup) -    defp get_scrubbers(scrubber) when is_atom(scrubber), do: [scrubber]    defp get_scrubbers(scrubbers) when is_list(scrubbers), do: scrubbers    defp get_scrubbers(_), do: [Pleroma.HTML.Scrubber.Default]    def get_scrubbers() do -    Keyword.get(@markup, :scrub_policy) +    Pleroma.Config.get([:markup, :scrub_policy])      |> get_scrubbers    end diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index e0dcd9823..a3aeb1221 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -1,6 +1,6 @@  defmodule Pleroma.Notification do    use Ecto.Schema -  alias Pleroma.{User, Activity, Notification, Repo} +  alias Pleroma.{User, Activity, Notification, Repo, Object}    import Ecto.Query    schema "notifications" do @@ -42,6 +42,20 @@ defmodule Pleroma.Notification do      Repo.all(query)    end +  def set_read_up_to(%{id: user_id} = _user, id) do +    query = +      from( +        n in Notification, +        where: n.user_id == ^user_id, +        where: n.id <= ^id, +        update: [ +          set: [seen: true] +        ] +      ) + +    Repo.update_all(query, []) +  end +    def get(%{id: user_id} = _user, id) do      query =        from( @@ -81,7 +95,7 @@ defmodule Pleroma.Notification do    def create_notifications(%Activity{id: _, data: %{"to" => _, "type" => type}} = activity)        when type in ["Create", "Like", "Announce", "Follow"] do -    users = User.get_notified_from_activity(activity) +    users = get_notified_from_activity(activity)      notifications = Enum.map(users, fn user -> create_notification(activity, user) end)      {:ok, notifications} @@ -99,4 +113,64 @@ defmodule Pleroma.Notification do        notification      end    end + +  def get_notified_from_activity(activity, local_only \\ true) + +  def get_notified_from_activity( +        %Activity{data: %{"to" => _, "type" => type} = data} = activity, +        local_only +      ) +      when type in ["Create", "Like", "Announce", "Follow"] do +    recipients = +      [] +      |> maybe_notify_to_recipients(activity) +      |> maybe_notify_mentioned_recipients(activity) +      |> Enum.uniq() + +    User.get_users_from_set(recipients, local_only) +  end + +  def get_notified_from_activity(_, local_only), do: [] + +  defp maybe_notify_to_recipients( +         recipients, +         %Activity{data: %{"to" => to, "type" => type}} = activity +       ) do +    recipients ++ to +  end + +  defp maybe_notify_mentioned_recipients( +         recipients, +         %Activity{data: %{"to" => to, "type" => type} = data} = activity +       ) +       when type == "Create" do +    object = Object.normalize(data["object"]) + +    object_data = +      cond do +        !is_nil(object) -> +          object.data + +        is_map(data["object"]) -> +          data["object"] + +        true -> +          %{} +      end + +    tagged_mentions = maybe_extract_mentions(object_data) + +    recipients ++ tagged_mentions +  end + +  defp maybe_notify_mentioned_recipients(recipients, _), do: recipients + +  defp maybe_extract_mentions(%{"tag" => tag}) do +    tag +    |> Enum.filter(fn x -> is_map(x) end) +    |> Enum.filter(fn x -> x["type"] == "Mention" end) +    |> Enum.map(fn x -> x["href"] end) +  end + +  defp maybe_extract_mentions(_), do: []  end diff --git a/lib/pleroma/plugs/federating_plug.ex b/lib/pleroma/plugs/federating_plug.ex new file mode 100644 index 000000000..4108d90af --- /dev/null +++ b/lib/pleroma/plugs/federating_plug.ex @@ -0,0 +1,18 @@ +defmodule Pleroma.Web.FederatingPlug do +  import Plug.Conn + +  def init(options) do +    options +  end + +  def call(conn, opts) do +    if Keyword.get(Application.get_env(:pleroma, :instance), :federating) do +      conn +    else +      conn +      |> put_status(404) +      |> Phoenix.Controller.render(Pleroma.Web.ErrorView, "404.json") +      |> halt() +    end +  end +end diff --git a/lib/pleroma/upload.ex b/lib/pleroma/upload.ex index 2293ff54e..89aa779f9 100644 --- a/lib/pleroma/upload.ex +++ b/lib/pleroma/upload.ex @@ -1,9 +1,6 @@  defmodule Pleroma.Upload do    alias Ecto.UUID -  @storage_backend Application.get_env(:pleroma, Pleroma.Upload) -                   |> Keyword.fetch!(:uploader) -    def check_file_size(path, nil), do: true    def check_file_size(path, size_limit) do @@ -21,8 +18,7 @@ defmodule Pleroma.Upload do           true <- check_file_size(file.path, size_limit) do        strip_exif_data(content_type, file.path) -      {:ok, url_path} = -        @storage_backend.put_file(name, uuid, file.path, content_type, should_dedupe) +      {:ok, url_path} = uploader().put_file(name, uuid, file.path, content_type, should_dedupe)        %{          "type" => "Document", @@ -57,8 +53,7 @@ defmodule Pleroma.Upload do            content_type          ) -      {:ok, url_path} = -        @storage_backend.put_file(name, uuid, tmp_path, content_type, should_dedupe) +      {:ok, url_path} = uploader().put_file(name, uuid, tmp_path, content_type, should_dedupe)        %{          "type" => "Image", @@ -182,4 +177,8 @@ defmodule Pleroma.Upload do        _e -> "application/octet-stream"      end    end + +  defp uploader() do +    Pleroma.Config.get!([Pleroma.Upload, :uploader]) +  end  end diff --git a/lib/pleroma/uploaders/swift/keystone.ex b/lib/pleroma/uploaders/swift/keystone.ex index a79214319..e578b3c61 100644 --- a/lib/pleroma/uploaders/swift/keystone.ex +++ b/lib/pleroma/uploaders/swift/keystone.ex @@ -1,11 +1,9 @@  defmodule Pleroma.Uploaders.Swift.Keystone do    use HTTPoison.Base -  @settings Application.get_env(:pleroma, Pleroma.Uploaders.Swift) -    def process_url(url) do      Enum.join( -      [Keyword.fetch!(@settings, :auth_url), url], +      [Pleroma.Config.get!([Pleroma.Uploaders.Swift, :auth_url]), url],        "/"      )    end @@ -16,9 +14,10 @@ defmodule Pleroma.Uploaders.Swift.Keystone do    end    def get_token() do -    username = Keyword.fetch!(@settings, :username) -    password = Keyword.fetch!(@settings, :password) -    tenant_id = Keyword.fetch!(@settings, :tenant_id) +    settings = Pleroma.Config.get(Pleroma.Uploaders.Swift) +    username = Keyword.fetch!(settings, :username) +    password = Keyword.fetch!(settings, :password) +    tenant_id = Keyword.fetch!(settings, :tenant_id)      case post(             "/tokens", diff --git a/lib/pleroma/uploaders/swift/swift.ex b/lib/pleroma/uploaders/swift/swift.ex index 819dfebda..fa08ca966 100644 --- a/lib/pleroma/uploaders/swift/swift.ex +++ b/lib/pleroma/uploaders/swift/swift.ex @@ -1,17 +1,15 @@  defmodule Pleroma.Uploaders.Swift.Client do    use HTTPoison.Base -  @settings Application.get_env(:pleroma, Pleroma.Uploaders.Swift) -    def process_url(url) do      Enum.join( -      [Keyword.fetch!(@settings, :storage_url), url], +      [Pleroma.Config.get!([Pleroma.Uploaders.Swift, :storage_url]), url],        "/"      )    end    def upload_file(filename, body, content_type) do -    object_url = Keyword.fetch!(@settings, :object_url) +    object_url = Pleroma.Config.get!([Pleroma.Uploaders.Swift, :object_url])      token = Pleroma.Uploaders.Swift.Keystone.get_token()      case put("#{filename}", body, "X-Auth-Token": token, "Content-Type": content_type) do diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index b2f59ab6b..be634a8e1 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -464,36 +464,25 @@ defmodule Pleroma.User do      update_and_set_cache(cs)    end -  def get_notified_from_activity_query(to) do +  def get_users_from_set_query(ap_ids, false) do      from(        u in User, -      where: u.ap_id in ^to, -      where: u.local == true +      where: u.ap_id in ^ap_ids      )    end -  def get_notified_from_activity(%Activity{recipients: to, data: %{"type" => "Announce"} = data}) do -    object = Object.normalize(data["object"]) -    actor = User.get_cached_by_ap_id(data["actor"]) - -    # ensure that the actor who published the announced object appears only once -    to = -      if actor.nickname != nil do -        to ++ [object.data["actor"]] -      else -        to -      end -      |> Enum.uniq() - -    query = get_notified_from_activity_query(to) +  def get_users_from_set_query(ap_ids, true) do +    query = get_users_from_set_query(ap_ids, false) -    Repo.all(query) +    from( +      u in query, +      where: u.local == true +    )    end -  def get_notified_from_activity(%Activity{recipients: to}) do -    query = get_notified_from_activity_query(to) - -    Repo.all(query) +  def get_users_from_set(ap_ids, local_only \\ true) do +    get_users_from_set_query(ap_ids, local_only) +    |> Repo.all()    end    def get_recipients_from_activity(%Activity{recipients: to}) do diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 32c14995f..c6733e487 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -10,8 +10,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do    @httpoison Application.get_env(:pleroma, :httpoison) -  @instance Application.get_env(:pleroma, :instance) -    # For Announce activities, we filter the recipients based on following status for any actors    # that match actual users.  See issue #164 for more information about why this is necessary.    defp get_recipients(%{"type" => "Announce"} = data) do @@ -659,14 +657,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do      end    end -  @quarantined_instances Keyword.get(@instance, :quarantined_instances, []) -    def should_federate?(inbox, public) do      if public do        true      else        inbox_info = URI.parse(inbox) -      inbox_info.host not in @quarantined_instances +      !Enum.member?(Pleroma.Config.get([:instance, :quarantined_instances], []), inbox_info.host)      end    end diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index 531e98237..3570a75cb 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -6,16 +6,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do    alias Pleroma.Web.ActivityPub.Relay    alias Pleroma.Web.ActivityPub.Utils    alias Pleroma.Web.Federator -  alias Pleroma.Config    require Logger    action_fallback(:errors) +  plug(Pleroma.Web.FederatingPlug when action in [:inbox, :relay])    plug(:relay_active? when action in [:relay])    def relay_active?(conn, _) do -    if Config.get([:instance, :allow_relay]) do +    if Keyword.get(Application.get_env(:pleroma, :instance), :allow_relay) do        conn      else        conn diff --git a/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex b/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex index b4f91f3cc..c53cb1ad2 100644 --- a/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex +++ b/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex @@ -3,10 +3,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.NormalizeMarkup do    @behaviour Pleroma.Web.ActivityPub.MRF -  @mrf_normalize_markup Application.get_env(:pleroma, :mrf_normalize_markup) -    def filter(%{"type" => activity_type} = object) when activity_type == "Create" do -    scrub_policy = Keyword.get(@mrf_normalize_markup, :scrub_policy) +    scrub_policy = Pleroma.Config.get([:mrf_normalize_markup, :scrub_policy])      child = object["object"] diff --git a/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex b/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex index 129d04617..627284083 100644 --- a/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex +++ b/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex @@ -2,10 +2,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublic do    alias Pleroma.User    @behaviour Pleroma.Web.ActivityPub.MRF -  @mrf_rejectnonpublic Application.get_env(:pleroma, :mrf_rejectnonpublic) -  @allow_followersonly Keyword.get(@mrf_rejectnonpublic, :allow_followersonly) -  @allow_direct Keyword.get(@mrf_rejectnonpublic, :allow_direct) -    @impl true    def filter(%{"type" => "Create"} = object) do      user = User.get_cached_by_ap_id(object["actor"]) @@ -20,6 +16,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublic do          true -> "direct"        end +    policy = Pleroma.Config.get(:mrf_rejectnonpublic) +      case visibility do        "public" ->          {:ok, object} @@ -28,14 +26,14 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublic do          {:ok, object}        "followers" -> -        with true <- @allow_followersonly do +        with true <- Keyword.get(policy, :allow_followersonly) do            {:ok, object}          else            _e -> {:reject, nil}          end        "direct" -> -        with true <- @allow_direct do +        with true <- Keyword.get(policy, :allow_direct) do            {:ok, object}          else            _e -> {:reject, nil} diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex index 319721d48..86dcf5080 100644 --- a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex @@ -2,60 +2,76 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do    alias Pleroma.User    @behaviour Pleroma.Web.ActivityPub.MRF -  @mrf_policy Application.get_env(:pleroma, :mrf_simple) - -  @accept Keyword.get(@mrf_policy, :accept) -  defp check_accept(%{host: actor_host} = actor_info, object) -       when length(@accept) > 0 and not (actor_host in @accept) do -    {:reject, nil} +  defp check_accept(%{host: actor_host} = _actor_info, object) do +    accepts = Pleroma.Config.get([:mrf_simple, :accept]) + +    cond do +      accepts == [] -> {:ok, object} +      actor_host == Pleroma.Config.get([Pleroma.Web.Endpoint, :url, :host]) -> {:ok, object} +      Enum.member?(accepts, actor_host) -> {:ok, object} +      true -> {:reject, nil} +    end    end -  defp check_accept(actor_info, object), do: {:ok, object} - -  @reject Keyword.get(@mrf_policy, :reject) -  defp check_reject(%{host: actor_host} = actor_info, object) when actor_host in @reject do -    {:reject, nil} +  defp check_reject(%{host: actor_host} = _actor_info, object) do +    if Enum.member?(Pleroma.Config.get([:mrf_simple, :reject]), actor_host) do +      {:reject, nil} +    else +      {:ok, object} +    end    end -  defp check_reject(actor_info, object), do: {:ok, object} +  defp check_media_removal( +         %{host: actor_host} = _actor_info, +         %{"type" => "Create", "object" => %{"attachement" => child_attachment}} = object +       ) +       when length(child_attachment) > 0 do +    object = +      if Enum.member?(Pleroma.Config.get([:mrf_simple, :media_removal]), actor_host) do +        child_object = Map.delete(object["object"], "attachment") +        Map.put(object, "object", child_object) +      else +        object +      end -  @media_removal Keyword.get(@mrf_policy, :media_removal) -  defp check_media_removal(%{host: actor_host} = actor_info, %{"type" => "Create"} = object) -       when actor_host in @media_removal do -    child_object = Map.delete(object["object"], "attachment") -    object = Map.put(object, "object", child_object)      {:ok, object}    end -  defp check_media_removal(actor_info, object), do: {:ok, object} +  defp check_media_removal(_actor_info, object), do: {:ok, object} -  @media_nsfw Keyword.get(@mrf_policy, :media_nsfw)    defp check_media_nsfw( -         %{host: actor_host} = actor_info, +         %{host: actor_host} = _actor_info,           %{             "type" => "Create",             "object" => %{"attachment" => child_attachment} = child_object           } = object         ) -       when actor_host in @media_nsfw and length(child_attachment) > 0 do -    tags = (child_object["tag"] || []) ++ ["nsfw"] -    child_object = Map.put(child_object, "tags", tags) -    child_object = Map.put(child_object, "sensitive", true) -    object = Map.put(object, "object", child_object) +       when length(child_attachment) > 0 do +    object = +      if Enum.member?(Pleroma.Config.get([:mrf_simple, :media_nsfw]), actor_host) do +        tags = (child_object["tag"] || []) ++ ["nsfw"] +        child_object = Map.put(child_object, "tags", tags) +        child_object = Map.put(child_object, "sensitive", true) +        Map.put(object, "object", child_object) +      else +        object +      end +      {:ok, object}    end -  defp check_media_nsfw(actor_info, object), do: {:ok, object} - -  @ftl_removal Keyword.get(@mrf_policy, :federated_timeline_removal) -  defp check_ftl_removal(%{host: actor_host} = actor_info, object) -       when actor_host in @ftl_removal do -    user = User.get_by_ap_id(object["actor"]) +  defp check_media_nsfw(_actor_info, object), do: {:ok, object} -    # flip to/cc relationship to make the post unlisted +  defp check_ftl_removal(%{host: actor_host} = _actor_info, object) do      object = -      if "https://www.w3.org/ns/activitystreams#Public" in object["to"] and -           user.follower_address in object["cc"] do +      with true <- +             Enum.member?( +               Pleroma.Config.get([:mrf_simple, :federated_timeline_removal]), +               actor_host +             ), +           user <- User.get_cached_by_ap_id(object["actor"]), +           true <- "https://www.w3.org/ns/activitystreams#Public" in object["to"], +           true <- user.follower_address in object["cc"] do          to =            List.delete(object["to"], "https://www.w3.org/ns/activitystreams#Public") ++              [user.follower_address] @@ -68,14 +84,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do          |> Map.put("to", to)          |> Map.put("cc", cc)        else -        object +        _ -> object        end      {:ok, object}    end -  defp check_ftl_removal(actor_info, object), do: {:ok, object} -    @impl true    def filter(object) do      actor_info = URI.parse(object["actor"]) diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 56918342c..6a0fdb433 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -263,7 +263,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do    # - tags    # - emoji    def handle_incoming(%{"type" => "Create", "object" => %{"type" => objtype} = object} = data) -      when objtype in ["Article", "Note", "Video"] do +      when objtype in ["Article", "Note", "Video", "Page"] do      actor = get_actor(data)      data = @@ -506,9 +506,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do      end    end -  @ap_config Application.get_env(:pleroma, :activitypub) -  @accept_blocks Keyword.get(@ap_config, :accept_blocks) -    def handle_incoming(          %{            "type" => "Undo", @@ -517,7 +514,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do            "id" => id          } = _data        ) do -    with true <- @accept_blocks, +    with true <- Pleroma.Config.get([:activitypub, :accept_blocks]),           %User{local: true} = blocked <- User.get_cached_by_ap_id(blocked),           %User{} = blocker <- User.get_or_fetch_by_ap_id(blocker),           {:ok, activity} <- ActivityPub.unblock(blocker, blocked, id, false) do @@ -531,7 +528,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do    def handle_incoming(          %{"type" => "Block", "object" => blocked, "actor" => blocker, "id" => id} = data        ) do -    with true <- @accept_blocks, +    with true <- Pleroma.Config.get([:activitypub, :accept_blocks]),           %User{local: true} = blocked = User.get_cached_by_ap_id(blocked),           %User{} = blocker = User.get_or_fetch_by_ap_id(blocker),           {:ok, activity} <- ActivityPub.block(blocker, blocked, id, false) do @@ -607,7 +604,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do      data =        data        |> Map.put("object", object) -      |> Map.put("@context", "https://www.w3.org/ns/activitystreams") +      |> Map.merge(Utils.make_json_ld_header())      {:ok, data}    end @@ -626,7 +623,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do        data =          data          |> Map.put("object", object) -        |> Map.put("@context", "https://www.w3.org/ns/activitystreams") +        |> Map.merge(Utils.make_json_ld_header())        {:ok, data}      end @@ -644,7 +641,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do        data =          data          |> Map.put("object", object) -        |> Map.put("@context", "https://www.w3.org/ns/activitystreams") +        |> Map.merge(Utils.make_json_ld_header())        {:ok, data}      end @@ -654,7 +651,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do      data =        data        |> maybe_fix_object_url -      |> Map.put("@context", "https://www.w3.org/ns/activitystreams") +      |> Map.merge(Utils.make_json_ld_header())      {:ok, data}    end @@ -696,12 +693,9 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do    end    def add_mention_tags(object) do -    recipients = object["to"] ++ (object["cc"] || []) -      mentions = -      recipients -      |> Enum.map(fn ap_id -> User.get_cached_by_ap_id(ap_id) end) -      |> Enum.filter(& &1) +      object +      |> Utils.get_notified_from_object()        |> Enum.map(fn user ->          %{"type" => "Mention", "href" => user.ap_id, "name" => "@#{user.nickname}"}        end) diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index d6ac2dd8c..fac91830a 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -1,11 +1,13 @@  defmodule Pleroma.Web.ActivityPub.Utils do -  alias Pleroma.{Repo, Web, Object, Activity, User} +  alias Pleroma.{Repo, Web, Object, Activity, User, Notification}    alias Pleroma.Web.Router.Helpers    alias Pleroma.Web.Endpoint    alias Ecto.{Changeset, UUID}    import Ecto.Query    require Logger +  @supported_object_types ["Article", "Note", "Video", "Page"] +    # 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_ap_id(object) do @@ -70,18 +72,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do      %{        "@context" => [          "https://www.w3.org/ns/activitystreams", -        "https://w3id.org/security/v1", -        %{ -          "manuallyApprovesFollowers" => "as:manuallyApprovesFollowers", -          "sensitive" => "as:sensitive", -          "Hashtag" => "as:Hashtag", -          "ostatus" => "http://ostatus.org#", -          "atomUri" => "ostatus:atomUri", -          "inReplyToAtomUri" => "ostatus:inReplyToAtomUri", -          "conversation" => "ostatus:conversation", -          "toot" => "http://joinmastodon.org/ns#", -          "Emoji" => "toot:Emoji" -        } +        "https://litepub.github.io/litepub/context.jsonld"        ]      }    end @@ -106,6 +97,21 @@ defmodule Pleroma.Web.ActivityPub.Utils do      "#{Web.base_url()}/#{type}/#{UUID.generate()}"    end +  def get_notified_from_object(%{"type" => type} = object) when type in @supported_object_types do +    fake_create_activity = %{ +      "to" => object["to"], +      "cc" => object["cc"], +      "type" => "Create", +      "object" => object +    } + +    Notification.get_notified_from_activity(%Activity{data: fake_create_activity}, false) +  end + +  def get_notified_from_object(object) do +    Notification.get_notified_from_activity(%Activity{data: object}, false) +  end +    def create_context(context) do      context = context || generate_id("contexts")      changeset = Object.context_mapping(context) @@ -175,7 +181,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do    Inserts a full object if it is contained in an activity.    """    def insert_full_object(%{"object" => %{"type" => type} = object_data}) -      when is_map(object_data) and type in ["Article", "Note", "Video"] do +      when is_map(object_data) and type in @supported_object_types do      with {:ok, _} <- Object.create(object_data) do        :ok      end diff --git a/lib/pleroma/web/activity_pub/views/object_view.ex b/lib/pleroma/web/activity_pub/views/object_view.ex index cc0b0556b..df734a871 100644 --- a/lib/pleroma/web/activity_pub/views/object_view.ex +++ b/lib/pleroma/web/activity_pub/views/object_view.ex @@ -3,23 +3,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectView do    alias Pleroma.Web.ActivityPub.Transmogrifier    def render("object.json", %{object: object}) do -    base = %{ -      "@context" => [ -        "https://www.w3.org/ns/activitystreams", -        "https://w3id.org/security/v1", -        %{ -          "manuallyApprovesFollowers" => "as:manuallyApprovesFollowers", -          "sensitive" => "as:sensitive", -          "Hashtag" => "as:Hashtag", -          "ostatus" => "http://ostatus.org#", -          "atomUri" => "ostatus:atomUri", -          "inReplyToAtomUri" => "ostatus:inReplyToAtomUri", -          "conversation" => "ostatus:conversation", -          "toot" => "http://joinmastodon.org/ns#", -          "Emoji" => "toot:Emoji" -        } -      ] -    } +    base = Pleroma.Web.ActivityPub.Utils.make_json_ld_header()      additional = Transmogrifier.prepare_object(object.data)      Map.merge(base, additional) diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 16419e1b7..eb335813d 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -17,7 +17,6 @@ defmodule Pleroma.Web.ActivityPub.UserView do      public_key = :public_key.pem_encode([public_key])      %{ -      "@context" => "https://www.w3.org/ns/activitystreams",        "id" => user.ap_id,        "type" => "Application",        "following" => "#{user.ap_id}/following", @@ -36,6 +35,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do          "sharedInbox" => "#{Pleroma.Web.Endpoint.url()}/inbox"        }      } +    |> Map.merge(Utils.make_json_ld_header())    end    def render("user.json", %{user: user}) do diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 8f47bb127..77e4dbbd7 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -70,15 +70,17 @@ defmodule Pleroma.Web.CommonAPI do    def get_visibility(_), do: "public" -  @instance Application.get_env(:pleroma, :instance) -  @allowed_post_formats Keyword.get(@instance, :allowed_post_formats) - -  defp get_content_type(content_type) when content_type in @allowed_post_formats, do: content_type -  defp get_content_type(_), do: "text/plain" +  defp get_content_type(content_type) do +    if Enum.member?(Pleroma.Config.get([:instance, :allowed_post_formats]), content_type) do +      content_type +    else +      "text/plain" +    end +  end -  @limit Keyword.get(@instance, :limit)    def post(user, %{"status" => status} = data) do      visibility = get_visibility(data) +    limit = Pleroma.Config.get([:instance, :limit])      with status <- String.trim(status),           attachments <- attachments_from_ids(data["media_ids"]), @@ -98,7 +100,7 @@ defmodule Pleroma.Web.CommonAPI do           context <- make_context(inReplyTo),           cw <- data["spoiler_text"],           full_payload <- String.trim(status <> (data["spoiler_text"] || "")), -         length when length in 1..@limit <- String.length(full_payload), +         length when length in 1..limit <- String.length(full_payload),           object <-             make_note_data(               user.ap_id, diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex index 2a5a2cc15..728f24c7e 100644 --- a/lib/pleroma/web/common_api/utils.ex +++ b/lib/pleroma/web/common_api/utils.ex @@ -19,6 +19,8 @@ defmodule Pleroma.Web.CommonAPI.Utils do        end    end +  def get_replied_to_activity(""), do: nil +    def get_replied_to_activity(id) when not is_nil(id) do      Repo.get(Activity, id)    end @@ -32,21 +34,29 @@ defmodule Pleroma.Web.CommonAPI.Utils do    end    def to_for_user_and_mentions(user, mentions, inReplyTo, "public") do -    to = ["https://www.w3.org/ns/activitystreams#Public"] -      mentioned_users = Enum.map(mentions, fn {_, %{ap_id: ap_id}} -> ap_id end) -    cc = [user.follower_address | mentioned_users] + +    to = ["https://www.w3.org/ns/activitystreams#Public" | mentioned_users] +    cc = [user.follower_address]      if inReplyTo do -      {to, Enum.uniq([inReplyTo.data["actor"] | cc])} +      {Enum.uniq([inReplyTo.data["actor"] | to]), cc}      else        {to, cc}      end    end    def to_for_user_and_mentions(user, mentions, inReplyTo, "unlisted") do -    {to, cc} = to_for_user_and_mentions(user, mentions, inReplyTo, "public") -    {cc, to} +    mentioned_users = Enum.map(mentions, fn {_, %{ap_id: ap_id}} -> ap_id end) + +    to = [user.follower_address | mentioned_users] +    cc = ["https://www.w3.org/ns/activitystreams#Public"] + +    if inReplyTo do +      {Enum.uniq([inReplyTo.data["actor"] | to]), cc} +    else +      {to, cc} +    end    end    def to_for_user_and_mentions(user, mentions, inReplyTo, "private") do diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex index 955bd61f3..6673ab576 100644 --- a/lib/pleroma/web/endpoint.ex +++ b/lib/pleroma/web/endpoint.ex @@ -56,6 +56,7 @@ defmodule Pleroma.Web.Endpoint do      extra: "SameSite=Strict"    ) +  plug(CORSPlug)    plug(Pleroma.Web.Router)    @doc """ diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex index 9ea2507a1..6071d08e4 100644 --- a/lib/pleroma/web/federator/federator.ex +++ b/lib/pleroma/web/federator/federator.ex @@ -7,14 +7,11 @@ defmodule Pleroma.Web.Federator do    alias Pleroma.Web.ActivityPub.Relay    alias Pleroma.Web.ActivityPub.Transmogrifier    alias Pleroma.Web.ActivityPub.Utils -  alias Pleroma.Config    require Logger    @websub Application.get_env(:pleroma, :websub)    @ostatus Application.get_env(:pleroma, :ostatus)    @httpoison Application.get_env(:pleroma, :httpoison) -  @instance Application.get_env(:pleroma, :instance) -  @federating Keyword.get(@instance, :federating)    @max_jobs 20    def init(args) do @@ -72,7 +69,7 @@ defmodule Pleroma.Web.Federator do          Logger.info(fn -> "Sending #{activity.data["id"]} out via Salmon" end)          Pleroma.Web.Salmon.publish(actor, activity) -        if Config.get([:instance, :allow_relay]) do +        if Keyword.get(Application.get_env(:pleroma, :instance), :allow_relay) do            Logger.info(fn -> "Relaying #{activity.data["id"]} out" end)            Relay.publish(activity)          end @@ -148,7 +145,7 @@ defmodule Pleroma.Web.Federator do    end    def enqueue(type, payload, priority \\ 1) do -    if @federating do +    if Pleroma.Config.get([:instance, :federating]) do        if Mix.env() == :test do          handle(type, payload)        else diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index e03027be7..83728c81e 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -132,22 +132,23 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do      end    end -  @instance Application.get_env(:pleroma, :instance)    @mastodon_api_level "2.5.0"    def masto_instance(conn, _params) do +    instance = Pleroma.Config.get(:instance) +      response = %{        uri: Web.base_url(), -      title: Keyword.get(@instance, :name), -      description: Keyword.get(@instance, :description), -      version: "#{@mastodon_api_level} (compatible; #{Keyword.get(@instance, :version)})", -      email: Keyword.get(@instance, :email), +      title: Keyword.get(instance, :name), +      description: Keyword.get(instance, :description), +      version: "#{@mastodon_api_level} (compatible; #{Keyword.get(instance, :version)})", +      email: Keyword.get(instance, :email),        urls: %{          streaming_api: String.replace(Pleroma.Web.Endpoint.static_url(), "http", "ws")        },        stats: Stats.get_stats(),        thumbnail: Web.base_url() <> "/instance/thumbnail.jpeg", -      max_toot_chars: Keyword.get(@instance, :limit) +      max_toot_chars: Keyword.get(instance, :limit)      }      json(conn, response) @@ -158,7 +159,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do    end    defp mastodonized_emoji do -    Pleroma.Formatter.get_custom_emoji() +    Pleroma.Emoji.get_all()      |> Enum.map(fn {shortcode, relative_url} ->        url = to_string(URI.merge(Web.base_url(), relative_url)) @@ -443,6 +444,12 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do      render(conn, AccountView, "relationships.json", %{user: user, targets: targets})    end +  # Instead of returning a 400 when no "id" params is present, Mastodon returns an empty array. +  def relationships(%{assigns: %{user: user}} = conn, _) do +    conn +    |> json([]) +  end +    def update_media(%{assigns: %{user: _}} = conn, data) do      with %Object{} = object <- Repo.get(Object, data["id"]),           true <- is_binary(data["description"]), @@ -508,6 +515,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do        |> Map.put("type", "Create")        |> Map.put("local_only", local_only)        |> Map.put("blocking_user", user) +      |> Map.put("tag", String.downcase(params["tag"]))      activities =        ActivityPub.fetch_public_activities(params) @@ -580,15 +588,16 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do      end    end -  @activitypub Application.get_env(:pleroma, :activitypub) -  @follow_handshake_timeout Keyword.get(@activitypub, :follow_handshake_timeout) -    def follow(%{assigns: %{user: follower}} = conn, %{"id" => id}) do      with %User{} = followed <- Repo.get(User, id),           {:ok, follower} <- User.maybe_direct_follow(follower, followed),           {:ok, _activity} <- ActivityPub.follow(follower, followed),           {:ok, follower, followed} <- -           User.wait_and_refresh(@follow_handshake_timeout, follower, followed) do +           User.wait_and_refresh( +             Pleroma.Config.get([:activitypub, :follow_handshake_timeout]), +             follower, +             followed +           ) do        render(conn, AccountView, "relationship.json", %{user: follower, target: followed})      else        {:error, message} -> @@ -879,6 +888,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do      if user && token do        mastodon_emoji = mastodonized_emoji() +      limit = Pleroma.Config.get([:instance, :limit]) +        accounts =          Map.put(%{}, user.id, AccountView.render("account.json", %{user: user, for: user})) @@ -898,7 +909,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do              auto_play_gif: false,              display_sensitive_media: false,              reduce_motion: false, -            max_toot_chars: Keyword.get(@instance, :limit) +            max_toot_chars: limit            },            rights: %{              delete_others_notice: !!user.info["is_moderator"] @@ -958,7 +969,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do            push_subscription: nil,            accounts: accounts,            custom_emojis: mastodon_emoji, -          char_limit: Keyword.get(@instance, :limit) +          char_limit: limit          }          |> Jason.encode!() @@ -984,9 +995,29 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do      end    end +  def login(conn, %{"code" => code}) do +    with {:ok, app} <- get_or_make_app(), +         %Authorization{} = auth <- Repo.get_by(Authorization, token: code, app_id: app.id), +         {:ok, token} <- Token.exchange_token(app, auth) do +      conn +      |> put_session(:oauth_token, token.token) +      |> redirect(to: "/web/getting-started") +    end +  end +    def login(conn, _) do -    conn -    |> render(MastodonView, "login.html", %{error: false}) +    with {:ok, app} <- get_or_make_app() do +      path = +        o_auth_path(conn, :authorize, +          response_type: "code", +          client_id: app.client_id, +          redirect_uri: ".", +          scope: app.scopes +        ) + +      conn +      |> redirect(to: path) +    end    end    defp get_or_make_app() do @@ -1005,22 +1036,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do      end    end -  def login_post(conn, %{"authorization" => %{"name" => name, "password" => password}}) do -    with %User{} = user <- User.get_by_nickname_or_email(name), -         true <- Pbkdf2.checkpw(password, user.password_hash), -         {:ok, app} <- get_or_make_app(), -         {:ok, auth} <- Authorization.create_authorization(app, user), -         {:ok, token} <- Token.exchange_token(app, auth) do -      conn -      |> put_session(:oauth_token, token.token) -      |> redirect(to: "/web/getting-started") -    else -      _e -> -        conn -        |> render(MastodonView, "login.html", %{error: "Wrong username or password"}) -    end -  end -    def logout(conn, _) do      conn      |> clear_session @@ -1164,18 +1179,15 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do      |> json("Something went wrong")    end -  @suggestions Application.get_env(:pleroma, :suggestions) -    def suggestions(%{assigns: %{user: user}} = conn, _) do -    if Keyword.get(@suggestions, :enabled, false) do -      api = Keyword.get(@suggestions, :third_party_engine, "") -      timeout = Keyword.get(@suggestions, :timeout, 5000) -      limit = Keyword.get(@suggestions, :limit, 23) - -      host = -        Application.get_env(:pleroma, Pleroma.Web.Endpoint) -        |> Keyword.get(:url) -        |> Keyword.get(:host) +    suggestions = Pleroma.Config.get(:suggestions) + +    if Keyword.get(suggestions, :enabled, false) do +      api = Keyword.get(suggestions, :third_party_engine, "") +      timeout = Keyword.get(suggestions, :timeout, 5000) +      limit = Keyword.get(suggestions, :limit, 23) + +      host = Pleroma.Config.get([Pleroma.Web.Endpoint, :url, :host])        user = user.nickname        url = String.replace(api, "{{host}}", host) |> String.replace("{{user}}", user) diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 1efd99470..2d9a915f0 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -61,7 +61,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do        in_reply_to_id: nil,        in_reply_to_account_id: nil,        reblog: reblogged, -      content: reblogged[:content], +      content: reblogged[:content] || "",        created_at: created_at,        reblogs_count: 0,        replies_count: 0, @@ -230,24 +230,24 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do        if !!name and name != "" do          "<p><a href=\"#{object["id"]}\">#{name}</a></p>#{object["content"]}"        else -        object["content"] +        object["content"] || ""        end      content    end -  def render_content(%{"type" => "Article"} = object) do +  def render_content(%{"type" => object_type} = object) when object_type in ["Article", "Page"] do      summary = object["name"]      content =        if !!summary and summary != "" and is_bitstring(object["url"]) do          "<p><a href=\"#{object["url"]}\">#{summary}</a></p>#{object["content"]}"        else -        object["content"] +        object["content"] || ""        end      content    end -  def render_content(object), do: object["content"] +  def render_content(object), do: object["content"] || ""  end diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex index 5446179cb..d58f08881 100644 --- a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex +++ b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex @@ -6,6 +6,8 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do    alias Pleroma.{User, Repo}    alias Pleroma.Web.ActivityPub.MRF +  plug(Pleroma.Web.FederatingPlug) +    def schemas(conn, _params) do      response = %{        links: [ diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index 5441ee0a8..35c158fbb 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -33,25 +33,35 @@ defmodule Pleroma.Web.OAuth.OAuthController do           true <- Pbkdf2.checkpw(password, user.password_hash),           %App{} = app <- Repo.get_by(App, client_id: client_id),           {:ok, auth} <- Authorization.create_authorization(app, user) do -      if redirect_uri == "urn:ietf:wg:oauth:2.0:oob" do -        render(conn, "results.html", %{ -          auth: auth -        }) -      else -        connector = if String.contains?(redirect_uri, "?"), do: "&", else: "?" -        url = "#{redirect_uri}#{connector}" -        url_params = %{:code => auth.token} - -        url_params = -          if params["state"] do -            Map.put(url_params, :state, params["state"]) -          else -            url_params -          end - -        url = "#{url}#{Plug.Conn.Query.encode(url_params)}" - -        redirect(conn, external: url) +      # Special case: Local MastodonFE. +      redirect_uri = +        if redirect_uri == "." do +          mastodon_api_url(conn, :login) +        else +          redirect_uri +        end + +      cond do +        redirect_uri == "urn:ietf:wg:oauth:2.0:oob" -> +          render(conn, "results.html", %{ +            auth: auth +          }) + +        true -> +          connector = if String.contains?(redirect_uri, "?"), do: "&", else: "?" +          url = "#{redirect_uri}#{connector}" +          url_params = %{:code => auth.token} + +          url_params = +            if params["state"] do +              Map.put(url_params, :state, params["state"]) +            else +              url_params +            end + +          url = "#{url}#{Plug.Conn.Query.encode(url_params)}" + +          redirect(conn, external: url)        end      end    end diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex index 09d1b1110..2f92935e7 100644 --- a/lib/pleroma/web/ostatus/ostatus_controller.ex +++ b/lib/pleroma/web/ostatus/ostatus_controller.ex @@ -10,6 +10,7 @@ defmodule Pleroma.Web.OStatus.OStatusController do    alias Pleroma.Web.ActivityPub.ActivityPubController    alias Pleroma.Web.ActivityPub.ActivityPub +  plug(Pleroma.Web.FederatingPlug when action in [:salmon_incoming])    action_fallback(:errors)    def feed_redirect(conn, %{"nickname" => nickname}) do diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 7b7affe5e..06d0f0623 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -3,11 +3,6 @@ defmodule Pleroma.Web.Router do    alias Pleroma.{Repo, User, Web.Router} -  @instance Application.get_env(:pleroma, :instance) -  @federating Keyword.get(@instance, :federating) -  @public Keyword.get(@instance, :public) -  @registrations_open Keyword.get(@instance, :registrations_open) -    pipeline :api do      plug(:accepts, ["json"])      plug(:fetch_session) @@ -242,11 +237,7 @@ defmodule Pleroma.Web.Router do    end    scope "/api", Pleroma.Web do -    if @public do -      pipe_through(:api) -    else -      pipe_through(:authenticated_api) -    end +    pipe_through(:api)      get("/statuses/public_timeline", TwitterAPI.Controller, :public_timeline) @@ -281,6 +272,10 @@ defmodule Pleroma.Web.Router do      get("/statuses/mentions_timeline", TwitterAPI.Controller, :mentions_timeline)      get("/qvitter/statuses/notifications", TwitterAPI.Controller, :notifications) +    # XXX: this is really a pleroma API, but we want to keep the pleroma namespace clean +    #      for now. +    post("/qvitter/statuses/notifications/read", TwitterAPI.Controller, :notifications_read) +      post("/statuses/update", TwitterAPI.Controller, :status_update)      post("/statuses/retweet/:id", TwitterAPI.Controller, :retweet)      post("/statuses/unretweet/:id", TwitterAPI.Controller, :unretweet) @@ -330,12 +325,10 @@ defmodule Pleroma.Web.Router do      get("/users/:nickname/feed", OStatus.OStatusController, :feed)      get("/users/:nickname", OStatus.OStatusController, :feed_redirect) -    if @federating do -      post("/users/:nickname/salmon", OStatus.OStatusController, :salmon_incoming) -      post("/push/hub/:nickname", Websub.WebsubController, :websub_subscription_request) -      get("/push/subscriptions/:id", Websub.WebsubController, :websub_subscription_confirmation) -      post("/push/subscriptions/:id", Websub.WebsubController, :websub_incoming) -    end +    post("/users/:nickname/salmon", OStatus.OStatusController, :salmon_incoming) +    post("/push/hub/:nickname", Websub.WebsubController, :websub_subscription_request) +    get("/push/subscriptions/:id", Websub.WebsubController, :websub_subscription_confirmation) +    post("/push/subscriptions/:id", Websub.WebsubController, :websub_incoming)    end    pipeline :activitypub do @@ -352,29 +345,27 @@ defmodule Pleroma.Web.Router do      get("/users/:nickname/outbox", ActivityPubController, :outbox)    end -  if @federating do -    scope "/relay", Pleroma.Web.ActivityPub do -      pipe_through(:ap_relay) -      get("/", ActivityPubController, :relay) -    end +  scope "/relay", Pleroma.Web.ActivityPub do +    pipe_through(:ap_relay) +    get("/", ActivityPubController, :relay) +  end -    scope "/", Pleroma.Web.ActivityPub do -      pipe_through(:activitypub) -      post("/users/:nickname/inbox", ActivityPubController, :inbox) -      post("/inbox", ActivityPubController, :inbox) -    end +  scope "/", Pleroma.Web.ActivityPub do +    pipe_through(:activitypub) +    post("/users/:nickname/inbox", ActivityPubController, :inbox) +    post("/inbox", ActivityPubController, :inbox) +  end -    scope "/.well-known", Pleroma.Web do -      pipe_through(:well_known) +  scope "/.well-known", Pleroma.Web do +    pipe_through(:well_known) -      get("/host-meta", WebFinger.WebFingerController, :host_meta) -      get("/webfinger", WebFinger.WebFingerController, :webfinger) -      get("/nodeinfo", Nodeinfo.NodeinfoController, :schemas) -    end +    get("/host-meta", WebFinger.WebFingerController, :host_meta) +    get("/webfinger", WebFinger.WebFingerController, :webfinger) +    get("/nodeinfo", Nodeinfo.NodeinfoController, :schemas) +  end -    scope "/nodeinfo", Pleroma.Web do -      get("/:version", Nodeinfo.NodeinfoController, :nodeinfo) -    end +  scope "/nodeinfo", Pleroma.Web do +    get("/:version", Nodeinfo.NodeinfoController, :nodeinfo)    end    scope "/", Pleroma.Web.MastodonAPI do diff --git a/lib/pleroma/web/templates/mastodon_api/mastodon/login.html.eex b/lib/pleroma/web/templates/mastodon_api/mastodon/login.html.eex deleted file mode 100644 index 34cd7ed89..000000000 --- a/lib/pleroma/web/templates/mastodon_api/mastodon/login.html.eex +++ /dev/null @@ -1,11 +0,0 @@ -<h2>Login to Mastodon Frontend</h2> -<%= if @error do %> -  <h2><%= @error %></h2> -<% end %> -<%= form_for @conn, mastodon_api_path(@conn, :login), [as: "authorization"], fn f -> %> -<%= text_input f, :name, placeholder: "Username or email" %> -<br> -<%= password_input f, :password, placeholder: "Password" %> -<br> -<%= submit "Log in" %> -<% end %> diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index 01cd17121..dc4a864d6 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -6,7 +6,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do    alias Pleroma.Web.WebFinger    alias Pleroma.Web.CommonAPI    alias Comeonin.Pbkdf2 -  alias Pleroma.Formatter +  alias Pleroma.{Formatter, Emoji}    alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.{Repo, PasswordResetToken, User} @@ -134,19 +134,20 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do      end    end -  @instance Application.get_env(:pleroma, :instance) -  @instance_fe Application.get_env(:pleroma, :fe) -  @instance_chat Application.get_env(:pleroma, :chat)    def config(conn, _params) do +    instance = Pleroma.Config.get(:instance) +    instance_fe = Pleroma.Config.get(:fe) +    instance_chat = Pleroma.Config.get(:chat) +      case get_format(conn) do        "xml" ->          response = """          <config>            <site> -            <name>#{Keyword.get(@instance, :name)}</name> +            <name>#{Keyword.get(instance, :name)}</name>              <site>#{Web.base_url()}</site> -            <textlimit>#{Keyword.get(@instance, :limit)}</textlimit> -            <closed>#{!Keyword.get(@instance, :registrations_open)}</closed> +            <textlimit>#{Keyword.get(instance, :limit)}</textlimit> +            <closed>#{!Keyword.get(instance, :registrations_open)}</closed>            </site>          </config>          """ @@ -157,32 +158,32 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do        _ ->          data = %{ -          name: Keyword.get(@instance, :name), -          description: Keyword.get(@instance, :description), +          name: Keyword.get(instance, :name), +          description: Keyword.get(instance, :description),            server: Web.base_url(), -          textlimit: to_string(Keyword.get(@instance, :limit)), -          closed: if(Keyword.get(@instance, :registrations_open), do: "0", else: "1"), -          private: if(Keyword.get(@instance, :public, true), do: "0", else: "1") +          textlimit: to_string(Keyword.get(instance, :limit)), +          closed: if(Keyword.get(instance, :registrations_open), do: "0", else: "1"), +          private: if(Keyword.get(instance, :public, true), do: "0", else: "1")          }          pleroma_fe = %{ -          theme: Keyword.get(@instance_fe, :theme), -          background: Keyword.get(@instance_fe, :background), -          logo: Keyword.get(@instance_fe, :logo), -          logoMask: Keyword.get(@instance_fe, :logo_mask), -          logoMargin: Keyword.get(@instance_fe, :logo_margin), -          redirectRootNoLogin: Keyword.get(@instance_fe, :redirect_root_no_login), -          redirectRootLogin: Keyword.get(@instance_fe, :redirect_root_login), -          chatDisabled: !Keyword.get(@instance_chat, :enabled), -          showInstanceSpecificPanel: Keyword.get(@instance_fe, :show_instance_panel), -          scopeOptionsEnabled: Keyword.get(@instance_fe, :scope_options_enabled), -          formattingOptionsEnabled: Keyword.get(@instance_fe, :formatting_options_enabled), -          collapseMessageWithSubject: Keyword.get(@instance_fe, :collapse_message_with_subject), -          hidePostStats: Keyword.get(@instance_fe, :hide_post_stats), -          hideUserStats: Keyword.get(@instance_fe, :hide_user_stats) +          theme: Keyword.get(instance_fe, :theme), +          background: Keyword.get(instance_fe, :background), +          logo: Keyword.get(instance_fe, :logo), +          logoMask: Keyword.get(instance_fe, :logo_mask), +          logoMargin: Keyword.get(instance_fe, :logo_margin), +          redirectRootNoLogin: Keyword.get(instance_fe, :redirect_root_no_login), +          redirectRootLogin: Keyword.get(instance_fe, :redirect_root_login), +          chatDisabled: !Keyword.get(instance_chat, :enabled), +          showInstanceSpecificPanel: Keyword.get(instance_fe, :show_instance_panel), +          scopeOptionsEnabled: Keyword.get(instance_fe, :scope_options_enabled), +          formattingOptionsEnabled: Keyword.get(instance_fe, :formatting_options_enabled), +          collapseMessageWithSubject: Keyword.get(instance_fe, :collapse_message_with_subject), +          hidePostStats: Keyword.get(instance_fe, :hide_post_stats), +          hideUserStats: Keyword.get(instance_fe, :hide_user_stats)          } -        managed_config = Keyword.get(@instance, :managed_config) +        managed_config = Keyword.get(instance, :managed_config)          data =            if managed_config do @@ -196,7 +197,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do    end    def version(conn, _params) do -    version = Keyword.get(@instance, :version) +    version = Pleroma.Config.get([:instance, :version])      case get_format(conn) do        "xml" -> @@ -212,7 +213,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do    end    def emoji(conn, _params) do -    json(conn, Enum.into(Formatter.get_custom_emoji(), %{})) +    json(conn, Enum.into(Emoji.get_all(), %{}))    end    def follow_import(conn, %{"list" => %Plug.Upload{} = listfile}) do diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index cb483df9d..5bfb83b1e 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -6,9 +6,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do    alias Pleroma.Web.MediaProxy    import Ecto.Query -  @instance Application.get_env(:pleroma, :instance)    @httpoison Application.get_env(:pleroma, :httpoison) -  @registrations_open Keyword.get(@instance, :registrations_open)    def create_status(%User{} = user, %{"status" => _} = data) do      CommonAPI.post(user, data) @@ -21,15 +19,16 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do      end    end -  @activitypub Application.get_env(:pleroma, :activitypub) -  @follow_handshake_timeout Keyword.get(@activitypub, :follow_handshake_timeout) -    def follow(%User{} = follower, params) do      with {:ok, %User{} = followed} <- get_user(params),           {:ok, follower} <- User.maybe_direct_follow(follower, followed),           {:ok, activity} <- ActivityPub.follow(follower, followed),           {:ok, follower, followed} <- -           User.wait_and_refresh(@follow_handshake_timeout, follower, followed) do +           User.wait_and_refresh( +             Pleroma.Config.get([:activitypub, :follow_handshake_timeout]), +             follower, +             followed +           ) do        {:ok, follower, followed, activity}      else        err -> err @@ -139,18 +138,20 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do        password_confirmation: params["confirm"]      } +    registrations_open = Pleroma.Config.get([:instance, :registrations_open]) +      # no need to query DB if registration is open      token = -      unless @registrations_open || is_nil(tokenString) do +      unless registrations_open || is_nil(tokenString) do          Repo.get_by(UserInviteToken, %{token: tokenString})        end      cond do -      @registrations_open || (!is_nil(token) && !token.used) -> +      registrations_open || (!is_nil(token) && !token.used) ->          changeset = User.register_changeset(%User{}, params)          with {:ok, user} <- Repo.insert(changeset) do -          !@registrations_open && UserInviteToken.mark_as_used(token.token) +          !registrations_open && UserInviteToken.mark_as_used(token.token)            {:ok, user}          else            {:error, changeset} -> @@ -161,10 +162,10 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do              {:error, %{error: errors}}          end -      !@registrations_open && is_nil(token) -> +      !registrations_open && is_nil(token) ->          {:error, "Invalid token"} -      !@registrations_open && token.used -> +      !registrations_open && token.used ->          {:error, "Expired token"}      end    end diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex index 7153a2bd6..727469a66 100644 --- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex +++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex @@ -11,6 +11,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do    require Logger +  plug(:only_if_public_instance when action in [:public_timeline, :public_and_external_timeline])    action_fallback(:errors)    def verify_credentials(%{assigns: %{user: user}} = conn, _params) do @@ -132,6 +133,19 @@ defmodule Pleroma.Web.TwitterAPI.Controller do      |> render(NotificationView, "notification.json", %{notifications: notifications, for: user})    end +  def notifications_read(%{assigns: %{user: user}} = conn, %{"latest_id" => latest_id} = params) do +    Notification.set_read_up_to(user, latest_id) + +    notifications = Notification.for_user(user, params) + +    conn +    |> render(NotificationView, "notification.json", %{notifications: notifications, for: user}) +  end + +  def notifications_read(%{assigns: %{user: user}} = conn, _) do +    bad_request_reply(conn, "You need to specify latest_id") +  end +    def follow(%{assigns: %{user: user}} = conn, params) do      case TwitterAPI.follow(user, params) do        {:ok, user, followed, _activity} -> @@ -518,6 +532,18 @@ defmodule Pleroma.Web.TwitterAPI.Controller do      json_reply(conn, 403, json)    end +  def only_if_public_instance(conn = %{conn: %{assigns: %{user: _user}}}, _), do: conn + +  def only_if_public_instance(conn, _) do +    if Keyword.get(Application.get_env(:pleroma, :instance), :public) do +      conn +    else +      conn +      |> forbidden_json_reply("Invalid credentials.") +      |> halt() +    end +  end +    defp error_json(conn, error_message) do      %{"error" => error_message, "request" => conn.request_path} |> Jason.encode!()    end diff --git a/lib/pleroma/web/twitter_api/views/activity_view.ex b/lib/pleroma/web/twitter_api/views/activity_view.ex index fb97f199b..83e8fb765 100644 --- a/lib/pleroma/web/twitter_api/views/activity_view.ex +++ b/lib/pleroma/web/twitter_api/views/activity_view.ex @@ -283,11 +283,11 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do      {summary, content}    end -  def render_content(%{"type" => "Article"} = object) do +  def render_content(%{"type" => object_type} = object) when object_type in ["Article", "Page"] do      summary = object["name"] || object["summary"]      content = -      if !!summary and summary != "" do +      if !!summary and summary != "" and is_bitstring(object["url"]) do          "<p><a href=\"#{object["url"]}\">#{summary}</a></p>#{object["content"]}"        else          object["content"] diff --git a/lib/pleroma/web/web_finger/web_finger_controller.ex b/lib/pleroma/web/web_finger/web_finger_controller.ex index 50d816256..002353166 100644 --- a/lib/pleroma/web/web_finger/web_finger_controller.ex +++ b/lib/pleroma/web/web_finger/web_finger_controller.ex @@ -3,6 +3,8 @@ defmodule Pleroma.Web.WebFinger.WebFingerController do    alias Pleroma.Web.WebFinger +  plug(Pleroma.Web.FederatingPlug) +    def host_meta(conn, _params) do      xml = WebFinger.host_meta() diff --git a/lib/pleroma/web/websub/websub_controller.ex b/lib/pleroma/web/websub/websub_controller.ex index 590dd74a1..c1934ba92 100644 --- a/lib/pleroma/web/websub/websub_controller.ex +++ b/lib/pleroma/web/websub/websub_controller.ex @@ -5,6 +5,15 @@ defmodule Pleroma.Web.Websub.WebsubController do    alias Pleroma.Web.Websub.WebsubClientSubscription    require Logger +  plug( +    Pleroma.Web.FederatingPlug +    when action in [ +           :websub_subscription_request, +           :websub_subscription_confirmation, +           :websub_incoming +         ] +  ) +    def websub_subscription_request(conn, %{"nickname" => nickname} = params) do      user = User.get_cached_by_nickname(nickname) | 
