diff options
Diffstat (limited to 'lib')
25 files changed, 516 insertions, 84 deletions
diff --git a/lib/mix/tasks/relay_follow.ex b/lib/mix/tasks/relay_follow.ex index 4d57c6bca..85b1c024d 100644 --- a/lib/mix/tasks/relay_follow.ex +++ b/lib/mix/tasks/relay_follow.ex @@ -14,9 +14,11 @@ defmodule Mix.Tasks.RelayFollow do    def run([target]) do      Mix.Task.run("app.start") -    :ok = Relay.follow(target) - -    # put this task to sleep to allow the genserver to push out the messages -    :timer.sleep(500) +    with {:ok, activity} <- Relay.follow(target) do +      # put this task to sleep to allow the genserver to push out the messages +      :timer.sleep(500) +    else +      {:error, e} -> Mix.shell().error("Error while following #{target}: #{inspect(e)}") +    end    end  end diff --git a/lib/mix/tasks/relay_unfollow.ex b/lib/mix/tasks/relay_unfollow.ex index bd69fd8a0..237fb771c 100644 --- a/lib/mix/tasks/relay_unfollow.ex +++ b/lib/mix/tasks/relay_unfollow.ex @@ -13,9 +13,11 @@ defmodule Mix.Tasks.RelayUnfollow do    def run([target]) do      Mix.Task.run("app.start") -    :ok = Relay.unfollow(target) - -    # put this task to sleep to allow the genserver to push out the messages -    :timer.sleep(500) +    with {:ok, activity} <- Relay.follow(target) do +      # put this task to sleep to allow the genserver to push out the messages +      :timer.sleep(500) +    else +      {:error, e} -> Mix.shell().error("Error while following #{target}: #{inspect(e)}") +    end    end  end diff --git a/lib/mix/tasks/set_admin.ex b/lib/mix/tasks/set_admin.ex new file mode 100644 index 000000000..d5ccf261b --- /dev/null +++ b/lib/mix/tasks/set_admin.ex @@ -0,0 +1,32 @@ +defmodule Mix.Tasks.SetAdmin do +  use Mix.Task +  alias Pleroma.User + +  @doc """ +  Sets admin status +  Usage: set_admin nickname [true|false] +  """ +  def run([nickname | rest]) do +    Application.ensure_all_started(:pleroma) + +    status = +      case rest do +        [status] -> status == "true" +        _ -> true +      end + +    with %User{local: true} = user <- User.get_by_nickname(nickname) do +      info = +        user.info +        |> Map.put("is_admin", !!status) + +      cng = User.info_changeset(user, %{info: info}) +      {:ok, user} = User.update_and_set_cache(cng) + +      IO.puts("Admin status of #{nickname}: #{user.info["is_admin"]}") +    else +      _ -> +        IO.puts("No local user #{nickname}") +    end +  end +end diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index eedad7675..2d86efae5 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -1,8 +1,15 @@  defmodule Pleroma.Application do    use Application +  @name "Pleroma" +  @version Mix.Project.config()[:version] +  def name, do: @name +  def version, do: @version +  def named_version(), do: @name <> " " <> @version +    # See http://elixir-lang.org/docs/stable/elixir/Application.html    # for more information on OTP Applications +  @env Mix.env()    def start(_type, _args) do      import Supervisor.Spec      import Cachex.Spec @@ -57,10 +64,11 @@ defmodule Pleroma.Application do            id: :cachex_idem          ),          worker(Pleroma.Web.Federator, []), -        worker(Pleroma.Stats, []), -        worker(Pleroma.Gopher.Server, []) +        worker(Pleroma.Web.Federator.RetryQueue, []), +        worker(Pleroma.Gopher.Server, []), +        worker(Pleroma.Stats, [])        ] ++ -        if Mix.env() == :test, +        if @env == :test,            do: [],            else:              [worker(Pleroma.Web.Streamer, [])] ++ diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index 067ecfaf4..03a75dfbd 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -31,10 +31,12 @@ defmodule Pleroma.Object do    def normalize(ap_id) when is_binary(ap_id), do: Object.get_by_ap_id(ap_id)    def normalize(_), do: nil -  def get_cached_by_ap_id(ap_id) do -    if Mix.env() == :test do +  if Mix.env() == :test do +    def get_cached_by_ap_id(ap_id) do        get_by_ap_id(ap_id) -    else +    end +  else +    def get_cached_by_ap_id(ap_id) do        key = "object:#{ap_id}"        Cachex.fetch!(:object_cache, key, fn _ -> diff --git a/lib/pleroma/plugs/http_security_plug.ex b/lib/pleroma/plugs/http_security_plug.ex index 31c7332f8..4c32653ea 100644 --- a/lib/pleroma/plugs/http_security_plug.ex +++ b/lib/pleroma/plugs/http_security_plug.ex @@ -29,6 +29,8 @@ defmodule Pleroma.Plugs.HTTPSecurityPlug do    end    defp csp_string do +    protocol = Config.get([Pleroma.Web.Endpoint, :protocol]) +      [        "default-src 'none'",        "base-uri 'self'", @@ -39,7 +41,10 @@ defmodule Pleroma.Plugs.HTTPSecurityPlug do        "font-src 'self'",        "script-src 'self'",        "connect-src 'self' " <> String.replace(Pleroma.Web.Endpoint.static_url(), "http", "ws"), -      "upgrade-insecure-requests" +      "manifest-src 'self'", +      if @protocol == "https" do +        "upgrade-insecure-requests" +      end      ]      |> Enum.join("; ")    end diff --git a/lib/pleroma/plugs/user_is_admin_plug.ex b/lib/pleroma/plugs/user_is_admin_plug.ex new file mode 100644 index 000000000..5312f1499 --- /dev/null +++ b/lib/pleroma/plugs/user_is_admin_plug.ex @@ -0,0 +1,19 @@ +defmodule Pleroma.Plugs.UserIsAdminPlug do +  import Plug.Conn +  alias Pleroma.User + +  def init(options) do +    options +  end + +  def call(%{assigns: %{user: %User{info: %{"is_admin" => true}}}} = conn, _) do +    conn +  end + +  def call(conn, _) do +    conn +    |> put_resp_content_type("application/json") +    |> send_resp(403, Jason.encode!(%{error: "User is not admin."})) +    |> halt +  end +end diff --git a/lib/pleroma/upload.ex b/lib/pleroma/upload.ex index 89aa779f9..238630bf3 100644 --- a/lib/pleroma/upload.ex +++ b/lib/pleroma/upload.ex @@ -162,7 +162,13 @@ defmodule Pleroma.Upload do              "audio/mpeg"            <<0x4F, 0x67, 0x67, 0x53, 0x00, 0x02, 0x00, 0x00>> -> -            "audio/ogg" +            case IO.binread(f, 27) do +              <<_::size(160), 0x80, 0x74, 0x68, 0x65, 0x6F, 0x72, 0x61>> -> +                "video/ogg" + +              _ -> +                "audio/ogg" +            end            <<0x52, 0x49, 0x46, 0x46, _, _, _, _>> ->              "audio/wav" diff --git a/lib/pleroma/web/activity_pub/mrf/user_allowlist.ex b/lib/pleroma/web/activity_pub/mrf/user_allowlist.ex new file mode 100644 index 000000000..3503d8692 --- /dev/null +++ b/lib/pleroma/web/activity_pub/mrf/user_allowlist.ex @@ -0,0 +1,23 @@ +defmodule Pleroma.Web.ActivityPub.MRF.UserAllowListPolicy do +  alias Pleroma.Config + +  @behaviour Pleroma.Web.ActivityPub.MRF + +  defp filter_by_list(object, []), do: {:ok, object} + +  defp filter_by_list(%{"actor" => actor} = object, allow_list) do +    if actor in allow_list do +      {:ok, object} +    else +      {:reject, nil} +    end +  end + +  @impl true +  def filter(object) do +    actor_info = URI.parse(object["actor"]) +    allow_list = Config.get([:mrf_user_allowlist, String.to_atom(actor_info.host)], []) + +    filter_by_list(object, allow_list) +  end +end diff --git a/lib/pleroma/web/activity_pub/relay.ex b/lib/pleroma/web/activity_pub/relay.ex index d30853d62..fcdc6b1c0 100644 --- a/lib/pleroma/web/activity_pub/relay.ex +++ b/lib/pleroma/web/activity_pub/relay.ex @@ -12,11 +12,12 @@ defmodule Pleroma.Web.ActivityPub.Relay do           %User{} = target_user <- User.get_or_fetch_by_ap_id(target_instance),           {:ok, activity} <- ActivityPub.follow(local_user, target_user) do        Logger.info("relay: followed instance: #{target_instance}; id=#{activity.data["id"]}") +      {:ok, activity}      else -      e -> Logger.error("error: #{inspect(e)}") +      e -> +        Logger.error("error: #{inspect(e)}") +        {:error, e}      end - -    :ok    end    def unfollow(target_instance) do @@ -24,11 +25,12 @@ defmodule Pleroma.Web.ActivityPub.Relay do           %User{} = target_user <- User.get_or_fetch_by_ap_id(target_instance),           {:ok, activity} <- ActivityPub.unfollow(local_user, target_user) do        Logger.info("relay: unfollowed instance: #{target_instance}: id=#{activity.data["id"]}") +      {:ok, activity}      else -      e -> Logger.error("error: #{inspect(e)}") +      e -> +        Logger.error("error: #{inspect(e)}") +        {:error, e}      end - -    :ok    end    def publish(%Activity{data: %{"type" => "Create"}} = activity) do diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex new file mode 100644 index 000000000..bcdb4ba37 --- /dev/null +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -0,0 +1,158 @@ +defmodule Pleroma.Web.AdminAPI.AdminAPIController do +  use Pleroma.Web, :controller +  alias Pleroma.{User, Repo} +  alias Pleroma.Web.ActivityPub.Relay + +  require Logger + +  action_fallback(:errors) + +  def user_delete(conn, %{"nickname" => nickname}) do +    user = User.get_by_nickname(nickname) + +    if user.local == true do +      User.delete(user) +    else +      User.delete(user) +    end + +    conn +    |> json(nickname) +  end + +  def user_create( +        conn, +        %{"nickname" => nickname, "email" => email, "password" => password} +      ) do +    new_user = %{ +      nickname: nickname, +      name: nickname, +      email: email, +      password: password, +      password_confirmation: password, +      bio: "." +    } + +    User.register_changeset(%User{}, new_user) +    |> Repo.insert!() + +    conn +    |> json(new_user.nickname) +  end + +  def right_add(conn, %{"permission_group" => permission_group, "nickname" => nickname}) +      when permission_group in ["moderator", "admin"] do +    user = User.get_by_nickname(nickname) + +    info = +      user.info +      |> Map.put("is_" <> permission_group, true) + +    cng = User.info_changeset(user, %{info: info}) +    {:ok, user} = User.update_and_set_cache(cng) + +    conn +    |> json(user.info) +  end + +  def right_get(conn, %{"nickname" => nickname}) do +    user = User.get_by_nickname(nickname) + +    conn +    |> json(user.info) +  end + +  def right_add(conn, _) do +    conn +    |> put_status(404) +    |> json(%{error: "No such permission_group"}) +  end + +  def right_delete( +        %{assigns: %{user: %User{:nickname => admin_nickname}}} = conn, +        %{ +          "permission_group" => permission_group, +          "nickname" => nickname +        } +      ) +      when permission_group in ["moderator", "admin"] do +    if admin_nickname == nickname do +      conn +      |> put_status(403) +      |> json(%{error: "You can't revoke your own admin status."}) +    else +      user = User.get_by_nickname(nickname) + +      info = +        user.info +        |> Map.put("is_" <> permission_group, false) + +      cng = User.info_changeset(user, %{info: info}) +      {:ok, user} = User.update_and_set_cache(cng) + +      conn +      |> json(user.info) +    end +  end + +  def right_delete(conn, _) do +    conn +    |> put_status(404) +    |> json(%{error: "No such permission_group"}) +  end + +  def relay_follow(conn, %{"relay_url" => target}) do +    {status, message} = Relay.follow(target) + +    if status == :ok do +      conn +      |> json(target) +    else +      conn +      |> put_status(500) +      |> json(target) +    end +  end + +  def relay_unfollow(conn, %{"relay_url" => target}) do +    {status, message} = Relay.unfollow(target) + +    if status == :ok do +      conn +      |> json(target) +    else +      conn +      |> put_status(500) +      |> json(target) +    end +  end + +  @shortdoc "Get a account registeration invite token (base64 string)" +  def get_invite_token(conn, _params) do +    {:ok, token} = Pleroma.UserInviteToken.create_token() + +    conn +    |> json(token.token) +  end + +  @shortdoc "Get a password reset token (base64 string) for given nickname" +  def get_password_reset(conn, %{"nickname" => nickname}) do +    (%User{local: true} = user) = User.get_by_nickname(nickname) +    {:ok, token} = Pleroma.PasswordResetToken.create_token(user) + +    conn +    |> json(token.token) +  end + +  def errors(conn, {:param_cast, _}) do +    conn +    |> put_status(400) +    |> json("Invalid parameters") +  end + +  def errors(conn, _) do +    conn +    |> put_status(500) +    |> json("Something went wrong") +  end +end diff --git a/lib/pleroma/web/channels/user_socket.ex b/lib/pleroma/web/channels/user_socket.ex index 21b22b409..07ddee169 100644 --- a/lib/pleroma/web/channels/user_socket.ex +++ b/lib/pleroma/web/channels/user_socket.ex @@ -4,9 +4,7 @@ defmodule Pleroma.Web.UserSocket do    ## Channels    # channel "room:*", Pleroma.Web.RoomChannel -  if Application.get_env(:pleroma, :chat) |> Keyword.get(:enabled) do -    channel("chat:*", Pleroma.Web.ChatChannel) -  end +  channel("chat:*", Pleroma.Web.ChatChannel)    ## Transports    transport(:websocket, Phoenix.Transports.WebSocket) @@ -24,7 +22,8 @@ defmodule Pleroma.Web.UserSocket do    # See `Phoenix.Token` documentation for examples in    # performing token verification on connect.    def connect(%{"token" => token}, socket) do -    with {:ok, user_id} <- Phoenix.Token.verify(socket, "user socket", token, max_age: 84600), +    with true <- Pleroma.Config.get([:chat, :enabled]), +         {:ok, user_id} <- Phoenix.Token.verify(socket, "user socket", token, max_age: 84600),           %User{} = user <- Pleroma.Repo.get(User, user_id) do        {:ok, assign(socket, :user_name, user.nickname)}      else diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex index 85bb4ff5f..8728c908b 100644 --- a/lib/pleroma/web/endpoint.ex +++ b/lib/pleroma/web/endpoint.ex @@ -1,9 +1,7 @@  defmodule Pleroma.Web.Endpoint do    use Phoenix.Endpoint, otp_app: :pleroma -  if Application.get_env(:pleroma, :chat) |> Keyword.get(:enabled) do -    socket("/socket", Pleroma.Web.UserSocket) -  end +  socket("/socket", Pleroma.Web.UserSocket)    socket("/api/v1", Pleroma.Web.MastodonAPI.MastodonSocket) @@ -58,7 +56,7 @@ defmodule Pleroma.Web.Endpoint do      Plug.Session,      store: :cookie,      key: cookie_name, -    signing_salt: "CqaoopA2", +    signing_salt: {Pleroma.Config, :get, [[__MODULE__, :signing_salt], "CqaoopA2"]},      http_only: true,      secure:        Application.get_env(:pleroma, Pleroma.Web.Endpoint) |> Keyword.get(:secure_cookie_flag), diff --git a/lib/pleroma/web/federator/federator.ex b/lib/pleroma/web/federator/federator.ex index 6554fd2ef..ac3d7c132 100644 --- a/lib/pleroma/web/federator/federator.ex +++ b/lib/pleroma/web/federator/federator.ex @@ -3,6 +3,7 @@ defmodule Pleroma.Web.Federator do    alias Pleroma.User    alias Pleroma.Activity    alias Pleroma.Web.{WebFinger, Websub} +  alias Pleroma.Web.Federator.RetryQueue    alias Pleroma.Web.ActivityPub.ActivityPub    alias Pleroma.Web.ActivityPub.Relay    alias Pleroma.Web.ActivityPub.Transmogrifier @@ -122,29 +123,25 @@ defmodule Pleroma.Web.Federator do    end    def handle(:publish_single_ap, params) do -    ActivityPub.publish_one(params) -  end - -  def handle(:publish_single_websub, %{xml: xml, topic: topic, callback: callback, secret: secret}) do -    signature = @websub.sign(secret || "", xml) -    Logger.debug(fn -> "Pushing #{topic} to #{callback}" end) - -    with {:ok, %{status_code: code}} <- -           @httpoison.post( -             callback, -             xml, -             [ -               {"Content-Type", "application/atom+xml"}, -               {"X-Hub-Signature", "sha1=#{signature}"} -             ], -             timeout: 10000, -             recv_timeout: 20000, -             hackney: [pool: :default] -           ) do -      Logger.debug(fn -> "Pushed to #{callback}, code #{code}" end) -    else -      e -> -        Logger.debug(fn -> "Couldn't push to #{callback}, #{inspect(e)}" end) +    case ActivityPub.publish_one(params) do +      {:ok, _} -> +        :ok + +      {:error, _} -> +        RetryQueue.enqueue(params, ActivityPub) +    end +  end + +  def handle( +        :publish_single_websub, +        %{xml: xml, topic: topic, callback: callback, secret: secret} = params +      ) do +    case Websub.publish_one(params) do +      {:ok, _} -> +        :ok + +      {:error, _} -> +        RetryQueue.enqueue(params, Websub)      end    end @@ -153,11 +150,15 @@ defmodule Pleroma.Web.Federator do      {:error, "Don't know what to do with this"}    end -  def enqueue(type, payload, priority \\ 1) do -    if Pleroma.Config.get([:instance, :federating]) do -      if Mix.env() == :test do +  if Mix.env() == :test do +    def enqueue(type, payload, priority \\ 1) do +      if Pleroma.Config.get([:instance, :federating]) do          handle(type, payload) -      else +      end +    end +  else +    def enqueue(type, payload, priority \\ 1) do +      if Pleroma.Config.get([:instance, :federating]) do          GenServer.cast(__MODULE__, {:enqueue, type, payload, priority})        end      end diff --git a/lib/pleroma/web/federator/retry_queue.ex b/lib/pleroma/web/federator/retry_queue.ex new file mode 100644 index 000000000..06c094f26 --- /dev/null +++ b/lib/pleroma/web/federator/retry_queue.ex @@ -0,0 +1,71 @@ +defmodule Pleroma.Web.Federator.RetryQueue do +  use GenServer +  alias Pleroma.Web.{WebFinger, Websub} +  alias Pleroma.Web.ActivityPub.ActivityPub +  require Logger + +  @websub Application.get_env(:pleroma, :websub) +  @ostatus Application.get_env(:pleroma, :websub) +  @httpoison Application.get_env(:pleroma, :websub) +  @instance Application.get_env(:pleroma, :websub) +  # initial timeout, 5 min +  @initial_timeout 30_000 +  @max_retries 5 + +  def init(args) do +    {:ok, args} +  end + +  def start_link() do +    GenServer.start_link(__MODULE__, %{delivered: 0, dropped: 0}, name: __MODULE__) +  end + +  def enqueue(data, transport, retries \\ 0) do +    GenServer.cast(__MODULE__, {:maybe_enqueue, data, transport, retries + 1}) +  end + +  def get_retry_params(retries) do +    if retries > @max_retries do +      {:drop, "Max retries reached"} +    else +      {:retry, growth_function(retries)} +    end +  end + +  def handle_cast({:maybe_enqueue, data, transport, retries}, %{dropped: drop_count} = state) do +    case get_retry_params(retries) do +      {:retry, timeout} -> +        Process.send_after( +          __MODULE__, +          {:send, data, transport, retries}, +          growth_function(retries) +        ) + +        {:noreply, state} + +      {:drop, message} -> +        Logger.debug(message) +        {:noreply, %{state | dropped: drop_count + 1}} +    end +  end + +  def handle_info({:send, data, transport, retries}, %{delivered: delivery_count} = state) do +    case transport.publish_one(data) do +      {:ok, _} -> +        {:noreply, %{state | delivered: delivery_count + 1}} + +      {:error, reason} -> +        enqueue(data, transport, retries) +        {:noreply, state} +    end +  end + +  def handle_info(unknown, state) do +    Logger.debug("RetryQueue: don't know what to do with #{inspect(unknown)}, ignoring") +    {:noreply, state} +  end + +  defp growth_function(retries) do +    round(@initial_timeout * :math.pow(retries, 3)) +  end +end diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex index bfd0f7ff4..3a49a96a1 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex @@ -141,7 +141,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do        uri: Web.base_url(),        title: Keyword.get(instance, :name),        description: Keyword.get(instance, :description), -      version: "#{@mastodon_api_level} (compatible; #{Keyword.get(instance, :version)})", +      version: "#{@mastodon_api_level} (compatible; #{Pleroma.Application.named_version()})",        email: Keyword.get(instance, :email),        urls: %{          streaming_api: String.replace(Pleroma.Web.Endpoint.static_url(), "http", "ws") diff --git a/lib/pleroma/web/mastodon_api/mastodon_socket.ex b/lib/pleroma/web/mastodon_api/mastodon_socket.ex index 0f3d5ff7c..f3c13d1aa 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_socket.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_socket.ex @@ -11,9 +11,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonSocket do      timeout: :infinity    ) -  def connect(params, socket) do -    with token when not is_nil(token) <- params["access_token"], -         %Token{user_id: user_id} <- Repo.get_by(Token, token: token), +  def connect(%{"access_token" => token} = params, socket) do +    with %Token{user_id: user_id} <- Repo.get_by(Token, token: token),           %User{} = user <- Repo.get(User, user_id),           stream           when stream in [ @@ -45,6 +44,24 @@ defmodule Pleroma.Web.MastodonAPI.MastodonSocket do      end    end +  def connect(%{"stream" => stream} = params, socket) +      when stream in ["public", "public:local", "hashtag"] do +    topic = +      case stream do +        "hashtag" -> "hashtag:#{params["tag"]}" +        _ -> stream +      end + +    with socket = +           socket +           |> assign(:topic, topic) do +      Pleroma.Web.Streamer.add_socket(topic, socket) +      {:ok, socket} +    else +      _e -> :error +    end +  end +    def id(_), do: nil    def handle(:text, message, _state) do diff --git a/lib/pleroma/web/media_proxy/media_proxy.ex b/lib/pleroma/web/media_proxy/media_proxy.ex index 93c36b4ed..0fc0a07b2 100644 --- a/lib/pleroma/web/media_proxy/media_proxy.ex +++ b/lib/pleroma/web/media_proxy/media_proxy.ex @@ -3,6 +3,8 @@ defmodule Pleroma.Web.MediaProxy do    def url(nil), do: nil +  def url(""), do: nil +    def url(url = "/" <> _), do: url    def url(url) do @@ -15,10 +17,10 @@ defmodule Pleroma.Web.MediaProxy do        base64 = Base.url_encode64(url, @base64_opts)        sig = :crypto.hmac(:sha, secret, base64)        sig64 = sig |> Base.url_encode64(@base64_opts) -      filename = Path.basename(URI.parse(url).path) +      filename = if path = URI.parse(url).path, do: "/" <> Path.basename(path), else: ""        Keyword.get(config, :base_url, Pleroma.Web.base_url()) <> -        "/proxy/#{sig64}/#{base64}/#{filename}" +        "/proxy/#{sig64}/#{base64}#{filename}"      end    end diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex index d58f08881..2ea75cf16 100644 --- a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex +++ b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex @@ -4,6 +4,7 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do    alias Pleroma.Stats    alias Pleroma.Web    alias Pleroma.{User, Repo} +  alias Pleroma.Config    alias Pleroma.Web.ActivityPub.MRF    plug(Pleroma.Web.FederatingPlug) @@ -52,6 +53,10 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do        |> Repo.all()        |> Enum.map(fn u -> u.ap_id end) +    mrf_user_allowlist = +      Config.get([:mrf_user_allowlist], []) +      |> Enum.into(%{}, fn {k, v} -> {k, length(v)} end) +      mrf_transparency = Keyword.get(instance, :mrf_transparency)      federation_response = @@ -59,6 +64,7 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do          %{            mrf_policies: mrf_policies,            mrf_simple: mrf_simple, +          mrf_user_allowlist: mrf_user_allowlist,            quarantined_instances: quarantined          }        else @@ -86,8 +92,8 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do      response = %{        version: "2.0",        software: %{ -        name: "pleroma", -        version: Keyword.get(instance, :version) +        name: Pleroma.Application.name(), +        version: Pleroma.Application.version()        },        protocols: ["ostatus", "activitypub"],        services: %{ diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex index 34fdf9727..af6e22c2b 100644 --- a/lib/pleroma/web/ostatus/ostatus_controller.ex +++ b/lib/pleroma/web/ostatus/ostatus_controller.ex @@ -136,7 +136,7 @@ defmodule Pleroma.Web.OStatus.OStatusController do          "html" ->            conn            |> put_resp_content_type("text/html") -          |> send_file(200, "priv/static/index.html") +          |> send_file(200, Application.app_dir(:pleroma, "priv/static/index.html"))          _ ->            represent_activity(conn, format, activity, user) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index a8468ea12..d6a9d5779 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -31,6 +31,21 @@ defmodule Pleroma.Web.Router do      plug(Pleroma.Plugs.EnsureAuthenticatedPlug)    end +  pipeline :admin_api do +    plug(:accepts, ["json"]) +    plug(:fetch_session) +    plug(Pleroma.Plugs.OAuthPlug) +    plug(Pleroma.Plugs.BasicAuthDecoderPlug) +    plug(Pleroma.Plugs.UserFetcherPlug) +    plug(Pleroma.Plugs.SessionAuthenticationPlug) +    plug(Pleroma.Plugs.LegacyAuthenticationPlug) +    plug(Pleroma.Plugs.AuthenticationPlug) +    plug(Pleroma.Plugs.UserEnabledPlug) +    plug(Pleroma.Plugs.SetUserSessionIdPlug) +    plug(Pleroma.Plugs.EnsureAuthenticatedPlug) +    plug(Pleroma.Plugs.UserIsAdminPlug) +  end +    pipeline :mastodon_html do      plug(:accepts, ["html"])      plug(:fetch_session) @@ -79,6 +94,23 @@ defmodule Pleroma.Web.Router do      get("/emoji", UtilController, :emoji)    end +  scope "/api/pleroma/admin", Pleroma.Web.AdminAPI do +    pipe_through(:admin_api) +    delete("/user", AdminAPIController, :user_delete) +    post("/user", AdminAPIController, :user_create) + +    get("/permission_group/:nickname", AdminAPIController, :right_get) +    get("/permission_group/:nickname/:permission_group", AdminAPIController, :right_get) +    post("/permission_group/:nickname/:permission_group", AdminAPIController, :right_add) +    delete("/permission_group/:nickname/:permission_group", AdminAPIController, :right_delete) + +    post("/relay", AdminAPIController, :relay_follow) +    delete("/relay", AdminAPIController, :relay_unfollow) + +    get("/invite_token", AdminAPIController, :get_invite_token) +    get("/password_reset", AdminAPIController, :get_password_reset) +  end +    scope "/", Pleroma.Web.TwitterAPI do      pipe_through(:pleroma_html)      get("/ostatus_subscribe", UtilController, :remote_follow) @@ -398,11 +430,9 @@ defmodule Fallback.RedirectController do    use Pleroma.Web, :controller    def redirector(conn, _params) do -    if Mix.env() != :test do -      conn -      |> put_resp_content_type("text/html") -      |> send_file(200, "priv/static/index.html") -    end +    conn +    |> put_resp_content_type("text/html") +    |> send_file(200, Application.app_dir(:pleroma, "priv/static/index.html"))    end    def registration_page(conn, params) do diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex index 209450383..99b8b7063 100644 --- a/lib/pleroma/web/streamer.ex +++ b/lib/pleroma/web/streamer.ex @@ -73,7 +73,8 @@ defmodule Pleroma.Web.Streamer do            Pleroma.List.get_lists_from_activity(item)            |> Enum.filter(fn list ->              owner = Repo.get(User, list.user_id) -            author.follower_address in owner.following + +            ActivityPub.visible_for_user?(item, owner)            end)        end @@ -169,16 +170,33 @@ defmodule Pleroma.Web.Streamer do      |> Jason.encode!()    end +  defp represent_update(%Activity{} = activity) do +    %{ +      event: "update", +      payload: +        Pleroma.Web.MastodonAPI.StatusView.render( +          "status.json", +          activity: activity +        ) +        |> Jason.encode!() +    } +    |> Jason.encode!() +  end +    def push_to_socket(topics, topic, %Activity{data: %{"type" => "Announce"}} = item) do      Enum.each(topics[topic] || [], fn socket ->        # Get the current user so we have up-to-date blocks etc. -      user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id) -      blocks = user.info.blocks || [] +      if socket.assigns[:user] do +        user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id) +        blocks = user.info.blocks || [] -      parent = Object.normalize(item.data["object"]) +        parent = Object.normalize(item.data["object"]) -      unless is_nil(parent) or item.actor in blocks or parent.data["actor"] in blocks do -        send(socket.transport_pid, {:text, represent_update(item, user)}) +        unless is_nil(parent) or item.actor in blocks or parent.data["actor"] in blocks do +          send(socket.transport_pid, {:text, represent_update(item, user)}) +        end +      else +        send(socket.transport_pid, {:text, represent_update(item)})        end      end)    end @@ -186,11 +204,15 @@ defmodule Pleroma.Web.Streamer do    def push_to_socket(topics, topic, item) do      Enum.each(topics[topic] || [], fn socket ->        # Get the current user so we have up-to-date blocks etc. -      user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id) -      blocks = user.info.blocks || [] - -      unless item.actor in blocks do -        send(socket.transport_pid, {:text, represent_update(item, user)}) +      if socket.assigns[:user] do +        user = User.get_cached_by_ap_id(socket.assigns[:user].ap_id) +        blocks = user.info.blocks || [] + +        unless item.actor in blocks do +          send(socket.transport_pid, {:text, represent_update(item, user)}) +        end +      else +        send(socket.transport_pid, {:text, represent_update(item)})        end      end)    end diff --git a/lib/pleroma/web/templates/layout/app.html.eex b/lib/pleroma/web/templates/layout/app.html.eex index 2a8dede80..2e96c1509 100644 --- a/lib/pleroma/web/templates/layout/app.html.eex +++ b/lib/pleroma/web/templates/layout/app.html.eex @@ -2,7 +2,9 @@  <html>    <head>      <meta charset=utf-8 /> -    <title>Pleroma</title> +    <title> +    <%= Application.get_env(:pleroma, :instance)[:name] %> +    </title>      <style>        body {          background-color: #282c37; diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex index dc4a864d6..b0ed8387e 100644 --- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex +++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex @@ -197,7 +197,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do    end    def version(conn, _params) do -    version = Pleroma.Config.get([:instance, :version]) +    version = Pleroma.Application.named_version()      case get_format(conn) do        "xml" -> diff --git a/lib/pleroma/web/websub/websub.ex b/lib/pleroma/web/websub/websub.ex index 440b48665..905d8d658 100644 --- a/lib/pleroma/web/websub/websub.ex +++ b/lib/pleroma/web/websub/websub.ex @@ -252,4 +252,29 @@ defmodule Pleroma.Web.Websub do        Pleroma.Web.Federator.enqueue(:request_subscription, sub)      end)    end + +  def publish_one(%{xml: xml, topic: topic, callback: callback, secret: secret}) do +    signature = sign(secret || "", xml) +    Logger.info(fn -> "Pushing #{topic} to #{callback}" end) + +    with {:ok, %{status_code: code}} <- +           @httpoison.post( +             callback, +             xml, +             [ +               {"Content-Type", "application/atom+xml"}, +               {"X-Hub-Signature", "sha1=#{signature}"} +             ], +             timeout: 10000, +             recv_timeout: 20000, +             hackney: [pool: :default] +           ) do +      Logger.info(fn -> "Pushed to #{callback}, code #{code}" end) +      {:ok, code} +    else +      e -> +        Logger.debug(fn -> "Couldn't push to #{callback}, #{inspect(e)}" end) +        {:error, e} +    end +  end  end  | 
